Merge "Cleanup USER_OWNER in a11y manager and tests"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 48be749..6e44d77 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -235,6 +235,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libinputflingerhost_intermediates $(PRODUCT_OUT)/obj_arm/SHARED_LIBRARIES/libinputflingerhost_intermediates)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/target/common/obj/framework.aidl)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/DocumentsUI_intermediates)
 
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/api/current.txt b/api/current.txt
index 1eb37b3..f5e2cda 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -992,6 +992,7 @@
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
+    field public static final int resizeableActivity = 16844022; // 0x10104f6
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
diff --git a/api/system-current.txt b/api/system-current.txt
index f913e6c..ec8f952 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1084,6 +1084,7 @@
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
+    field public static final int resizeableActivity = 16844022; // 0x10104f6
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ec0cc6d..d4e6c82 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -100,6 +100,16 @@
     public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
 
     /**
+     * A temporary hack until SUPL system can get off the legacy APIS.
+     * They do too many network requests and the long list of apps listening
+     * and waking due to the CONNECTIVITY_ACTION bcast makes it expensive.
+     * Use this bcast intent instead for SUPL requests.
+     * @hide
+     */
+    public static final String CONNECTIVITY_ACTION_SUPL =
+            "android.net.conn.CONNECTIVITY_CHANGE_SUPL";
+
+    /**
      * The device has connected to a network that has presented a captive
      * portal, which is blocking Internet connectivity. The user was presented
      * with a notification that network sign in is required,
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 665069c..ed48319 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6687,14 +6687,15 @@
     }
 
     /**
-     * Gets the {@link View} description. It briefly describes the view and is
-     * primarily used for accessibility support. Set this property to enable
-     * better accessibility support for your application. This is especially
-     * true for views that do not have textual representation (For example,
-     * ImageButton).
+     * Returns the {@link View}'s content description.
+     * <p>
+     * <strong>Note:</strong> Do not override this method, as it will have no
+     * effect on the content description presented to accessibility services.
+     * You must call {@link #setContentDescription(CharSequence)} to modify the
+     * content description.
      *
-     * @return The content description.
-     *
+     * @return the content description
+     * @see #setContentDescription(CharSequence)
      * @attr ref android.R.styleable#View_contentDescription
      */
     @ViewDebug.ExportedProperty(category = "accessibility")
@@ -6703,14 +6704,19 @@
     }
 
     /**
-     * Sets the {@link View} description. It briefly describes the view and is
-     * primarily used for accessibility support. Set this property to enable
-     * better accessibility support for your application. This is especially
-     * true for views that do not have textual representation (For example,
-     * ImageButton).
+     * Sets the {@link View}'s content description.
+     * <p>
+     * A content description briefly describes the view and is primarily used
+     * for accessibility support to determine how a view should be presented to
+     * the user. In the case of a view with no textual representation, such as
+     * {@link android.widget.ImageButton}, a useful content description
+     * explains what the view does. For example, an image button with a phone
+     * icon that is used to place a call may use "Call" as its content
+     * description. An image of a floppy disk that is used to save a file may
+     * use "Save".
      *
      * @param contentDescription The content description.
-     *
+     * @see #getContentDescription()
      * @attr ref android.R.styleable#View_contentDescription
      */
     @RemotableViewMethod
diff --git a/core/java/android/widget/ForwardingListener.java b/core/java/android/widget/ForwardingListener.java
index fd7140f..7ddeff9 100644
--- a/core/java/android/widget/ForwardingListener.java
+++ b/core/java/android/widget/ForwardingListener.java
@@ -25,7 +25,7 @@
 import com.android.internal.view.menu.ShowableListMenu;
 
 /**
- * Abstract class that forwards touch events to a {@link ListPopupWindow}.
+ * Abstract class that forwards touch events to a {@link ShowableListMenu}.
  *
  * @hide
  */
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 9761661..44df0ce 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -76,6 +76,15 @@
         mMenu = new MenuBuilder(context).setDefaultShowAsAction(
                 MenuItem.SHOW_AS_ACTION_IF_ROOM);
         setType(ActionMode.TYPE_FLOATING);
+        mMenu.setCallback(new MenuBuilder.Callback() {
+            @Override
+            public void onMenuModeChange(MenuBuilder menu) {}
+
+            @Override
+            public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+                return mCallback.onActionItemClicked(FloatingActionMode.this, item);
+            }
+        });
         mContentRect = new Rect();
         mContentRectOnScreen = new Rect();
         mPreviousContentRectOnScreen = new Rect();
@@ -99,7 +108,7 @@
                 .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                         @Override
                     public boolean onMenuItemClick(MenuItem item) {
-                        return mCallback.onActionItemClicked(FloatingActionMode.this, item);
+                        return mMenu.performItemAction(item, 0);
                     }
                 });
         mFloatingToolbarVisibilityHelper = new FloatingToolbarVisibilityHelper(mFloatingToolbar);
diff --git a/core/java/com/android/internal/view/menu/MenuPopup.java b/core/java/com/android/internal/view/menu/MenuPopup.java
new file mode 100644
index 0000000..91788ca
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/MenuPopup.java
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+package com.android.internal.view.menu;
+
+import android.content.Context;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ListAdapter;
+import android.widget.PopupWindow;
+
+/**
+ * Base class for a menu popup abstraction - i.e., some type of menu, housed in a popup window
+ * environment.
+ *
+ * @hide
+ */
+public abstract class MenuPopup implements ShowableListMenu, MenuPresenter {
+
+    public abstract void setForceShowIcon(boolean forceShow);
+
+    /**
+     * Adds the given menu to the popup. If this is the first menu shown it'll be displayed; if it's
+     * a submenu it will be displayed adjacent to the most recent menu (if supported by the
+     * implementation).
+     *
+     * @param menu
+     */
+    public abstract void addMenu(MenuBuilder menu);
+
+    public abstract void setGravity(int dropDownGravity);
+
+    public abstract void setAnchorView(View anchor);
+
+    /**
+     * Set a listener to receive a callback when the popup is dismissed.
+     *
+     * @param listener Listener that will be notified when the popup is dismissed.
+     */
+    public abstract void setOnDismissListener(PopupWindow.OnDismissListener listener);
+
+    @Override
+    public void initForMenu(Context context, MenuBuilder menu) {
+        // Don't need to do anything; we added as a presenter in the constructor.
+    }
+
+    @Override
+    public MenuView getMenuView(ViewGroup root) {
+        throw new UnsupportedOperationException("MenuPopups manage their own views");
+    }
+
+    @Override
+    public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+        return false;
+    }
+
+    @Override
+    public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+        return false;
+    }
+
+    @Override
+    public int getId() {
+        return 0;
+    }
+
+    /**
+     * Measures the width of the given menu view.
+     *
+     * @param view The view to measure.
+     * @return The width.
+     */
+    protected static int measureIndividualMenuWidth(ListAdapter adapter, ViewGroup parent,
+            Context context, int maxAllowedWidth) {
+        // Menus don't tend to be long, so this is more sane than it looks.
+        int maxWidth = 0;
+        View itemView = null;
+        int itemType = 0;
+
+        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final int count = adapter.getCount();
+        for (int i = 0; i < count; i++) {
+            final int positionType = adapter.getItemViewType(i);
+            if (positionType != itemType) {
+                itemType = positionType;
+                itemView = null;
+            }
+
+            if (parent == null) {
+                parent = new FrameLayout(context);
+            }
+
+            itemView = adapter.getView(i, itemView, parent);
+            itemView.measure(widthMeasureSpec, heightMeasureSpec);
+
+            final int itemWidth = itemView.getMeasuredWidth();
+            if (itemWidth >= maxAllowedWidth) {
+                return maxAllowedWidth;
+            } else if (itemWidth > maxWidth) {
+                maxWidth = itemWidth;
+            }
+        }
+
+        return maxWidth;
+    }
+}
\ 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 e6bc6c3..9a47fc1 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -17,57 +17,29 @@
 package com.android.internal.view.menu;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.os.Parcelable;
 import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
 import android.view.View;
-import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
-import android.widget.ListAdapter;
-import android.widget.MenuPopupWindow;
 import android.widget.PopupWindow;
 
-import java.util.ArrayList;
-
 /**
  * Presents a menu as a small, simple popup anchored to another view.
+ *
  * @hide
  */
-public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener,
-        ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener,
-        View.OnAttachStateChangeListener, MenuPresenter {
-    static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout;
-
+public class MenuPopupHelper implements ViewTreeObserver.OnGlobalLayoutListener,
+        PopupWindow.OnDismissListener, View.OnAttachStateChangeListener, MenuPresenter {
     private final Context mContext;
-    private final LayoutInflater mInflater;
     private final MenuBuilder mMenu;
-    private final MenuAdapter mAdapter;
     private final boolean mOverflowOnly;
-    private final int mPopupMaxWidth;
     private final int mPopupStyleAttr;
     private final int mPopupStyleRes;
 
     private View mAnchorView;
-    private MenuPopupWindow mPopup;
+    private MenuPopup mPopup;
     private ViewTreeObserver mTreeObserver;
-    private Callback mPresenterCallback;
-
-    boolean mForceShowIcon;
-
-    private ViewGroup mMeasureParent;
-
-    /** Whether the cached content width value is valid. */
-    private boolean mHasContentWidth;
-
-    /** Cached content width from {@link #measureContentWidth}. */
-    private int mContentWidth;
 
     private int mDropDownGravity = Gravity.NO_GRAVITY;
 
@@ -87,33 +59,37 @@
     public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView,
             boolean overflowOnly, int popupStyleAttr, int popupStyleRes) {
         mContext = context;
-        mInflater = LayoutInflater.from(context);
         mMenu = menu;
-        mAdapter = new MenuAdapter(mMenu, mInflater, overflowOnly);
         mOverflowOnly = overflowOnly;
         mPopupStyleAttr = popupStyleAttr;
         mPopupStyleRes = popupStyleRes;
-
-        final Resources res = context.getResources();
-        mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
-                res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
-
         mAnchorView = anchorView;
+        mPopup = createMenuPopup();
+    }
 
-        // Present the menu using our context, not the menu builder's context.
-        menu.addMenuPresenter(this, context);
+    private MenuPopup createMenuPopup() {
+        if (mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableCascadingSubmenus)) {
+            // TODO: Return a Cascading implementation of MenuPopup instead.
+            return new StandardMenuPopup(
+                    mContext, mMenu, mAnchorView, mPopupStyleAttr, mPopupStyleRes, mOverflowOnly);
+        }
+        return new StandardMenuPopup(
+                mContext, mMenu, mAnchorView, mPopupStyleAttr, mPopupStyleRes, mOverflowOnly);
     }
 
     public void setAnchorView(View anchor) {
         mAnchorView = anchor;
+        mPopup.setAnchorView(anchor);
     }
 
     public void setForceShowIcon(boolean forceShow) {
-        mForceShowIcon = forceShow;
+        mPopup.setForceShowIcon(forceShow);
     }
 
     public void setGravity(int gravity) {
         mDropDownGravity = gravity;
+        mPopup.setGravity(gravity);
     }
 
     public int getGravity() {
@@ -126,28 +102,21 @@
         }
     }
 
-    public MenuPopupWindow getPopup() {
+    public ShowableListMenu getPopup() {
         return mPopup;
     }
 
     /**
-     * Attempts to show the popup anchored to the view specified by
-     * {@link #setAnchorView(View)}.
+     * Attempts to show the popup anchored to the view specified by {@link #setAnchorView(View)}.
      *
-     * @return {@code true} if the popup was shown or was already showing prior
-     *         to calling this method, {@code false} otherwise
+     * @return {@code true} if the popup was shown or was already showing prior to calling this
+     *         method, {@code false} otherwise
      */
     public boolean tryShow() {
         if (isShowing()) {
             return true;
         }
 
-        mPopup = new MenuPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes);
-        mPopup.setOnDismissListener(this);
-        mPopup.setOnItemClickListener(this);
-        mPopup.setAdapter(mAdapter);
-        mPopup.setModal(true);
-
         final View anchor = mAnchorView;
         if (anchor != null) {
             final boolean addGlobalListener = mTreeObserver == null;
@@ -155,20 +124,19 @@
             if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
             anchor.addOnAttachStateChangeListener(this);
             mPopup.setAnchorView(anchor);
-            mPopup.setDropDownGravity(mDropDownGravity);
+            mPopup.setGravity(mDropDownGravity);
         } else {
             return false;
         }
 
-        if (!mHasContentWidth) {
-            mContentWidth = measureContentWidth();
-            mHasContentWidth = true;
-        }
+        // 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
+        // its own handling.
+        mPopup.setOnDismissListener(this);
 
-        mPopup.setContentWidth(mContentWidth);
-        mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+        mPopup.addMenu(mMenu);
         mPopup.show();
-        mPopup.getListView().setOnKeyListener(this);
         return true;
     }
 
@@ -181,7 +149,6 @@
     @Override
     public void onDismiss() {
         mPopup = null;
-        mMenu.close();
         if (mTreeObserver != null) {
             if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver();
             mTreeObserver.removeGlobalOnLayoutListener(this);
@@ -195,56 +162,6 @@
     }
 
     @Override
-    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        MenuAdapter adapter = mAdapter;
-        adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
-    }
-
-    @Override
-    public boolean onKey(View v, int keyCode, KeyEvent event) {
-        if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
-            dismiss();
-            return true;
-        }
-        return false;
-    }
-
-    private int measureContentWidth() {
-        // Menus don't tend to be long, so this is more sane than it looks.
-        int maxWidth = 0;
-        View itemView = null;
-        int itemType = 0;
-
-        final ListAdapter adapter = mAdapter;
-        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-        final int count = adapter.getCount();
-        for (int i = 0; i < count; i++) {
-            final int positionType = adapter.getItemViewType(i);
-            if (positionType != itemType) {
-                itemType = positionType;
-                itemView = null;
-            }
-
-            if (mMeasureParent == null) {
-                mMeasureParent = new FrameLayout(mContext);
-            }
-
-            itemView = adapter.getView(i, itemView, mMeasureParent);
-            itemView.measure(widthMeasureSpec, heightMeasureSpec);
-
-            final int itemWidth = itemView.getMeasuredWidth();
-            if (itemWidth >= mPopupMaxWidth) {
-                return mPopupMaxWidth;
-            } else if (itemWidth > maxWidth) {
-                maxWidth = itemWidth;
-            }
-        }
-
-        return maxWidth;
-    }
-
-    @Override
     public void onGlobalLayout() {
         if (isShowing()) {
             final View anchor = mAnchorView;
@@ -282,54 +199,22 @@
 
     @Override
     public void updateMenuView(boolean cleared) {
-        mHasContentWidth = false;
-
-        if (mAdapter != null) {
-            mAdapter.notifyDataSetChanged();
-        }
+        mPopup.updateMenuView(cleared);
     }
 
     @Override
     public void setCallback(Callback cb) {
-        mPresenterCallback = cb;
+        mPopup.setCallback(cb);
     }
 
     @Override
     public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
-        if (subMenu.hasVisibleItems()) {
-            MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView);
-            subPopup.setCallback(mPresenterCallback);
-
-            boolean preserveIconSpacing = false;
-            final int count = subMenu.size();
-            for (int i = 0; i < count; i++) {
-                MenuItem childItem = subMenu.getItem(i);
-                if (childItem.isVisible() && childItem.getIcon() != null) {
-                    preserveIconSpacing = true;
-                    break;
-                }
-            }
-            subPopup.setForceShowIcon(preserveIconSpacing);
-
-            if (subPopup.tryShow()) {
-                if (mPresenterCallback != null) {
-                    mPresenterCallback.onOpenSubMenu(subMenu);
-                }
-                return true;
-            }
-        }
-        return false;
+        return mPopup.onSubMenuSelected(subMenu);
     }
 
     @Override
     public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
-        // Only care about the (sub)menu we're presenting.
-        if (menu != mMenu) return;
-
-        dismiss();
-        if (mPresenterCallback != null) {
-            mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
-        }
+        mPopup.onCloseMenu(menu, allMenusAreClosing);
     }
 
     @Override
@@ -337,10 +222,12 @@
         return false;
     }
 
+    @Override
     public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
         return false;
     }
 
+    @Override
     public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
         return false;
     }
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
new file mode 100644
index 0000000..9a30ffa
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -0,0 +1,246 @@
+package com.android.internal.view.menu;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Parcelable;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnKeyListener;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.MenuPopupWindow;
+import android.widget.PopupWindow;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.PopupWindow.OnDismissListener;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A standard menu popup in which when a submenu is opened, it replaces its parent menu in the
+ * viewport.
+ */
+final class StandardMenuPopup extends MenuPopup implements OnDismissListener, OnItemClickListener,
+        MenuPresenter, OnKeyListener {
+
+    private final Context mContext;
+    private final LayoutInflater mInflater;
+    private final MenuBuilder mMenu;
+    private final MenuAdapter mAdapter;
+    private final boolean mOverflowOnly;
+    private final int mPopupMaxWidth;
+    private final int mPopupStyleAttr;
+    private final int mPopupStyleRes;
+
+    private PopupWindow.OnDismissListener mOnDismissListener;
+
+    private View mAnchorView;
+    private MenuPopupWindow mPopup;
+    private Callback mPresenterCallback;
+
+    private ViewGroup mMeasureParent;
+
+    /** Whether the cached content width value is valid. */
+    private boolean mHasContentWidth;
+
+    /** Cached content width. */
+    private int mContentWidth;
+
+    private int mDropDownGravity = Gravity.NO_GRAVITY;
+
+    public StandardMenuPopup(Context context, MenuBuilder menu, View anchorView, int popupStyleAttr,
+            int popupStyleRes, boolean overflowOnly) {
+        mContext = Preconditions.checkNotNull(context);
+        mInflater = LayoutInflater.from(context);
+        mMenu = menu;
+        mOverflowOnly = overflowOnly;
+        mAdapter = new MenuAdapter(menu, mInflater, mOverflowOnly);
+        mPopupStyleAttr = popupStyleAttr;
+        mPopupStyleRes = popupStyleRes;
+
+        final Resources res = context.getResources();
+        mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
+                res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
+
+        mAnchorView = anchorView;
+
+        mPopup = new MenuPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes);
+
+        // Present the menu using our context, not the menu builder's context.
+        menu.addMenuPresenter(this, context);
+    }
+
+    @Override
+    public void setForceShowIcon(boolean forceShow) {
+        mAdapter.setForceShowIcon(forceShow);
+    }
+
+    @Override
+    public void setGravity(int gravity) {
+        mDropDownGravity = gravity;
+    }
+
+    private boolean tryShow() {
+        if (isShowing()) {
+            return true;
+        }
+
+        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;
+        }
+
+        if (!mHasContentWidth) {
+            mContentWidth = measureIndividualMenuWidth(
+                    mAdapter, mMeasureParent, mContext, mPopupMaxWidth);
+            mHasContentWidth = true;
+        }
+
+        mPopup.setContentWidth(mContentWidth);
+        mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+        mPopup.show();
+        mPopup.getListView().setOnKeyListener(this);
+        return true;
+    }
+
+    @Override
+    public void show() {
+        if (!tryShow()) {
+            throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
+        }
+    }
+
+    @Override
+    public void dismiss() {
+        if (isShowing()) {
+            mPopup.dismiss();
+        }
+    }
+
+    @Override
+    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        MenuAdapter adapter = mAdapter;
+        adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
+    }
+
+    @Override
+    public void addMenu(MenuBuilder menu) {
+        // No-op: standard implementation has only one menu which is set in the constructor.
+    }
+
+    @Override
+    public boolean isShowing() {
+        return mPopup != null && mPopup.isShowing();
+    }
+
+    @Override
+    public void onDismiss() {
+        mPopup = null;
+        mMenu.close();
+
+        mOnDismissListener.onDismiss();
+    }
+
+    @Override
+    public void updateMenuView(boolean cleared) {
+        mHasContentWidth = false;
+
+        if (mAdapter != null) {
+            mAdapter.notifyDataSetChanged();
+        }
+    }
+
+    @Override
+    public void setCallback(Callback cb) {
+        mPresenterCallback = cb;
+    }
+
+    @Override
+    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+        if (subMenu.hasVisibleItems()) {
+            MenuPopupHelper subPopup = new MenuPopupHelper(
+                    mContext, subMenu, mAnchorView, mOverflowOnly, mPopupStyleAttr, mPopupStyleRes);
+            subPopup.setCallback(mPresenterCallback);
+
+            boolean preserveIconSpacing = false;
+            final int count = subMenu.size();
+            for (int i = 0; i < count; i++) {
+                MenuItem childItem = subMenu.getItem(i);
+                if (childItem.isVisible() && childItem.getIcon() != null) {
+                    preserveIconSpacing = true;
+                    break;
+                }
+            }
+            subPopup.setForceShowIcon(preserveIconSpacing);
+
+            if (subPopup.tryShow()) {
+                if (mPresenterCallback != null) {
+                    mPresenterCallback.onOpenSubMenu(subMenu);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+        // Only care about the (sub)menu we're presenting.
+        if (menu != mMenu) return;
+
+        dismiss();
+        if (mPresenterCallback != null) {
+            mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
+        }
+    }
+
+    @Override
+    public boolean flagActionItems() {
+        return false;
+    }
+
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        return null;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+    }
+
+    @Override
+    public void setAnchorView(View anchor) {
+        mAnchorView = anchor;
+    }
+
+    @Override
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
+            dismiss();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void setOnDismissListener(OnDismissListener listener) {
+        mOnDismissListener = listener;
+    }
+
+    @Override
+    public ListView getListView() {
+        return mPopup.getListView();
+    }
+}
\ No newline at end of file
diff --git a/core/res/res/values-mcc204-mnc12/config.xml b/core/res/res/values-mcc204-mnc12/config.xml
new file mode 100644
index 0000000..80432d7
--- /dev/null
+++ b/core/res/res/values-mcc204-mnc12/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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 my 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>20408</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc450-mnc06/config.xml b/core/res/res/values-mcc450-mnc06/config.xml
index 63f9823..819c2a5 100644
--- a/core/res/res/values-mcc450-mnc06/config.xml
+++ b/core/res/res/values-mcc450-mnc06/config.xml
@@ -25,4 +25,7 @@
     -->
     <integer name="config_mobile_mtu">1428</integer>
 
+    <!-- Do not set the system language as value of EF LI/EF PL -->
+    <bool name="config_use_sim_language_file">false</bool>
+
 </resources>
diff --git a/core/res/res/values-mcc450-mnc08/config.xml b/core/res/res/values-mcc450-mnc08/config.xml
index 950c62b..ca26ec1 100644
--- a/core/res/res/values-mcc450-mnc08/config.xml
+++ b/core/res/res/values-mcc450-mnc08/config.xml
@@ -25,4 +25,7 @@
     -->
     <integer name="config_mobile_mtu">1450</integer>
 
+    <!-- Do not set the system language as value of EF LI/EF PL -->
+    <bool name="config_use_sim_language_file">false</bool>
+
 </resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 4531f75..091d57f 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -24,7 +24,7 @@
     <!-- The overall theme to use for an activity.  Use with either the
          application tag (to supply a default theme for all activities) or
          the activity tag (to supply a specific theme for that activity).
-    
+
          <p>This automatically sets
          your activity's Context to use this theme, and may also be used
          for "starting" animations prior to the activity being launched (to
@@ -39,7 +39,7 @@
          tag (to supply a specific label for that component).  It may also be
          used with the intent-filter tag to supply a label to show to the
          user when an activity is being selected based on a particular Intent.
-    
+
          <p>The given label will be used wherever the user sees information
          about its associated component; for example, as the name of a
          main activity that is displayed in the launcher.  You should
@@ -47,7 +47,7 @@
          it can be localized, however it is also allowed to supply a plain
          string for quick and dirty programming. -->
     <attr name="label" format="reference|string" />
-    
+
     <!-- A Drawable resource providing a graphical representation of its
          associated item.  Use with the
          application tag (to supply a default icon for all application
@@ -55,7 +55,7 @@
          tag (to supply a specific icon for that component).  It may also be
          used with the intent-filter tag to supply an icon to show to the
          user when an activity is being selected based on a particular Intent.
-    
+
          <p>The given icon will be used to display to the user a graphical
          representation of its associated component; for example, as the icon
          for main activity that is displayed in the launcher.  This must be
@@ -95,15 +95,15 @@
 
     <!-- Name of the activity to be launched to manage application's space on
          device. The specified activity gets automatically launched when the
-         application's space needs to be managed and is usually invoked 
+         application's space needs to be managed and is usually invoked
          through user actions. Applications can thus provide their own custom
          behavior for managing space for various scenarios like out of memory
          conditions. This is an optional attribute and
-         applications can choose not to specify a default activity to 
+         applications can choose not to specify a default activity to
          manage space. -->
     <attr name="manageSpaceActivity" format="string" />
 
-    <!-- Option to let applications specify that user data can/cannot be 
+    <!-- Option to let applications specify that user data can/cannot be
          cleared. This flag is turned on by default.
          <em>This attribute is usable only by applications
          included in the system image. Third-party apps cannot use it.</em> -->
@@ -122,31 +122,31 @@
          kind of application can not be installed without the
          INSTALL_ALLOW_TEST flag, which means only through adb install.  -->
     <attr name="testOnly" format="boolean" />
-    
+
     <!-- A unique name for the given item.  This must use a Java-style naming
          convention to ensure the name is unique, for example
-         "com.mycompany.MyName". -->  
+         "com.mycompany.MyName". -->
     <attr name="name" format="string" />
-    
+
     <!-- Specify a permission that a client is required to have in order to
     	 use the associated object.  If the client does not hold the named
     	 permission, its request will fail.  See the
          <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
          document for more information on permissions. -->
     <attr name="permission" format="string" />
-    
+
     <!-- A specific {@link android.R.attr#permission} name for read-only
          access to a {@link android.content.ContentProvider}.  See the
          <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
          document for more information on permissions. -->
     <attr name="readPermission" format="string" />
-    
+
     <!-- A specific {@link android.R.attr#permission} name for write
          access to a {@link android.content.ContentProvider}.  See the
          <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
          document for more information on permissions. -->
     <attr name="writePermission" format="string" />
-    
+
     <!-- If true, the {@link android.content.Context#grantUriPermission
          Context.grantUriPermission} or corresponding Intent flags can
          be used to allow others to access specific URIs in the content
@@ -156,7 +156,7 @@
          Context.revokeUriPermission} when URIs are deleted from your
          provider.-->
     <attr name="grantUriPermissions" format="boolean" />
-    
+
     <!-- Characterizes the potential risk implied in a permission and
          indicates the procedure the system should follow when determining
          whether to grant the permission to an application requesting it. {@link
@@ -257,7 +257,7 @@
          with.  The group must have been defined with the
          {@link android.R.styleable#AndroidManifestPermissionGroup permission-group} tag. -->
     <attr name="permissionGroup" format="string" />
-    
+
     <!-- Specify the name of a user ID that will be shared between multiple
          packages.  By default, each package gets its own unique user-id.
          By setting this value on two or more packages, each of these packages
@@ -265,13 +265,13 @@
          in the same process.  Note that for them to actually get the same
          user ID, they must also be signed with the same signature. -->
     <attr name="sharedUserId" format="string" />
-    
+
     <!-- Specify a label for the shared user UID of this package.  This is
          only used if you have also used android:sharedUserId.  This must
          be a reference to a string resource; it can not be an explicit
          string. -->
     <attr name="sharedUserLabel" format="reference" />
-    
+
     <!-- Internal version code.  This is the number used to determine whether
          one version is more recent than another: it has no other meaning than
          that higher numbers are more recent.  You could use this number to
@@ -279,7 +279,7 @@
          number, simply increase it by one each time a new version is
          released, or define it however else you want, as long as each
          successive version has a higher number.  This is not a version
-         number generally shown to the user, that is usually supplied 
+         number generally shown to the user, that is usually supplied
          with {@link android.R.attr#versionName}.  When an app is delivered
          as multiple split APKs, each APK must have the exact same versionCode. -->
     <attr name="versionCode" format="integer" />
@@ -296,7 +296,7 @@
          is used for no other purpose than display to the user; the actual
          significant version number is given by {@link android.R.attr#versionCode}. -->
     <attr name="versionName" format="string" />
-    
+
     <!-- Flag to control special persistent mode of an application.  This should
          not normally be used by applications; it requires that the system keep
          your application running at all times. -->
@@ -309,7 +309,7 @@
     <!-- Flag indicating whether the application can be debugged, even when
          running on a device that is running in user mode. -->
     <attr name="debuggable" format="boolean" />
-    
+
     <!-- Flag indicating whether the application requests the VM to operate in
          the safe mode.  -->
     <attr name="vmSafeMode" format="boolean" />
@@ -367,7 +367,7 @@
          Use with the application tag (to supply a default process for all
          application components), or with the activity, receiver, service,
          or provider tag (to supply a specific icon for that component).
-    
+
          <p>Application components are normally run in a single process that
          is created for the entire application.  You can use this tag to modify
          where they run.  If the process name begins with a ':' character,
@@ -378,12 +378,12 @@
          provided that you have permission to do so, allowing multiple
          applications to share one process to reduce resource usage. -->
     <attr name="process" format="string" />
-    
+
     <!-- Specify a task name that activities have an "affinity" to.
          Use with the application tag (to supply a default affinity for all
          activities in the application), or with the activity tag (to supply
          a specific affinity for that component).
-    
+
          <p>The default value for this attribute is the same as the package
          name, indicating that all activities in the manifest should generally
          be considered a single "application" to the user.  You can use this
@@ -392,13 +392,13 @@
          task from the user's perspective, or using an empty string for
          activities that have no affinity to a task. -->
     <attr name="taskAffinity" format="string" />
-    
+
     <!-- Specify that an activity can be moved out of a task it is in to
          the task it has an affinity for when appropriate.  Use with the
          application tag (to supply a default for all activities in the
          application), or with an activity tag (to supply a specific
          setting for that component).
-    
+
          <p>Normally when an application is started, it is associated with
          the task of the activity that started it and stays there for its
          entire lifetime.  You can use the allowTaskReparenting feature to force an
@@ -422,17 +422,17 @@
          applications' processes. On devices that support multiple instruction sets,
          this implies the code might be loaded into a process that's using any of the devices
          supported instruction sets.
-         
+
          <p> The system might treat such applications specially, for eg., by
          extracting the application's native libraries for all supported instruction
          sets or by compiling the application's dex code for all supported instruction
          sets. -->
     <attr name="multiArch" format ="boolean" />
-    
+
     <!-- Specify whether a component is allowed to have multiple instances
          of itself running in different processes.  Use with the activity
          and provider tags.
-    
+
          <p>Normally the system will ensure that all instances of a particular
          component are only running in a single process.  You can use this
          attribute to disable that behavior, allowing the system to create
@@ -441,28 +441,28 @@
          of a provider can be created in each client process, allowing them
          to be used without performing IPC.  -->
     <attr name="multiprocess" format="boolean" />
-    
+
     <!-- Specify whether an activity should be finished when its task is
          brought to the foreground by relaunching from the home screen.
-         
+
          <p>If both this option and {@link android.R.attr#allowTaskReparenting} are
          specified, the finish trumps the affinity: the affinity will be
          ignored and the activity simply finished. -->
     <attr name="finishOnTaskLaunch" format="boolean" />
-    
+
     <!-- Specify whether an activity should be finished when a "close system
          windows" request has been made.  This happens, for example, when
          the home key is pressed, when the device is locked, when a system
          dialog showing recent applications is displayed, etc. -->
     <attr name="finishOnCloseSystemDialogs" format="boolean" />
-    
+
     <!-- Specify whether an activity's task should be cleared when it
          is re-launched from the home screen.  As a result, every time the
          user starts the task, they will be brought to its root activity,
          regardless of whether they used BACK or HOME to last leave it.
          This flag only applies to activities that
          are used to start the root of a new task.
-         
+
          <p>An example of the use of this flag would be for the case where
          a user launches activity A from home, and from there goes to
          activity B.  They now press home, and then return to activity A.
@@ -471,7 +471,7 @@
          then upon going to the background all of the tasks on top of it (B
          in this case) are removed, so when the user next returns to A they
          will restart at its original activity.
-         
+
          <p>When this option is used in conjunction with
          {@link android.R.attr#allowTaskReparenting}, the allowTaskReparenting trumps the
          clear.  That is, all activities above the root activity of the
@@ -479,30 +479,30 @@
          to the task they are associated with, otherwise they will simply
          be dropped as described here. -->
     <attr name="clearTaskOnLaunch" format="boolean" />
-    
+
     <!-- Specify whether an activity should be kept in its history stack.
          If this attribute is set, then as soon as the user navigates away
          from the activity it will be finished and they will no longer be
          able to return to it. -->
     <attr name="noHistory" format="boolean" />
-    
+
     <!-- Specify whether an acitivty's task state should always be maintained
          by the system, or if it is allowed to reset the task to its initial
          state in certain situations.
-         
+
          <p>Normally the system will reset a task (remove all activities from
          the stack and reset the root activity) in certain situations when
          the user re-selects that task from the home screen.  Typically this
          will be done if the user hasn't visited that task for a certain
          amount of time, such as 30 minutes.
-         
+
          <p>By setting this attribute, the user will always return to your
          task in its last state, regardless of how they get there.  This is
          useful, for example, in an application like the web browser where there
          is a lot of state (such as multiple open tabs) that the application
          would not like to lose. -->
     <attr name="alwaysRetainTaskState" format="boolean" />
-    
+
     <!-- Indicates that an Activity does not need to have its freeze state
          (as returned by {@link android.app.Activity#onSaveInstanceState}
          retained in order to be restarted.  Generally you use this for activities
@@ -512,7 +512,7 @@
          it normally would.  Instead, the next time the user navigates to
          it its {@link android.app.Activity#onCreate} method will be called
          with a null icicle, just like it was starting for the first time.
-         
+
          <p>This is used by the Home activity to make sure it does not get
          removed if it crashes for some reason. -->
     <attr name="stateNotNeeded" format="boolean" />
@@ -539,11 +539,11 @@
          in order to avoid conflicts.  Typically this name is the same
          as the class implementation describing the provider's data structure. -->
     <attr name="authorities" format="string" />
-    
+
     <!-- Flag indicating whether this content provider would like to
          participate in data synchronization. -->
     <attr name="syncable" format="boolean" />
-    
+
     <!-- Flag declaring this activity to be 'immersive'; immersive activities
          should not be interrupted with other activities or notifications. -->
     <attr name="immersive" format="boolean" />
@@ -555,7 +555,7 @@
          The value is a simple integer, with higher numbers being
          initialized first. -->
     <attr name="initOrder" format="integer" />
-    
+
     <!-- Specify the relative importance or ability in handling a particular
          Intent.  For receivers, this controls the order in which they are
          executed to receive a broadcast (note that for
@@ -564,18 +564,18 @@
          Intent; when multiple activities match an intent and have different
          priorities, only those with the higher priority value will be
          considered a match.
-         
+
          <p>Only use if you really need to impose some specific
          order in which the broadcasts are received, or want to forcibly
          place an activity to always be preferred over others.  The value is a
          single integer, with higher numbers considered to be better. -->
     <attr name="priority" format="integer" />
-    
+
     <!-- Specify how an activity should be launched.  See the
          <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
          Stack</a> document for important information on how these options impact
          the behavior of your application.
-         
+
          <p>If this attribute is not specified, <code>standard</code> launch
          mode will be used.  Note that the particular launch behavior can
          be changed in some ways at runtime through the
@@ -612,19 +612,19 @@
             <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
             Stack</a> document for more details about tasks.-->
         <enum name="singleTask" value="2" />
-        <!-- Only allow one instance of this activity to ever be 
-            running.  This activity gets a unique task with only itself running 
-            in it; if it is ever launched again with the same Intent, then that 
-            task will be brought forward and its 
+        <!-- Only allow one instance of this activity to ever be
+            running.  This activity gets a unique task with only itself running
+            in it; if it is ever launched again with the same Intent, then that
+            task will be brought forward and its
             {@link android.app.Activity#onNewIntent Activity.onNewIntent()}
-            method called.  If this 
-            activity tries to start a new activity, that new activity will be 
+            method called.  If this
+            activity tries to start a new activity, that new activity will be
             launched in a separate task.  See the
             <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
             Stack</a> document for more details about tasks.-->
         <enum name="singleInstance" value="3" />
     </attr>
-    
+
     <!-- Specify the orientation an activity should be run in.  If not
          specified, it will run in the current preferred orientation
          of the screen.
@@ -638,7 +638,7 @@
              if this activity is the bottom of a task. If the user
              explicitly turned off sensor based orientation through settings
              sensor based device rotation will be ignored. If not by default
-             sensor based orientation will be taken into account and the 
+             sensor based orientation will be taken into account and the
              orientation will changed based on how the user rotates the device.
              Corresponds to
              {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}. -->
@@ -726,19 +726,19 @@
              {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LOCKED}. -->
         <enum name="locked" value="14" />
     </attr>
-    
+
     <!-- Specify one or more configuration changes that the activity will
          handle itself.  If not specified, the activity will be restarted
          if any of these configuration changes happen in the system.  Otherwise,
          the activity will remain running and its
          {@link android.app.Activity#onConfigurationChanged Activity.onConfigurationChanged}
          method called with the new configuration.
-         
+
          <p>Note that all of these configuration changes can impact the
          resource values seen by the application, so you will generally need
          to re-retrieve all resources (including view layouts, drawables, etc)
          to correctly handle any configuration change.
-         
+
          <p>These values must be kept in sync with those in
          {@link android.content.pm.ActivityInfo} and
          include/utils/ResourceTypes.h. -->
@@ -804,18 +804,18 @@
 
     <!-- Descriptive text for the associated data. -->
     <attr name="description" format="reference" />
-    
+
     <!-- The name of the application package that an Instrumentation object
          will run against. -->
     <attr name="targetPackage" format="string" />
-    
+
     <!-- Flag indicating that an Instrumentation class wants to take care
          of starting/stopping profiling itself, rather than relying on
          the default behavior of profiling the complete time it is running.
          This allows it to target profiling data at a specific set of
          operations. -->
     <attr name="handleProfiling" format="boolean" />
-    
+
     <!-- Flag indicating that an Instrumentation class should be run as a
          functional test. -->
     <attr name="functionalTest" format="boolean" />
@@ -1069,8 +1069,7 @@
 
          <p>NOTE: The value of {@link android.R.attr#screenOrientation} will be ignored for
          resizeable activities as the system doesn't support fixed orientation on a resizeable
-         activity.
-         @hide -->
+         activity. -->
     <attr name="resizeableActivity" format="boolean" />
 
     <!-- This value indicates how tasks rooted at this activity will behave in lockTask mode.
@@ -1271,7 +1270,7 @@
          features in your package (or other packages).  See the
          <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
          document for more information on permissions.
-         
+
          <p>This appears as a child tag of the root
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestPermission" parent="AndroidManifest">
@@ -1290,15 +1289,15 @@
         <attr name="protectionLevel" />
         <attr name="permissionFlags" />
     </declare-styleable>
-    
+
     <!-- The <code>permission-group</code> tag declares a logical grouping of
          related permissions.
-         
+
          <p>Note that this tag does not declare a permission itself, only
          a namespace in which further permissions can be placed.  See
          the {@link #AndroidManifestPermission &lt;permission&gt;} tag for
          more information.
-         
+
          <p>This appears as a child tag of the root
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestPermissionGroup" parent="AndroidManifest">
@@ -1316,7 +1315,7 @@
         <attr name="permissionGroupFlags" />
         <attr name="priority" />
     </declare-styleable>
-    
+
     <!-- The <code>permission-tree</code> tag declares the base of a tree of
          permission values: it declares that this package has ownership of
          the given permission name, as well as all names underneath it
@@ -1324,12 +1323,12 @@
          {@link android.content.pm.PackageManager#addPermission
          PackageManager.addPermission()} method to dynamically add new
          permissions under this tree.
-         
+
          <p>Note that this tag does not declare a permission itself, only
          a namespace in which further permissions can be placed.  See
          the {@link #AndroidManifestPermission &lt;permission&gt;} tag for
          more information.
-         
+
          <p>This appears as a child tag of the root
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestPermissionTree" parent="AndroidManifest">
@@ -1346,7 +1345,7 @@
         <attr name="banner" />
         <attr name="logo" />
     </declare-styleable>
-    
+
     <!-- The <code>uses-permission</code> tag requests a
          {@link #AndroidManifestPermission &lt;permission&gt;} that the containing
          package must be granted in order for it to operate correctly. For runtime
@@ -1359,7 +1358,7 @@
          document for more information on permissions.  Also available is a
          {@link android.Manifest.permission list of permissions} included
          with the base platform.
-         
+
          <p>This appears as a child tag of the root
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestUsesPermission" parent="AndroidManifest">
@@ -1436,7 +1435,7 @@
 
     <!-- The <code>uses-sdk</code> tag describes the SDK features that the
          containing package must be running on to operate correctly.
-         
+
          <p>This appears as a child tag of the root
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestUsesSdk" parent="AndroidManifest">
@@ -1464,7 +1463,7 @@
              incompatibility with them. -->
         <attr name="maxSdkVersion" />
     </declare-styleable>
-    
+
     <!-- The <code>library</code> tag declares that this apk is providing itself
          as a shared library for other applications to use.  It can only be used
          with apks that are built in to the system image.  Other apks can link to
@@ -1483,7 +1482,7 @@
     <!-- The <code>uses-libraries</code> specifies a shared library that this
          package requires to be linked against.  Specifying this flag tells the
          system to include this library's code in your class loader.
-         
+
          <p>This appears as a child tag of the
          {@link #AndroidManifestApplication application} tag. -->
     <declare-styleable name="AndroidManifestUsesLibrary" parent="AndroidManifestApplication">
@@ -1498,7 +1497,7 @@
               dynamically at runtime. -->
         <attr name="required" />
     </declare-styleable>
-    
+
     <!-- The <code>supports-screens</code> specifies the screen dimensions an
          application supports.  By default a modern application supports all
          screen sizes and must explicitly disable certain screen sizes here;
@@ -1506,7 +1505,7 @@
          (HVGA) screen size.  Note that screen size is a separate axis from
          density, and is determined as the available pixels to an application
          after density scaling has been applied.
-         
+
          <p>This appears as a child tag of the
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestSupportsScreens" parent="AndroidManifest">
@@ -1609,7 +1608,7 @@
          {@link android.content.ContentProvider} class that is available
          as part of the package's application components, supplying structured
          access to data managed by the application.
-         
+
          <p>This appears as a child tag of the
          {@link #AndroidManifestApplication application} tag. -->
     <declare-styleable name="AndroidManifestProvider" parent="AndroidManifestApplication">
@@ -1641,7 +1640,7 @@
         <attr name="exported" />
         <attr name="singleUser" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>grant-uri-permission</code> tag, a child of the
          {@link #AndroidManifestProvider provider} tag, describing a specific
@@ -1658,7 +1657,7 @@
         <attr name="pathPrefix" format="string" />
         <!-- Specify a URI path that matches a simple pattern, as per
              {@link android.os.PatternMatcher} with
-             {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}. 
+             {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}.
              Note that because '\' is used as an escape character when
              reading the string from XML (before it is parsed as a pattern),
              you will need to double-escape: for example a literal "*" would
@@ -1667,7 +1666,7 @@
              write if constructing the string in Java code. -->
         <attr name="pathPattern" format="string" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>path-permission</code> tag, a child of the
          {@link #AndroidManifestProvider provider} tag, describing a permission
@@ -1681,13 +1680,13 @@
         <attr name="readPermission" />
         <attr name="writePermission" />
     </declare-styleable>
-    
+
     <!-- The <code>service</code> tag declares a
          {@link android.app.Service} class that is available
          as part of the package's application components, implementing
          long-running background operations or a rich communication API
          that can be called by other packages.
-         
+
          <p>Zero or more {@link #AndroidManifestIntentFilter intent-filter}
          tags can be included inside of a service, to specify the Intents
          that can connect with it.  If none are specified, the service can
@@ -1724,13 +1723,13 @@
         <attr name="isolatedProcess" format="boolean" />
         <attr name="singleUser" />
     </declare-styleable>
-    
+
     <!-- The <code>receiver</code> tag declares an
          {@link android.content.BroadcastReceiver} class that is available
          as part of the package's application components, allowing the
          application to receive actions or data broadcast by other
          applications even if it is not currently running.
-         
+
          <p>Zero or more {@link #AndroidManifestIntentFilter intent-filter}
          tags can be included inside of a receiver, to specify the Intents
          it will receive.  If none are specified, the receiver will only
@@ -1826,7 +1825,6 @@
         <attr name="autoRemoveFromRecents" />
         <attr name="relinquishTaskIdentity" />
         <attr name="resumeWhilePausing" />
-        <!-- @hide -->
         <attr name="resizeableActivity" />
         <attr name="lockTaskMode" />
         <attr name="showForAllUsers" />
@@ -1878,7 +1876,7 @@
          data by the system.  You may supply the data through either the
          <code>value</code> or <code>resource</code> attribute; if both
          are given, then <code>resource</code> will be used.
-         
+
          <p>It is highly recommended that you avoid supplying related data as
          multiple separate meta-data entries.  Instead, if you have complex
          data to associate with a component, then use the <code>resource</code>
@@ -1907,22 +1905,22 @@
              Bundle through {@link android.os.Bundle#getInt Bundle.getInt}. -->
         <attr name="resource" format="reference" />
     </declare-styleable>
-    
+
     <!-- The <code>intent-filter</code> tag is used to construct an
          {@link android.content.IntentFilter} object that will be used
          to determine which component can handle a particular
          {@link android.content.Intent} that has been given to the system.
          It can be used as a child of the
          {@link #AndroidManifestActivity activity},
-         {@link #AndroidManifestReceiver receiver} and 
+         {@link #AndroidManifestReceiver receiver} and
          {@link #AndroidManifestService service}
          tags.
-         
+
          <p> Zero or more {@link #AndroidManifestAction action},
          {@link #AndroidManifestCategory category}, and/or
          {@link #AndroidManifestData data} tags should be
          included inside to describe the contents of the filter.
-         
+
          <p> The optional label and icon attributes here are used with
          an activity to supply an alternative description of that activity
          when it is being started through an Intent matching this filter. -->
@@ -1935,7 +1933,7 @@
         <attr name="priority" />
         <attr name="autoVerify" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>action</code> tag, a child of the
          {@link #AndroidManifestIntentFilter intent-filter} tag.
@@ -1950,7 +1948,7 @@
              package name. -->
         <attr name="name" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>data</code> tag, a child of the
          {@link #AndroidManifestIntentFilter intent-filter} tag, describing
@@ -2022,7 +2020,7 @@
         <!-- Specify a URI path that matches a simple pattern, as per
              {@link android.content.IntentFilter#addDataPath
              IntentFilter.addDataPath()} with
-             {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}. 
+             {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}.
              Note that because '\' is used as an escape character when
              reading the string from XML (before it is parsed as a pattern),
              you will need to double-escape: for example a literal "*" would
@@ -2031,10 +2029,10 @@
              write if constructing the string in Java code. -->
         <attr name="pathPattern" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>category</code> tag, a child of the
-         {@link #AndroidManifestIntentFilter intent-filter} tag. 
+         {@link #AndroidManifestIntentFilter intent-filter} tag.
          See {@link android.content.IntentFilter#addCategory} for
          more information. -->
     <declare-styleable name="AndroidManifestCategory" parent="AndroidManifestIntentFilter">
@@ -2046,7 +2044,7 @@
              package name. -->
         <attr name="name" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>instrumentation</code> tag, a child of the root
          {@link #AndroidManifest manifest} tag. -->
@@ -2065,7 +2063,7 @@
         <attr name="handleProfiling" />
         <attr name="functionalTest" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>screen</code> tag, a child of <code>compatible-screens</code>,
          which is itself a child of the root
@@ -2162,14 +2160,14 @@
             {@link android.content.Intent#setComponent Intent.setComponent()}. -->
         <attr name="targetClass" format="string" />
     </declare-styleable>
-    
+
     <!-- A category to add to an Intent, as per
             {@link android.content.Intent#addCategory Intent.addCategory()}. -->
     <declare-styleable name="IntentCategory" parent="Intent">
         <!-- Required name of the category. -->
         <attr name="name" />
     </declare-styleable>
-    
+
     <!-- An extra data value to place into a an extra/name value pair held
             in a Bundle, as per {@link android.os.Bundle}. -->
     <declare-styleable name="Extra" parent="Intent">
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ef4e261..e43a8d3 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -170,6 +170,21 @@
          so that applications can still use their own mechanisms. -->
     <bool name="config_enableAutoPowerModes">false</bool>
 
+    <!-- The threshold angle for any motion detection in auto-power save modes.
+         In hundreths of a degree. -->
+    <integer name="config_autoPowerModeThresholdAngle">200</integer>
+
+    <!-- The sensor id of an "any motion" sensor used in auto-power save modes.
+         0 indicates this sensor is not available. -->
+    <integer name="config_autoPowerModeAnyMotionSensor">0</integer>
+
+    <!-- If an any motion sensor is not available, prefer the wrist tilt detector over the
+         SMD. -->
+    <bool name="config_autoPowerModePreferWristTilt">false</bool>
+
+    <!-- If a location should be pre-fetched when going into device idle. -->
+    <bool name="config_autoPowerModePrefetchLocation">true</bool>
+
     <!-- The duration (in milliseconds) that the radio will scan for a signal
          when there's no network connection. If the scan doesn't timeout, use zero -->
     <integer name="config_radioScanningTimeout">0</integer>
@@ -2283,4 +2298,8 @@
     <!-- The OEM specified sensor string type for the gesture to launch camera app, this value
          must match the value of config_cameraLaunchGestureSensorType in OEM's HAL -->
     <string translatable="false" name="config_cameraLaunchGestureSensorStringType"></string>
+
+    <!-- Whether to open UI submenus side by side with the top menu (as opposed to
+         replacing the top menu). -->
+    <bool name="config_enableCascadingSubmenus">false</bool>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c89b31b..a2b6a7b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2684,5 +2684,6 @@
     <public type="id" name="accessibilityActionSetProgress" />
     <public type="attr" name="activityWidth" />
     <public type="attr" name="activityHeight" />
+    <public type="attr" name="resizeableActivity" />
 
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 98c9f77..48a7a1c5 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -254,6 +254,10 @@
   <java-symbol type="bool" name="config_cellBroadcastAppLinks" />
   <java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
   <java-symbol type="bool" name="config_enableAutoPowerModes" />
+  <java-symbol type="integer" name="config_autoPowerModeThresholdAngle" />
+  <java-symbol type="integer" name="config_autoPowerModeAnyMotionSensor" />
+  <java-symbol type="bool" name="config_autoPowerModePreferWristTilt" />
+  <java-symbol type="bool" name="config_autoPowerModePrefetchLocation" />
   <java-symbol type="bool" name="config_enable_emergency_call_while_sim_locked" />
   <java-symbol type="bool" name="config_enable_puk_unlock_screen" />
   <java-symbol type="bool" name="config_enableBurnInProtection" />
@@ -2186,6 +2190,8 @@
   <java-symbol type="string" name="prohibit_manual_network_selection_in_gobal_mode" />
   <java-symbol type="id" name="profile_button" />
 
+  <java-symbol type="bool" name="config_enableCascadingSubmenus" />
+
   <!-- From SignalStrength -->
   <java-symbol type="integer" name="config_LTE_RSRP_threshold_type" />
 
diff --git a/core/tests/bluetoothtests/AndroidManifest.xml b/core/tests/bluetoothtests/AndroidManifest.xml
index e43ba12..7f9d874 100644
--- a/core/tests/bluetoothtests/AndroidManifest.xml
+++ b/core/tests/bluetoothtests/AndroidManifest.xml
@@ -21,6 +21,7 @@
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 676ab1c..3eb13ab 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -165,6 +165,7 @@
 LOCAL_CFLAGS := $(hwui_cflags)
 
 LOCAL_SRC_FILES += \
+    unit_tests/CanvasStateTests.cpp \
     unit_tests/ClipAreaTests.cpp \
     unit_tests/DamageAccumulatorTests.cpp \
     unit_tests/LinearAllocatorTests.cpp
diff --git a/libs/hwui/unit_tests/CanvasStateTests.cpp b/libs/hwui/unit_tests/CanvasStateTests.cpp
new file mode 100644
index 0000000..79852be
--- /dev/null
+++ b/libs/hwui/unit_tests/CanvasStateTests.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+#include "CanvasState.h"
+
+#include "Matrix.h"
+#include "Rect.h"
+#include "utils/LinearAllocator.h"
+
+#include <gtest/gtest.h>
+#include <SkPath.h>
+#include <SkRegion.h>
+#include <SkCanvas.h>
+
+namespace android {
+namespace uirenderer {
+
+class NullClient: public CanvasStateClient {
+    void onViewportInitialized() override {}
+    void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
+    GLuint getTargetFbo() const override { return 0; }
+};
+
+static NullClient sNullClient;
+
+static bool approxEqual(const Matrix4& a, const Matrix4& b) {
+    for (int i = 0; i < 16; i++) {
+        if (!MathUtils::areEqual(a[i], b[i])) {
+            return false;
+        }
+    }
+    return true;
+}
+
+TEST(CanvasState, gettersAndSetters) {
+    CanvasState state(sNullClient);
+    state.setViewport(200, 200);
+    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+
+    ASSERT_EQ(state.getWidth(), 200);
+    ASSERT_EQ(state.getHeight(), 200);
+
+    Matrix4 simpleTranslate;
+    simpleTranslate.loadTranslate(10, 20, 0);
+    state.setMatrix(simpleTranslate);
+
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 200, 200));
+    ASSERT_EQ(state.getLocalClipBounds(), Rect(-10, -20, 190, 180));
+    EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
+    EXPECT_TRUE(state.clipIsSimple());
+}
+
+TEST(CanvasState, simpleClipping) {
+    CanvasState state(sNullClient);
+    state.setViewport(200, 200);
+    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+
+    state.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 100, 100));
+
+    state.clipRect(10, 10, 200, 200, SkRegion::kIntersect_Op);
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10, 100, 100));
+
+    state.clipRect(50, 50, 150, 150, SkRegion::kReplace_Op);
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(50, 50, 150, 150));
+}
+
+TEST(CanvasState, complexClipping) {
+    CanvasState state(sNullClient);
+    state.setViewport(200, 200);
+    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+
+    state.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+    {
+        // rotated clip causes complex clip
+        state.rotate(10);
+        EXPECT_TRUE(state.clipIsSimple());
+        state.clipRect(0, 0, 200, 200, SkRegion::kIntersect_Op);
+        EXPECT_FALSE(state.clipIsSimple());
+    }
+    state.restore();
+
+    state.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+    {
+        // subtracted clip causes complex clip
+        EXPECT_TRUE(state.clipIsSimple());
+        state.clipRect(50, 50, 150, 150, SkRegion::kDifference_Op);
+        EXPECT_FALSE(state.clipIsSimple());
+    }
+    state.restore();
+
+    state.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+    {
+        // complex path causes complex clip
+        SkPath path;
+        path.addOval(SkRect::MakeWH(200, 200));
+        EXPECT_TRUE(state.clipIsSimple());
+        state.clipPath(&path, SkRegion::kDifference_Op);
+        EXPECT_FALSE(state.clipIsSimple());
+    }
+    state.restore();
+}
+
+TEST(CanvasState, saveAndRestore) {
+    CanvasState state(sNullClient);
+    state.setViewport(200, 200);
+    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+
+    state.save(SkCanvas::kClip_SaveFlag);
+    {
+        state.clipRect(0, 0, 10, 10, SkRegion::kIntersect_Op);
+        ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 10, 10));
+    }
+    state.restore();
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 200, 200)); // verify restore
+
+    Matrix4 simpleTranslate;
+    simpleTranslate.loadTranslate(10, 10, 0);
+    state.save(SkCanvas::kMatrix_SaveFlag);
+    {
+        state.translate(10, 10, 0);
+        EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
+    }
+    state.restore();
+    EXPECT_FALSE(approxEqual(*state.currentTransform(), simpleTranslate));
+}
+
+TEST(CanvasState, saveAndRestoreButNotTooMuch) {
+    CanvasState state(sNullClient);
+    state.setViewport(200, 200);
+    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+
+    state.save(SkCanvas::kMatrix_SaveFlag); // Note: clip not saved
+    {
+        state.clipRect(0, 0, 10, 10, SkRegion::kIntersect_Op);
+        ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 10, 10));
+    }
+    state.restore();
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 10, 10)); // verify not restored
+
+    Matrix4 simpleTranslate;
+    simpleTranslate.loadTranslate(10, 10, 0);
+    state.save(SkCanvas::kClip_SaveFlag); // NOTE: matrix not saved
+    {
+        state.translate(10, 10, 0);
+        EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
+    }
+    state.restore();
+    EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate)); // verify not restored
+}
+
+}
+}
diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp
index 01cf5d2..0abe88b 100644
--- a/libs/hwui/utils/LinearAllocator.cpp
+++ b/libs/hwui/utils/LinearAllocator.cpp
@@ -140,7 +140,7 @@
 }
 
 void* LinearAllocator::start(Page* p) {
-    return ALIGN_PTR(((size_t*)p) + sizeof(Page));
+    return ALIGN_PTR((size_t)p + sizeof(Page));
 }
 
 void* LinearAllocator::end(Page* p) {
diff --git a/packages/DocumentsUI/Android.mk b/packages/DocumentsUI/Android.mk
index c21c5cc..1a4e3eb 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -13,17 +13,21 @@
 LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview
 LOCAL_STATIC_JAVA_LIBRARIES += guava
 
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res 
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 # Not quite sure why it is necessary to explicitly pull in resources from the
 # appcompat lib, but the demo code indicates it's necessary (see
 # development/samples/Support7Demos/Android.mk)
-LOCAL_RESOURCE_DIR += frameworks/support/v7/appcompat/res
-LOCAL_RESOURCE_DIR += frameworks/support/design/res
+LOCAL_RESOURCE_DIR += \
+  frameworks/support/v7/appcompat/res \
+  frameworks/support/design/res \
+  frameworks/support/v7/recyclerview/res
 
 # Again, required to pull in appcompat resources.  See abovementioned demo code.
-LOCAL_AAPT_FLAGS := --auto-add-overlay
-LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.appcompat
-LOCAL_AAPT_FLAGS += --extra-packages android.support.design
+LOCAL_AAPT_FLAGS := \
+  --auto-add-overlay \
+  --extra-packages android.support.v7.appcompat \
+  --extra-packages android.support.design \
+  --extra-packages android.support.v7.recyclerview
 
 LOCAL_PACKAGE_NAME := DocumentsUI
 LOCAL_CERTIFICATE := platform
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 616f4dd..4b44d7c 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -139,6 +139,13 @@
         <item quantity="one">Moving <xliff:g id="count" example="1">%1$d</xliff:g> file.</item>
         <item quantity="other">Moving <xliff:g id="count" example="3">%1$d</xliff:g> files.</item>
     </plurals>
+    <!-- Text shown when files are deleted -->
+    <plurals name="deleting">
+        <item quantity="one">Deleting <xliff:g id="count" example="1">%1$d</xliff:g> file.</item>
+        <item quantity="other">Deleting <xliff:g id="count" example="3">%1$d</xliff:g> files.</item>
+    </plurals>
+    <!-- Text shown for the undo button -->
+    <string name="undo">Undo</string>
     <!-- Text shown on the notification while DocumentsUI performs setup in preparation for copying files [CHAR LIMIT=32] -->
     <string name="copy_preparing">Preparing for copy\u2026</string>
     <!-- Text shown on the notification while DocumentsUI performs setup in preparation for moving files [CHAR LIMIT=32] -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index ecf03f5..b7a3e4b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -62,6 +62,7 @@
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.support.annotation.Nullable;
+import android.support.design.widget.Snackbar;
 import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -74,6 +75,7 @@
 import android.text.format.Time;
 import android.util.Log;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.view.ActionMode;
 import android.view.DragEvent;
 import android.view.GestureDetector;
@@ -803,41 +805,33 @@
     }
 
     private void deleteDocuments(final Selection selected) {
-        final Context context = getActivity();
-        final ContentResolver resolver = context.getContentResolver();
+        Context context = getActivity();
+        ContentResolver resolver = context.getContentResolver();
+        String message = Shared.getQuantityString(context, R.plurals.deleting, selected.size());
 
-        new GetDocumentsTask() {
-            @Override
-            void onDocumentsReady(List<DocumentInfo> docs) {
-                boolean hadTrouble = false;
-                for (DocumentInfo doc : docs) {
-                    if (!doc.isDeleteSupported()) {
-                        Log.w(TAG, "Skipping " + doc);
-                        hadTrouble = true;
-                        continue;
-                    }
+        mModel.markForDeletion(selected);
 
-                    ContentProviderClient client = null;
-                    try {
-                        client = DocumentsApplication.acquireUnstableProviderOrThrow(
-                                resolver, doc.derivedUri.getAuthority());
-                        DocumentsContract.deleteDocument(client, doc.derivedUri);
-                    } catch (Exception e) {
-                        Log.w(TAG, "Failed to delete " + doc);
-                        hadTrouble = true;
-                    } finally {
-                        ContentProviderClient.releaseQuietly(client);
-                    }
-                }
-
-                if (hadTrouble) {
-                    Toast.makeText(
-                            context,
-                            R.string.toast_failed_delete,
-                            Toast.LENGTH_SHORT).show();
-                }
-            }
-        }.execute(selected);
+        Activity activity = getActivity();
+        Snackbar.make(this.getView(), message, Snackbar.LENGTH_LONG)
+                .setAction(
+                        R.string.undo,
+                        new android.view.View.OnClickListener() {
+                            @Override
+                            public void onClick(View view) {}
+                        })
+                .setCallback(
+                        new Snackbar.Callback() {
+                            @Override
+                            public void onDismissed(Snackbar snackbar, int event) {
+                                if (event == Snackbar.Callback.DISMISS_EVENT_ACTION) {
+                                    mModel.undoDeletion();
+                                } else {
+                                    mModel.finalizeDeletion();
+                                }
+                                ;
+                            }
+                        })
+                .show();
     }
 
     private void transferDocuments(final Selection selected, final int mode) {
@@ -1405,7 +1399,7 @@
      * @return true if the list of files can be copied to destination.
      */
     boolean canCopy(List<DocumentInfo> files, DocumentInfo dest) {
-        BaseActivity activity = (BaseActivity)getActivity();
+        BaseActivity activity = (BaseActivity) getActivity();
 
         final RootInfo root = activity.getCurrentRoot();
 
@@ -1735,6 +1729,7 @@
         @Nullable private Cursor mCursor;
         @Nullable private String info;
         @Nullable private String error;
+        private SparseBooleanArray mMarkedForDeletion = new SparseBooleanArray();
 
         /**
          * Sets the selection manager used by the model.
@@ -1806,10 +1801,28 @@
         }
 
         private int getItemCount() {
-            return mCursorCount;
+            return mCursorCount - mMarkedForDeletion.size();
         }
 
         private Cursor getItem(int position) {
+            // Items marked for deletion are masked out of the UI.  To do this, for every marked
+            // item whose position is less than the requested item position, advance the requested
+            // position by 1.
+            final int originalPos = position;
+            final int size = mMarkedForDeletion.size();
+            for (int i = 0; i <= size; ++i) {
+                // It'd be more concise, but less efficient, to iterate over positions while calling
+                // mMarkedForDeletion.get.  Instead, iterate over deleted entries.
+                if (mMarkedForDeletion.keyAt(i) <= position && mMarkedForDeletion.valueAt(i)) {
+                    ++position;
+                }
+            }
+
+            if (DEBUG) {
+                Log.d(TAG, "Item position adjusted for deletion.  Original: " + originalPos
+                        + "  Adjusted: " + position);
+            }
+
             if (position >= mCursorCount) {
                 throw new IndexOutOfBoundsException("Attempt to retrieve " + position + " of " +
                         mCursorCount + " items");
@@ -1833,12 +1846,9 @@
         }
 
         private List<DocumentInfo> getDocuments(Selection items) {
-            if (items == null || items.size() == 0) {
-                return new ArrayList<>(0);
-            }
+            final int size = (items != null) ? items.size() : 0;
 
-            final List<DocumentInfo> docs =  new ArrayList<>(items.size());
-            final int size = items.size();
+            final List<DocumentInfo> docs =  new ArrayList<>(size);
             for (int i = 0; i < size; i++) {
                 final Cursor cursor = getItem(items.get(i));
                 checkNotNull(cursor, "Cursor cannot be null.");
@@ -1855,5 +1865,122 @@
             }
             return mCursor;
         }
+
+        private List<DocumentInfo> getDocumentsMarkedForDeletion() {
+            final int size = mMarkedForDeletion.size();
+            List<DocumentInfo> docs =  new ArrayList<>(size);
+
+            for (int i = 0; i < size; ++i) {
+                final int position = mMarkedForDeletion.keyAt(i);
+                checkState(position < mCursorCount);
+                mCursor.moveToPosition(position);
+                final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(mCursor);
+                docs.add(doc);
+            }
+            return docs;
+        }
+
+        /**
+         * Marks the given files for deletion. This will remove them from the UI. Clients must then
+         * call either {@link #undoDeletion()} or {@link #finalizeDeletion()} to cancel or confirm
+         * the deletion, respectively. Only one deletion operation is allowed at a time.
+         *
+         * @param selected A selection representing the files to delete.
+         */
+        public void markForDeletion(Selection selected) {
+            // Only one deletion operation at a time.
+            checkState(mMarkedForDeletion.size() == 0);
+            // There should never be more to delete than what exists.
+            checkState(mCursorCount >= selected.size());
+
+            final int size = selected.size();
+            for (int i = 0; i < size; ++i) {
+                int position = selected.get(i);
+                if (DEBUG) Log.d(TAG, "Marked position " + position + " for deletion");
+                mMarkedForDeletion.append(position, true);
+                mAdapter.notifyItemRemoved(position);
+            }
+        }
+
+        /**
+         * Cancels an ongoing deletion operation. All files currently marked for deletion will be
+         * unmarked, and restored in the UI.  See {@link #markForDeletion(Selection)}.
+         */
+        public void undoDeletion() {
+            // Iterate over deleted items, temporarily marking them false in the deletion list, and
+            // re-adding them to the UI.
+            final int size = mMarkedForDeletion.size();
+            for (int i = 0; i < size; ++i) {
+                final int position = mMarkedForDeletion.keyAt(i);
+                mMarkedForDeletion.put(position, false);
+                mAdapter.notifyItemInserted(position);
+            }
+
+            // Then, clear the deletion list.
+            mMarkedForDeletion.clear();
+        }
+
+        /**
+         * Finalizes an ongoing deletion operation. All files currently marked for deletion will be
+         * deleted.  See {@link #markForDeletion(Selection)}.
+         */
+        public void finalizeDeletion() {
+            final Context context = getActivity();
+            final ContentResolver resolver = context.getContentResolver();
+            new DeleteFilesTask(resolver).execute();
+        }
+
+        /**
+         * A Task which collects the DocumentInfo for documents that have been marked for deletion,
+         * and actually deletes them.
+         */
+        private class DeleteFilesTask extends AsyncTask<Void, Void, List<DocumentInfo>> {
+            private ContentResolver mResolver;
+
+            public DeleteFilesTask(ContentResolver resolver) {
+                mResolver = resolver;
+            }
+
+            @Override
+            protected List<DocumentInfo> doInBackground(Void... params) {
+                return getDocumentsMarkedForDeletion();
+            }
+
+            @Override
+            protected void onPostExecute(List<DocumentInfo> docs) {
+                boolean hadTrouble = false;
+                for (DocumentInfo doc : docs) {
+                    if (!doc.isDeleteSupported()) {
+                        Log.w(TAG, doc + " could not be deleted.  Skipping...");
+                        hadTrouble = true;
+                        continue;
+                    }
+
+                    ContentProviderClient client = null;
+                    try {
+                        if (DEBUG) Log.d(TAG, "Deleting: " + doc.displayName);
+                        client = DocumentsApplication.acquireUnstableProviderOrThrow(
+                            mResolver, doc.derivedUri.getAuthority());
+                        DocumentsContract.deleteDocument(client, doc.derivedUri);
+                    } catch (Exception e) {
+                        Log.w(TAG, "Failed to delete " + doc);
+                        hadTrouble = true;
+                    } finally {
+                        ContentProviderClient.releaseQuietly(client);
+                    }
+                }
+
+                if (hadTrouble) {
+                    // TODO show which files failed?
+                    Snackbar.make(DirectoryFragment.this.getView(),
+                       R.string.toast_failed_delete,
+                       Snackbar.LENGTH_LONG).show();
+                    if (DEBUG) Log.d(TAG, "Deletion task completed.  Some deletions failed.");
+                } else {
+                    if (DEBUG) Log.d(TAG, "Deletion task completed successfully.");
+                }
+                mMarkedForDeletion.clear();
+            }
+        }
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index 4284f6f..30a5a47 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -339,7 +339,7 @@
         }
 
         handlePositionChanged(position, metaState);
-        return false;
+        return true;
     }
 
     /**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index b414ee3..2bf0562 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -16,9 +16,18 @@
 
 package com.android.documentsui;
 
+import android.content.Context;
+
 /**
  * @hide
  */
 public final class Shared {
     public static final String TAG = "Documents";
+
+    /**
+     * Generates a formatted quantity string.
+     */
+    public static final String getQuantityString(Context context, int resourceId, int quantity) {
+        return context.getResources().getQuantityString(resourceId, quantity, quantity);
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index ce2d11a..f51e10f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -64,7 +64,7 @@
 
     @Override
     protected void resetState() {
-        mPasswordEntry.setEnabled(true);
+        setPasswordEntryEnabled(true);
     }
 
     @Override
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e00b55e..05591cc 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -39,6 +39,7 @@
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <!-- System tool permissions granted to the shell. -->
     <uses-permission android:name="android.permission.REAL_GET_TASKS" />
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index de6c4b1..2c964be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1754,11 +1754,13 @@
     protected void handleVisibleToUserChanged(boolean visibleToUser) {
         try {
             if (visibleToUser) {
-                boolean clearNotificationEffects = !isPanelFullyCollapsed() &&
-                    (mShowLockscreenNotifications ||
-                        (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED));
+                boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
+                boolean clearNotificationEffects =
+                    ((mShowLockscreenNotifications && mState == StatusBarState.KEYGUARD) ||
+                            (!pinnedHeadsUp && (mState == StatusBarState.SHADE
+                                    || mState == StatusBarState.SHADE_LOCKED)));
                 int notificationLoad = mNotificationData.getActiveNotifications().size();
-                if (mHeadsUpManager.hasPinnedHeadsUp() && isPanelFullyCollapsed())  {
+                if (pinnedHeadsUp && isPanelFullyCollapsed())  {
                     notificationLoad = 1;
                 } else {
                     MetricsLogger.histogram(mContext, "note_load", notificationLoad);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 4e69999..84082db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -227,7 +227,7 @@
                 return MODE_DISMISS_BOUNCER;
             } else if (unlockingAllowed) {
                 return MODE_UNLOCK;
-            } else {
+            } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 return MODE_SHOW_BOUNCER;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 950b162..310625e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -78,6 +78,13 @@
         Notification notif = sbn.getNotification();
         String groupKey = sbn.getGroupKey();
         final NotificationGroup group = mGroupMap.get(groupKey);
+        if (group == null) {
+            // When an app posts 2 different notifications as summary of the same group, then a
+            // cancellation of the first notification removes this group.
+            // This situation is not supported and we will not allow such notifications anymore in
+            // the close future. See b/23676310 for reference.
+            return;
+        }
         if (notif.isGroupSummary()) {
             group.summary = null;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index ab1b597..55fbb2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3794,12 +3794,9 @@
         // down on the lockscreen), clear notification LED, vibration,
         // ringing.
         // Other transitions are covered in handleVisibleToUserChanged().
-        if (state != mState && mVisible && state == StatusBarState.SHADE_LOCKED) {
-            try {
-                mBarService.clearNotificationEffects();
-            } catch (RemoteException e) {
-                // Ignore.
-            }
+        if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED
+                || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) {
+            clearNotificationEffects();
         }
         mState = state;
         mGroupManager.setStatusBarState(state);
diff --git a/services/core/java/com/android/server/AnyMotionDetector.java b/services/core/java/com/android/server/AnyMotionDetector.java
index 6a67316..a0b5c15 100644
--- a/services/core/java/com/android/server/AnyMotionDetector.java
+++ b/services/core/java/com/android/server/AnyMotionDetector.java
@@ -58,9 +58,6 @@
     /** Current measurement state. */
     private int mState;
 
-    /** Threshold angle in degrees beyond which the device is considered moving. */
-    private final float THRESHOLD_ANGLE = 2f;
-
     /** Threshold energy above which the device is considered moving. */
     private final float THRESHOLD_ENERGY = 5f;
 
@@ -88,6 +85,9 @@
     private SensorManager mSensorManager;
     private PowerManager.WakeLock mWakeLock;
 
+    /** Threshold angle in degrees beyond which the device is considered moving. */
+    private final float mThresholdAngle;
+
     /** The minimum number of samples required to detect AnyMotion. */
     private int mNumSufficientSamples;
 
@@ -106,7 +106,7 @@
     private DeviceIdleCallback mCallback = null;
 
     public AnyMotionDetector(PowerManager pm, Handler handler, SensorManager sm,
-            DeviceIdleCallback callback) {
+            DeviceIdleCallback callback, float thresholdAngle) {
         if (DEBUG) Slog.d(TAG, "AnyMotionDetector instantiated.");
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
         mWakeLock.setReferenceCounted(false);
@@ -116,6 +116,7 @@
         mMeasurementInProgress = false;
         mState = STATE_INACTIVE;
         mCallback = callback;
+        mThresholdAngle = thresholdAngle;
         mRunningStats = new RunningSignalStats();
         mNumSufficientSamples = (int) Math.ceil(
                 ((double)ORIENTATION_MEASUREMENT_DURATION_MILLIS / SAMPLING_INTERVAL_MILLIS));
@@ -224,8 +225,9 @@
         Vector3 previousGravityVectorNormalized = mPreviousGravityVector.normalized();
         Vector3 currentGravityVectorNormalized = mCurrentGravityVector.normalized();
         float angle = previousGravityVectorNormalized.angleBetween(currentGravityVectorNormalized);
-        if (DEBUG) Slog.d(TAG, "getStationaryStatus: angle = " + angle);
-        if ((angle < THRESHOLD_ANGLE) && (mRunningStats.getEnergy() < THRESHOLD_ENERGY)) {
+        if (DEBUG) Slog.d(TAG, "getStationaryStatus: angle = " + angle
+                + " energy = " + mRunningStats.getEnergy());
+        if ((angle < mThresholdAngle) && (mRunningStats.getEnergy() < THRESHOLD_ENERGY)) {
             return RESULT_STATIONARY;
         } else if (Float.isNaN(angle)) {
           /**
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index e19447d..2bcee91 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1524,10 +1524,14 @@
 
             final long ident = Binder.clearCallingIdentity();
             if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
+                final NetworkInfo ni = intent.getParcelableExtra(
+                        ConnectivityManager.EXTRA_NETWORK_INFO);
+                if (ni.getType() == ConnectivityManager.TYPE_MOBILE_SUPL) {
+                    intent.setAction(ConnectivityManager.CONNECTIVITY_ACTION_SUPL);
+                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                }
                 final IBatteryStats bs = BatteryStatsService.getService();
                 try {
-                    NetworkInfo ni = intent.getParcelableExtra(
-                            ConnectivityManager.EXTRA_NETWORK_INFO);
                     bs.noteConnectivityChanged(intent.getIntExtra(
                             ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
                             ni != null ? ni.getState().toString() : "?");
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 80fd441..46fd28a 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -128,7 +128,8 @@
     private boolean mNotMoving;
     private boolean mLocating;
     private boolean mLocated;
-    private boolean mHaveGps;
+    private boolean mHasGps;
+    private boolean mHasNetworkLocation;
     private Location mLastGenericLocation;
     private Location mLastGpsLocation;
 
@@ -882,17 +883,37 @@
                 mDisplayManager = (DisplayManager) getContext().getSystemService(
                         Context.DISPLAY_SERVICE);
                 mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
-                mSigMotionSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
-                mLocationManager = (LocationManager) getContext().getSystemService(
-                        Context.LOCATION_SERVICE);
-                mLocationRequest = new LocationRequest()
-                    .setQuality(LocationRequest.ACCURACY_FINE)
-                    .setInterval(0)
-                    .setFastestInterval(0)
-                    .setNumUpdates(1);
+                int sigMotionSensorId = getContext().getResources().getInteger(
+                        com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor);
+                if (sigMotionSensorId > 0) {
+                    mSigMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true);
+                }
+                if (mSigMotionSensor == null && getContext().getResources().getBoolean(
+                        com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) {
+                    mSigMotionSensor = mSensorManager.getDefaultSensor(
+                            Sensor.TYPE_WRIST_TILT_GESTURE);
+                }
+                if (mSigMotionSensor == null) {
+                    // As a last ditch, fall back to SMD.
+                    mSigMotionSensor = mSensorManager.getDefaultSensor(
+                            Sensor.TYPE_SIGNIFICANT_MOTION);
+                }
+                if (getContext().getResources().getBoolean(
+                        com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
+                    mLocationManager = (LocationManager) getContext().getSystemService(
+                            Context.LOCATION_SERVICE);
+                    mLocationRequest = new LocationRequest()
+                        .setQuality(LocationRequest.ACCURACY_FINE)
+                        .setInterval(0)
+                        .setFastestInterval(0)
+                        .setNumUpdates(1);
+                }
+
+                float angleThreshold = getContext().getResources().getInteger(
+                        com.android.internal.R.integer.config_autoPowerModeThresholdAngle) / 100f;
                 mAnyMotionDetector = new AnyMotionDetector(
                         (PowerManager) getContext().getSystemService(Context.POWER_SERVICE),
-                        mHandler, mSensorManager, this);
+                        mHandler, mSensorManager, this, angleThreshold);
 
                 Intent intent = new Intent(ACTION_STEP_IDLE_STATE)
                         .setPackage("android")
@@ -1279,17 +1300,30 @@
                 EventLogTags.writeDeviceIdle(mState, "step");
                 cancelSensingAlarmLocked();
                 scheduleSensingAlarmLocked(mConstants.LOCATING_TIMEOUT);
-                mLocating = true;
-                mLocationManager.requestLocationUpdates(mLocationRequest, mGenericLocationListener,
-                        mHandler.getLooper());
-                if (mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
-                    mHaveGps = true;
+                if (mLocationManager != null
+                        && mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
+                    mLocationManager.requestLocationUpdates(mLocationRequest,
+                            mGenericLocationListener, mHandler.getLooper());
+                    mLocating = true;
+                } else {
+                    mHasNetworkLocation = false;
+                }
+                if (mLocationManager != null
+                        && mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
+                    mHasGps = true;
                     mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,
                             mGpsLocationListener, mHandler.getLooper());
+                    mLocating = true;
                 } else {
-                    mHaveGps = false;
+                    mHasGps = false;
                 }
-                break;
+                // If we have a location provider, we're all set, the listeners will move state
+                // forward.
+                if (mLocating) {
+                    break;
+                }
+
+                // Otherwise, we have to move from locating into idle maintenance.
             case STATE_LOCATING:
                 cancelSensingAlarmLocked();
                 cancelLocatingLocked();
@@ -1346,7 +1380,7 @@
         }
         if (DEBUG) Slog.d(TAG, "Generic location: " + location);
         mLastGenericLocation = new Location(location);
-        if (location.getAccuracy() > mConstants.LOCATION_ACCURACY && mHaveGps) {
+        if (location.getAccuracy() > mConstants.LOCATION_ACCURACY && mHasGps) {
             return;
         }
         mLocated = true;
@@ -1413,9 +1447,9 @@
     void scheduleAlarmLocked(long delay, boolean idleUntil) {
         if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")");
         if (mSigMotionSensor == null) {
-            // If there is no significant motion sensor on this device, then we won't schedule
+            // If there is no motion sensor on this device, then we won't schedule
             // alarms, because we can't determine if the device is not moving.  This effectively
-            // turns off normal exeuction of device idling, although it is still possible to
+            // turns off normal execution of device idling, although it is still possible to
             // manually poke it by pretending like the alarm is going off.
             return;
         }
@@ -1902,8 +1936,9 @@
             pw.print("  mSigMotionActive="); pw.println(mSigMotionActive);
             pw.print("  mSensing="); pw.print(mSensing); pw.print(" mNotMoving=");
                     pw.println(mNotMoving);
-            pw.print("  mLocating="); pw.print(mLocating); pw.print(" mHaveGps=");
-                    pw.print(mHaveGps); pw.print(" mLocated="); pw.println(mLocated);
+            pw.print("  mLocating="); pw.print(mLocating); pw.print(" mHasGps=");
+                    pw.print(mHasGps); pw.print(" mHasNetwork=");
+                    pw.print(mHasNetworkLocation); pw.print(" mLocated="); pw.println(mLocated);
             if (mLastGenericLocation != null) {
                 pw.print("  mLastGenericLocation="); pw.println(mLastGenericLocation);
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 09ac7d9..3554c39 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -407,6 +407,17 @@
     private static final int PERSISTENT_MASK =
             ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
 
+
+    // Delay to disable app launch boost
+    static final int APP_BOOST_MESSAGE_DELAY = 3000;
+    // Lower delay than APP_BOOST_MESSAGE_DELAY to disable the boost
+    static final int APP_BOOST_TIMEOUT = 2500;
+
+    private static native int nativeMigrateToBoost();
+    private static native int nativeMigrateFromBoost();
+    private boolean mIsBoosted = false;
+    private long mBoostStartTime = 0;
+
     /** All system services */
     SystemServiceManager mSystemServiceManager;
 
@@ -1368,6 +1379,7 @@
     static final int REPORT_TIME_TRACKER_MSG = 55;
     static final int REPORT_USER_SWITCH_COMPLETE_MSG = 56;
     static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 57;
+    static final int APP_BOOST_DEACTIVATE_MSG = 58;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -2048,6 +2060,20 @@
                 // it is finished we make sure it is reset to its default.
                 mUserIsMonkey = false;
             } break;
+            case APP_BOOST_DEACTIVATE_MSG : {
+                synchronized(ActivityManagerService.this) {
+                    if (mIsBoosted) {
+                        if (mBoostStartTime < (SystemClock.uptimeMillis() - APP_BOOST_TIMEOUT)) {
+                            nativeMigrateFromBoost();
+                            mIsBoosted = false;
+                            mBoostStartTime = 0;
+                        } else {
+                            Message newmsg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG);
+                            mHandler.sendMessageDelayed(newmsg, APP_BOOST_TIMEOUT);
+                        }
+                    }
+                }
+            } break;
             }
         }
     };
@@ -3180,6 +3206,16 @@
             app = null;
         }
 
+        // app launch boost for big.little configurations
+        // use cpusets to migrate freshly launched tasks to big cores
+        synchronized(ActivityManagerService.this) {
+            nativeMigrateToBoost();
+            mIsBoosted = true;
+            mBoostStartTime = SystemClock.uptimeMillis();
+            Message msg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG);
+            mHandler.sendMessageDelayed(msg, APP_BOOST_MESSAGE_DELAY);
+        }
+
         // We don't have to do anything more if:
         // (1) There is an existing application record; and
         // (2) The caller doesn't think it is dead, OR there is no thread
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index a956c56..960cbf1 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -509,7 +509,7 @@
                     break;
                 }
                 int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
-                if (appOp != r.appOp
+                if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
                         && mService.mAppOpsService.noteOperation(appOp,
                         filter.receiverList.uid, filter.packageName)
                         != AppOpsManager.MODE_ALLOWED) {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index cbb3c39..67c9ee8 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -18,9 +18,12 @@
 
 import android.Manifest;
 import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
 import android.app.IUserSwitchObserver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
@@ -54,6 +57,7 @@
 import android.hardware.fingerprint.IFingerprintDaemonCallback;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
 import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
 import static android.Manifest.permission.USE_FINGERPRINT;
@@ -93,6 +97,7 @@
     private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
     private static final int MAX_FAILED_ATTEMPTS = 5;
     private static final int FINGERPRINT_ACQUIRED_GOOD = 0;
+    private final String mKeyguardPackage;
 
     Handler mHandler = new Handler() {
         @Override
@@ -125,6 +130,8 @@
     public FingerprintService(Context context) {
         super(context);
         mContext = context;
+        mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
+                com.android.internal.R.string.config_keyguardComponent)).getPackageName();
         mAppOps = context.getSystemService(AppOpsManager.class);
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
     }
@@ -498,10 +505,50 @@
         return false;
     }
 
-    private boolean canUseFingerprint(String opPackageName) {
+    private boolean isForegroundActivity(int uid, int pid) {
+        try {
+            List<RunningAppProcessInfo> procs =
+                    ActivityManagerNative.getDefault().getRunningAppProcesses();
+            int N = procs.size();
+            for (int i = 0; i < N; i++) {
+                RunningAppProcessInfo proc = procs.get(i);
+                if (proc.pid == pid && proc.uid == uid
+                        && proc.importance == IMPORTANCE_FOREGROUND) {
+                    return true;
+                }
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "am.getRunningAppProcesses() failed");
+        }
+        return false;
+    }
+
+    /**
+     * @param opPackageName name of package for caller
+     * @param foregroundOnly only allow this call while app is in the foreground
+     * @return true if caller can use fingerprint API
+     */
+    private boolean canUseFingerprint(String opPackageName, boolean foregroundOnly) {
         checkPermission(USE_FINGERPRINT);
-        return mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, Binder.getCallingUid(),
-                opPackageName) == AppOpsManager.MODE_ALLOWED;
+        final int uid = Binder.getCallingUid();
+        final int pid = Binder.getCallingPid();
+        if (opPackageName.equals(mKeyguardPackage)) {
+            return true; // Keyguard is always allowed
+        }
+        if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
+            Slog.w(TAG,"Rejecting " + opPackageName + " ; not a current user or profile");
+            return false;
+        }
+        if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
+                != AppOpsManager.MODE_ALLOWED) {
+            Slog.v(TAG, "Rejecting " + opPackageName + " ; permission denied");
+            return false;
+        }
+        if (foregroundOnly && !isForegroundActivity(uid, pid)) {
+            Slog.v(TAG, "Rejecting " + opPackageName + " ; not in foreground");
+            return false;
+        }
+        return true;
     }
 
     private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
@@ -834,12 +881,7 @@
         public void authenticate(final IBinder token, final long opId, final int groupId,
                 final IFingerprintServiceReceiver receiver, final int flags,
                 final String opPackageName) {
-            if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
-                Slog.w(TAG, "Can't authenticate non-current user");
-                return;
-            }
-            if (!canUseFingerprint(opPackageName)) {
-                Slog.w(TAG, "Calling not granted permission to use fingerprint");
+            if (!canUseFingerprint(opPackageName, true /* foregroundOnly */)) {
                 return;
             }
 
@@ -859,7 +901,7 @@
 
         @Override // Binder call
         public void cancelAuthentication(final IBinder token, String opPackageName) {
-            if (!canUseFingerprint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
                 return;
             }
             mHandler.post(new Runnable() {
@@ -890,7 +932,7 @@
 
         @Override // Binder call
         public boolean isHardwareDetected(long deviceId, String opPackageName) {
-            if (!canUseFingerprint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
                 return false;
             }
             return mHalDeviceId != 0;
@@ -914,7 +956,7 @@
 
         @Override // Binder call
         public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
-            if (!canUseFingerprint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
                 return Collections.emptyList();
             }
             int effectiveUserId = getEffectiveUserId(userId);
@@ -924,7 +966,7 @@
 
         @Override // Binder call
         public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
-            if (!canUseFingerprint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
                 return false;
             }
 
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 5c60a61..239c471 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -434,8 +434,11 @@
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-
             if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
+            if (action == null) {
+                return;
+            }
+
             if (action.equals(ALARM_WAKEUP)) {
                 startNavigating(false);
             } else if (action.equals(ALARM_TIMEOUT)) {
@@ -490,21 +493,27 @@
 
     private void checkSmsSuplInit(Intent intent) {
         SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
-
         if (messages == null) {
             Log.e(TAG, "Message does not exist in the intent.");
             return;
         }
 
-        for (int i=0; i <messages.length; i++) {
-            byte[] supl_init = messages[i].getUserData();
-            native_agps_ni_message(supl_init,supl_init.length);
+        for (SmsMessage message : messages) {
+            if (message != null && message.mWrappedSmsMessage != null) {
+                byte[] suplInit = message.getUserData();
+                if (suplInit != null) {
+                    native_agps_ni_message(suplInit, suplInit.length);
+                }
+            }
         }
     }
 
     private void checkWapSuplInit(Intent intent) {
-        byte[] supl_init = (byte[]) intent.getExtra("data");
-        native_agps_ni_message(supl_init,supl_init.length);
+        byte[] suplInit = intent.getByteArrayExtra("data");
+        if (suplInit == null) {
+            return;
+        }
+        native_agps_ni_message(suplInit,suplInit.length);
     }
 
     private void updateLowPowerMode() {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index e69dda1..3991489 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -978,13 +978,12 @@
         }
 
         // TODO: move to NotificationManager once we can mock it
-        // XXX what to do about multi-user?
         try {
             final String packageName = mContext.getPackageName();
             final int[] idReceived = new int[1];
             mNotifManager.enqueueNotificationWithTag(
                     packageName, packageName, tag, 0x0, builder.getNotification(), idReceived,
-                    UserHandle.USER_OWNER);
+                    UserHandle.USER_ALL);
             mActiveNotifs.add(tag);
         } catch (RemoteException e) {
             // ignored; service lives in system_server
@@ -1016,12 +1015,11 @@
                 PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
 
         // TODO: move to NotificationManager once we can mock it
-        // XXX what to do about multi-user?
         try {
             final String packageName = mContext.getPackageName();
             final int[] idReceived = new int[1];
             mNotifManager.enqueueNotificationWithTag(packageName, packageName, tag,
-                    0x0, builder.getNotification(), idReceived, UserHandle.USER_OWNER);
+                    0x0, builder.getNotification(), idReceived, UserHandle.USER_ALL);
             mActiveNotifs.add(tag);
         } catch (RemoteException e) {
             // ignored; service lives in system_server
@@ -1030,11 +1028,10 @@
 
     private void cancelNotification(String tag) {
         // TODO: move to NotificationManager once we can mock it
-        // XXX what to do about multi-user?
         try {
             final String packageName = mContext.getPackageName();
             mNotifManager.cancelNotificationWithTag(
-                    packageName, tag, 0x0, UserHandle.USER_OWNER);
+                    packageName, tag, 0x0, UserHandle.USER_ALL);
         } catch (RemoteException e) {
             // ignored; service lives in system_server
         }
@@ -1418,7 +1415,8 @@
                         final int policy = readIntAttribute(in, ATTR_POLICY);
 
                         // TODO: set for other users during upgrade
-                        final int uid = UserHandle.getUid(UserHandle.USER_OWNER, appId);
+                        // app policy is deprecated so this is only used in pre system user split.
+                        final int uid = UserHandle.getUid(UserHandle.USER_SYSTEM, appId);
                         if (UserHandle.isApp(uid)) {
                             setUidPolicyUncheckedLocked(uid, policy, false);
                         } else {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e1f3528..88088fa 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2319,16 +2319,16 @@
             }
             updatePermissionsLPw(null, null, updateFlags);
             ver.sdkVersion = mSdkVersion;
-            // clear only after permissions have been updated
-            mExistingSystemPackages.clear();
-            mPromoteSystemApps = false;
 
-            // If this is the first boot, and it is a normal boot, then
-            // we need to initialize the default preferred apps.
-            if (!mRestoredSettings && !onlyCore) {
-                mSettings.applyDefaultPreferredAppsLPw(this, UserHandle.USER_OWNER);
-                applyFactoryDefaultBrowserLPw(UserHandle.USER_OWNER);
-                primeDomainVerificationsLPw(UserHandle.USER_OWNER);
+            // If this is the first boot or an update from pre-M, and it is a normal
+            // boot, then we need to initialize the default preferred apps across
+            // all defined users.
+            if (!onlyCore && (mPromoteSystemApps || !mRestoredSettings)) {
+                for (UserInfo user : sUserManager.getUsers(true)) {
+                    mSettings.applyDefaultPreferredAppsLPw(this, user.id);
+                    applyFactoryDefaultBrowserLPw(user.id);
+                    primeDomainVerificationsLPw(user.id);
+                }
             }
 
             // If this is first boot after an OTA, and a normal boot, then
@@ -2346,6 +2346,10 @@
 
             checkDefaultBrowser();
 
+            // clear only after permissions and other defaults have been updated
+            mExistingSystemPackages.clear();
+            mPromoteSystemApps = false;
+
             // All the changes are done during package scanning.
             ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 48e205f..958a9d5 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -6633,6 +6633,11 @@
         if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
             tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
         }
+
+        if (mUiMode == Configuration.UI_MODE_TYPE_CAR) {
+            tmpVisibility |= StatusBarManager.DISABLE_RECENT;
+        }
+
         tmpVisibility = updateLightStatusBarLw(tmpVisibility);
         final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
         final int diff = visibility ^ mLastSystemUiFlags;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index a7ef2f8..f21f00a 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -405,7 +405,10 @@
             for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) {
                 final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows;
                 for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
-                    mService.removeWindowInnerLocked(appWindows.get(winNdx));
+                    // We are in the middle of changing the state of displays/stacks/tasks. We need
+                    // to finish that, before we let layout interfere with it.
+                    mService.removeWindowInnerLocked(appWindows.get(winNdx),
+                            false /* performLayout */);
                     doAnotherLayoutPass = true;
                 }
             }
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index d0962f4..fc23fd1 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -750,7 +750,7 @@
     }
 
     boolean adjustWallpaperWindows() {
-        mService.mInnerFields.mWallpaperMayChange = false;
+        mService.mWindowPlacerLocked.mWallpaperMayChange = false;
 
         final WindowList windows = mService.getDefaultWindowListLocked();
         // First find top-most window that has asked to be on top of the wallpaper;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index e6a1be1..b334a05 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -23,11 +23,11 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static com.android.server.wm.WindowManagerService.DEBUG_KEYGUARD;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_UPDATE_ROTATION;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_FORCE_HIDING_CHANGED;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_ACTION_PENDING;
+import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
+import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
+import static com.android.server.wm.WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED;
+import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
+import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING;
 
 import android.content.Context;
 import android.os.RemoteException;
@@ -41,8 +41,6 @@
 import android.view.animation.Animation;
 import android.view.Choreographer;
 
-import com.android.server.wm.WindowManagerService.LayoutFields;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
@@ -84,8 +82,7 @@
     int mBulkUpdateParams = 0;
     Object mLastWindowFreezeSource;
 
-    SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
-            new SparseArray<DisplayContentsAnimator>(2);
+    SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = new SparseArray<>(2);
 
     boolean mInitialized = false;
 
@@ -179,10 +176,12 @@
                     mAnimating = mAppWindowAnimating = true;
                 } else if (appAnimator.wasAnimating) {
                     // stopped animating, do one more pass through the layout
-                    setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                        "exiting appToken " + appAnimator.mAppToken + " done", displayId);
+                    setAppLayoutChanges(appAnimator,
+                            WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
+                            "exiting appToken " + appAnimator.mAppToken + " done", displayId);
                     if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
-                            "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
+                            "updateWindowsApps...: done animating exiting "
+                                    + appAnimator.mAppToken);
                 }
             }
         }
@@ -301,7 +300,8 @@
                     setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
                             WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                     if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                        mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 2",
+                        mService.mWindowPlacerLocked.debugLayoutRepeats(
+                                "updateWindowsAndWallpaperLocked 2",
                                 getPendingLayoutChanges(Display.DEFAULT_DISPLAY));
                     }
                 }
@@ -315,7 +315,8 @@
                         setPendingLayoutChanges(displayId,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                            mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 3",
+                            mService.mWindowPlacerLocked.debugLayoutRepeats(
+                                    "updateWindowsAndWallpaperLocked 3",
                                     getPendingLayoutChanges(displayId));
                         }
                         mService.mFocusMayChange = true;
@@ -409,7 +410,8 @@
                         setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                            mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 4",
+                            mService.mWindowPlacerLocked.debugLayoutRepeats(
+                                    "updateWindowsAndWallpaperLocked 4",
                                     getPendingLayoutChanges(Display.DEFAULT_DISPLAY));
                         }
                     }
@@ -433,7 +435,8 @@
                         setPendingLayoutChanges(displayId,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                            mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 5",
+                            mService.mWindowPlacerLocked.debugLayoutRepeats(
+                                    "updateWindowsAndWallpaperLocked 5",
                                     getPendingLayoutChanges(displayId));
                         }
                     }
@@ -607,7 +610,8 @@
                                     "Setting mOrientationChangeComplete=true because wtoken "
                                     + wtoken + " numInteresting=" + wtoken.numInterestingWindows
                                     + " numDrawn=" + wtoken.numDrawnWindows);
-                            // This will set mOrientationChangeComplete and cause a pass through layout.
+                            // This will set mOrientationChangeComplete and cause a pass through
+                            // layout.
                             setAppLayoutChanges(appAnimator,
                                     WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
                                     "testTokenMayBeDrawnLocked: freezingScreen", displayId);
@@ -737,7 +741,7 @@
 
         boolean doRequest = false;
         if (mBulkUpdateParams != 0) {
-            doRequest = mService.copyAnimToLayoutParamsLocked();
+            doRequest = mService.mWindowPlacerLocked.copyAnimToLayoutParamsLocked();
         }
 
         if (hasPendingLayoutChanges || doRequest) {
@@ -755,21 +759,21 @@
         }
     }
 
-    static String bulkUpdateParamsToString(int bulkUpdateParams) {
+    private static String bulkUpdateParamsToString(int bulkUpdateParams) {
         StringBuilder builder = new StringBuilder(128);
-        if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
+        if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) {
             builder.append(" UPDATE_ROTATION");
         }
-        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
+        if ((bulkUpdateParams & WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE) != 0) {
             builder.append(" WALLPAPER_MAY_CHANGE");
         }
-        if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
+        if ((bulkUpdateParams & WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED) != 0) {
             builder.append(" FORCE_HIDING_CHANGED");
         }
-        if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
+        if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
             builder.append(" ORIENTATION_CHANGE_COMPLETE");
         }
-        if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
+        if ((bulkUpdateParams & WindowSurfacePlacer.SET_TURN_ON_SCREEN) != 0) {
             builder.append(" TURN_ON_SCREEN");
         }
         return builder.toString();
@@ -846,7 +850,8 @@
             if (displayId == windows.get(i).getDisplayId()) {
                 setPendingLayoutChanges(displayId, changes);
                 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                    mService.debugLayoutRepeats(reason, getPendingLayoutChanges(displayId));
+                    mService.mWindowPlacerLocked.debugLayoutRepeats(reason,
+                            getPendingLayoutChanges(displayId));
                 }
                 break;
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index bf7d1e7..cf093f5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -34,8 +34,6 @@
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -70,7 +68,6 @@
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
-import android.util.IntArray;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
@@ -112,7 +109,6 @@
 import android.view.WindowManagerPolicy;
 import android.view.WindowManagerPolicy.PointerEventListener;
 import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
 
 import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
 import com.android.internal.app.IAssistScreenshotReceiver;
@@ -157,16 +153,12 @@
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
@@ -177,11 +169,8 @@
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -313,6 +302,7 @@
             }
         }
     };
+    final WindowSurfacePlacer mWindowPlacerLocked;
 
     /**
      * Current user when multi-user is enabled. Don't show windows of
@@ -444,7 +434,6 @@
 
     final float[] mTmpFloats = new float[9];
     final Rect mTmpContentRect = new Rect();
-    private final Rect mTmpStartRect = new Rect();
 
     boolean mDisplayReady;
     boolean mSafeMode;
@@ -491,7 +480,7 @@
     final static int WINDOWS_FREEZING_SCREENS_NONE = 0;
     final static int WINDOWS_FREEZING_SCREENS_ACTIVE = 1;
     final static int WINDOWS_FREEZING_SCREENS_TIMEOUT = 2;
-    private int mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
+    int mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
 
     boolean mClientFreezingScreen = false;
     int mAppsFreezingScreen = 0;
@@ -614,51 +603,11 @@
     // For frozen screen animations.
     int mExitAnimId, mEnterAnimId;
 
-    /** Pulled out of performLayoutAndPlaceSurfacesLockedInner in order to refactor into multiple
-     * methods. */
-    class LayoutFields {
-        static final int SET_UPDATE_ROTATION                = 1 << 0;
-        static final int SET_WALLPAPER_MAY_CHANGE           = 1 << 1;
-        static final int SET_FORCE_HIDING_CHANGED           = 1 << 2;
-        static final int SET_ORIENTATION_CHANGE_COMPLETE    = 1 << 3;
-        static final int SET_TURN_ON_SCREEN                 = 1 << 4;
-        static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 5;
-
-        boolean mWallpaperForceHidingChanged = false;
-        boolean mWallpaperMayChange = false;
-        boolean mOrientationChangeComplete = true;
-        Object mLastWindowFreezeSource = null;
-        private Session mHoldScreen = null;
-        private boolean mObscured = false;
-        private boolean mSyswin = false;
-        private float mScreenBrightness = -1;
-        private float mButtonBrightness = -1;
-        private long mUserActivityTimeout = -1;
-        private boolean mUpdateRotation = false;
-        boolean mWallpaperActionPending = false;
-
-        // Set to true when the display contains content to show the user.
-        // When false, the display manager may choose to mirror or blank the display.
-        boolean mDisplayHasContent = false;
-
-        // Only set while traversing the default display based on its content.
-        // Affects the behavior of mirroring on secondary displays.
-        boolean mObscureApplicationContentOnSecondaryDisplays = false;
-
-        float mPreferredRefreshRate = 0;
-
-        int mPreferredModeId = 0;
-    }
-    final LayoutFields mInnerFields = new LayoutFields();
-
     boolean mAnimationScheduled;
 
     /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
      * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
-    private int mTransactionSequence;
-
-    /** Only do a maximum of 6 repeated layouts. After that quit */
-    private int mLayoutRepeatCount;
+    int mTransactionSequence;
 
     final WindowAnimator mAnimator;
 
@@ -768,7 +717,7 @@
     boolean mInTouchMode;
 
     private ViewServer mViewServer;
-    private final ArrayList<WindowChangeListener> mWindowChangeListeners = new ArrayList<>();
+    final ArrayList<WindowChangeListener> mWindowChangeListeners = new ArrayList<>();
     boolean mWindowsChanged = false;
 
     public interface WindowChangeListener {
@@ -788,7 +737,7 @@
 
     // List of clients without a transtiton animation that we notify once we are done transitioning
     // since they won't be notified through the app window animator.
-    private final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>();
+    final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>();
 
     /** Listener to notify activity manager about app transitions. */
     private final WindowManagerInternal.AppTransitionListener mActivityManagerAppTransitionNotifier
@@ -866,6 +815,9 @@
         mDisplaySettings = new DisplaySettings();
         mDisplaySettings.readSettingsLocked();
 
+        mWallpaperControllerLocked = new WallpaperController(this);
+        mWindowPlacerLocked = new WindowSurfacePlacer(this);
+
         LocalServices.addService(WindowManagerPolicy.class, mPolicy);
 
         mPointerEventDispatcher = new PointerEventDispatcher(mInputManager.monitorInput(TAG));
@@ -953,8 +905,6 @@
 
         updateCircularDisplayMaskIfNeeded();
         showEmulatorDisplayOverlayIfNeeded();
-
-        mWallpaperControllerLocked = new WallpaperController(this);
     }
 
     public InputMonitor getInputMonitor() {
@@ -2154,7 +2104,7 @@
                 }
                 final boolean focusChanged = updateFocusedWindowLocked(
                         UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
-                performLayoutAndPlaceSurfacesLocked();
+                mWindowPlacerLocked.performSurfacePlacement();
                 if (appToken != null) {
                     appToken.updateReportedVisibilityLocked();
                 }
@@ -2177,6 +2127,10 @@
     }
 
     void removeWindowInnerLocked(WindowState win) {
+        removeWindowInnerLocked(win, true);
+    }
+
+    void removeWindowInnerLocked(WindowState win, boolean performLayout) {
         if (win.mRemoved) {
             // Nothing to do.
             return;
@@ -2268,13 +2222,15 @@
         final WindowList windows = win.getWindowList();
         if (windows != null) {
             windows.remove(win);
-            if (!mInLayout) {
+            if (!mWindowPlacerLocked.isInLayout()) {
                 assignLayersLocked(windows);
                 final DisplayContent displayContent = win.getDisplayContent();
                 if (displayContent != null) {
                     displayContent.layoutNeeded = true;
                 }
-                performLayoutAndPlaceSurfacesLocked();
+                if (performLayout) {
+                    mWindowPlacerLocked.performSurfacePlacement();
+                }
                 if (win.mAppToken != null) {
                     win.mAppToken.updateReportedVisibilityLocked();
                 }
@@ -2357,7 +2313,7 @@
                     if (displayContent != null) {
                         displayContent.layoutNeeded = true;
                     }
-                    performLayoutAndPlaceSurfacesLocked();
+                    mWindowPlacerLocked.performSurfacePlacement();
                 }
             }
         } finally {
@@ -2686,7 +2642,7 @@
             }
             win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
             configChanged = updateOrientationFromAppTokensLocked(false);
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
             if (toBeDisplayed && win.mIsWallpaper) {
                 DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
                 mWallpaperControllerLocked.updateWallpaperOffset(
@@ -3019,7 +2975,7 @@
                     wtoken.hidden = true;
 
                     if (changed) {
-                        performLayoutAndPlaceSurfacesLocked();
+                        mWindowPlacerLocked.performSurfacePlacement();
                         updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
                                 false /*updateInputWindows*/);
                     }
@@ -3385,7 +3341,7 @@
                 mWaitingForConfig = false;
                 mLastFinishedFreezeSource = "new-config";
             }
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
@@ -3583,7 +3539,7 @@
                 mAppTransition.setReady();
                 final long origId = Binder.clearCallingIdentity();
                 try {
-                    performLayoutAndPlaceSurfacesLocked();
+                    mWindowPlacerLocked.performSurfacePlacement();
                 } finally {
                     Binder.restoreCallingIdentity(origId);
                 }
@@ -3690,7 +3646,7 @@
                         updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                                 true /*updateInputWindows*/);
                         getDefaultDisplayContentLocked().layoutNeeded = true;
-                        performLayoutAndPlaceSurfacesLocked();
+                        mWindowPlacerLocked.performSurfacePlacement();
                         Binder.restoreCallingIdentity(origId);
                         return;
                     } else if (ttoken.startingData != null) {
@@ -3956,7 +3912,7 @@
                 if (performLayout) {
                     updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                             false /*updateInputWindows*/);
-                    performLayoutAndPlaceSurfacesLocked();
+                    mWindowPlacerLocked.performSurfacePlacement();
                 }
                 mInputMonitor.updateInputWindowsLw(false /*force*/);
             }
@@ -4094,7 +4050,7 @@
                             && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
                         if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w);
                         w.mOrientationChanging = true;
-                        mInnerFields.mOrientationChangeComplete = false;
+                        mWindowPlacerLocked.mOrientationChangeComplete = false;
                     }
                     w.mLastFreezeDuration = 0;
                     unfrozeWindows = true;
@@ -4114,7 +4070,7 @@
             }
             if (unfreezeSurfaceNow) {
                 if (unfrozeWindows) {
-                    performLayoutAndPlaceSurfacesLocked();
+                    mWindowPlacerLocked.performSurfacePlacement();
                 }
                 stopFreezingDisplayLocked();
             }
@@ -4402,7 +4358,7 @@
         }
 
         mInputMonitor.setUpdateInputWindowsNeededLw();
-        performLayoutAndPlaceSurfacesLocked();
+        mWindowPlacerLocked.performSurfacePlacement();
         mInputMonitor.updateInputWindowsLw(false /*force*/);
 
         //dump();
@@ -4525,7 +4481,9 @@
     }
 
     public void removeStack(int stackId) {
-        mStackIdToStack.remove(stackId);
+        synchronized (mWindowMap) {
+            mStackIdToStack.remove(stackId);
+        }
     }
 
     public void removeTask(int taskId) {
@@ -4552,7 +4510,7 @@
             stack.addTask(task, toTop);
             final DisplayContent displayContent = stack.getDisplayContent();
             displayContent.layoutNeeded = true;
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
@@ -4573,7 +4531,7 @@
             task.moveTaskToStack(stack, toTop);
             final DisplayContent displayContent = stack.getDisplayContent();
             displayContent.layoutNeeded = true;
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
@@ -4608,7 +4566,7 @@
             if (stack.setBounds(bounds, resizeTasks, configs, taskBounds)) {
                 stack.resizeWindows();
                 stack.getDisplayContent().layoutNeeded = true;
-                performLayoutAndPlaceSurfacesLocked();
+                mWindowPlacerLocked.performSurfacePlacement();
             }
             return stack.isFullscreen();
         }
@@ -4633,7 +4591,7 @@
             task.positionTaskInStack(stack, position);
             final DisplayContent displayContent = stack.getDisplayContent();
             displayContent.layoutNeeded = true;
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
@@ -4653,7 +4611,7 @@
                 task.resizeWindows();
                 if (relayout) {
                     task.getDisplayContent().layoutNeeded = true;
-                    performLayoutAndPlaceSurfacesLocked();
+                    mWindowPlacerLocked.performSurfacePlacement();
                 }
             }
         }
@@ -5046,7 +5004,7 @@
                 displayContent.switchUserStacks();
                 rebuildAppWindowListLocked(displayContent);
             }
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
@@ -5885,7 +5843,7 @@
             changed = updateRotationUncheckedLocked(false);
             if (!changed || forceRelayout) {
                 getDefaultDisplayContentLocked().layoutNeeded = true;
-                performLayoutAndPlaceSurfacesLocked();
+                mWindowPlacerLocked.performSurfacePlacement();
             }
         }
 
@@ -6019,7 +5977,7 @@
             if (w.mHasSurface) {
                 if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
                 w.mOrientationChanging = true;
-                mInnerFields.mOrientationChangeComplete = false;
+                mWindowPlacerLocked.mOrientationChangeComplete = false;
             }
             w.mLastFreezeDuration = 0;
         }
@@ -7170,7 +7128,7 @@
                 case DO_TRAVERSAL: {
                     synchronized(mWindowMap) {
                         mTraversalScheduled = false;
-                        performLayoutAndPlaceSurfacesLocked();
+                        mWindowPlacerLocked.performSurfacePlacement();
                     }
                 } break;
 
@@ -7342,7 +7300,7 @@
                                 Slog.w(TAG, "Force clearing orientation change: " + w);
                             }
                         }
-                        performLayoutAndPlaceSurfacesLocked();
+                        mWindowPlacerLocked.performSurfacePlacement();
                     }
                     break;
                 }
@@ -7356,7 +7314,7 @@
                                     + " mOpeningApps.size()=" + mOpeningApps.size()
                                     + " mClosingApps.size()=" + mClosingApps.size());
                             mAppTransition.setTimeout();
-                            performLayoutAndPlaceSurfacesLocked();
+                            mWindowPlacerLocked.performSurfacePlacement();
                         }
                     }
                     break;
@@ -7619,7 +7577,7 @@
                 case WALLPAPER_DRAW_PENDING_TIMEOUT: {
                     synchronized (mWindowMap) {
                         if (mWallpaperControllerLocked.processWallpaperDrawPendingTimeout()) {
-                            performLayoutAndPlaceSurfacesLocked();
+                            mWindowPlacerLocked.performSurfacePlacement();
                         }
                     }
                 }
@@ -8011,7 +7969,7 @@
             mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
         }
 
-        performLayoutAndPlaceSurfacesLocked();
+        mWindowPlacerLocked.performSurfacePlacement();
     }
 
     private void configureDisplayPolicyLocked(DisplayContent displayContent) {
@@ -8199,7 +8157,7 @@
         Arrays.fill(mRebuildTmp, null);
     }
 
-    private final void assignLayersLocked(WindowList windows) {
+    final void assignLayersLocked(WindowList windows) {
         int N = windows.size();
         int curBaseLayer = 0;
         int curLayer = 0;
@@ -8269,253 +8227,6 @@
         }
     }
 
-    private final void performLayoutAndPlaceSurfacesLocked() {
-        int loopCount = 6;
-        do {
-            mTraversalScheduled = false;
-            performLayoutAndPlaceSurfacesLockedLoop();
-            mH.removeMessages(H.DO_TRAVERSAL);
-            loopCount--;
-        } while (mTraversalScheduled && loopCount > 0);
-        mInnerFields.mWallpaperActionPending = false;
-    }
-
-    private boolean mInLayout = false;
-    private final void performLayoutAndPlaceSurfacesLockedLoop() {
-        if (mInLayout) {
-            if (DEBUG) {
-                throw new RuntimeException("Recursive call!");
-            }
-            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
-                    + Debug.getCallers(3));
-            return;
-        }
-
-        if (mWaitingForConfig) {
-            // Our configuration has changed (most likely rotation), but we
-            // don't yet have the complete configuration to report to
-            // applications.  Don't do any window layout until we have it.
-            return;
-        }
-
-        if (!mDisplayReady) {
-            // Not yet initialized, nothing to do.
-            return;
-        }
-
-        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
-        mInLayout = true;
-
-        boolean recoveringMemory = false;
-        if (!mForceRemoves.isEmpty()) {
-            recoveringMemory = true;
-            // Wait a little bit for things to settle down, and off we go.
-            while (!mForceRemoves.isEmpty()) {
-                WindowState ws = mForceRemoves.remove(0);
-                Slog.i(TAG, "Force removing: " + ws);
-                removeWindowInnerLocked(ws);
-            }
-            Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
-            Object tmp = new Object();
-            synchronized (tmp) {
-                try {
-                    tmp.wait(250);
-                } catch (InterruptedException e) {
-                }
-            }
-        }
-
-        try {
-            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
-
-            mInLayout = false;
-
-            if (needsLayout()) {
-                if (++mLayoutRepeatCount < 6) {
-                    requestTraversalLocked();
-                } else {
-                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
-                    mLayoutRepeatCount = 0;
-                }
-            } else {
-                mLayoutRepeatCount = 0;
-            }
-
-            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
-                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
-                mH.sendEmptyMessage(H.REPORT_WINDOWS_CHANGE);
-            }
-        } catch (RuntimeException e) {
-            mInLayout = false;
-            Slog.wtf(TAG, "Unhandled exception while laying out windows", e);
-        }
-
-        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
-    }
-
-    private final void performLayoutLockedInner(final DisplayContent displayContent,
-                                    boolean initial, boolean updateInputWindows) {
-        if (!displayContent.layoutNeeded) {
-            return;
-        }
-        displayContent.layoutNeeded = false;
-        WindowList windows = displayContent.getWindowList();
-        boolean isDefaultDisplay = displayContent.isDefaultDisplay;
-
-        DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final int dw = displayInfo.logicalWidth;
-        final int dh = displayInfo.logicalHeight;
-
-        if (mInputConsumer != null) {
-            mInputConsumer.layout(dw, dh);
-        }
-
-        final int N = windows.size();
-        int i;
-
-        if (DEBUG_LAYOUT) {
-            Slog.v(TAG, "-------------------------------------");
-            Slog.v(TAG, "performLayout: needed="
-                    + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
-        }
-
-        mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation);
-        if (isDefaultDisplay) {
-            // Not needed on non-default displays.
-            mSystemDecorLayer = mPolicy.getSystemDecorLayerLw();
-            mScreenRect.set(0, 0, dw, dh);
-        }
-
-        mPolicy.getContentRectLw(mTmpContentRect);
-        displayContent.resize(mTmpContentRect);
-
-        int seq = mLayoutSeq+1;
-        if (seq < 0) seq = 0;
-        mLayoutSeq = seq;
-
-        boolean behindDream = false;
-
-        // First perform layout of any root windows (not attached
-        // to another window).
-        int topAttached = -1;
-        for (i = N-1; i >= 0; i--) {
-            final WindowState win = windows.get(i);
-
-            // Don't do layout of a window if it is not visible, or
-            // soon won't be visible, to avoid wasting time and funky
-            // changes while a window is animating away.
-            final boolean gone = (behindDream && mPolicy.canBeForceHidden(win, win.mAttrs))
-                    || win.isGoneForLayoutLw();
-
-            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
-                Slog.v(TAG, "1ST PASS " + win
-                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
-                        + " mLayoutAttached=" + win.mLayoutAttached
-                        + " screen changed=" + win.isConfigChanged());
-                final AppWindowToken atoken = win.mAppToken;
-                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
-                        + win.mViewVisibility + " mRelayoutCalled="
-                        + win.mRelayoutCalled + " hidden="
-                        + win.mRootToken.hidden + " hiddenRequested="
-                        + (atoken != null && atoken.hiddenRequested)
-                        + " mAttachedHidden=" + win.mAttachedHidden);
-                else Slog.v(TAG, "  VIS: mViewVisibility="
-                        + win.mViewVisibility + " mRelayoutCalled="
-                        + win.mRelayoutCalled + " hidden="
-                        + win.mRootToken.hidden + " hiddenRequested="
-                        + (atoken != null && atoken.hiddenRequested)
-                        + " mAttachedHidden=" + win.mAttachedHidden);
-            }
-
-            // If this view is GONE, then skip it -- keep the current
-            // frame, and let the caller know so they can ignore it
-            // if they want.  (We do the normal layout for INVISIBLE
-            // windows, since that means "perform layout as normal,
-            // just don't display").
-            if (!gone || !win.mHaveFrame || win.mLayoutNeeded
-                    || ((win.isConfigChanged() || win.setInsetsChanged()) &&
-                            ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
-                            (win.mHasSurface && win.mAppToken != null &&
-                            win.mAppToken.layoutConfigChanges)))) {
-                if (!win.mLayoutAttached) {
-                    if (initial) {
-                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
-                        win.mContentChanged = false;
-                    }
-                    if (win.mAttrs.type == TYPE_DREAM) {
-                        // Don't layout windows behind a dream, so that if it
-                        // does stuff like hide the status bar we won't get a
-                        // bad transition when it goes away.
-                        behindDream = true;
-                    }
-                    win.mLayoutNeeded = false;
-                    win.prelayout();
-                    mPolicy.layoutWindowLw(win, null);
-                    win.mLayoutSeq = seq;
-                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
-                            + win.mFrame + " mContainingFrame="
-                            + win.mContainingFrame + " mDisplayFrame="
-                            + win.mDisplayFrame);
-                } else {
-                    if (topAttached < 0) topAttached = i;
-                }
-            }
-        }
-
-        boolean attachedBehindDream = false;
-
-        // Now perform layout of attached windows, which usually
-        // depend on the position of the window they are attached to.
-        // XXX does not deal with windows that are attached to windows
-        // that are themselves attached.
-        for (i = topAttached; i >= 0; i--) {
-            final WindowState win = windows.get(i);
-
-            if (win.mLayoutAttached) {
-                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
-                        + " mHaveFrame=" + win.mHaveFrame
-                        + " mViewVisibility=" + win.mViewVisibility
-                        + " mRelayoutCalled=" + win.mRelayoutCalled);
-                // If this view is GONE, then skip it -- keep the current
-                // frame, and let the caller know so they can ignore it
-                // if they want.  (We do the normal layout for INVISIBLE
-                // windows, since that means "perform layout as normal,
-                // just don't display").
-                if (attachedBehindDream && mPolicy.canBeForceHidden(win, win.mAttrs)) {
-                    continue;
-                }
-                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
-                        || !win.mHaveFrame || win.mLayoutNeeded) {
-                    if (initial) {
-                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
-                        win.mContentChanged = false;
-                    }
-                    win.mLayoutNeeded = false;
-                    win.prelayout();
-                    mPolicy.layoutWindowLw(win, win.mAttachedWindow);
-                    win.mLayoutSeq = seq;
-                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
-                            + win.mFrame + " mContainingFrame="
-                            + win.mContainingFrame + " mDisplayFrame="
-                            + win.mDisplayFrame);
-                }
-            } else if (win.mAttrs.type == TYPE_DREAM) {
-                // Don't layout windows behind a dream, so that if it
-                // does stuff like hide the status bar we won't get a
-                // bad transition when it goes away.
-                attachedBehindDream = behindDream;
-            }
-        }
-
-        // Window frames may have changed.  Tell the input dispatcher about it.
-        mInputMonitor.setUpdateInputWindowsNeededLw();
-        if (updateInputWindows) {
-            mInputMonitor.updateInputWindowsLw(false /*force*/);
-        }
-
-        mPolicy.finishLayoutLw();
-    }
-
     void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
         // If the screen is currently frozen or off, then keep
         // it frozen/off until this window draws at its new
@@ -8524,7 +8235,7 @@
             if (DEBUG_ORIENTATION) Slog.v(TAG, "Changing surface while display frozen: " + w);
             w.mOrientationChanging = true;
             w.mLastFreezeDuration = 0;
-            mInnerFields.mOrientationChangeComplete = false;
+            mWindowPlacerLocked.mOrientationChangeComplete = false;
             if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
                 mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
                 // XXX should probably keep timeout from
@@ -8537,411 +8248,9 @@
     }
 
     /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     * @param windows List of windows on default display.
      * @return bitmap indicating if another pass through layout must be made.
      */
-    public int handleAppTransitionReadyLocked(WindowList windows) {
-        int appsCount = mOpeningApps.size();
-        if (!checkIfTransitionGoodToGo(appsCount)) {
-            return 0;
-        }
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
-        int transit = mAppTransition.getAppTransition();
-        if (mSkipAppTransitionAnimation) {
-            transit = AppTransition.TRANSIT_UNSET;
-        }
-        mSkipAppTransitionAnimation = false;
-        mNoAnimationNotifyOnTransitionFinished.clear();
-
-        mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
-
-        rebuildAppWindowListLocked();
-
-        mInnerFields.mWallpaperMayChange = false;
-
-        // The top-most window will supply the layout params,
-        // and we will determine it below.
-        LayoutParams animLp = null;
-        int bestAnimLayer = -1;
-        boolean fullscreenAnim = false;
-        boolean voiceInteraction = false;
-
-        final WindowState lowerWallpaperTarget =
-                mWallpaperControllerLocked.getLowerWallpaperTarget();
-        final WindowState upperWallpaperTarget =
-                mWallpaperControllerLocked.getUpperWallpaperTarget();
-
-        boolean openingAppHasWallpaper = false;
-        boolean closingAppHasWallpaper = false;
-        final AppWindowToken lowerWallpaperAppToken;
-        final AppWindowToken upperWallpaperAppToken;
-        if (lowerWallpaperTarget == null) {
-            lowerWallpaperAppToken = upperWallpaperAppToken = null;
-        } else {
-            lowerWallpaperAppToken = lowerWallpaperTarget.mAppToken;
-            upperWallpaperAppToken = upperWallpaperTarget.mAppToken;
-        }
-
-        int i;
-        // Do a first pass through the tokens for two
-        // things:
-        // (1) Determine if both the closing and opening
-        // app token sets are wallpaper targets, in which
-        // case special animations are needed
-        // (since the wallpaper needs to stay static
-        // behind them).
-        // (2) Find the layout params of the top-most
-        // application window in the tokens, which is
-        // what will control the animation theme.
-        final int closingAppsCount = mClosingApps.size();
-        appsCount = closingAppsCount + mOpeningApps.size();
-        for (i = 0; i < appsCount; i++) {
-            final AppWindowToken wtoken;
-            if (i < closingAppsCount) {
-                wtoken = mClosingApps.valueAt(i);
-                if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
-                    closingAppHasWallpaper = true;
-                }
-            } else {
-                wtoken = mOpeningApps.valueAt(i - closingAppsCount);
-                if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
-                    openingAppHasWallpaper = true;
-                }
-            }
-
-            voiceInteraction |= wtoken.voiceInteraction;
-
-            if (wtoken.appFullscreen) {
-                WindowState ws = wtoken.findMainWindow();
-                if (ws != null) {
-                    animLp = ws.mAttrs;
-                    bestAnimLayer = ws.mLayer;
-                    fullscreenAnim = true;
-                }
-            } else if (!fullscreenAnim) {
-                WindowState ws = wtoken.findMainWindow();
-                if (ws != null) {
-                    if (ws.mLayer > bestAnimLayer) {
-                        animLp = ws.mAttrs;
-                        bestAnimLayer = ws.mLayer;
-                    }
-                }
-            }
-        }
-
-        transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
-                closingAppHasWallpaper, lowerWallpaperTarget, upperWallpaperTarget);
-
-        // If all closing windows are obscured, then there is
-        // no need to do an animation.  This is the case, for
-        // example, when this transition is being done behind
-        // the lock screen.
-        if (!mPolicy.allowAppAnimationsLw()) {
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                    "Animations disallowed by keyguard or dream.");
-            animLp = null;
-        }
-
-        processApplicationsAnimatingInPlace(transit);
-
-        AppWindowToken topClosingApp = null;
-        int topClosingLayer = 0;
-        appsCount = mClosingApps.size();
-        for (i = 0; i < appsCount; i++) {
-            AppWindowToken wtoken = mClosingApps.valueAt(i);
-            final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
-            appAnimator.clearThumbnail();
-            appAnimator.animation = null;
-            wtoken.inPendingTransaction = false;
-            setTokenVisibilityLocked(wtoken, animLp, false, transit, false, voiceInteraction);
-            wtoken.updateReportedVisibilityLocked();
-            // Force the allDrawn flag, because we want to start
-            // this guy's animations regardless of whether it's
-            // gotten drawn.
-            wtoken.allDrawn = true;
-            wtoken.deferClearAllDrawn = false;
-            // Ensure that apps that are mid-starting are also scheduled to have their
-            // starting windows removed after the animation is complete
-            if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
-                scheduleRemoveStartingWindowLocked(wtoken);
-            }
-            mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
-
-            if (animLp != null) {
-                int layer = -1;
-                for (int j = 0; j < wtoken.windows.size(); j++) {
-                    WindowState win = wtoken.windows.get(j);
-                    if (win.mWinAnimator.mAnimLayer > layer) {
-                        layer = win.mWinAnimator.mAnimLayer;
-                    }
-                }
-                if (topClosingApp == null || layer > topClosingLayer) {
-                    topClosingApp = wtoken;
-                    topClosingLayer = layer;
-                }
-            }
-        }
-
-        AppWindowToken topOpeningApp = null;
-        appsCount = mOpeningApps.size();
-        for (i = 0; i < appsCount; i++) {
-            AppWindowToken wtoken = mOpeningApps.valueAt(i);
-            final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
-
-            if (!appAnimator.usingTransferredAnimation) {
-                appAnimator.clearThumbnail();
-                appAnimator.animation = null;
-            }
-            wtoken.inPendingTransaction = false;
-            if (!setTokenVisibilityLocked(
-                    wtoken, animLp, true, transit, false, voiceInteraction)){
-                // This token isn't going to be animating. Add it to the list of tokens to
-                // be notified of app transition complete since the notification will not be
-                // sent be the app window animator.
-                mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
-            }
-            wtoken.updateReportedVisibilityLocked();
-            wtoken.waitingToShow = false;
-
-            appAnimator.mAllAppWinAnimators.clear();
-            final int windowsCount = wtoken.allAppWindows.size();
-            for (int j = 0; j < windowsCount; j++) {
-                appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
-            }
-            mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
-            mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
-
-            int topOpeningLayer = 0;
-            if (animLp != null) {
-                int layer = -1;
-                for (int j = 0; j < wtoken.windows.size(); j++) {
-                    WindowState win = wtoken.windows.get(j);
-                    if (win.mWinAnimator.mAnimLayer > layer) {
-                        layer = win.mWinAnimator.mAnimLayer;
-                    }
-                }
-                if (topOpeningApp == null || layer > topOpeningLayer) {
-                    topOpeningApp = wtoken;
-                    topOpeningLayer = layer;
-                }
-            }
-            createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer);
-        }
-
-        AppWindowAnimator openingAppAnimator = (topOpeningApp == null) ?  null :
-                topOpeningApp.mAppAnimator;
-        AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :
-                topClosingApp.mAppAnimator;
-
-        mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);
-        mAppTransition.postAnimationCallback();
-        mAppTransition.clear();
-
-        mOpeningApps.clear();
-        mClosingApps.clear();
-
-        // This has changed the visibility of windows, so perform
-        // a new layout to get them all up-to-date.
-        getDefaultDisplayContentLocked().layoutNeeded = true;
-
-        // TODO(multidisplay): IMEs are only supported on the default display.
-        if (windows == getDefaultWindowListLocked()
-                && !moveInputMethodWindowsIfNeededLocked(true)) {
-            assignLayersLocked(windows);
-        }
-        updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, true /*updateInputWindows*/);
-        mFocusMayChange = false;
-        notifyActivityDrawnForKeyguard();
-        return WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
-                | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
-
-    }
-
-    private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
-            boolean closingAppHasWallpaper, WindowState lowerWallpaperTarget,
-            WindowState upperWallpaperTarget) {
-        // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
-        final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
-        final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating()
-                ? null : wallpaperTarget;
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                "New wallpaper target=" + wallpaperTarget
-                        + ", oldWallpaper=" + oldWallpaper
-                        + ", lower target=" + lowerWallpaperTarget
-                        + ", upper target=" + upperWallpaperTarget);
-        mAnimateWallpaperWithTarget = false;
-        if (closingAppHasWallpaper && openingAppHasWallpaper) {
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
-            switch (transit) {
-                case AppTransition.TRANSIT_ACTIVITY_OPEN:
-                case AppTransition.TRANSIT_TASK_OPEN:
-                case AppTransition.TRANSIT_TASK_TO_FRONT:
-                    transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
-                    break;
-                case AppTransition.TRANSIT_ACTIVITY_CLOSE:
-                case AppTransition.TRANSIT_TASK_CLOSE:
-                case AppTransition.TRANSIT_TASK_TO_BACK:
-                    transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
-                    break;
-            }
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                    "New transit: " + AppTransition.appTransitionToString(transit));
-        } else if ((oldWallpaper != null) && !mOpeningApps.isEmpty()
-                && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
-            // We are transitioning from an activity with
-            // a wallpaper to one without.
-            transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                    "New transit away from wallpaper: "
-                    + AppTransition.appTransitionToString(transit));
-        } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()) {
-            // We are transitioning from an activity without
-            // a wallpaper to now showing the wallpaper
-            transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                    "New transit into wallpaper: "
-                    + AppTransition.appTransitionToString(transit));
-        } else {
-            mAnimateWallpaperWithTarget = true;
-        }
-        return transit;
-    }
-
-    private void processApplicationsAnimatingInPlace(int transit) {
-        if (transit == AppTransition.TRANSIT_TASK_IN_PLACE) {
-            // Find the focused window
-            final WindowState win =
-                    findFocusedWindowLocked(getDefaultDisplayContentLocked());
-            if (win != null) {
-                final AppWindowToken wtoken = win.mAppToken;
-                final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now animating app in place " + wtoken);
-                appAnimator.clearThumbnail();
-                appAnimator.animation = null;
-                updateTokenInPlaceLocked(wtoken, transit);
-                wtoken.updateReportedVisibilityLocked();
-
-                appAnimator.mAllAppWinAnimators.clear();
-                final int N = wtoken.allAppWindows.size();
-                for (int j = 0; j < N; j++) {
-                    appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
-                }
-                mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
-                mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
-            }
-        }
-    }
-
-    private boolean checkIfTransitionGoodToGo(int appsCount) {
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                "Checking " + appsCount + " opening apps (frozen="
-                        + mDisplayFrozen + " timeout="
-                        + mAppTransition.isTimeout() + ")...");
-        if (!mAppTransition.isTimeout()) {
-            for (int i = 0; i < appsCount; i++) {
-                AppWindowToken wtoken = mOpeningApps.valueAt(i);
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                        "Check opening app=" + wtoken + ": allDrawn="
-                        + wtoken.allDrawn + " startingDisplayed="
-                        + wtoken.startingDisplayed + " startingMoved="
-                        + wtoken.startingMoved);
-                if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
-                    return false;
-                }
-            }
-
-            // If the wallpaper is visible, we need to check it's ready too.
-            return !mWallpaperControllerLocked.isWallpaperVisible() ||
-                    mWallpaperControllerLocked.wallpaperTransitionReady();
-        }
-        return true;
-    }
-
-    private void createThumbnailAppAnimator(int transit, AppWindowToken appToken,
-            int openingLayer, int closingLayer) {
-        AppWindowAnimator openingAppAnimator = (appToken == null) ? null : appToken.mAppAnimator;
-        if (openingAppAnimator == null || openingAppAnimator.animation == null) {
-            return;
-        }
-        final int taskId = appToken.mTask.mTaskId;
-        Bitmap thumbnailHeader = mAppTransition.getAppTransitionThumbnailHeader(taskId);
-        if (thumbnailHeader == null || thumbnailHeader.getConfig() == Config.ALPHA_8) {
-            return;
-        }
-        // This thumbnail animation is very special, we need to have
-        // an extra surface with the thumbnail included with the animation.
-        Rect dirty = new Rect(0, 0, thumbnailHeader.getWidth(), thumbnailHeader.getHeight());
-        try {
-            // TODO(multi-display): support other displays
-            final DisplayContent displayContent = getDefaultDisplayContentLocked();
-            final Display display = displayContent.getDisplay();
-            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-
-            // Create a new surface for the thumbnail
-            SurfaceControl surfaceControl = new SurfaceControl(mFxSession,
-                    "thumbnail anim", dirty.width(), dirty.height(),
-                    PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
-            surfaceControl.setLayerStack(display.getLayerStack());
-            if (SHOW_TRANSACTIONS) {
-                Slog.i(TAG, "  THUMBNAIL " + surfaceControl + ": CREATE");
-            }
-
-            // Draw the thumbnail onto the surface
-            Surface drawSurface = new Surface();
-            drawSurface.copyFrom(surfaceControl);
-            Canvas c = drawSurface.lockCanvas(dirty);
-            c.drawBitmap(thumbnailHeader, 0, 0, null);
-            drawSurface.unlockCanvasAndPost(c);
-            drawSurface.release();
-
-            // Get the thumbnail animation
-            Animation anim;
-            if (mAppTransition.isNextThumbnailTransitionAspectScaled()) {
-                // If this is a multi-window scenario, we use the windows frame as
-                // destination of the thumbnail header animation. If this is a full screen
-                // window scenario, we use the whole display as the target.
-                WindowState win = appToken.findMainWindow();
-                Rect appRect = win != null ? win.getContentFrameLw() :
-                        new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
-                // For the new aspect-scaled transition, we want it to always show
-                // above the animating opening/closing window, and we want to
-                // synchronize its thumbnail surface with the surface for the
-                // open/close animation (only on the way down)
-                anim = mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect,
-                        thumbnailHeader, taskId);
-                Log.d(TAG, "assigning thumbnail force above layer: " + openingLayer + " " +
-                        closingLayer);
-                openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer);
-                openingAppAnimator.deferThumbnailDestruction =
-                        !mAppTransition.isNextThumbnailTransitionScaleUp();
-            } else {
-                anim = mAppTransition.createThumbnailScaleAnimationLocked(
-                        displayInfo.appWidth, displayInfo.appHeight, transit, thumbnailHeader);
-            }
-            anim.restrictDuration(MAX_ANIMATION_DURATION);
-            anim.scaleCurrentDuration(getTransitionAnimationScaleLocked());
-
-            openingAppAnimator.thumbnail = surfaceControl;
-            openingAppAnimator.thumbnailLayer = openingLayer;
-            openingAppAnimator.thumbnailAnimation = anim;
-            mAppTransition.getNextAppTransitionStartRect(taskId, mTmpStartRect);
-            openingAppAnimator.thumbnailX = mTmpStartRect.left;
-            openingAppAnimator.thumbnailY = mTmpStartRect.top;
-        } catch (OutOfResourcesException e) {
-            Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w=" + dirty.width()
-                    + " h=" + dirty.height(), e);
-            openingAppAnimator.clearThumbnail();
-        }
-    }
-
-    /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     * @return bitmap indicating if another pass through layout must be made.
-     */
-    private int handleAnimatingStoppedAndTransitionLocked() {
+    int handleAnimatingStoppedAndTransitionLocked() {
         int changes = 0;
 
         mAppTransition.setIdle();
@@ -8971,7 +8280,7 @@
         if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
                 "Wallpaper layer changed: assigning layers + relayout");
         moveInputMethodWindowsIfNeededLocked(true);
-        mInnerFields.mWallpaperMayChange = true;
+        mWindowPlacerLocked.mWallpaperMayChange = true;
         // Since the window list has been rebuilt, focus might
         // have to be recomputed since the actual order of windows
         // might have changed again.
@@ -8980,7 +8289,7 @@
         return changes;
     }
 
-    private void updateResizingWindows(final WindowState w) {
+    void updateResizingWindows(final WindowState w) {
         final WindowStateAnimator winAnimator = w.mWinAnimator;
         if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
             w.setInsetsChanged();
@@ -9052,707 +8361,6 @@
         }
     }
 
-    /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     * @param w WindowState this method is applied to.
-     * @param innerDw Width of app window.
-     * @param innerDh Height of app window.
-     */
-    private void handleNotObscuredLocked(final WindowState w,
-            final int innerDw, final int innerDh) {
-        final WindowManager.LayoutParams attrs = w.mAttrs;
-        final int attrFlags = attrs.flags;
-        final boolean canBeSeen = w.isDisplayedLw();
-        final boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
-
-        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
-            // This window completely covers everything behind it,
-            // so we want to leave all of them as undimmed (for
-            // performance reasons).
-            mInnerFields.mObscured = true;
-        }
-
-        if (w.mHasSurface) {
-            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
-                mInnerFields.mHoldScreen = w.mSession;
-            }
-            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
-                    && mInnerFields.mScreenBrightness < 0) {
-                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
-            }
-            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
-                    && mInnerFields.mButtonBrightness < 0) {
-                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
-            }
-            if (!mInnerFields.mSyswin && w.mAttrs.userActivityTimeout >= 0
-                    && mInnerFields.mUserActivityTimeout < 0) {
-                mInnerFields.mUserActivityTimeout = w.mAttrs.userActivityTimeout;
-            }
-
-            final int type = attrs.type;
-            if (canBeSeen
-                    && (type == TYPE_SYSTEM_DIALOG
-                     || type == TYPE_SYSTEM_ERROR
-                     || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0)) {
-                mInnerFields.mSyswin = true;
-            }
-
-            if (canBeSeen) {
-                // This function assumes that the contents of the default display are
-                // processed first before secondary displays.
-                final DisplayContent displayContent = w.getDisplayContent();
-                if (displayContent != null && displayContent.isDefaultDisplay) {
-                    // While a dream or keyguard is showing, obscure ordinary application
-                    // content on secondary displays (by forcibly enabling mirroring unless
-                    // there is other content we want to show) but still allow opaque
-                    // keyguard dialogs to be shown.
-                    if (type == TYPE_DREAM || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-                        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = true;
-                    }
-                    mInnerFields.mDisplayHasContent = true;
-                } else if (displayContent != null &&
-                        (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays
-                        || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG))) {
-                    // Allow full screen keyguard presentation dialogs to be seen.
-                    mInnerFields.mDisplayHasContent = true;
-                }
-                if (mInnerFields.mPreferredRefreshRate == 0
-                        && w.mAttrs.preferredRefreshRate != 0) {
-                    mInnerFields.mPreferredRefreshRate = w.mAttrs.preferredRefreshRate;
-                }
-                if (mInnerFields.mPreferredModeId == 0
-                        && w.mAttrs.preferredDisplayModeId != 0) {
-                    mInnerFields.mPreferredModeId = w.mAttrs.preferredDisplayModeId;
-                }
-            }
-        }
-    }
-
-    private void handleFlagDimBehind(WindowState w) {
-        final WindowManager.LayoutParams attrs = w.mAttrs;
-        if ((attrs.flags & FLAG_DIM_BEHIND) != 0
-                && w.isDisplayedLw()
-                && !w.mExiting) {
-            final WindowStateAnimator winAnimator = w.mWinAnimator;
-            final Task task = w.getTask();
-            if (task == null) {
-                return;
-            }
-            task.setContinueDimming();
-            if (!task.isDimming(winAnimator)) {
-                if (localLOGV) Slog.v(TAG, "Win " + w + " start dimming.");
-                task.startDimmingIfNeeded(winAnimator);
-            }
-        }
-    }
-
-    private void updateAllDrawnLocked(DisplayContent displayContent) {
-        // See if any windows have been drawn, so they (and others
-        // associated with them) can now be shown.
-        ArrayList<TaskStack> stacks = displayContent.getStacks();
-        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                    final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    if (!wtoken.allDrawn) {
-                        int numInteresting = wtoken.numInterestingWindows;
-                        if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
-                            if (DEBUG_VISIBILITY) Slog.v(TAG,
-                                    "allDrawn: " + wtoken
-                                    + " interesting=" + numInteresting
-                                    + " drawn=" + wtoken.numDrawnWindows);
-                            wtoken.allDrawn = true;
-                            // Force an additional layout pass where WindowStateAnimator#
-                            // commitFinishDrawingLocked() will call performShowLocked().
-                            displayContent.layoutNeeded = true;
-                            mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // "Something has changed!  Let's make it correct now."
-    private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
-        if (DEBUG_WINDOW_TRACE) {
-            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
-                    + Debug.getCallers(3));
-        }
-
-        int i;
-        boolean updateInputWindowsNeeded = false;
-
-        if (mFocusMayChange) {
-            mFocusMayChange = false;
-            updateInputWindowsNeeded = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
-                    false /*updateInputWindows*/);
-        }
-
-        // Initialize state of exiting tokens.
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-            for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
-                displayContent.mExitingTokens.get(i).hasVisible = false;
-            }
-        }
-
-        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
-            // Initialize state of exiting applications.
-            final AppTokenList exitingAppTokens =
-                    mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
-            for (int tokenNdx = exitingAppTokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                exitingAppTokens.get(tokenNdx).hasVisible = false;
-            }
-        }
-
-        mInnerFields.mHoldScreen = null;
-        mInnerFields.mScreenBrightness = -1;
-        mInnerFields.mButtonBrightness = -1;
-        mInnerFields.mUserActivityTimeout = -1;
-        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = false;
-
-        mTransactionSequence++;
-
-        final DisplayContent defaultDisplay = getDefaultDisplayContentLocked();
-        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
-        final int defaultDw = defaultInfo.logicalWidth;
-        final int defaultDh = defaultInfo.logicalHeight;
-
-        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
-        SurfaceControl.openTransaction();
-        try {
-
-            if (mWatermark != null) {
-                mWatermark.positionSurface(defaultDw, defaultDh);
-            }
-            if (mStrictModeFlash != null) {
-                mStrictModeFlash.positionSurface(defaultDw, defaultDh);
-            }
-            if (mCircularDisplayMask != null) {
-                mCircularDisplayMask.positionSurface(defaultDw, defaultDh, mRotation);
-            }
-            if (mEmulatorDisplayOverlay != null) {
-                mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh, mRotation);
-            }
-
-            boolean focusDisplayed = false;
-
-            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-                boolean updateAllDrawn = false;
-                WindowList windows = displayContent.getWindowList();
-                DisplayInfo displayInfo = displayContent.getDisplayInfo();
-                final int displayId = displayContent.getDisplayId();
-                final int dw = displayInfo.logicalWidth;
-                final int dh = displayInfo.logicalHeight;
-                final int innerDw = displayInfo.appWidth;
-                final int innerDh = displayInfo.appHeight;
-                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
-
-                // Reset for each display.
-                mInnerFields.mDisplayHasContent = false;
-                mInnerFields.mPreferredRefreshRate = 0;
-                mInnerFields.mPreferredModeId = 0;
-
-                int repeats = 0;
-                do {
-                    repeats++;
-                    if (repeats > 6) {
-                        Slog.w(TAG, "Animation repeat aborted after too many iterations");
-                        displayContent.layoutNeeded = false;
-                        break;
-                    }
-
-                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
-                        displayContent.pendingLayoutChanges);
-
-                    if ((displayContent.pendingLayoutChanges &
-                            WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
-                            mWallpaperControllerLocked.adjustWallpaperWindows()) {
-                        assignLayersLocked(windows);
-                        displayContent.layoutNeeded = true;
-                    }
-
-                    if (isDefaultDisplay && (displayContent.pendingLayoutChanges
-                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
-                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
-                        if (updateOrientationFromAppTokensLocked(true)) {
-                            displayContent.layoutNeeded = true;
-                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
-                        }
-                    }
-
-                    if ((displayContent.pendingLayoutChanges
-                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
-                        displayContent.layoutNeeded = true;
-                    }
-
-                    // FIRST LOOP: Perform a layout, if needed.
-                    if (repeats < LAYOUT_REPEAT_THRESHOLD) {
-                        performLayoutLockedInner(displayContent, repeats == 1,
-                                false /*updateInputWindows*/);
-                    } else {
-                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
-                    }
-
-                    // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
-                    // it is animating.
-                    displayContent.pendingLayoutChanges = 0;
-
-                    if (isDefaultDisplay) {
-                        mPolicy.beginPostLayoutPolicyLw(dw, dh);
-                        for (i = windows.size() - 1; i >= 0; i--) {
-                            WindowState w = windows.get(i);
-                            if (w.mHasSurface) {
-                                mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs, w.mAttachedWindow);
-                            }
-                        }
-                        displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
-                        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
-                            "after finishPostLayoutPolicyLw", displayContent.pendingLayoutChanges);
-                    }
-                } while (displayContent.pendingLayoutChanges != 0);
-
-                mInnerFields.mObscured = false;
-                mInnerFields.mSyswin = false;
-                displayContent.resetDimming();
-
-                // Only used if default window
-                final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
-
-                final int N = windows.size();
-                for (i=N-1; i>=0; i--) {
-                    WindowState w = windows.get(i);
-                    final Task task = w.getTask();
-                    if (task == null && w.getAttrs().type != TYPE_PRIVATE_PRESENTATION) {
-                        continue;
-                    }
-
-                    final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
-
-                    // Update effect.
-                    w.mObscured = mInnerFields.mObscured;
-                    if (!mInnerFields.mObscured) {
-                        handleNotObscuredLocked(w, innerDw, innerDh);
-                    }
-
-                    if (task != null && !task.getContinueDimming()) {
-                        handleFlagDimBehind(w);
-                    }
-
-                    if (isDefaultDisplay && obscuredChanged
-                            && mWallpaperControllerLocked.isWallpaperTarget(w) && w.isVisibleLw()) {
-                        // This is the wallpaper target and its obscured state
-                        // changed... make sure the current wallaper's visibility
-                        // has been updated accordingly.
-                        mWallpaperControllerLocked.updateWallpaperVisibility();
-                    }
-
-                    final WindowStateAnimator winAnimator = w.mWinAnimator;
-
-                    // If the window has moved due to its containing content frame changing, then
-                    // notify the listeners and optionally animate it.
-                    if (w.hasMoved()) {
-                        // Frame has moved, containing content frame has also moved, and we're not
-                        // currently animating... let's do something.
-                        final int left = w.mFrame.left;
-                        final int top = w.mFrame.top;
-                        if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0) {
-                            Animation a = AnimationUtils.loadAnimation(mContext,
-                                    com.android.internal.R.anim.window_move_from_decor);
-                            winAnimator.setAnimation(a);
-                            winAnimator.mAnimDw = w.mLastFrame.left - left;
-                            winAnimator.mAnimDh = w.mLastFrame.top - top;
-                            winAnimator.mAnimateMove = true;
-                            winAnimator.mAnimatingMove = true;
-                        }
-
-                        //TODO (multidisplay): Accessibility supported only for the default display.
-                        if (mAccessibilityController != null
-                                && displayId == Display.DEFAULT_DISPLAY) {
-                            mAccessibilityController.onSomeWindowResizedOrMovedLocked();
-                        }
-
-                        try {
-                            w.mClient.moved(left, top);
-                        } catch (RemoteException e) {
-                        }
-                    }
-
-                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
-                    w.mContentChanged = false;
-
-                    // Moved from updateWindowsAndWallpaperLocked().
-                    if (w.mHasSurface) {
-                        // Take care of the window being ready to display.
-                        final boolean committed =
-                                winAnimator.commitFinishDrawingLocked();
-                        if (isDefaultDisplay && committed) {
-                            if (w.mAttrs.type == TYPE_DREAM) {
-                                // HACK: When a dream is shown, it may at that
-                                // point hide the lock screen.  So we need to
-                                // redo the layout to let the phone window manager
-                                // make this happen.
-                                displayContent.pendingLayoutChanges |=
-                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-                                if (DEBUG_LAYOUT_REPEATS) {
-                                    debugLayoutRepeats(
-                                            "dream and commitFinishDrawingLocked true",
-                                            displayContent.pendingLayoutChanges);
-                                }
-                            }
-                            if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
-                                if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
-                                            "First draw done in potential wallpaper target " + w);
-                                mInnerFields.mWallpaperMayChange = true;
-                                displayContent.pendingLayoutChanges |=
-                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                                if (DEBUG_LAYOUT_REPEATS) {
-                                    debugLayoutRepeats(
-                                            "wallpaper and commitFinishDrawingLocked true",
-                                            displayContent.pendingLayoutChanges);
-                                }
-                            }
-                        }
-
-                        winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
-                    }
-
-                    final AppWindowToken atoken = w.mAppToken;
-                    if (DEBUG_STARTING_WINDOW && atoken != null
-                            && w == atoken.startingWindow) {
-                        Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
-                            + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
-                            + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
-                    }
-                    if (atoken != null
-                            && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
-                        if (atoken.lastTransactionSequence != mTransactionSequence) {
-                            atoken.lastTransactionSequence = mTransactionSequence;
-                            atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
-                            atoken.startingDisplayed = false;
-                        }
-                        if ((w.isOnScreenIgnoringKeyguard()
-                                || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
-                                && !w.mExiting && !w.mDestroying) {
-                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
-                                Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
-                                        + ", isAnimating=" + winAnimator.isAnimating());
-                                if (!w.isDrawnLw()) {
-                                    Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceControl
-                                            + " pv=" + w.mPolicyVisibility
-                                            + " mDrawState=" + winAnimator.drawStateToString()
-                                            + " ah=" + w.mAttachedHidden
-                                            + " th=" + atoken.hiddenRequested
-                                            + " a=" + winAnimator.mAnimating);
-                                }
-                            }
-                            if (w != atoken.startingWindow) {
-                                if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
-                                    atoken.numInterestingWindows++;
-                                    if (w.isDrawnLw()) {
-                                        atoken.numDrawnWindows++;
-                                        if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
-                                                "tokenMayBeDrawn: " + atoken
-                                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
-                                                + " mAppFreezing=" + w.mAppFreezing);
-                                        updateAllDrawn = true;
-                                    }
-                                }
-                            } else if (w.isDrawnLw()) {
-                                atoken.startingDisplayed = true;
-                            }
-                        }
-                    }
-
-                    if (isDefaultDisplay && someoneLosingFocus && (w == mCurrentFocus)
-                            && w.isDisplayedLw()) {
-                        focusDisplayed = true;
-                    }
-
-                    updateResizingWindows(w);
-                }
-
-                mDisplayManagerInternal.setDisplayProperties(displayId,
-                        mInnerFields.mDisplayHasContent, mInnerFields.mPreferredRefreshRate,
-                        mInnerFields.mPreferredModeId,
-                        true /* inTraversal, must call performTraversalInTrans... below */);
-
-                getDisplayContentLocked(displayId).stopDimmingIfNeeded();
-
-                if (updateAllDrawn) {
-                    updateAllDrawnLocked(displayContent);
-                }
-            }
-
-            if (focusDisplayed) {
-                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
-            }
-
-            // Give the display manager a chance to adjust properties
-            // like display rotation if it needs to.
-            mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
-
-        } catch (RuntimeException e) {
-            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
-        } finally {
-            SurfaceControl.closeTransaction();
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
-        }
-
-        final WindowList defaultWindows = defaultDisplay.getWindowList();
-
-        // If we are ready to perform an app transition, check through
-        // all of the app tokens to be shown and see if they are ready
-        // to go.
-        if (mAppTransition.isReady()) {
-            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
-                    defaultDisplay.pendingLayoutChanges);
-        }
-
-        if (!mAnimator.mAppWindowAnimating && mAppTransition.isRunning()) {
-            // We have finished the animation of an app transition.  To do
-            // this, we have delayed a lot of operations like showing and
-            // hiding apps, moving apps in Z-order, etc.  The app token list
-            // reflects the correct Z-order, but the window list may now
-            // be out of sync with it.  So here we will just rebuild the
-            // entire app window list.  Fun!
-            defaultDisplay.pendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
-                defaultDisplay.pendingLayoutChanges);
-        }
-
-        if (mInnerFields.mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
-                && !mAppTransition.isReady()) {
-            // At this point, there was a window with a wallpaper that
-            // was force hiding other windows behind it, but now it
-            // is going away.  This may be simple -- just animate
-            // away the wallpaper and its window -- or it may be
-            // hard -- the wallpaper now needs to be shown behind
-            // something that was hidden.
-            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
-                defaultDisplay.pendingLayoutChanges);
-        }
-        mInnerFields.mWallpaperForceHidingChanged = false;
-
-        if (mInnerFields.mWallpaperMayChange) {
-            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Wallpaper may change!  Adjusting");
-            defaultDisplay.pendingLayoutChanges |=
-                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("WallpaperMayChange",
-                    defaultDisplay.pendingLayoutChanges);
-        }
-
-        if (mFocusMayChange) {
-            mFocusMayChange = false;
-            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
-                    false /*updateInputWindows*/)) {
-                updateInputWindowsNeeded = true;
-                defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
-            }
-        }
-
-        if (needsLayout()) {
-            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
-                    defaultDisplay.pendingLayoutChanges);
-        }
-
-        for (i = mResizingWindows.size() - 1; i >= 0; i--) {
-            WindowState win = mResizingWindows.get(i);
-            if (win.mAppFreezing) {
-                // Don't remove this window until rotation has completed.
-                continue;
-            }
-            win.reportResized();
-            mResizingWindows.remove(i);
-        }
-
-        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
-                "With display frozen, orientationChangeComplete="
-                + mInnerFields.mOrientationChangeComplete);
-        if (mInnerFields.mOrientationChangeComplete) {
-            if (mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
-                mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
-                mLastFinishedFreezeSource = mInnerFields.mLastWindowFreezeSource;
-                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
-            }
-            stopFreezingDisplayLocked();
-        }
-
-        // Destroy the surface of any windows that are no longer visible.
-        boolean wallpaperDestroyed = false;
-        i = mDestroySurface.size();
-        if (i > 0) {
-            do {
-                i--;
-                WindowState win = mDestroySurface.get(i);
-                win.mDestroying = false;
-                if (mInputMethodWindow == win) {
-                    mInputMethodWindow = null;
-                }
-                if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
-                    wallpaperDestroyed = true;
-                }
-                win.mWinAnimator.destroySurfaceLocked();
-            } while (i > 0);
-            mDestroySurface.clear();
-        }
-
-        // Time to remove any exiting tokens?
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-            ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
-            for (i = exitingTokens.size() - 1; i >= 0; i--) {
-                WindowToken token = exitingTokens.get(i);
-                if (!token.hasVisible) {
-                    exitingTokens.remove(i);
-                    if (token.windowType == TYPE_WALLPAPER) {
-                        mWallpaperControllerLocked.removeWallpaperToken(token);
-                    }
-                }
-            }
-        }
-
-        // Time to remove any exiting applications?
-        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
-            // Initialize state of exiting applications.
-            final AppTokenList exitingAppTokens =
-                    mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
-            for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
-                AppWindowToken token = exitingAppTokens.get(i);
-                if (!token.hasVisible && !mClosingApps.contains(token) &&
-                        (!token.mIsExiting || token.allAppWindows.isEmpty())) {
-                    // Make sure there is no animation running on this token,
-                    // so any windows associated with it will be removed as
-                    // soon as their animations are complete
-                    token.mAppAnimator.clearAnimation();
-                    token.mAppAnimator.animating = false;
-                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
-                            "performLayout: App token exiting now removed" + token);
-                    token.removeAppFromTaskLocked();
-                }
-            }
-        }
-
-        if (wallpaperDestroyed) {
-            defaultDisplay.pendingLayoutChanges |=
-                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-            defaultDisplay.layoutNeeded = true;
-        }
-
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-            if (displayContent.pendingLayoutChanges != 0) {
-                displayContent.layoutNeeded = true;
-            }
-        }
-
-        // Finally update all input windows now that the window changes have stabilized.
-        mInputMonitor.updateInputWindowsLw(true /*force*/);
-
-        setHoldScreenLocked(mInnerFields.mHoldScreen);
-        if (!mDisplayFrozen) {
-            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
-                mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(-1);
-            } else {
-                mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
-                        toBrightnessOverride(mInnerFields.mScreenBrightness));
-            }
-            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
-                mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(-1);
-            } else {
-                mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(
-                        toBrightnessOverride(mInnerFields.mButtonBrightness));
-            }
-            mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
-                    mInnerFields.mUserActivityTimeout);
-        }
-
-        if (mTurnOnScreen) {
-            if (mAllowTheaterModeWakeFromLayout
-                    || Settings.Global.getInt(mContext.getContentResolver(),
-                        Settings.Global.THEATER_MODE_ON, 0) == 0) {
-                if (DEBUG_VISIBILITY || DEBUG_POWER) {
-                    Slog.v(TAG, "Turning screen on after layout!");
-                }
-                mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.wm:TURN_ON");
-            }
-            mTurnOnScreen = false;
-        }
-
-        if (mInnerFields.mUpdateRotation) {
-            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
-            if (updateRotationUncheckedLocked(false)) {
-                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
-            } else {
-                mInnerFields.mUpdateRotation = false;
-            }
-        }
-
-        if (mWaitingForDrawnCallback != null ||
-                (mInnerFields.mOrientationChangeComplete && !defaultDisplay.layoutNeeded &&
-                        !mInnerFields.mUpdateRotation)) {
-            checkDrawnWindowsLocked();
-        }
-
-        final int N = mPendingRemove.size();
-        if (N > 0) {
-            if (mPendingRemoveTmp.length < N) {
-                mPendingRemoveTmp = new WindowState[N+10];
-            }
-            mPendingRemove.toArray(mPendingRemoveTmp);
-            mPendingRemove.clear();
-            DisplayContentList displayList = new DisplayContentList();
-            for (i = 0; i < N; i++) {
-                WindowState w = mPendingRemoveTmp[i];
-                removeWindowInnerLocked(w);
-                final DisplayContent displayContent = w.getDisplayContent();
-                if (displayContent != null && !displayList.contains(displayContent)) {
-                    displayList.add(displayContent);
-                }
-            }
-
-            for (DisplayContent displayContent : displayList) {
-                assignLayersLocked(displayContent.getWindowList());
-                displayContent.layoutNeeded = true;
-            }
-        }
-
-        // Remove all deferred displays stacks, tasks, and activities.
-        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
-            mDisplayContents.valueAt(displayNdx).checkForDeferredActions();
-        }
-
-        if (updateInputWindowsNeeded) {
-            mInputMonitor.updateInputWindowsLw(false /*force*/);
-        }
-        setFocusTaskRegion();
-
-        // Check to see if we are now in a state where the screen should
-        // be enabled, because the window obscured flags have changed.
-        enableScreenIfNeededLocked();
-
-        scheduleAnimationLocked();
-
-        if (DEBUG_WINDOW_TRACE) {
-            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: animating="
-                    + mAnimator.mAnimating);
-        }
-    }
-
-    private int toBrightnessOverride(float value) {
-        return (int)(value * PowerManager.BRIGHTNESS_ON);
-    }
-
     void checkDrawnWindowsLocked() {
         if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
             return;
@@ -9821,7 +8429,7 @@
         }
     }
 
-    private boolean needsLayout() {
+    boolean needsLayout() {
         final int numDisplays = mDisplayContents.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
@@ -9832,41 +8440,6 @@
         return false;
     }
 
-    boolean copyAnimToLayoutParamsLocked() {
-        boolean doRequest = false;
-
-        final int bulkUpdateParams = mAnimator.mBulkUpdateParams;
-        if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
-            mInnerFields.mUpdateRotation = true;
-            doRequest = true;
-        }
-        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
-            mInnerFields.mWallpaperMayChange = true;
-            doRequest = true;
-        }
-        if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
-            mInnerFields.mWallpaperForceHidingChanged = true;
-            doRequest = true;
-        }
-        if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
-            mInnerFields.mOrientationChangeComplete = false;
-        } else {
-            mInnerFields.mOrientationChangeComplete = true;
-            mInnerFields.mLastWindowFreezeSource = mAnimator.mLastWindowFreezeSource;
-            if (mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
-                doRequest = true;
-            }
-        }
-        if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
-            mTurnOnScreen = true;
-        }
-        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_ACTION_PENDING) != 0) {
-            mInnerFields.mWallpaperActionPending = true;
-        }
-
-        return doRequest;
-    }
-
     /** If a window that has an animation specifying a colored background and the current wallpaper
      * is visible, then the color goes *below* the wallpaper so we don't cause the wallpaper to
      * suddenly disappear. */
@@ -9990,7 +8563,7 @@
         return leakedSurface || killedApps;
     }
 
-    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
+    boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
         WindowState newFocus = computeFocusedWindowLocked();
         if (mCurrentFocus != newFocus) {
             Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
@@ -10019,7 +8592,8 @@
             if (imWindowChanged && oldFocus != mInputMethodWindow) {
                 // Focus of the input method window changed. Perform layout if needed.
                 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
-                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
+                    mWindowPlacerLocked.performLayoutLockedInner(displayContent, true /*initial*/,
+                            updateInputWindows);
                     focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
                 } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
                     // Client will do the layout, but we need to assign layers
@@ -10032,7 +8606,8 @@
                 // The change in focus caused us to need to do a layout.  Okay.
                 displayContent.layoutNeeded = true;
                 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
-                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
+                    mWindowPlacerLocked.performLayoutLockedInner(displayContent, true /*initial*/,
+                            updateInputWindows);
                 }
             }
 
@@ -10060,7 +8635,7 @@
         return null;
     }
 
-    private WindowState findFocusedWindowLocked(DisplayContent displayContent) {
+    WindowState findFocusedWindowLocked(DisplayContent displayContent) {
         final WindowList windows = displayContent.getWindowList();
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState win = windows.get(i);
@@ -10184,7 +8759,7 @@
         }
     }
 
-    private void stopFreezingDisplayLocked() {
+    void stopFreezingDisplayLocked() {
         if (!mDisplayFrozen) {
             return;
         }
@@ -10391,7 +8966,7 @@
         synchronized (mWindowMap) {
             int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
             updateStatusBarVisibilityLocked(visibility);
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
@@ -11005,13 +9580,6 @@
         synchronized (mWindowMap) { }
     }
 
-    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
-        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
-            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
-                    Integer.toHexString(pendingLayoutChanges));
-        }
-    }
-
     private DisplayContent newDisplayContentLocked(final Display display) {
         DisplayContent displayContent = new DisplayContent(display, this);
         final int displayId = display.getDisplayId();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 761e5eb..7e15dd5 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -18,6 +18,7 @@
 
 import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
@@ -1255,6 +1256,20 @@
         mInputWindowHandle.inputChannel = null;
     }
 
+    void handleFlagDimBehind() {
+        if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0 && isDisplayedLw() && !mExiting) {
+            final Task task = getTask();
+            if (task == null) {
+                return;
+            }
+            task.setContinueDimming();
+            if (!task.isDimming(mWinAnimator)) {
+                if (WindowManagerService.localLOGV) Slog.v(TAG, "Win " + this + " start dimming.");
+                task.startDimmingIfNeeded(mWinAnimator);
+            }
+        }
+    }
+
     private class DeathRecipient implements IBinder.DeathRecipient {
         @Override
         public void binderDied() {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 109e627..a79d2aa 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -27,8 +27,8 @@
 import static com.android.server.wm.WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerService.SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.WindowManagerService.localLOGV;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_TURN_ON_SCREEN;
+import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
+import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
 
 import android.content.Context;
 import android.graphics.Matrix;
@@ -424,8 +424,9 @@
         finishExit();
         final int displayId = mWin.getDisplayId();
         mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
-        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats(
-                "WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
+        if (WindowManagerService.DEBUG_LAYOUT_REPEATS)
+            mService.mWindowPlacerLocked.debugLayoutRepeats(
+                    "WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
 
         if (mWin.mAppToken != null) {
             mWin.mAppToken.updateReportedVisibilityLocked();
@@ -1184,7 +1185,7 @@
                     + " screen=" + (screenAnimation ?
                             screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
             return;
-        } else if (mIsWallpaper && mService.mInnerFields.mWallpaperActionPending) {
+        } else if (mIsWallpaper && mService.mWindowPlacerLocked.mWallpaperActionPending) {
             return;
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
new file mode 100644
index 0000000..ce07a9d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -0,0 +1,1523 @@
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.WindowManagerService.DEBUG;
+import static com.android.server.wm.WindowManagerService.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerService.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT_REPEATS;
+import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerService.DEBUG_POWER;
+import static com.android.server.wm.WindowManagerService.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerService.DEBUG_TOKEN_MOVEMENT;
+import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerService.DEBUG_WALLPAPER_LIGHT;
+import static com.android.server.wm.WindowManagerService.DEBUG_WINDOW_TRACE;
+import static com.android.server.wm.WindowManagerService.H.*;
+import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
+import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
+import static com.android.server.wm.WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerService.SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerService.TAG;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
+import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.Debug;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.Slog;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Positions windows and their surfaces.
+ *
+ * It sets positions of windows by calculating their frames and then applies this by positioning
+ * surfaces according to these frames. Z layer is still assigned withing WindowManagerService.
+ */
+class WindowSurfacePlacer {
+    private final WindowManagerService mService;
+    private final WallpaperController mWallpaperControllerLocked;
+
+    private boolean mInLayout = false;
+
+    /** Only do a maximum of 6 repeated layouts. After that quit */
+    private int mLayoutRepeatCount;
+
+    static final int SET_UPDATE_ROTATION                = 1 << 0;
+    static final int SET_WALLPAPER_MAY_CHANGE           = 1 << 1;
+    static final int SET_FORCE_HIDING_CHANGED           = 1 << 2;
+    static final int SET_ORIENTATION_CHANGE_COMPLETE    = 1 << 3;
+    static final int SET_TURN_ON_SCREEN                 = 1 << 4;
+    static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 5;
+
+    boolean mWallpaperMayChange = false;
+    boolean mOrientationChangeComplete = true;
+    boolean mWallpaperActionPending = false;
+
+    private boolean mWallpaperForceHidingChanged = false;
+    private Object mLastWindowFreezeSource = null;
+    private Session mHoldScreen = null;
+    private boolean mObscured = false;
+    private boolean mSyswin = false;
+    private float mScreenBrightness = -1;
+    private float mButtonBrightness = -1;
+    private long mUserActivityTimeout = -1;
+    private boolean mUpdateRotation = false;
+    private final Rect mTmpStartRect = new Rect();
+
+    // Set to true when the display contains content to show the user.
+    // When false, the display manager may choose to mirror or blank the display.
+    private boolean mDisplayHasContent = false;
+
+    // Only set while traversing the default display based on its content.
+    // Affects the behavior of mirroring on secondary displays.
+    private boolean mObscureApplicationContentOnSecondaryDisplays = false;
+
+    private float mPreferredRefreshRate = 0;
+
+    private int mPreferredModeId = 0;
+
+    public WindowSurfacePlacer(WindowManagerService service) {
+        mService = service;
+        mWallpaperControllerLocked = mService.mWallpaperControllerLocked;
+    }
+
+    final void performSurfacePlacement() {
+        int loopCount = 6;
+        do {
+            mService.mTraversalScheduled = false;
+            performSurfacePlacementLoop();
+            mService.mH.removeMessages(DO_TRAVERSAL);
+            loopCount--;
+        } while (mService.mTraversalScheduled && loopCount > 0);
+        mWallpaperActionPending = false;
+    }
+
+    private void performSurfacePlacementLoop() {
+        if (mInLayout) {
+            if (DEBUG) {
+                throw new RuntimeException("Recursive call!");
+            }
+            Slog.w(TAG,
+                    "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
+                    + Debug.getCallers(3));
+            return;
+        }
+
+        if (mService.mWaitingForConfig) {
+            // Our configuration has changed (most likely rotation), but we
+            // don't yet have the complete configuration to report to
+            // applications.  Don't do any window layout until we have it.
+            return;
+        }
+
+        if (!mService.mDisplayReady) {
+            // Not yet initialized, nothing to do.
+            return;
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
+        mInLayout = true;
+
+        boolean recoveringMemory = false;
+        if (!mService.mForceRemoves.isEmpty()) {
+            recoveringMemory = true;
+            // Wait a little bit for things to settle down, and off we go.
+            while (!mService.mForceRemoves.isEmpty()) {
+                WindowState ws = mService.mForceRemoves.remove(0);
+                Slog.i(TAG, "Force removing: " + ws);
+                mService.removeWindowInnerLocked(ws);
+            }
+            Slog.w(TAG,
+                    "Due to memory failure, waiting a bit for next layout");
+            Object tmp = new Object();
+            synchronized (tmp) {
+                try {
+                    tmp.wait(250);
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+
+        try {
+            performSurfacePlacementInner(recoveringMemory);
+
+            mInLayout = false;
+
+            if (mService.needsLayout()) {
+                if (++mLayoutRepeatCount < 6) {
+                    mService.requestTraversalLocked();
+                } else {
+                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
+                    mLayoutRepeatCount = 0;
+                }
+            } else {
+                mLayoutRepeatCount = 0;
+            }
+
+            if (mService.mWindowsChanged && !mService.mWindowChangeListeners.isEmpty()) {
+                mService.mH.removeMessages(REPORT_WINDOWS_CHANGE);
+                mService.mH.sendEmptyMessage(REPORT_WINDOWS_CHANGE);
+            }
+        } catch (RuntimeException e) {
+            mInLayout = false;
+            Slog.wtf(TAG, "Unhandled exception while laying out windows", e);
+        }
+
+        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+    }
+
+    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
+        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
+            Slog.v(TAG, "Layouts looping: " + msg +
+                    ", mPendingLayoutChanges = 0x" + Integer.toHexString(pendingLayoutChanges));
+        }
+    }
+
+    // "Something has changed!  Let's make it correct now."
+    private void performSurfacePlacementInner(boolean recoveringMemory) {
+        if (DEBUG_WINDOW_TRACE) {
+            Slog.v(TAG,
+                    "performSurfacePlacementInner: entry. Called by "
+                    + Debug.getCallers(3));
+        }
+
+        int i;
+        boolean updateInputWindowsNeeded = false;
+
+        if (mService.mFocusMayChange) {
+            mService.mFocusMayChange = false;
+            updateInputWindowsNeeded = mService.updateFocusedWindowLocked(
+                    UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
+        }
+
+        // Initialize state of exiting tokens.
+        final int numDisplays = mService.mDisplayContents.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
+            for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
+                displayContent.mExitingTokens.get(i).hasVisible = false;
+            }
+        }
+
+        for (int stackNdx = mService.mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
+            // Initialize state of exiting applications.
+            final AppTokenList exitingAppTokens =
+                    mService.mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
+            for (int tokenNdx = exitingAppTokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                exitingAppTokens.get(tokenNdx).hasVisible = false;
+            }
+        }
+
+        mHoldScreen = null;
+        mScreenBrightness = -1;
+        mButtonBrightness = -1;
+        mUserActivityTimeout = -1;
+        mObscureApplicationContentOnSecondaryDisplays = false;
+
+        mService.mTransactionSequence++;
+
+        final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
+        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
+        final int defaultDw = defaultInfo.logicalWidth;
+        final int defaultDh = defaultInfo.logicalHeight;
+
+        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
+        SurfaceControl.openTransaction();
+        try {
+
+            if (mService.mWatermark != null) {
+                mService.mWatermark.positionSurface(defaultDw, defaultDh);
+            }
+            if (mService.mStrictModeFlash != null) {
+                mService.mStrictModeFlash.positionSurface(defaultDw, defaultDh);
+            }
+            if (mService.mCircularDisplayMask != null) {
+                mService.mCircularDisplayMask.positionSurface(defaultDw, defaultDh,
+                        mService.mRotation);
+            }
+            if (mService.mEmulatorDisplayOverlay != null) {
+                mService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,
+                        mService.mRotation);
+            }
+
+            boolean focusDisplayed = false;
+
+            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+                final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
+                boolean updateAllDrawn = false;
+                WindowList windows = displayContent.getWindowList();
+                DisplayInfo displayInfo = displayContent.getDisplayInfo();
+                final int displayId = displayContent.getDisplayId();
+                final int dw = displayInfo.logicalWidth;
+                final int dh = displayInfo.logicalHeight;
+                final int innerDw = displayInfo.appWidth;
+                final int innerDh = displayInfo.appHeight;
+                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+
+                // Reset for each display.
+                mDisplayHasContent = false;
+                mPreferredRefreshRate = 0;
+                mPreferredModeId = 0;
+
+                int repeats = 0;
+                do {
+                    repeats++;
+                    if (repeats > 6) {
+                        Slog.w(TAG, "Animation repeat aborted after too many iterations");
+                        displayContent.layoutNeeded = false;
+                        break;
+                    }
+
+                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
+                            "On entry to LockedInner", displayContent.pendingLayoutChanges);
+
+                    if ((displayContent.pendingLayoutChanges &
+                            FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
+                            mWallpaperControllerLocked.adjustWallpaperWindows()) {
+                        mService.assignLayersLocked(windows);
+                        displayContent.layoutNeeded = true;
+                    }
+
+                    if (isDefaultDisplay && (displayContent.pendingLayoutChanges
+                            & FINISH_LAYOUT_REDO_CONFIG) != 0) {
+                        if (DEBUG_LAYOUT) Slog.v(TAG,
+                                "Computing new config from layout");
+                        if (mService.updateOrientationFromAppTokensLocked(true)) {
+                            displayContent.layoutNeeded = true;
+                            mService.mH.sendEmptyMessage(
+                                    SEND_NEW_CONFIGURATION);
+                        }
+                    }
+
+                    if ((displayContent.pendingLayoutChanges
+                            & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+                        displayContent.layoutNeeded = true;
+                    }
+
+                    // FIRST LOOP: Perform a layout, if needed.
+                    if (repeats < LAYOUT_REPEAT_THRESHOLD) {
+                        performLayoutLockedInner(displayContent, repeats == 1,
+                                false /*updateInputWindows*/);
+                    } else {
+                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
+                    }
+
+                    // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
+                    // it is animating.
+                    displayContent.pendingLayoutChanges = 0;
+
+                    if (isDefaultDisplay) {
+                        mService.mPolicy.beginPostLayoutPolicyLw(dw, dh);
+                        for (i = windows.size() - 1; i >= 0; i--) {
+                            WindowState w = windows.get(i);
+                            if (w.mHasSurface) {
+                                mService.mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs,
+                                        w.mAttachedWindow);
+                            }
+                        }
+                        displayContent.pendingLayoutChanges |=
+                                mService.mPolicy.finishPostLayoutPolicyLw();
+                        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
+                                "after finishPostLayoutPolicyLw",
+                                displayContent.pendingLayoutChanges);
+                    }
+                } while (displayContent.pendingLayoutChanges != 0);
+
+                mObscured = false;
+                mSyswin = false;
+                displayContent.resetDimming();
+
+                // Only used if default window
+                final boolean someoneLosingFocus = !mService.mLosingFocus.isEmpty();
+
+                final int N = windows.size();
+                for (i=N-1; i>=0; i--) {
+                    WindowState w = windows.get(i);
+                    final Task task = w.getTask();
+                    if (task == null && w.getAttrs().type != TYPE_PRIVATE_PRESENTATION) {
+                        continue;
+                    }
+
+                    final boolean obscuredChanged = w.mObscured != mObscured;
+
+                    // Update effect.
+                    w.mObscured = mObscured;
+                    if (!mObscured) {
+                        handleNotObscuredLocked(w, innerDw, innerDh);
+                    }
+
+                    if (task != null && !task.getContinueDimming()) {
+                        w.handleFlagDimBehind();
+                    }
+
+                    if (isDefaultDisplay && obscuredChanged
+                            && mWallpaperControllerLocked.isWallpaperTarget(w)
+                            && w.isVisibleLw()) {
+                        // This is the wallpaper target and its obscured state
+                        // changed... make sure the current wallaper's visibility
+                        // has been updated accordingly.
+                        mWallpaperControllerLocked.updateWallpaperVisibility();
+                    }
+
+                    final WindowStateAnimator winAnimator = w.mWinAnimator;
+
+                    // If the window has moved due to its containing content frame changing, then
+                    // notify the listeners and optionally animate it.
+                    if (w.hasMoved()) {
+                        // Frame has moved, containing content frame has also moved, and we're not
+                        // currently animating... let's do something.
+                        final int left = w.mFrame.left;
+                        final int top = w.mFrame.top;
+                        if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0) {
+                            Animation a = AnimationUtils.loadAnimation(mService.mContext,
+                                    com.android.internal.R.anim.window_move_from_decor);
+                            winAnimator.setAnimation(a);
+                            winAnimator.mAnimDw = w.mLastFrame.left - left;
+                            winAnimator.mAnimDh = w.mLastFrame.top - top;
+                            winAnimator.mAnimateMove = true;
+                            winAnimator.mAnimatingMove = true;
+                        }
+
+                        //TODO (multidisplay): Accessibility supported only for the default display.
+                        if (mService.mAccessibilityController != null
+                                && displayId == Display.DEFAULT_DISPLAY) {
+                            mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+                        }
+
+                        try {
+                            w.mClient.moved(left, top);
+                        } catch (RemoteException e) {
+                        }
+                    }
+
+                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
+                    w.mContentChanged = false;
+
+                    // Moved from updateWindowsAndWallpaperLocked().
+                    if (w.mHasSurface) {
+                        // Take care of the window being ready to display.
+                        final boolean committed =
+                                winAnimator.commitFinishDrawingLocked();
+                        if (isDefaultDisplay && committed) {
+                            if (w.mAttrs.type == TYPE_DREAM) {
+                                // HACK: When a dream is shown, it may at that
+                                // point hide the lock screen.  So we need to
+                                // redo the layout to let the phone window manager
+                                // make this happen.
+                                displayContent.pendingLayoutChanges |=
+                                        FINISH_LAYOUT_REDO_LAYOUT;
+                                if (DEBUG_LAYOUT_REPEATS) {
+                                    debugLayoutRepeats(
+                                            "dream and commitFinishDrawingLocked true",
+                                            displayContent.pendingLayoutChanges);
+                                }
+                            }
+                            if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
+                                if (DEBUG_WALLPAPER_LIGHT)
+                                    Slog.v(TAG,
+                                            "First draw done in potential wallpaper target " + w);
+                                mWallpaperMayChange = true;
+                                displayContent.pendingLayoutChanges |=
+                                        FINISH_LAYOUT_REDO_WALLPAPER;
+                                if (DEBUG_LAYOUT_REPEATS) {
+                                    debugLayoutRepeats(
+                                            "wallpaper and commitFinishDrawingLocked true",
+                                            displayContent.pendingLayoutChanges);
+                                }
+                            }
+                        }
+
+                        winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
+                    }
+
+                    final AppWindowToken atoken = w.mAppToken;
+                    if (DEBUG_STARTING_WINDOW && atoken != null
+                            && w == atoken.startingWindow) {
+                        Slog.d(TAG, "updateWindows: starting " + w
+                                + " isOnScreen=" + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
+                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
+                    }
+                    if (atoken != null
+                            && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
+                        if (atoken.lastTransactionSequence != mService.mTransactionSequence) {
+                            atoken.lastTransactionSequence = mService.mTransactionSequence;
+                            atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
+                            atoken.startingDisplayed = false;
+                        }
+                        if ((w.isOnScreenIgnoringKeyguard()
+                                || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
+                                && !w.mExiting && !w.mDestroying) {
+                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
+                                Slog.v(TAG, "Eval win " + w + ": isDrawn="
+                                        + w.isDrawnLw()
+                                        + ", isAnimating=" + winAnimator.isAnimating());
+                                if (!w.isDrawnLw()) {
+                                    Slog.v(TAG, "Not displayed: s="
+                                            + winAnimator.mSurfaceControl
+                                            + " pv=" + w.mPolicyVisibility
+                                            + " mDrawState=" + winAnimator.drawStateToString()
+                                            + " ah=" + w.mAttachedHidden
+                                            + " th=" + atoken.hiddenRequested
+                                            + " a=" + winAnimator.mAnimating);
+                                }
+                            }
+                            if (w != atoken.startingWindow) {
+                                if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
+                                    atoken.numInterestingWindows++;
+                                    if (w.isDrawnLw()) {
+                                        atoken.numDrawnWindows++;
+                                        if (DEBUG_VISIBILITY
+                                                || DEBUG_ORIENTATION)
+                                            Slog.v(TAG,
+                                                "tokenMayBeDrawn: " + atoken
+                                                + " freezingScreen="
+                                                + atoken.mAppAnimator.freezingScreen
+                                                + " mAppFreezing=" + w.mAppFreezing);
+                                        updateAllDrawn = true;
+                                    }
+                                }
+                            } else if (w.isDrawnLw()) {
+                                atoken.startingDisplayed = true;
+                            }
+                        }
+                    }
+
+                    if (isDefaultDisplay && someoneLosingFocus && (w == mService.mCurrentFocus)
+                            && w.isDisplayedLw()) {
+                        focusDisplayed = true;
+                    }
+
+                    mService.updateResizingWindows(w);
+                }
+
+                mService.mDisplayManagerInternal.setDisplayProperties(displayId,
+                        mDisplayHasContent,
+                        mPreferredRefreshRate,
+                        mPreferredModeId,
+                        true /* inTraversal, must call performTraversalInTrans... below */);
+
+                mService.getDisplayContentLocked(displayId).stopDimmingIfNeeded();
+
+                if (updateAllDrawn) {
+                    updateAllDrawnLocked(displayContent);
+                }
+            }
+
+            if (focusDisplayed) {
+                mService.mH.sendEmptyMessage(REPORT_LOSING_FOCUS);
+            }
+
+            // Give the display manager a chance to adjust properties
+            // like display rotation if it needs to.
+            mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
+
+        } catch (RuntimeException e) {
+            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
+        } finally {
+            SurfaceControl.closeTransaction();
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
+        }
+
+        final WindowList defaultWindows = defaultDisplay.getWindowList();
+
+        // If we are ready to perform an app transition, check through
+        // all of the app tokens to be shown and see if they are ready
+        // to go.
+        if (mService.mAppTransition.isReady()) {
+            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
+            if (DEBUG_LAYOUT_REPEATS)
+                debugLayoutRepeats("after handleAppTransitionReadyLocked",
+                        defaultDisplay.pendingLayoutChanges);
+        }
+
+        if (!mService.mAnimator.mAppWindowAnimating && mService.mAppTransition.isRunning()) {
+            // We have finished the animation of an app transition.  To do
+            // this, we have delayed a lot of operations like showing and
+            // hiding apps, moving apps in Z-order, etc.  The app token list
+            // reflects the correct Z-order, but the window list may now
+            // be out of sync with it.  So here we will just rebuild the
+            // entire app window list.  Fun!
+            defaultDisplay.pendingLayoutChanges |=
+                    mService.handleAnimatingStoppedAndTransitionLocked();
+            if (DEBUG_LAYOUT_REPEATS)
+                debugLayoutRepeats("after handleAnimStopAndXitionLock",
+                        defaultDisplay.pendingLayoutChanges);
+        }
+
+        if (mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
+                && !mService.mAppTransition.isReady()) {
+            // At this point, there was a window with a wallpaper that
+            // was force hiding other windows behind it, but now it
+            // is going away.  This may be simple -- just animate
+            // away the wallpaper and its window -- or it may be
+            // hard -- the wallpaper now needs to be shown behind
+            // something that was hidden.
+            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
+            if (DEBUG_LAYOUT_REPEATS)
+                debugLayoutRepeats("after animateAwayWallpaperLocked",
+                        defaultDisplay.pendingLayoutChanges);
+        }
+        mWallpaperForceHidingChanged = false;
+
+        if (mWallpaperMayChange) {
+            if (DEBUG_WALLPAPER_LIGHT)
+                Slog.v(TAG, "Wallpaper may change!  Adjusting");
+            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("WallpaperMayChange",
+                    defaultDisplay.pendingLayoutChanges);
+        }
+
+        if (mService.mFocusMayChange) {
+            mService.mFocusMayChange = false;
+            if (mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
+                    false /*updateInputWindows*/)) {
+                updateInputWindowsNeeded = true;
+                defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
+            }
+        }
+
+        if (mService.needsLayout()) {
+            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
+            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
+                    defaultDisplay.pendingLayoutChanges);
+        }
+
+        for (i = mService.mResizingWindows.size() - 1; i >= 0; i--) {
+            WindowState win = mService.mResizingWindows.get(i);
+            if (win.mAppFreezing) {
+                // Don't remove this window until rotation has completed.
+                continue;
+            }
+            win.reportResized();
+            mService.mResizingWindows.remove(i);
+        }
+
+        if (DEBUG_ORIENTATION && mService.mDisplayFrozen)
+            Slog.v(TAG,
+                "With display frozen, orientationChangeComplete="
+                + mOrientationChangeComplete);
+        if (mOrientationChangeComplete) {
+            if (mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
+                mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
+                mService.mLastFinishedFreezeSource = mLastWindowFreezeSource;
+                mService.mH.removeMessages(WINDOW_FREEZE_TIMEOUT);
+            }
+            mService.stopFreezingDisplayLocked();
+        }
+
+        // Destroy the surface of any windows that are no longer visible.
+        boolean wallpaperDestroyed = false;
+        i = mService.mDestroySurface.size();
+        if (i > 0) {
+            do {
+                i--;
+                WindowState win = mService.mDestroySurface.get(i);
+                win.mDestroying = false;
+                if (mService.mInputMethodWindow == win) {
+                    mService.mInputMethodWindow = null;
+                }
+                if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
+                    wallpaperDestroyed = true;
+                }
+                win.mWinAnimator.destroySurfaceLocked();
+            } while (i > 0);
+            mService.mDestroySurface.clear();
+        }
+
+        // Time to remove any exiting tokens?
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
+            ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
+            for (i = exitingTokens.size() - 1; i >= 0; i--) {
+                WindowToken token = exitingTokens.get(i);
+                if (!token.hasVisible) {
+                    exitingTokens.remove(i);
+                    if (token.windowType == TYPE_WALLPAPER) {
+                        mWallpaperControllerLocked.removeWallpaperToken(token);
+                    }
+                }
+            }
+        }
+
+        // Time to remove any exiting applications?
+        for (int stackNdx = mService.mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
+            // Initialize state of exiting applications.
+            final AppTokenList exitingAppTokens =
+                    mService.mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
+            for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
+                AppWindowToken token = exitingAppTokens.get(i);
+                if (!token.hasVisible && !mService.mClosingApps.contains(token) &&
+                        (!token.mIsExiting || token.allAppWindows.isEmpty())) {
+                    // Make sure there is no animation running on this token,
+                    // so any windows associated with it will be removed as
+                    // soon as their animations are complete
+                    token.mAppAnimator.clearAnimation();
+                    token.mAppAnimator.animating = false;
+                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT)
+                        Slog.v(TAG,
+                                "performLayout: App token exiting now removed" + token);
+                    token.removeAppFromTaskLocked();
+                }
+            }
+        }
+
+        if (wallpaperDestroyed) {
+            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+            defaultDisplay.layoutNeeded = true;
+        }
+
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
+            if (displayContent.pendingLayoutChanges != 0) {
+                displayContent.layoutNeeded = true;
+            }
+        }
+
+        // Finally update all input windows now that the window changes have stabilized.
+        mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
+
+        mService.setHoldScreenLocked(mHoldScreen);
+        if (!mService.mDisplayFrozen) {
+            if (mScreenBrightness < 0 || mScreenBrightness > 1.0f) {
+                mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(-1);
+            } else {
+                mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
+                        toBrightnessOverride(mScreenBrightness));
+            }
+            if (mButtonBrightness < 0
+                    || mButtonBrightness > 1.0f) {
+                mService.mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(-1);
+            } else {
+                mService.mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(
+                        toBrightnessOverride(mButtonBrightness));
+            }
+            mService.mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
+                    mUserActivityTimeout);
+        }
+
+        if (mService.mTurnOnScreen) {
+            if (mService.mAllowTheaterModeWakeFromLayout
+                    || Settings.Global.getInt(mService.mContext.getContentResolver(),
+                        Settings.Global.THEATER_MODE_ON, 0) == 0) {
+                if (DEBUG_VISIBILITY || DEBUG_POWER) {
+                    Slog.v(TAG, "Turning screen on after layout!");
+                }
+                mService.mPowerManager.wakeUp(SystemClock.uptimeMillis(),
+                        "android.server.wm:TURN_ON");
+            }
+            mService.mTurnOnScreen = false;
+        }
+
+        if (mUpdateRotation) {
+            if (DEBUG_ORIENTATION) Slog.d(TAG,
+                    "Performing post-rotate rotation");
+            if (mService.updateRotationUncheckedLocked(false)) {
+                mService.mH.sendEmptyMessage(SEND_NEW_CONFIGURATION);
+            } else {
+                mUpdateRotation = false;
+            }
+        }
+
+        if (mService.mWaitingForDrawnCallback != null ||
+                (mOrientationChangeComplete && !defaultDisplay.layoutNeeded &&
+                        !mUpdateRotation)) {
+            mService.checkDrawnWindowsLocked();
+        }
+
+        final int N = mService.mPendingRemove.size();
+        if (N > 0) {
+            if (mService.mPendingRemoveTmp.length < N) {
+                mService.mPendingRemoveTmp = new WindowState[N+10];
+            }
+            mService.mPendingRemove.toArray(mService.mPendingRemoveTmp);
+            mService.mPendingRemove.clear();
+            DisplayContentList displayList = new DisplayContentList();
+            for (i = 0; i < N; i++) {
+                WindowState w = mService.mPendingRemoveTmp[i];
+                mService.removeWindowInnerLocked(w);
+                final DisplayContent displayContent = w.getDisplayContent();
+                if (displayContent != null && !displayList.contains(displayContent)) {
+                    displayList.add(displayContent);
+                }
+            }
+
+            for (DisplayContent displayContent : displayList) {
+                mService.assignLayersLocked(displayContent.getWindowList());
+                displayContent.layoutNeeded = true;
+            }
+        }
+
+        // Remove all deferred displays stacks, tasks, and activities.
+        for (int displayNdx = mService.mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            mService.mDisplayContents.valueAt(displayNdx).checkForDeferredActions();
+        }
+
+        if (updateInputWindowsNeeded) {
+            mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
+        }
+        mService.setFocusTaskRegion();
+
+        // Check to see if we are now in a state where the screen should
+        // be enabled, because the window obscured flags have changed.
+        mService.enableScreenIfNeededLocked();
+
+        mService.scheduleAnimationLocked();
+
+        if (DEBUG_WINDOW_TRACE) {
+            Slog.e(TAG,
+                    "performSurfacePlacementInner exit: animating="
+                            + mService.mAnimator.mAnimating);
+        }
+    }
+
+    boolean isInLayout() {
+        return mInLayout;
+    }
+
+    final void performLayoutLockedInner(final DisplayContent displayContent,
+            boolean initial, boolean updateInputWindows) {
+        if (!displayContent.layoutNeeded) {
+            return;
+        }
+        displayContent.layoutNeeded = false;
+        WindowList windows = displayContent.getWindowList();
+        boolean isDefaultDisplay = displayContent.isDefaultDisplay;
+
+        DisplayInfo displayInfo = displayContent.getDisplayInfo();
+        final int dw = displayInfo.logicalWidth;
+        final int dh = displayInfo.logicalHeight;
+
+        if (mService.mInputConsumer != null) {
+            mService.mInputConsumer.layout(dw, dh);
+        }
+
+        final int N = windows.size();
+        int i;
+
+        if (DEBUG_LAYOUT) {
+            Slog.v(TAG, "-------------------------------------");
+            Slog.v(TAG, "performLayout: needed="
+                    + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
+        }
+
+        mService.mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mService.mRotation);
+        if (isDefaultDisplay) {
+            // Not needed on non-default displays.
+            mService.mSystemDecorLayer = mService.mPolicy.getSystemDecorLayerLw();
+            mService.mScreenRect.set(0, 0, dw, dh);
+        }
+
+        mService.mPolicy.getContentRectLw(mService.mTmpContentRect);
+        displayContent.resize(mService.mTmpContentRect);
+
+        int seq = mService.mLayoutSeq+1;
+        if (seq < 0) seq = 0;
+        mService.mLayoutSeq = seq;
+
+        boolean behindDream = false;
+
+        // First perform layout of any root windows (not attached
+        // to another window).
+        int topAttached = -1;
+        for (i = N-1; i >= 0; i--) {
+            final WindowState win = windows.get(i);
+
+            // Don't do layout of a window if it is not visible, or
+            // soon won't be visible, to avoid wasting time and funky
+            // changes while a window is animating away.
+            final boolean gone = (behindDream && mService.mPolicy.canBeForceHidden(win, win.mAttrs))
+                    || win.isGoneForLayoutLw();
+
+            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
+                Slog.v(TAG, "1ST PASS " + win
+                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
+                        + " mLayoutAttached=" + win.mLayoutAttached
+                        + " screen changed=" + win.isConfigChanged());
+                final AppWindowToken atoken = win.mAppToken;
+                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
+                        + win.mViewVisibility + " mRelayoutCalled="
+                        + win.mRelayoutCalled + " hidden="
+                        + win.mRootToken.hidden + " hiddenRequested="
+                        + (atoken != null && atoken.hiddenRequested)
+                        + " mAttachedHidden=" + win.mAttachedHidden);
+                else Slog.v(TAG, "  VIS: mViewVisibility="
+                        + win.mViewVisibility + " mRelayoutCalled="
+                        + win.mRelayoutCalled + " hidden="
+                        + win.mRootToken.hidden + " hiddenRequested="
+                        + (atoken != null && atoken.hiddenRequested)
+                        + " mAttachedHidden=" + win.mAttachedHidden);
+            }
+
+            // If this view is GONE, then skip it -- keep the current
+            // frame, and let the caller know so they can ignore it
+            // if they want.  (We do the normal layout for INVISIBLE
+            // windows, since that means "perform layout as normal,
+            // just don't display").
+            if (!gone || !win.mHaveFrame || win.mLayoutNeeded
+                    || ((win.isConfigChanged() || win.setInsetsChanged()) &&
+                            ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
+                            (win.mHasSurface && win.mAppToken != null &&
+                            win.mAppToken.layoutConfigChanges)))) {
+                if (!win.mLayoutAttached) {
+                    if (initial) {
+                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
+                        win.mContentChanged = false;
+                    }
+                    if (win.mAttrs.type == TYPE_DREAM) {
+                        // Don't layout windows behind a dream, so that if it
+                        // does stuff like hide the status bar we won't get a
+                        // bad transition when it goes away.
+                        behindDream = true;
+                    }
+                    win.mLayoutNeeded = false;
+                    win.prelayout();
+                    mService.mPolicy.layoutWindowLw(win, null);
+                    win.mLayoutSeq = seq;
+                    if (DEBUG_LAYOUT) Slog.v(TAG,
+                            "  LAYOUT: mFrame="
+                            + win.mFrame + " mContainingFrame="
+                            + win.mContainingFrame + " mDisplayFrame="
+                            + win.mDisplayFrame);
+                } else {
+                    if (topAttached < 0) topAttached = i;
+                }
+            }
+        }
+
+        boolean attachedBehindDream = false;
+
+        // Now perform layout of attached windows, which usually
+        // depend on the position of the window they are attached to.
+        // XXX does not deal with windows that are attached to windows
+        // that are themselves attached.
+        for (i = topAttached; i >= 0; i--) {
+            final WindowState win = windows.get(i);
+
+            if (win.mLayoutAttached) {
+                if (DEBUG_LAYOUT) Slog.v(TAG,
+                        "2ND PASS " + win + " mHaveFrame=" + win.mHaveFrame + " mViewVisibility="
+                        + win.mViewVisibility + " mRelayoutCalled=" + win.mRelayoutCalled);
+                // If this view is GONE, then skip it -- keep the current
+                // frame, and let the caller know so they can ignore it
+                // if they want.  (We do the normal layout for INVISIBLE
+                // windows, since that means "perform layout as normal,
+                // just don't display").
+                if (attachedBehindDream && mService.mPolicy.canBeForceHidden(win, win.mAttrs)) {
+                    continue;
+                }
+                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
+                        || !win.mHaveFrame || win.mLayoutNeeded) {
+                    if (initial) {
+                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
+                        win.mContentChanged = false;
+                    }
+                    win.mLayoutNeeded = false;
+                    win.prelayout();
+                    mService.mPolicy.layoutWindowLw(win, win.mAttachedWindow);
+                    win.mLayoutSeq = seq;
+                    if (DEBUG_LAYOUT) Slog.v(TAG,
+                            "  LAYOUT: mFrame=" + win.mFrame + " mContainingFrame="
+                            + win.mContainingFrame + " mDisplayFrame=" + win.mDisplayFrame);
+                }
+            } else if (win.mAttrs.type == TYPE_DREAM) {
+                // Don't layout windows behind a dream, so that if it
+                // does stuff like hide the status bar we won't get a
+                // bad transition when it goes away.
+                attachedBehindDream = behindDream;
+            }
+        }
+
+        // Window frames may have changed.  Tell the input dispatcher about it.
+        mService.mInputMonitor.setUpdateInputWindowsNeededLw();
+        if (updateInputWindows) {
+            mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
+        }
+
+        mService.mPolicy.finishLayoutLw();
+    }
+
+    /**
+     * @param windows List of windows on default display.
+     * @return bitmap indicating if another pass through layout must be made.
+     */
+    private int handleAppTransitionReadyLocked(WindowList windows) {
+        int appsCount = mService.mOpeningApps.size();
+        if (!transitionGoodToGo(appsCount)) {
+            return 0;
+        }
+        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
+        int transit = mService.mAppTransition.getAppTransition();
+        if (mService.mSkipAppTransitionAnimation) {
+            transit = AppTransition.TRANSIT_UNSET;
+        }
+        mService.mSkipAppTransitionAnimation = false;
+        mService.mNoAnimationNotifyOnTransitionFinished.clear();
+
+        mService.mH.removeMessages(APP_TRANSITION_TIMEOUT);
+
+        mService.rebuildAppWindowListLocked();
+
+        mWallpaperMayChange = false;
+
+        // The top-most window will supply the layout params,
+        // and we will determine it below.
+        WindowManager.LayoutParams animLp = null;
+        int bestAnimLayer = -1;
+        boolean fullscreenAnim = false;
+        boolean voiceInteraction = false;
+
+        final WindowState lowerWallpaperTarget =
+                mWallpaperControllerLocked.getLowerWallpaperTarget();
+        final WindowState upperWallpaperTarget =
+                mWallpaperControllerLocked.getUpperWallpaperTarget();
+
+        boolean openingAppHasWallpaper = false;
+        boolean closingAppHasWallpaper = false;
+        final AppWindowToken lowerWallpaperAppToken;
+        final AppWindowToken upperWallpaperAppToken;
+        if (lowerWallpaperTarget == null) {
+            lowerWallpaperAppToken = upperWallpaperAppToken = null;
+        } else {
+            lowerWallpaperAppToken = lowerWallpaperTarget.mAppToken;
+            upperWallpaperAppToken = upperWallpaperTarget.mAppToken;
+        }
+
+        int i;
+        // Do a first pass through the tokens for two
+        // things:
+        // (1) Determine if both the closing and opening
+        // app token sets are wallpaper targets, in which
+        // case special animations are needed
+        // (since the wallpaper needs to stay static
+        // behind them).
+        // (2) Find the layout params of the top-most
+        // application window in the tokens, which is
+        // what will control the animation theme.
+        final int closingAppsCount = mService.mClosingApps.size();
+        appsCount = closingAppsCount + mService.mOpeningApps.size();
+        for (i = 0; i < appsCount; i++) {
+            final AppWindowToken wtoken;
+            if (i < closingAppsCount) {
+                wtoken = mService.mClosingApps.valueAt(i);
+                if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
+                    closingAppHasWallpaper = true;
+                }
+            } else {
+                wtoken = mService.mOpeningApps.valueAt(i - closingAppsCount);
+                if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
+                    openingAppHasWallpaper = true;
+                }
+            }
+
+            voiceInteraction |= wtoken.voiceInteraction;
+
+            if (wtoken.appFullscreen) {
+                WindowState ws = wtoken.findMainWindow();
+                if (ws != null) {
+                    animLp = ws.mAttrs;
+                    bestAnimLayer = ws.mLayer;
+                    fullscreenAnim = true;
+                }
+            } else if (!fullscreenAnim) {
+                WindowState ws = wtoken.findMainWindow();
+                if (ws != null) {
+                    if (ws.mLayer > bestAnimLayer) {
+                        animLp = ws.mAttrs;
+                        bestAnimLayer = ws.mLayer;
+                    }
+                }
+            }
+        }
+
+        transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
+                closingAppHasWallpaper, lowerWallpaperTarget, upperWallpaperTarget);
+
+        // If all closing windows are obscured, then there is
+        // no need to do an animation.  This is the case, for
+        // example, when this transition is being done behind
+        // the lock screen.
+        if (!mService.mPolicy.allowAppAnimationsLw()) {
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "Animations disallowed by keyguard or dream.");
+            animLp = null;
+        }
+
+        processApplicationsAnimatingInPlace(transit);
+
+        AppWindowToken topClosingApp = null;
+        int topClosingLayer = 0;
+        appsCount = mService.mClosingApps.size();
+        for (i = 0; i < appsCount; i++) {
+            AppWindowToken wtoken = mService.mClosingApps.valueAt(i);
+            final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "Now closing app " + wtoken);
+            appAnimator.clearThumbnail();
+            appAnimator.animation = null;
+            wtoken.inPendingTransaction = false;
+            mService.setTokenVisibilityLocked(wtoken, animLp, false, transit, false,
+                    voiceInteraction);
+            wtoken.updateReportedVisibilityLocked();
+            // Force the allDrawn flag, because we want to start
+            // this guy's animations regardless of whether it's
+            // gotten drawn.
+            wtoken.allDrawn = true;
+            wtoken.deferClearAllDrawn = false;
+            // Ensure that apps that are mid-starting are also scheduled to have their
+            // starting windows removed after the animation is complete
+            if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
+                mService.scheduleRemoveStartingWindowLocked(wtoken);
+            }
+            mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
+
+            if (animLp != null) {
+                int layer = -1;
+                for (int j = 0; j < wtoken.windows.size(); j++) {
+                    WindowState win = wtoken.windows.get(j);
+                    if (win.mWinAnimator.mAnimLayer > layer) {
+                        layer = win.mWinAnimator.mAnimLayer;
+                    }
+                }
+                if (topClosingApp == null || layer > topClosingLayer) {
+                    topClosingApp = wtoken;
+                    topClosingLayer = layer;
+                }
+            }
+        }
+
+        AppWindowToken topOpeningApp = null;
+        appsCount = mService.mOpeningApps.size();
+        for (i = 0; i < appsCount; i++) {
+            AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
+            final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "Now opening app" + wtoken);
+
+            if (!appAnimator.usingTransferredAnimation) {
+                appAnimator.clearThumbnail();
+                appAnimator.animation = null;
+            }
+            wtoken.inPendingTransaction = false;
+            if (!mService.setTokenVisibilityLocked(
+                    wtoken, animLp, true, transit, false, voiceInteraction)){
+                // This token isn't going to be animating. Add it to the list of tokens to
+                // be notified of app transition complete since the notification will not be
+                // sent be the app window animator.
+                mService.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
+            }
+            wtoken.updateReportedVisibilityLocked();
+            wtoken.waitingToShow = false;
+
+            appAnimator.mAllAppWinAnimators.clear();
+            final int windowsCount = wtoken.allAppWindows.size();
+            for (int j = 0; j < windowsCount; j++) {
+                appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
+            }
+            mService.mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
+            mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
+
+            int topOpeningLayer = 0;
+            if (animLp != null) {
+                int layer = -1;
+                for (int j = 0; j < wtoken.windows.size(); j++) {
+                    WindowState win = wtoken.windows.get(j);
+                    if (win.mWinAnimator.mAnimLayer > layer) {
+                        layer = win.mWinAnimator.mAnimLayer;
+                    }
+                }
+                if (topOpeningApp == null || layer > topOpeningLayer) {
+                    topOpeningApp = wtoken;
+                    topOpeningLayer = layer;
+                }
+            }
+            createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer);
+        }
+
+        AppWindowAnimator openingAppAnimator = (topOpeningApp == null) ?  null :
+                topOpeningApp.mAppAnimator;
+        AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :
+                topClosingApp.mAppAnimator;
+
+        mService.mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);
+        mService.mAppTransition.postAnimationCallback();
+        mService.mAppTransition.clear();
+
+        mService.mOpeningApps.clear();
+        mService.mClosingApps.clear();
+
+        // This has changed the visibility of windows, so perform
+        // a new layout to get them all up-to-date.
+        mService.getDefaultDisplayContentLocked().layoutNeeded = true;
+
+        // TODO(multidisplay): IMEs are only supported on the default display.
+        if (windows == mService.getDefaultWindowListLocked()
+                && !mService.moveInputMethodWindowsIfNeededLocked(true)) {
+            mService.assignLayersLocked(windows);
+        }
+        mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
+                true /*updateInputWindows*/);
+        mService.mFocusMayChange = false;
+        mService.notifyActivityDrawnForKeyguard();
+        return FINISH_LAYOUT_REDO_LAYOUT
+                | FINISH_LAYOUT_REDO_CONFIG;
+
+    }
+
+    private boolean transitionGoodToGo(int appsCount) {
+        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                "Checking " + appsCount + " opening apps (frozen="
+                        + mService.mDisplayFrozen + " timeout="
+                        + mService.mAppTransition.isTimeout() + ")...");
+        if (!mService.mAppTransition.isTimeout()) {
+            for (int i = 0; i < appsCount; i++) {
+                AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                        "Check opening app=" + wtoken + ": allDrawn="
+                        + wtoken.allDrawn + " startingDisplayed="
+                        + wtoken.startingDisplayed + " startingMoved="
+                        + wtoken.startingMoved);
+                if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
+                    return false;
+                }
+            }
+
+            // If the wallpaper is visible, we need to check it's ready too.
+            return !mWallpaperControllerLocked.isWallpaperVisible() ||
+                    mWallpaperControllerLocked.wallpaperTransitionReady();
+        }
+        return true;
+    }
+
+    private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
+            boolean closingAppHasWallpaper, WindowState lowerWallpaperTarget,
+            WindowState upperWallpaperTarget) {
+        // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
+        final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
+        final WindowState oldWallpaper =
+                mWallpaperControllerLocked.isWallpaperTargetAnimating()
+                        ? null : wallpaperTarget;
+        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                "New wallpaper target=" + wallpaperTarget
+                        + ", oldWallpaper=" + oldWallpaper
+                        + ", lower target=" + lowerWallpaperTarget
+                        + ", upper target=" + upperWallpaperTarget);
+        mService.mAnimateWallpaperWithTarget = false;
+        if (closingAppHasWallpaper && openingAppHasWallpaper) {
+            if (DEBUG_APP_TRANSITIONS)
+                Slog.v(TAG, "Wallpaper animation!");
+            switch (transit) {
+                case AppTransition.TRANSIT_ACTIVITY_OPEN:
+                case AppTransition.TRANSIT_TASK_OPEN:
+                case AppTransition.TRANSIT_TASK_TO_FRONT:
+                    transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
+                    break;
+                case AppTransition.TRANSIT_ACTIVITY_CLOSE:
+                case AppTransition.TRANSIT_TASK_CLOSE:
+                case AppTransition.TRANSIT_TASK_TO_BACK:
+                    transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
+                    break;
+            }
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "New transit: " + AppTransition.appTransitionToString(transit));
+        } else if ((oldWallpaper != null) && !mService.mOpeningApps.isEmpty()
+                && !mService.mOpeningApps.contains(oldWallpaper.mAppToken)) {
+            // We are transitioning from an activity with
+            // a wallpaper to one without.
+            transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "New transit away from wallpaper: "
+                    + AppTransition.appTransitionToString(transit));
+        } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()) {
+            // We are transitioning from an activity without
+            // a wallpaper to now showing the wallpaper
+            transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "New transit into wallpaper: "
+                    + AppTransition.appTransitionToString(transit));
+        } else {
+            mService.mAnimateWallpaperWithTarget = true;
+        }
+        return transit;
+    }
+
+    /**
+     * @param w WindowState this method is applied to.
+     * @param innerDw Width of app window.
+     * @param innerDh Height of app window.
+     */
+    private void handleNotObscuredLocked(final WindowState w, final int innerDw, final int innerDh) {
+        final WindowManager.LayoutParams attrs = w.mAttrs;
+        final int attrFlags = attrs.flags;
+        final boolean canBeSeen = w.isDisplayedLw();
+        final boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
+
+        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
+            // This window completely covers everything behind it,
+            // so we want to leave all of them as undimmed (for
+            // performance reasons).
+            mObscured = true;
+        }
+
+        if (w.mHasSurface) {
+            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
+                mHoldScreen = w.mSession;
+            }
+            if (!mSyswin && w.mAttrs.screenBrightness >= 0
+                    && mScreenBrightness < 0) {
+                mScreenBrightness = w.mAttrs.screenBrightness;
+            }
+            if (!mSyswin && w.mAttrs.buttonBrightness >= 0
+                    && mButtonBrightness < 0) {
+                mButtonBrightness = w.mAttrs.buttonBrightness;
+            }
+            if (!mSyswin && w.mAttrs.userActivityTimeout >= 0
+                    && mUserActivityTimeout < 0) {
+                mUserActivityTimeout = w.mAttrs.userActivityTimeout;
+            }
+
+            final int type = attrs.type;
+            if (canBeSeen
+                    && (type == TYPE_SYSTEM_DIALOG
+                     || type == TYPE_SYSTEM_ERROR
+                     || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0)) {
+                mSyswin = true;
+            }
+
+            if (canBeSeen) {
+                // This function assumes that the contents of the default display are
+                // processed first before secondary displays.
+                final DisplayContent displayContent = w.getDisplayContent();
+                if (displayContent != null && displayContent.isDefaultDisplay) {
+                    // While a dream or keyguard is showing, obscure ordinary application
+                    // content on secondary displays (by forcibly enabling mirroring unless
+                    // there is other content we want to show) but still allow opaque
+                    // keyguard dialogs to be shown.
+                    if (type == TYPE_DREAM || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+                        mObscureApplicationContentOnSecondaryDisplays = true;
+                    }
+                    mDisplayHasContent = true;
+                } else if (displayContent != null &&
+                        (!mObscureApplicationContentOnSecondaryDisplays
+                        || (mObscured && type == TYPE_KEYGUARD_DIALOG))) {
+                    // Allow full screen keyguard presentation dialogs to be seen.
+                    mDisplayHasContent = true;
+                }
+                if (mPreferredRefreshRate == 0
+                        && w.mAttrs.preferredRefreshRate != 0) {
+                    mPreferredRefreshRate = w.mAttrs.preferredRefreshRate;
+                }
+                if (mPreferredModeId == 0
+                        && w.mAttrs.preferredDisplayModeId != 0) {
+                    mPreferredModeId = w.mAttrs.preferredDisplayModeId;
+                }
+            }
+        }
+    }
+
+    private void updateAllDrawnLocked(DisplayContent displayContent) {
+        // See if any windows have been drawn, so they (and others
+        // associated with them) can now be shown.
+        ArrayList<TaskStack> stacks = displayContent.getStacks();
+        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                    final AppWindowToken wtoken = tokens.get(tokenNdx);
+                    if (!wtoken.allDrawn) {
+                        int numInteresting = wtoken.numInterestingWindows;
+                        if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
+                            if (DEBUG_VISIBILITY)
+                                Slog.v(TAG, "allDrawn: " + wtoken
+                                    + " interesting=" + numInteresting
+                                    + " drawn=" + wtoken.numDrawnWindows);
+                            wtoken.allDrawn = true;
+                            // Force an additional layout pass where WindowStateAnimator#
+                            // commitFinishDrawingLocked() will call performShowLocked().
+                            displayContent.layoutNeeded = true;
+                            mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN,
+                                    wtoken.token).sendToTarget();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private static int toBrightnessOverride(float value) {
+        return (int)(value * PowerManager.BRIGHTNESS_ON);
+    }
+
+    private void processApplicationsAnimatingInPlace(int transit) {
+        if (transit == AppTransition.TRANSIT_TASK_IN_PLACE) {
+            // Find the focused window
+            final WindowState win = mService.findFocusedWindowLocked(
+                    mService.getDefaultDisplayContentLocked());
+            if (win != null) {
+                final AppWindowToken wtoken = win.mAppToken;
+                final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
+                if (DEBUG_APP_TRANSITIONS)
+                    Slog.v(TAG, "Now animating app in place " + wtoken);
+                appAnimator.clearThumbnail();
+                appAnimator.animation = null;
+                mService.updateTokenInPlaceLocked(wtoken, transit);
+                wtoken.updateReportedVisibilityLocked();
+
+                appAnimator.mAllAppWinAnimators.clear();
+                final int N = wtoken.allAppWindows.size();
+                for (int j = 0; j < N; j++) {
+                    appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
+                }
+                mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
+                mService.mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
+            }
+        }
+    }
+
+    private void createThumbnailAppAnimator(int transit, AppWindowToken appToken,
+            int openingLayer, int closingLayer) {
+        AppWindowAnimator openingAppAnimator = (appToken == null) ? null : appToken.mAppAnimator;
+        if (openingAppAnimator == null || openingAppAnimator.animation == null) {
+            return;
+        }
+        final int taskId = appToken.mTask.mTaskId;
+        Bitmap thumbnailHeader = mService.mAppTransition.getAppTransitionThumbnailHeader(taskId);
+        if (thumbnailHeader == null || thumbnailHeader.getConfig() == Bitmap.Config.ALPHA_8) {
+            return;
+        }
+        // This thumbnail animation is very special, we need to have
+        // an extra surface with the thumbnail included with the animation.
+        Rect dirty = new Rect(0, 0, thumbnailHeader.getWidth(), thumbnailHeader.getHeight());
+        try {
+            // TODO(multi-display): support other displays
+            final DisplayContent displayContent = mService.getDefaultDisplayContentLocked();
+            final Display display = displayContent.getDisplay();
+            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+
+            // Create a new surface for the thumbnail
+            SurfaceControl surfaceControl = new SurfaceControl(mService.mFxSession,
+                    "thumbnail anim", dirty.width(), dirty.height(),
+                    PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+            surfaceControl.setLayerStack(display.getLayerStack());
+            if (SHOW_TRANSACTIONS) {
+                Slog.i(TAG, "  THUMBNAIL " + surfaceControl + ": CREATE");
+            }
+
+            // Draw the thumbnail onto the surface
+            Surface drawSurface = new Surface();
+            drawSurface.copyFrom(surfaceControl);
+            Canvas c = drawSurface.lockCanvas(dirty);
+            c.drawBitmap(thumbnailHeader, 0, 0, null);
+            drawSurface.unlockCanvasAndPost(c);
+            drawSurface.release();
+
+            // Get the thumbnail animation
+            Animation anim;
+            if (mService.mAppTransition.isNextThumbnailTransitionAspectScaled()) {
+                // If this is a multi-window scenario, we use the windows frame as
+                // destination of the thumbnail header animation. If this is a full screen
+                // window scenario, we use the whole display as the target.
+                WindowState win = appToken.findMainWindow();
+                Rect appRect = win != null ? win.getContentFrameLw() :
+                        new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
+                // For the new aspect-scaled transition, we want it to always show
+                // above the animating opening/closing window, and we want to
+                // synchronize its thumbnail surface with the surface for the
+                // open/close animation (only on the way down)
+                anim = mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect,
+                        thumbnailHeader, taskId);
+                Log.d(TAG, "assigning thumbnail force above layer: "
+                        + openingLayer + " " + closingLayer);
+                openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer);
+                openingAppAnimator.deferThumbnailDestruction =
+                        !mService.mAppTransition.isNextThumbnailTransitionScaleUp();
+            } else {
+                anim = mService.mAppTransition.createThumbnailScaleAnimationLocked(
+                        displayInfo.appWidth, displayInfo.appHeight, transit, thumbnailHeader);
+            }
+            anim.restrictDuration(MAX_ANIMATION_DURATION);
+            anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());
+
+            openingAppAnimator.thumbnail = surfaceControl;
+            openingAppAnimator.thumbnailLayer = openingLayer;
+            openingAppAnimator.thumbnailAnimation = anim;
+            mService.mAppTransition.getNextAppTransitionStartRect(taskId, mTmpStartRect);
+            openingAppAnimator.thumbnailX = mTmpStartRect.left;
+            openingAppAnimator.thumbnailY = mTmpStartRect.top;
+        } catch (Surface.OutOfResourcesException e) {
+            Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w="
+                    + dirty.width() + " h=" + dirty.height(), e);
+            openingAppAnimator.clearThumbnail();
+        }
+    }
+
+    boolean copyAnimToLayoutParamsLocked() {
+        boolean doRequest = false;
+
+        final int bulkUpdateParams = mService.mAnimator.mBulkUpdateParams;
+        if ((bulkUpdateParams & SET_UPDATE_ROTATION) != 0) {
+            mUpdateRotation = true;
+            doRequest = true;
+        }
+        if ((bulkUpdateParams & SET_WALLPAPER_MAY_CHANGE) != 0) {
+            mWallpaperMayChange = true;
+            doRequest = true;
+        }
+        if ((bulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0) {
+            mWallpaperForceHidingChanged = true;
+            doRequest = true;
+        }
+        if ((bulkUpdateParams & SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
+            mOrientationChangeComplete = false;
+        } else {
+            mOrientationChangeComplete = true;
+            mLastWindowFreezeSource = mService.mAnimator.mLastWindowFreezeSource;
+            if (mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
+                doRequest = true;
+            }
+        }
+        if ((bulkUpdateParams & SET_TURN_ON_SCREEN) != 0) {
+            mService.mTurnOnScreen = true;
+        }
+        if ((bulkUpdateParams & SET_WALLPAPER_ACTION_PENDING) != 0) {
+            mWallpaperActionPending = true;
+        }
+
+        return doRequest;
+    }
+}
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 9556b08..98d8d08 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -4,9 +4,16 @@
 
 LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
 
+ifneq ($(ENABLE_CPUSETS),)
+ifneq ($(ENABLE_SCHED_BOOST),)
+LOCAL_CFLAGS += -DUSE_SCHED_BOOST
+endif
+endif
+
 LOCAL_SRC_FILES += \
     $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_am_ActivityManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
     $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
diff --git a/services/core/jni/com_android_server_am_ActivityManagerService.cpp b/services/core/jni/com_android_server_am_ActivityManagerService.cpp
new file mode 100644
index 0000000..52217b9
--- /dev/null
+++ b/services/core/jni/com_android_server_am_ActivityManagerService.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ActivityManagerService"
+//#define LOG_NDEBUG 0
+
+#include <android_runtime/AndroidRuntime.h>
+#include <jni.h>
+
+#include <ScopedLocalRef.h>
+#include <ScopedPrimitiveArray.h>
+
+#include <cutils/log.h>
+#include <utils/misc.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android
+{
+
+    // migrate from foreground to foreground_boost
+    static jint migrateToBoost(JNIEnv *env, jobject _this)
+    {
+#ifdef USE_SCHED_BOOST
+        // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
+        FILE* fg_cpuset_file = NULL;
+        int   boost_cpuset_fd = 0;
+        if (!access("/dev/cpuset/tasks", F_OK)) {
+            fg_cpuset_file = fopen("/dev/cpuset/foreground/tasks", "r+");
+            if (ferror(fg_cpuset_file)) {
+                return 0;
+            }
+            boost_cpuset_fd = open("/dev/cpuset/foreground/boost/tasks", O_WRONLY);
+            if (boost_cpuset_fd < 0) {
+                fclose(fg_cpuset_file);
+                return 0;
+            }
+
+        }
+        if (!fg_cpuset_file || !boost_cpuset_fd) {
+            fclose(fg_cpuset_file);
+            close(boost_cpuset_fd);
+            return 0;
+        }
+        char buf[17];
+        while (fgets(buf, 16, fg_cpuset_file)) {
+            int i = 0;
+            for (; i < 16; i++) {
+                if (buf[i] == '\n') {
+                    buf[i] = 0;
+                    break;
+                }
+            }
+            if (write(boost_cpuset_fd, buf, i) < 0) {
+                // ignore error
+            }
+            if (feof(fg_cpuset_file))
+                break;
+        }
+        fclose(fg_cpuset_file);
+        close(boost_cpuset_fd);
+#endif
+        return 0;
+    }
+
+    // migrate from foreground_boost to foreground
+    static jint migrateFromBoost(JNIEnv *env, jobject _this)
+    {
+#ifdef USE_SCHED_BOOST
+        // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
+        int   fg_cpuset_fd = 0;
+        FILE* boost_cpuset_file = NULL;
+        if (!access("/dev/cpuset/tasks", F_OK)) {
+            boost_cpuset_file = fopen("/dev/cpuset/foreground/boost/tasks", "r+");
+            if (ferror(boost_cpuset_file)) {
+                return 0;
+            }
+            fg_cpuset_fd = open("/dev/cpuset/foreground/tasks", O_WRONLY);
+            if (fg_cpuset_fd < 0) {
+                fclose(boost_cpuset_file);
+                return 0;
+            }
+
+        }
+        if (!boost_cpuset_file || !fg_cpuset_fd) {
+            fclose(boost_cpuset_file);
+            close(fg_cpuset_fd);
+            return 0;
+        }
+        char buf[17];
+        char *curBuf = buf;
+        while (fgets(buf, 16, boost_cpuset_file)) {
+            //ALOGE("Appending FD %s to fg", buf);
+            int i = 0;
+            for (; i < 16; i++) {
+                if (buf[i] == '\n') {
+                    buf[i] = 0;
+                    break;
+                }
+            }
+            if (write(fg_cpuset_fd, buf, i) < 0) {
+                //ALOGE("Appending FD %s to fg ERROR", buf);
+                // handle error?
+            }
+            if (feof(boost_cpuset_file))
+                break;
+        }
+
+        close(fg_cpuset_fd);
+        fclose(boost_cpuset_file);
+
+#endif
+        return 0;
+
+    }
+
+
+    static JNINativeMethod method_table[] = {
+        { "nativeMigrateToBoost",   "()I", (void*)migrateToBoost },
+        { "nativeMigrateFromBoost", "()I", (void*)migrateFromBoost },
+    };
+
+    int register_android_server_ActivityManagerService(JNIEnv *env)
+    {
+        return jniRegisterNativeMethods(env, "com/android/server/am/ActivityManagerService",
+                                        method_table, NELEM(method_table));
+    }
+
+}
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 67872da..1f3fde6 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -20,6 +20,7 @@
 #include "utils/misc.h"
 
 namespace android {
+int register_android_server_ActivityManagerService(JNIEnv* env);
 int register_android_server_AlarmManagerService(JNIEnv* env);
 int register_android_server_AssetAtlasService(JNIEnv* env);
 int register_android_server_BatteryStatsService(JNIEnv* env);
@@ -57,6 +58,7 @@
     }
     ALOG_ASSERT(env, "Could not retrieve the env!");
 
+    register_android_server_ActivityManagerService(env);
     register_android_server_PowerManagerService(env);
     register_android_server_SerialService(env);
     register_android_server_InputApplicationHandle(env);
@@ -80,5 +82,6 @@
     register_android_server_PersistentDataBlockService(env);
     register_android_server_Watchdog(env);
 
+
     return JNI_VERSION_1_4;
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index e841f85..7a468ce 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -28,10 +28,10 @@
 import android.os.RemoteException;
 import android.os.UserManager;
 import android.util.AtomicFile;
+import android.util.Log;
 import android.util.Slog;
 import android.util.Xml;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FastXmlSerializer;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -58,6 +58,8 @@
 class Owners {
     private static final String TAG = "DevicePolicyManagerService";
 
+    private static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE
+
     private static final String DEVICE_OWNER_XML_LEGACY = "device_owner.xml";
 
     private static final String DEVICE_OWNER_XML = "device_owner_2.xml";
@@ -106,11 +108,18 @@
             final File legacy = getLegacyConfigFileWithTestOverride();
 
             if (readLegacyOwnerFile(legacy)) {
+                if (DEBUG) {
+                    Log.d(TAG, "Legacy config file found.");
+                }
+
                 // Legacy file exists, write to new files and remove the legacy one.
                 writeDeviceOwner();
                 for (int userId : getProfileOwnerKeys()) {
                     writeProfileOwner(userId);
                 }
+                if (DEBUG) {
+                    Log.d(TAG, "Deleting legacy config file");
+                }
                 if (!legacy.delete()) {
                     Slog.e(TAG, "Failed to remove the legacy setting file");
                 }
@@ -181,6 +190,11 @@
         return profileOwner != null ? profileOwner.name : null;
     }
 
+    String getProfileOwnerPackage(int userId) {
+        OwnerInfo profileOwner = mProfileOwners.get(userId);
+        return profileOwner != null ? profileOwner.packageName : null;
+    }
+
     Set<Integer> getProfileOwnerKeys() {
         return mProfileOwners.keySet();
     }
@@ -301,12 +315,18 @@
 
     void writeDeviceOwner() {
         synchronized (this) {
+            if (DEBUG) {
+                Log.d(TAG, "Writing to device owner file");
+            }
             new DeviceOwnerReadWriter().writeToFileLocked();
         }
     }
 
     void writeProfileOwner(int userId) {
         synchronized (this) {
+            if (DEBUG) {
+                Log.d(TAG, "Writing to profile owner file for user " + userId);
+            }
             new ProfileOwnerReadWriter(userId).writeToFileLocked();
         }
     }
@@ -322,14 +342,23 @@
 
         void writeToFileLocked() {
             if (!shouldWrite()) {
+                if (DEBUG) {
+                    Log.d(TAG, "No need to write to " + mFile);
+                }
                 // No contents, remove the file.
                 if (mFile.exists()) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Deleting existing " + mFile);
+                    }
                     if (!mFile.delete()) {
                         Slog.e(TAG, "Failed to remove " + mFile.getPath());
                     }
                 }
                 return;
             }
+            if (DEBUG) {
+                Log.d(TAG, "Writing to " + mFile);
+            }
 
             final AtomicFile f = new AtomicFile(mFile);
             FileOutputStream outputStream = null;
@@ -364,8 +393,14 @@
 
         void readFromFileLocked() {
             if (!mFile.exists()) {
+                if (DEBUG) {
+                    Log.d(TAG, "" + mFile + " doesn't exist");
+                }
                 return;
             }
+            if (DEBUG) {
+                Log.d(TAG, "Reading from " + mFile);
+            }
             final AtomicFile f = new AtomicFile(mFile);
             InputStream input = null;
             try {
diff --git a/services/tests/servicestests/assets/OwnersTest/test01/input.xml b/services/tests/servicestests/assets/OwnersTest/test01/input.xml
new file mode 100644
index 0000000..db3e974
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/test01/input.xml
@@ -0,0 +1 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
diff --git a/services/tests/servicestests/assets/OwnersTest/test02/input.xml b/services/tests/servicestests/assets/OwnersTest/test02/input.xml
new file mode 100644
index 0000000..321842b
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/test02/input.xml
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<device-owner package="com.google.android.testdpc" />
diff --git a/services/tests/servicestests/assets/OwnersTest/test03/input.xml b/services/tests/servicestests/assets/OwnersTest/test03/input.xml
new file mode 100644
index 0000000..1bbfdadf
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/test03/input.xml
@@ -0,0 +1,3 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<profile-owner package="com.google.android.testdpc0" name="0" userId="10" component="com.google.android.testdpc/com.google.android.testdpc.DeviceAdminReceiver0" />
+<profile-owner package="com.google.android.testdpc1" name="1" userId="11" />
diff --git a/services/tests/servicestests/assets/OwnersTest/test04/input.xml b/services/tests/servicestests/assets/OwnersTest/test04/input.xml
new file mode 100644
index 0000000..8be51d9
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/test04/input.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<device-owner package="com.google.android.testdpc" />
+<profile-owner package="com.google.android.testdpc0" name="0" userId="10" component="com.google.android.testdpc/com.google.android.testdpc.DeviceAdminReceiver0" />
+<profile-owner package="com.google.android.testdpc1" name="1" userId="11" />
+<device-initializer package="com.google.android.testdpcx" name="di" component="com.google.android.testdpcx/receiver" />
+<system-update-policy policy_type="5" />
diff --git a/services/tests/servicestests/assets/OwnersTest/test05/input.xml b/services/tests/servicestests/assets/OwnersTest/test05/input.xml
new file mode 100644
index 0000000..dbcb858
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/test05/input.xml
@@ -0,0 +1,3 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<device-initializer package="com.google.android.testdpcx" name="di" component="com.google.android.testdpcx/receiver" />
+
diff --git a/services/tests/servicestests/assets/OwnersTest/test06/input.xml b/services/tests/servicestests/assets/OwnersTest/test06/input.xml
new file mode 100644
index 0000000..794622b
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/test06/input.xml
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<system-update-policy policy_type="5" />
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
new file mode 100644
index 0000000..c2b8981
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.os.UserManager;
+
+import static org.mockito.Mockito.mock;
+
+public class DpmMockContext extends ContextWrapper {
+    private final UserManager mMockUserManager;
+
+
+    public DpmMockContext(Context context) {
+        super(context);
+        mMockUserManager = mock(UserManager.class);
+    }
+
+    public UserManager getMockUserManager() {
+        return mMockUserManager;
+    }
+
+    @Override
+    public Object getSystemService(String name) {
+        switch (name) {
+            case Context.USER_SERVICE:
+                return mMockUserManager;
+        }
+        return super.getSystemService(name);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
new file mode 100644
index 0000000..445260b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+
+public class DpmTestBase extends AndroidTestCase {
+    private DpmMockContext mMockContext;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mMockContext = new DpmMockContext(super.getContext());
+    }
+
+    @Override
+    public DpmMockContext getContext() {
+        return mMockContext;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
index 03e8d69..d8c4223 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -16,31 +16,52 @@
 
 package com.android.server.devicepolicy;
 
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.FileUtils;
 import android.test.AndroidTestCase;
+import android.util.Log;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
+import junit.framework.Assert;
+
+import static org.mockito.Mockito.when;
 
 /**
  * Tests for the DeviceOwner object that saves & loads device and policy owner information.
  * run this test with:
- *   make -j FrameworksServicesTests
- *   runtest --path frameworks/base/services/tests/servicestests/ \
- *       src/com/android/server/devicepolicy/DeviceOwnerTest.java
+ mmma frameworks/base/services/tests/servicestests/ &&
+ adb install \
+   -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ adb shell am instrument -e class com.android.server.devicepolicy.DeviceOwnerTest \
+   -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
  */
-public class OwnersTest extends AndroidTestCase {
+public class OwnersTest extends DpmTestBase {
+    private static final String TAG = "DeviceOwnerTest";
 
-    private static class OwnersSub extends Owners {
-        private final File mLegacyFile;
-        private final File mDeviceOwnerFile;
-        private final File mProfileOwnerBase;
+    private static final String LEGACY_FILE = "legacy.xml";
+    private static final String DEVICE_OWNER_FILE = "device_owner2.xml";
+    private static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml";
 
-        public OwnersSub(Context context, File legacyFile, File deviceOwnerFile,
-                File profileOwnerBase) {
-            super(context);
-            mLegacyFile = legacyFile;
-            mDeviceOwnerFile = deviceOwnerFile;
-            mProfileOwnerBase = profileOwnerBase;
+    private File mDataDir;
+
+    private class OwnersSub extends Owners {
+        final File mLegacyFile;
+        final File mDeviceOwnerFile;
+        final File mProfileOwnerBase;
+
+        public OwnersSub() {
+            super(getContext());
+            mLegacyFile = new File(mDataDir, LEGACY_FILE);
+            mDeviceOwnerFile = new File(mDataDir, DEVICE_OWNER_FILE);
+            mProfileOwnerBase = new File(mDataDir, PROFILE_OWNER_FILE_BASE);
         }
 
         @Override
@@ -59,5 +80,322 @@
         }
     }
 
-    // TODO Write tests
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mDataDir = new File(getContext().getCacheDir(), "OwnersTest");
+        if (mDataDir.exists()) {
+            assertTrue("failed to delete dir", FileUtils.deleteContents(mDataDir));
+        }
+        mDataDir.mkdirs();
+        Log.i(TAG, "Created " + mDataDir);
+    }
+
+    private String readAsset(String assetPath) throws IOException {
+        final StringBuilder sb = new StringBuilder();
+        try (BufferedReader br = new BufferedReader(
+                new InputStreamReader((getContext().getResources().getAssets().open(assetPath))))) {
+            String line;
+            while ((line = br.readLine()) != null) {
+                sb.append(line);
+                sb.append(System.lineSeparator());
+            }
+        }
+        return sb.toString();
+    }
+
+    private void createLegacyFile(File path, String content)
+            throws IOException {
+        path.getParentFile().mkdirs();
+
+        try (FileWriter writer = new FileWriter(path)) {
+            Log.i(TAG, "Writing to " + path);
+            Log.i(TAG, content);
+            writer.write(content);
+        }
+    }
+
+    private void addUsersToUserManager(int... userIds) {
+        final ArrayList<UserInfo> userInfos = new ArrayList<>();
+        for (int userId : userIds) {
+            final UserInfo ui = new UserInfo();
+            ui.id = userId;
+            userInfos.add(ui);
+        }
+        when(getContext().getMockUserManager().getUsers()).thenReturn(userInfos);
+    }
+
+    public void testUpgrade01() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        // First, migrate.
+        {
+            final OwnersSub owners = new OwnersSub();
+
+            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test01/input.xml"));
+
+            owners.load();
+
+            // The legacy file should be removed.
+            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+            // File was empty, so no new files should be created.
+            assertFalse(owners.getDeviceOwnerFileWithTestOverride().exists());
+
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(21).exists());
+        }
+
+        // Then re-read and check.
+        {
+            final OwnersSub owners = new OwnersSub();
+            owners.load();
+
+            assertFalse(owners.hasDeviceOwner());
+            assertFalse(owners.hasDeviceInitializer());
+            assertNull(owners.getSystemUpdatePolicy());
+            assertEquals(0, owners.getProfileOwnerKeys().size());
+        }
+    }
+
+    public void testUpgrade02() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        // First, migrate.
+        {
+            final OwnersSub owners = new OwnersSub();
+
+            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test02/input.xml"));
+
+            owners.load();
+
+            // The legacy file should be removed.
+            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+            assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists()); // TODO Check content
+
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(21).exists());
+        }
+
+        // Then re-read and check.
+        {
+            final OwnersSub owners = new OwnersSub();
+            owners.load();
+
+            assertTrue(owners.hasDeviceOwner());
+            assertEquals(null, owners.getDeviceOwnerName());
+            assertEquals("com.google.android.testdpc", owners.getDeviceOwnerPackageName());
+
+            assertFalse(owners.hasDeviceInitializer());
+            assertNull(owners.getSystemUpdatePolicy());
+            assertEquals(0, owners.getProfileOwnerKeys().size());
+        }
+    }
+
+    public void testUpgrade03() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        // First, migrate.
+        {
+            final OwnersSub owners = new OwnersSub();
+
+            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test03/input.xml"));
+
+            owners.load();
+
+            // The legacy file should be removed.
+            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+            assertFalse(owners.getDeviceOwnerFileWithTestOverride().exists());
+
+            assertTrue(owners.getProfileOwnerFileWithTestOverride(10).exists());
+            assertTrue(owners.getProfileOwnerFileWithTestOverride(11).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(21).exists());
+        }
+
+        // Then re-read and check.
+        {
+            final OwnersSub owners = new OwnersSub();
+            owners.load();
+
+            assertFalse(owners.hasDeviceOwner());
+            assertFalse(owners.hasDeviceInitializer());
+            assertNull(owners.getSystemUpdatePolicy());
+
+            assertEquals(2, owners.getProfileOwnerKeys().size());
+            assertEquals(new ComponentName("com.google.android.testdpc",
+                            "com.google.android.testdpc.DeviceAdminReceiver0"),
+                    owners.getProfileOwnerComponent(10));
+            assertEquals("0", owners.getProfileOwnerName(10));
+            assertEquals("com.google.android.testdpc", owners.getProfileOwnerPackage(10));
+
+            assertEquals(new ComponentName("com.google.android.testdpc1", ""),
+                    owners.getProfileOwnerComponent(11));
+            assertEquals("1", owners.getProfileOwnerName(11));
+            assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
+        }
+    }
+
+    public void testUpgrade04() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        // First, migrate.
+        {
+            final OwnersSub owners = new OwnersSub();
+
+            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test04/input.xml"));
+
+            owners.load();
+
+            // The legacy file should be removed.
+            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+            assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists());
+
+            assertTrue(owners.getProfileOwnerFileWithTestOverride(10).exists());
+            assertTrue(owners.getProfileOwnerFileWithTestOverride(11).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(21).exists());
+        }
+
+        // Then re-read and check.
+        {
+            final OwnersSub owners = new OwnersSub();
+            owners.load();
+
+            assertTrue(owners.hasDeviceOwner());
+            assertEquals(null, owners.getDeviceOwnerName());
+            assertEquals("com.google.android.testdpc", owners.getDeviceOwnerPackageName());
+
+            assertTrue(owners.hasDeviceInitializer());
+            assertEquals("com.google.android.testdpcx", owners.getDeviceInitializerPackageName());
+            assertNotNull(owners.getSystemUpdatePolicy());
+            assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType());
+
+            assertEquals(2, owners.getProfileOwnerKeys().size());
+            assertEquals(new ComponentName("com.google.android.testdpc",
+                            "com.google.android.testdpc.DeviceAdminReceiver0"),
+                    owners.getProfileOwnerComponent(10));
+            assertEquals("0", owners.getProfileOwnerName(10));
+            assertEquals("com.google.android.testdpc", owners.getProfileOwnerPackage(10));
+
+            assertEquals(new ComponentName("com.google.android.testdpc1", ""),
+                    owners.getProfileOwnerComponent(11));
+            assertEquals("1", owners.getProfileOwnerName(11));
+            assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
+        }
+    }
+
+    public void testUpgrade05() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        // First, migrate.
+        {
+            final OwnersSub owners = new OwnersSub();
+
+            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test05/input.xml"));
+
+            owners.load();
+
+            // The legacy file should be removed.
+            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+            assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists());
+
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
+        }
+
+        // Then re-read and check.
+        {
+            final OwnersSub owners = new OwnersSub();
+            owners.load();
+
+            assertFalse(owners.hasDeviceOwner());
+
+            assertTrue(owners.hasDeviceInitializer());
+            assertEquals("com.google.android.testdpcx", owners.getDeviceInitializerPackageName());
+
+            assertNull(owners.getSystemUpdatePolicy());
+            assertEquals(0, owners.getProfileOwnerKeys().size());
+        }
+    }
+
+    public void testUpgrade06() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        // First, migrate.
+        {
+            final OwnersSub owners = new OwnersSub();
+
+            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test06/input.xml"));
+
+            owners.load();
+
+            // The legacy file should be removed.
+            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+            assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists());
+
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
+        }
+
+        // Then re-read and check.
+        {
+            final OwnersSub owners = new OwnersSub();
+            owners.load();
+
+            assertFalse(owners.hasDeviceOwner());
+            assertFalse(owners.hasDeviceInitializer());
+            assertEquals(0, owners.getProfileOwnerKeys().size());
+
+            assertNotNull(owners.getSystemUpdatePolicy());
+            assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType());
+        }
+    }
+
+    public void testRemoveExistingFiles() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        final OwnersSub owners = new OwnersSub();
+
+        // First, migrate to create new-style config files.
+        createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test04/input.xml"));
+
+        owners.load();
+
+        assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+        assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists());
+        assertTrue(owners.getProfileOwnerFileWithTestOverride(10).exists());
+        assertTrue(owners.getProfileOwnerFileWithTestOverride(11).exists());
+
+        // Then clear all information and save.
+        owners.clearDeviceInitializer();
+        owners.clearDeviceOwner();
+        owners.clearSystemUpdatePolicy();
+        owners.removeProfileOwner(10);
+        owners.removeProfileOwner(11);
+
+        owners.writeDeviceOwner();
+        owners.writeProfileOwner(10);
+        owners.writeProfileOwner(11);
+        owners.writeProfileOwner(20);
+        owners.writeProfileOwner(21);
+
+        // Now all files should be removed.
+        assertFalse(owners.getDeviceOwnerFileWithTestOverride().exists());
+        assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
+        assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
+    }
 }
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 273cc93..b430340 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1457,10 +1457,15 @@
         String result = null;
         try {
             PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
+            /**
+             * Need to reformat any local Korean phone numbers (when the user is in Korea) with
+             * country code to corresponding national format which would replace the leading
+             * +82 with 0.
+             */
             if (KOREA_ISO_COUNTRY_CODE.equals(defaultCountryIso) &&
-                    (pn.getCountryCode() == util.getCountryCodeForRegion(KOREA_ISO_COUNTRY_CODE))) {
-                // Format local Korean phone numbers with country code to corresponding national
-                // format which would replace the leading +82 with 0.
+                    (pn.getCountryCode() == util.getCountryCodeForRegion(KOREA_ISO_COUNTRY_CODE)) &&
+                    (pn.getCountryCodeSource() ==
+                            PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
                 result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
             } else {
                 result = util.formatInOriginalFormat(pn, defaultCountryIso);
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index f892a68..9b3d186 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -121,5 +121,21 @@
                 <category android:name="com.android.test.uibench.TEST" />
             </intent-filter>
         </activity>
+        <activity
+            android:name=".TextCacheLowHitrateActivity"
+            android:label="Text/Layout Cache Low Hitrate" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".TextCacheHighHitrateActivity"
+            android:label="Text/Layout Cache High Hitrate" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/UiBench/src/com/android/test/uibench/CompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/CompatListActivity.java
new file mode 100644
index 0000000..40ec453
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/CompatListActivity.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+package com.android.test.uibench;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.ListFragment;
+import android.support.v7.app.AppCompatActivity;
+import android.widget.ListAdapter;
+
+public abstract class CompatListActivity extends AppCompatActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        FragmentManager fm = getSupportFragmentManager();
+        if (fm.findFragmentById(android.R.id.content) == null) {
+            ListFragment listFragment = new ListFragment();
+            listFragment.setListAdapter(createListAdapter());
+            fm.beginTransaction().add(android.R.id.content, listFragment).commit();
+        }
+    }
+
+    protected abstract ListAdapter createListAdapter();
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java b/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java
index 7b579a1..fe712d5 100644
--- a/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java
@@ -28,7 +28,7 @@
 
         ListView listView = new ListView(this);
         listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
-                TrivialListActivity.buildStringList()));
+                TextUtils.buildSimpleStringList()));
 
         AlertDialog.Builder builder = new AlertDialog.Builder(this);
         builder.setTitle("Dialog");
diff --git a/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java b/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
index 798c226..84383ec 100644
--- a/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
@@ -15,19 +15,16 @@
  */
 package com.android.test.uibench;
 
-import android.os.Bundle;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.ListFragment;
-import android.support.v7.app.AppCompatActivity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
 import android.widget.ListAdapter;
 
-public class InflatingListActivity extends AppCompatActivity {
-    private ListAdapter createListAdapter() {
+public class InflatingListActivity extends CompatListActivity {
+    @Override
+    protected ListAdapter createListAdapter() {
         return new ArrayAdapter<String>(this,
-                android.R.layout.simple_list_item_1, TrivialListActivity.buildStringList()) {
+                android.R.layout.simple_list_item_1, TextUtils.buildSimpleStringList()) {
             @Override
             public View getView(int position, View convertView, ViewGroup parent) {
                 // pathological getView behavior: drop convertView on the floor to force inflation
@@ -35,16 +32,4 @@
             }
         };
     }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        FragmentManager fm = getSupportFragmentManager();
-        if (fm.findFragmentById(android.R.id.content) == null) {
-            ListFragment listFragment = new ListFragment();
-            listFragment.setListAdapter(createListAdapter());
-            fm.beginTransaction().add(android.R.id.content, listFragment).commit();
-        }
-    }
 }
diff --git a/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java b/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java
index e39ec03..d32f071 100644
--- a/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java
@@ -38,7 +38,7 @@
             };
 
             listFragment.setListAdapter(new ArrayAdapter<>(this,
-                    R.layout.card_row, R.id.card_text, TrivialListActivity.buildStringList()));
+                    R.layout.card_row, R.id.card_text, TextUtils.buildSimpleStringList()));
             fm.beginTransaction().add(android.R.id.content, listFragment).commit();
         }
     }
diff --git a/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java b/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java
new file mode 100644
index 0000000..91d74ac
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+package com.android.test.uibench;
+
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+public class TextCacheHighHitrateActivity extends CompatListActivity {
+    @Override
+    protected ListAdapter createListAdapter() {
+        return new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+                TextUtils.buildParagraphListWithHitPercentage(80));
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java b/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java
new file mode 100644
index 0000000..b526cde
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+package com.android.test.uibench;
+
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+public class TextCacheLowHitrateActivity extends CompatListActivity {
+    @Override
+    protected ListAdapter createListAdapter() {
+        return new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+                TextUtils.buildParagraphListWithHitPercentage(20));
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TextUtils.java b/tests/UiBench/src/com/android/test/uibench/TextUtils.java
new file mode 100644
index 0000000..d88ca1e
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/TextUtils.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+package com.android.test.uibench;
+
+import java.util.Random;
+
+public class TextUtils {
+    private static final int STRING_COUNT = 200;
+    private static final int SIMPLE_STRING_LENGTH = 10;
+
+    /**
+     * Create word of random assortment of lower/upper case letters
+     */
+    private static String randomWord(Random random, int length) {
+        String result = "";
+        for (int j = 0; j < length; j++) {
+            // add random letter
+            int base = random.nextInt(2) == 0 ? 'A' : 'a';
+            result += (char)(random.nextInt(26) + base);
+        }
+        return result;
+    }
+
+    public static String[] buildSimpleStringList() {
+        String[] strings = new String[STRING_COUNT];
+        Random random = new Random(0);
+        for (int i = 0; i < strings.length; i++) {
+            strings[i] = randomWord(random, SIMPLE_STRING_LENGTH);
+        }
+        return strings;
+    }
+
+    // a small number of strings reused frequently, expected to hit
+    // in the word-granularity text layout cache
+    static final String[] CACHE_HIT_STRINGS = new String[] {
+            "a",
+            "small",
+            "number",
+            "of",
+            "strings",
+            "reused",
+            "frequently"
+    };
+
+    private static final int WORDS_IN_PARAGRAPH = 150;
+
+    // misses are fairly long 'words' to ensure they miss
+    private static final int PARAGRAPH_MISS_MIN_LENGTH = 4;
+    private static final int PARAGRAPH_MISS_MAX_LENGTH = 9;
+
+    static String[] buildParagraphListWithHitPercentage(int hitPercentage) {
+        if (hitPercentage < 0 || hitPercentage > 100) throw new IllegalArgumentException();
+
+        String[] strings = new String[STRING_COUNT];
+        Random random = new Random(0);
+        for (int i = 0; i < strings.length; i++) {
+            String result = "";
+            for (int word = 0; word < WORDS_IN_PARAGRAPH; word++) {
+                if (word != 0) {
+                    result += " ";
+                }
+                if (random.nextInt(100) < hitPercentage) {
+                    // add a common word, which is very likely to hit in the cache
+                    result += CACHE_HIT_STRINGS[random.nextInt(CACHE_HIT_STRINGS.length)];
+                } else {
+                    // construct a random word, which will *most likely* miss
+                    int length = PARAGRAPH_MISS_MIN_LENGTH;
+                    length += random.nextInt(PARAGRAPH_MISS_MAX_LENGTH - PARAGRAPH_MISS_MIN_LENGTH);
+
+                    result += randomWord(random, length);
+                }
+            }
+            strings[i] = result;
+        }
+
+        return strings;
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java b/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
index 9c8ae9b..339ac80 100644
--- a/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
@@ -15,41 +15,13 @@
  */
 package com.android.test.uibench;
 
-import android.os.Bundle;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.ListFragment;
-import android.support.v7.app.AppCompatActivity;
 import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
 
-import java.util.Random;
-
-public class TrivialListActivity extends AppCompatActivity {
-    static final int STRING_LENGTH = 10;
-
-    static String[] buildStringList() {
-        String[] strings = new String[200];
-        Random random = new Random(0);
-        for (int i = 0; i < strings.length; i++) {
-            String result = "";
-            for (int j = 0; j < STRING_LENGTH; j++) {
-                // add random letter
-                result += (char)(random.nextInt(26) + 65);
-            }
-            strings[i] = result;
-        }
-        return strings;
-    }
-
+public class TrivialListActivity extends CompatListActivity {
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        FragmentManager fm = getSupportFragmentManager();
-        if (fm.findFragmentById(android.R.id.content) == null) {
-            ListFragment listFragment = new ListFragment();
-            listFragment.setListAdapter(new ArrayAdapter<>(this,
-                    android.R.layout.simple_list_item_1, buildStringList()));
-            fm.beginTransaction().add(android.R.id.content, listFragment).commit();
-        }
+    protected ListAdapter createListAdapter() {
+        return new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+                TextUtils.buildSimpleStringList());
     }
 }
diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk
index 354563a..8e6189f 100644
--- a/tools/aidl/Android.mk
+++ b/tools/aidl/Android.mk
@@ -31,7 +31,6 @@
     aidl_language_y.y \
     generate_java.cpp \
     generate_java_binder.cpp \
-    generate_java_rpc.cpp \
     options.cpp \
     search_path.cpp \
 
@@ -49,22 +48,32 @@
 include $(BUILD_HOST_EXECUTABLE)
 
 
+# TODO(wiley) Compile these for mac as well after b/22771504
+ifeq ($(HOST_OS),linux)
 # Unit tests
 include $(CLEAR_VARS)
 LOCAL_MODULE := aidl_unittests
 
 LOCAL_CFLAGS := -g -DUNIT_TEST -Wall -Werror
+# Tragically, the code is riddled with unused parameters.
+LOCAL_CLANG_CFLAGS := -Wno-unused-parameter
 LOCAL_SRC_FILES := \
     options_unittest.cpp \
     test_main.cpp \
-    tests/test.cpp \
+    tests/end_to_end_tests.cpp \
+    tests/example_interface_test_data.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+    libchrome-host \
 
 LOCAL_STATIC_LIBRARIES := \
     libaidl-common \
     libgmock_host \
     libgtest_host \
 
-LOCAL_LDLIBS := -lrt
+LOCAL_LDLIBS_linux := -lrt
+
 include $(BUILD_HOST_NATIVE_TEST)
+endif # HOST_OS == linux
 
 endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
index 2267750..d9b8b88 100644
--- a/tools/aidl/Type.cpp
+++ b/tools/aidl/Type.cpp
@@ -28,9 +28,6 @@
 Type* MAP_TYPE;
 Type* LIST_TYPE;
 Type* CLASSLOADER_TYPE;
-Type* RPC_DATA_TYPE;
-Type* RPC_ERROR_TYPE;
-Type* EVENT_FAKE_TYPE;
 
 Expression* NULL_VALUE;
 Expression* THIS_VALUE;
@@ -42,7 +39,6 @@
 register_base_types()
 {
     VOID_TYPE = new BasicType("void",
-            "XXX", "XXX", "XXX", "XXX", "XXX",
             "XXX", "XXX", "XXX", "XXX", "XXX");
     NAMES.Add(VOID_TYPE);
 
@@ -50,37 +46,37 @@
     NAMES.Add(BOOLEAN_TYPE);
 
     BYTE_TYPE = new BasicType("byte",
-            "writeByte", "readByte", "writeByteArray", "createByteArray", "readByteArray",
-            "putByte", "getByte", "putByteArray", "createByteArray", "getByteArray");
+            "writeByte", "readByte", "writeByteArray", "createByteArray",
+            "readByteArray");
     NAMES.Add(BYTE_TYPE);
 
     CHAR_TYPE = new CharType();
     NAMES.Add(CHAR_TYPE);
 
     INT_TYPE = new BasicType("int",
-            "writeInt", "readInt", "writeIntArray", "createIntArray", "readIntArray",
-            "putInteger", "getInteger", "putIntegerArray", "createIntegerArray", "getIntegerArray");
+            "writeInt", "readInt", "writeIntArray", "createIntArray",
+            "readIntArray");
     NAMES.Add(INT_TYPE);
 
     LONG_TYPE = new BasicType("long",
-            "writeLong", "readLong", "writeLongArray", "createLongArray", "readLongArray",
-            "putLong", "getLong", "putLongArray", "createLongArray", "getLongArray");
+            "writeLong", "readLong", "writeLongArray", "createLongArray",
+            "readLongArray");
     NAMES.Add(LONG_TYPE);
 
     FLOAT_TYPE = new BasicType("float",
-            "writeFloat", "readFloat", "writeFloatArray", "createFloatArray", "readFloatArray",
-            "putFloat", "getFloat", "putFloatArray", "createFloatArray", "getFloatArray");
+            "writeFloat", "readFloat", "writeFloatArray", "createFloatArray",
+            "readFloatArray");
     NAMES.Add(FLOAT_TYPE);
 
     DOUBLE_TYPE = new BasicType("double",
-            "writeDouble", "readDouble", "writeDoubleArray", "createDoubleArray", "readDoubleArray",
-            "putDouble", "getDouble", "putDoubleArray", "createDoubleArray", "getDoubleArray");
+            "writeDouble", "readDouble", "writeDoubleArray",
+            "createDoubleArray", "readDoubleArray");
     NAMES.Add(DOUBLE_TYPE);
 
     STRING_TYPE = new StringType();
     NAMES.Add(STRING_TYPE);
 
-    OBJECT_TYPE = new Type("java.lang", "Object", Type::BUILT_IN, false, false, false);
+    OBJECT_TYPE = new Type("java.lang", "Object", Type::BUILT_IN, false, false);
     NAMES.Add(OBJECT_TYPE);
 
     CHAR_SEQUENCE_TYPE = new CharSequenceType();
@@ -92,7 +88,7 @@
     LIST_TYPE = new ListType();
     NAMES.Add(LIST_TYPE);
 
-    TEXT_UTILS_TYPE = new Type("android.text", "TextUtils", Type::BUILT_IN, false, false, false);
+    TEXT_UTILS_TYPE = new Type("android.text", "TextUtils", Type::BUILT_IN, false, false);
     NAMES.Add(TEXT_UTILS_TYPE);
 
     REMOTE_EXCEPTION_TYPE = new RemoteExceptionType();
@@ -119,19 +115,9 @@
     PARCELABLE_INTERFACE_TYPE = new ParcelableInterfaceType();
     NAMES.Add(PARCELABLE_INTERFACE_TYPE);
 
-    CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false, false);
+    CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false);
     NAMES.Add(CONTEXT_TYPE);
 
-    RPC_DATA_TYPE = new RpcDataType();
-    NAMES.Add(RPC_DATA_TYPE);
-
-    RPC_ERROR_TYPE = new UserDataType("android.support.place.rpc", "RpcError",
-                                    true, __FILE__, __LINE__);
-    NAMES.Add(RPC_ERROR_TYPE);
-
-    EVENT_FAKE_TYPE = new Type("event", Type::BUILT_IN, false, false, false);
-    NAMES.Add(EVENT_FAKE_TYPE);
-
     CLASSLOADER_TYPE = new ClassLoaderType();
     NAMES.Add(CLASSLOADER_TYPE);
 
@@ -158,30 +144,27 @@
 
 // ================================================================
 
-Type::Type(const string& name, int kind, bool canWriteToParcel, bool canWriteToRpcData,
-        bool canBeOut)
+Type::Type(const string& name, int kind, bool canWriteToParcel, bool canBeOut)
     :m_package(),
      m_name(name),
      m_declFile(""),
      m_declLine(-1),
      m_kind(kind),
      m_canWriteToParcel(canWriteToParcel),
-     m_canWriteToRpcData(canWriteToRpcData),
      m_canBeOut(canBeOut)
 {
     m_qualifiedName = name;
 }
 
 Type::Type(const string& package, const string& name,
-            int kind, bool canWriteToParcel, bool canWriteToRpcData,
-            bool canBeOut, const string& declFile, int declLine)
+            int kind, bool canWriteToParcel, bool canBeOut,
+            const string& declFile, int declLine)
     :m_package(package),
      m_name(name),
      m_declFile(declFile),
      m_declLine(declLine),
      m_kind(kind),
      m_canWriteToParcel(canWriteToParcel),
-     m_canWriteToRpcData(canWriteToRpcData),
      m_canBeOut(canBeOut)
 {
     if (package.length() > 0) {
@@ -214,12 +197,6 @@
 }
 
 string
-Type::RpcCreatorName() const
-{
-    return "";
-}
-
-string
 Type::InstantiableName() const
 {
     return QualifiedName();
@@ -282,26 +259,6 @@
 }
 
 void
-Type::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
-            __FILE__, __LINE__, m_qualifiedName.c_str());
-    addTo->Add(new LiteralExpression("/* WriteToRpcData error "
-                + m_qualifiedName + " */"));
-}
-
-void
-Type::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
-        Variable** cl)
-{
-    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
-            __FILE__, __LINE__, m_qualifiedName.c_str());
-    addTo->Add(new LiteralExpression("/* ReadFromRpcData error "
-                + m_qualifiedName + " */"));
-}
-
-void
 Type::SetQualifiedName(const string& qualified)
 {
     m_qualifiedName = qualified;
@@ -324,20 +281,13 @@
 
 BasicType::BasicType(const string& name, const string& marshallParcel,
           const string& unmarshallParcel, const string& writeArrayParcel,
-          const string& createArrayParcel, const string& readArrayParcel,
-          const string& marshallRpc, const string& unmarshallRpc,
-          const string& writeArrayRpc, const string& createArrayRpc, const string& readArrayRpc)
-    :Type(name, BUILT_IN, true, true, false),
+          const string& createArrayParcel, const string& readArrayParcel)
+    :Type(name, BUILT_IN, true, false),
      m_marshallParcel(marshallParcel),
      m_unmarshallParcel(unmarshallParcel),
      m_writeArrayParcel(writeArrayParcel),
      m_createArrayParcel(createArrayParcel),
-     m_readArrayParcel(readArrayParcel),
-     m_marshallRpc(marshallRpc),
-     m_unmarshallRpc(unmarshallRpc),
-     m_writeArrayRpc(writeArrayRpc),
-     m_createArrayRpc(createArrayRpc),
-     m_readArrayRpc(readArrayRpc)
+     m_readArrayParcel(readArrayParcel)
 {
 }
 
@@ -378,24 +328,10 @@
     addTo->Add(new MethodCall(parcel, m_readArrayParcel, 1, v));
 }
 
-void
-BasicType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    addTo->Add(new MethodCall(data, m_marshallRpc, 2, k, v));
-}
-
-void
-BasicType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
-        Variable** cl)
-{
-    addTo->Add(new Assignment(v, new MethodCall(data, m_unmarshallRpc, 1, k)));
-}
-
 // ================================================================
 
 BooleanType::BooleanType()
-    :Type("boolean", BUILT_IN, true, true, false)
+    :Type("boolean", BUILT_IN, true, false)
 {
 }
 
@@ -439,24 +375,10 @@
     addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
 }
 
-void
-BooleanType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    addTo->Add(new MethodCall(data, "putBoolean", 2, k, v));
-}
-
-void
-BooleanType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
-        Variable** cl)
-{
-    addTo->Add(new Assignment(v, new MethodCall(data, "getBoolean", 1, k)));
-}
-
 // ================================================================
 
 CharType::CharType()
-    :Type("char", BUILT_IN, true, true, false)
+    :Type("char", BUILT_IN, true, false)
 {
 }
 
@@ -498,24 +420,10 @@
     addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
 }
 
-void
-CharType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    addTo->Add(new MethodCall(data, "putChar", 2, k, v));
-}
-
-void
-CharType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
-        Variable** cl)
-{
-    addTo->Add(new Assignment(v, new MethodCall(data, "getChar", 1, k)));
-}
-
 // ================================================================
 
 StringType::StringType()
-    :Type("java.lang", "String", BUILT_IN, true, true, false)
+    :Type("java.lang", "String", BUILT_IN, true, false)
 {
 }
 
@@ -562,24 +470,10 @@
     addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
 }
 
-void
-StringType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    addTo->Add(new MethodCall(data, "putString", 2, k, v));
-}
-
-void
-StringType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, Variable**)
-{
-    addTo->Add(new Assignment(v, new MethodCall(data, "getString", 1, k)));
-}
-
 // ================================================================
 
 CharSequenceType::CharSequenceType()
-    :Type("java.lang", "CharSequence", BUILT_IN, true, true, false)
+    :Type("java.lang", "CharSequence", BUILT_IN, true, false)
 {
 }
 
@@ -639,7 +533,7 @@
 // ================================================================
 
 RemoteExceptionType::RemoteExceptionType()
-    :Type("android.os", "RemoteException", BUILT_IN, false, false, false)
+    :Type("android.os", "RemoteException", BUILT_IN, false, false)
 {
 }
 
@@ -658,7 +552,7 @@
 // ================================================================
 
 RuntimeExceptionType::RuntimeExceptionType()
-    :Type("java.lang", "RuntimeException", BUILT_IN, false, false, false)
+    :Type("java.lang", "RuntimeException", BUILT_IN, false, false)
 {
 }
 
@@ -678,7 +572,7 @@
 // ================================================================
 
 IBinderType::IBinderType()
-    :Type("android.os", "IBinder", BUILT_IN, true, false, false)
+    :Type("android.os", "IBinder", BUILT_IN, true, false)
 {
 }
 
@@ -717,7 +611,7 @@
 // ================================================================
 
 IInterfaceType::IInterfaceType()
-    :Type("android.os", "IInterface", BUILT_IN, false, false, false)
+    :Type("android.os", "IInterface", BUILT_IN, false, false)
 {
 }
 
@@ -737,7 +631,7 @@
 // ================================================================
 
 BinderType::BinderType()
-    :Type("android.os", "Binder", BUILT_IN, false, false, false)
+    :Type("android.os", "Binder", BUILT_IN, false, false)
 {
 }
 
@@ -758,7 +652,7 @@
 // ================================================================
 
 BinderProxyType::BinderProxyType()
-    :Type("android.os", "BinderProxy", BUILT_IN, false, false, false)
+    :Type("android.os", "BinderProxy", BUILT_IN, false, false)
 {
 }
 
@@ -779,7 +673,7 @@
 // ================================================================
 
 ParcelType::ParcelType()
-    :Type("android.os", "Parcel", BUILT_IN, false, false, false)
+    :Type("android.os", "Parcel", BUILT_IN, false, false)
 {
 }
 
@@ -798,7 +692,7 @@
 // ================================================================
 
 ParcelableInterfaceType::ParcelableInterfaceType()
-    :Type("android.os", "Parcelable", BUILT_IN, false, false, false)
+    :Type("android.os", "Parcelable", BUILT_IN, false, false)
 {
 }
 
@@ -817,7 +711,7 @@
 // ================================================================
 
 MapType::MapType()
-    :Type("java.util", "Map", BUILT_IN, true, false, true)
+    :Type("java.util", "Map", BUILT_IN, true, true)
 {
 }
 
@@ -857,7 +751,7 @@
 // ================================================================
 
 ListType::ListType()
-    :Type("java.util", "List", BUILT_IN, true, true, true)
+    :Type("java.util", "List", BUILT_IN, true, true)
 {
 }
 
@@ -888,26 +782,12 @@
     addTo->Add(new MethodCall(parcel, "readList", 2, v, *cl));
 }
 
-void
-ListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    addTo->Add(new MethodCall(data, "putList", 2, k, v));
-}
-
-void
-ListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
-        Variable** cl)
-{
-    addTo->Add(new Assignment(v, new MethodCall(data, "getList", 1, k)));
-}
-
 // ================================================================
 
 UserDataType::UserDataType(const string& package, const string& name,
-                        bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+                        bool builtIn, bool canWriteToParcel,
                         const string& declFile, int declLine)
-    :Type(package, name, builtIn ? BUILT_IN : USERDATA, canWriteToParcel, canWriteToRpcData,
+    :Type(package, name, builtIn ? BUILT_IN : USERDATA, canWriteToParcel,
             true, declFile, declLine)
 {
 }
@@ -918,12 +798,6 @@
     return QualifiedName() + ".CREATOR";
 }
 
-string
-UserDataType::RpcCreatorName() const
-{
-    return QualifiedName() + ".RPC_CREATOR";
-}
-
 void
 UserDataType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
 {
@@ -1014,29 +888,12 @@
                     v, new LiteralExpression(creator)));
 }
 
-void
-UserDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags)
-{
-    // data.putFlattenable(k, v);
-    addTo->Add(new MethodCall(data, "putFlattenable", 2, k, v));
-}
-
-void
-UserDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl)
-{
-    // data.getFlattenable(k, CLASS.RPC_CREATOR);
-    addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenable", 2, k,
-                new FieldVariable(v->type, "RPC_CREATOR"))));
-}
-
 // ================================================================
 
 InterfaceType::InterfaceType(const string& package, const string& name,
                         bool builtIn, bool oneway,
                         const string& declFile, int declLine)
-    :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false, false,
+    :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false,
                         declFile, declLine)
     ,m_oneway(oneway)
 {
@@ -1075,7 +932,7 @@
 
 GenericType::GenericType(const string& package, const string& name,
                          const vector<Type*>& args)
-    :Type(package, name, BUILT_IN, true, true, true)
+    :Type(package, name, BUILT_IN, true, true)
 {
     m_args = args;
 
@@ -1200,65 +1057,11 @@
     }
 }
 
-void
-GenericListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    Type* generic = GenericArgumentTypes()[0];
-    if (generic == RPC_DATA_TYPE) {
-        addTo->Add(new MethodCall(data, "putRpcDataList", 2, k, v));
-    } else if (generic->RpcCreatorName() != "") {
-        addTo->Add(new MethodCall(data, "putFlattenableList", 2, k, v));
-    } else {
-        addTo->Add(new MethodCall(data, "putList", 2, k, v));
-    }
-}
-
-void
-GenericListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, Variable** cl)
-{
-    Type* generic = GenericArgumentTypes()[0];
-    if (generic == RPC_DATA_TYPE) {
-        addTo->Add(new Assignment(v, new MethodCall(data, "getRpcDataList", 2, k)));
-    } else if (generic->RpcCreatorName() != "") {
-        addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenableList", 2, k, 
-                        new LiteralExpression(generic->RpcCreatorName()))));
-    } else {
-        string classArg = GenericArgumentTypes()[0]->QualifiedName();
-        classArg += ".class";
-        addTo->Add(new Assignment(v, new MethodCall(data, "getList", 2, k,
-                        new LiteralExpression(classArg))));
-    }
-}
-
-
-// ================================================================
-
-RpcDataType::RpcDataType()
-    :UserDataType("android.support.place.rpc", "RpcData", true, true, true)
-{
-}
-
-void
-RpcDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    addTo->Add(new MethodCall(data, "putRpcData", 2, k, v));
-}
-
-void
-RpcDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
-        Variable** cl)
-{
-    addTo->Add(new Assignment(v, new MethodCall(data, "getRpcData", 1, k)));
-}
-
 
 // ================================================================
 
 ClassLoaderType::ClassLoaderType()
-    :Type("java.lang", "ClassLoader", BUILT_IN, false, false, false)
+    :Type("java.lang", "ClassLoader", BUILT_IN, false, false)
 {
 }
 
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index d799fca..6ede79a 100644
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -24,9 +24,9 @@
     };
 
                     Type(const string& name, int kind, bool canWriteToParcel,
-                            bool canWriteToRpcData, bool canBeOut);
+                         bool canBeOut);
                     Type(const string& package, const string& name,
-                            int kind, bool canWriteToParcel, bool canWriteToRpcData, bool canBeOut,
+                            int kind, bool canWriteToParcel, bool canBeOut,
                             const string& declFile = "", int declLine = -1);
     virtual         ~Type();
 
@@ -37,12 +37,10 @@
     inline string   DeclFile() const            { return m_declFile; }
     inline int      DeclLine() const            { return m_declLine; }
     inline bool     CanWriteToParcel() const    { return m_canWriteToParcel; }
-    inline bool     CanWriteToRpcData() const   { return m_canWriteToRpcData; }
     inline bool     CanBeOutParameter() const   { return m_canBeOut; }
     
     virtual string  ImportType() const;
     virtual string  CreatorName() const;
-    virtual string  RpcCreatorName() const;
     virtual string  InstantiableName() const;
 
     virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
@@ -61,11 +59,6 @@
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
 
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
-
 protected:
     void SetQualifiedName(const string& qualified);
     Expression* BuildWriteToParcelFlags(int flags);
@@ -81,7 +74,6 @@
     int m_declLine;
     int m_kind;
     bool m_canWriteToParcel;
-    bool m_canWriteToRpcData;
     bool m_canBeOut;
 };
 
@@ -93,12 +85,7 @@
                               const string& unmarshallParcel,
                               const string& writeArrayParcel,
                               const string& createArrayParcel,
-                              const string& readArrayParcel,
-                              const string& marshallRpc,
-                              const string& unmarshallRpc,
-                              const string& writeArrayRpc,
-                              const string& createArrayRpc,
-                              const string& readArrayRpc);
+                              const string& readArrayParcel);
 
     virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, int flags);
@@ -114,22 +101,12 @@
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
 
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
-
 private:
     string m_marshallParcel;
     string m_unmarshallParcel;
     string m_writeArrayParcel;
     string m_createArrayParcel;
     string m_readArrayParcel;
-    string m_marshallRpc;
-    string m_unmarshallRpc;
-    string m_writeArrayRpc;
-    string m_createArrayRpc;
-    string m_readArrayRpc;
 };
 
 class BooleanType : public Type
@@ -150,11 +127,6 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
-
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
 };
 
 class CharType : public Type
@@ -175,11 +147,6 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
-
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
 };
 
 
@@ -203,11 +170,6 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
-
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
 };
 
 class CharSequenceType : public Type
@@ -344,22 +306,16 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
-
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
 };
 
 class UserDataType : public Type
 {
 public:
                     UserDataType(const string& package, const string& name,
-                            bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+                            bool builtIn, bool canWriteToParcel,
                             const string& declFile = "", int declLine = -1);
 
     virtual string  CreatorName() const;
-    virtual string  RpcCreatorName() const;
 
     virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, int flags);
@@ -376,11 +332,6 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
-
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
 };
 
 class InterfaceType : public Type
@@ -426,17 +377,6 @@
     vector<Type*> m_args;
 };
 
-class RpcDataType : public UserDataType
-{
-public:
-                    RpcDataType();
-
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
-};
-
 class ClassLoaderType : public Type
 {
 public:
@@ -459,11 +399,6 @@
     virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
 
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
-    
 private:
     string m_creator;
 };
@@ -526,11 +461,6 @@
 
 extern Type* CONTEXT_TYPE;
 
-extern Type* RPC_DATA_TYPE;
-extern Type* RPC_ERROR_TYPE;
-extern Type* RPC_CONTEXT_TYPE;
-extern Type* EVENT_FAKE_TYPE;
-
 extern Expression* NULL_VALUE;
 extern Expression* THIS_VALUE;
 extern Expression* SUPER_VALUE;
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index a4ecb75..832c51c 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -60,12 +60,9 @@
         }
         else if (d->item_type == USER_DATA_TYPE) {
             user_data_type* b = (user_data_type*)d;
-            if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
+            if (b->parcelable) {
                 printf("parcelable %s %s;\n", b->package, b->name.data);
             }
-            if ((b->flattening_methods & RPC_DATA) != 0) {
-                printf("flattenable %s %s;\n", b->package, b->name.data);
-            }
         }
         else {
             printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
@@ -251,8 +248,7 @@
             user_data_type* p = (user_data_type*)items;
             err |= check_filename(filename, p->package, &p->name);
         }
-        else if (items->item_type == INTERFACE_TYPE_BINDER
-                || items->item_type == INTERFACE_TYPE_RPC) {
+        else if (items->item_type == INTERFACE_TYPE_BINDER) {
             interface_type* c = (interface_type*)items;
             err |= check_filename(filename, c->package, &c->name);
         }
@@ -303,11 +299,9 @@
         if (items->item_type == USER_DATA_TYPE) {
             user_data_type* p = (user_data_type*)items;
             type = new UserDataType(p->package ? p->package : "", p->name.data,
-                    false, ((p->flattening_methods & PARCELABLE_DATA) != 0),
-                    ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno);
+                    false, p->parcelable, filename, p->name.lineno);
         }
-        else if (items->item_type == INTERFACE_TYPE_BINDER
-                || items->item_type == INTERFACE_TYPE_RPC) {
+        else if (items->item_type == INTERFACE_TYPE_BINDER) {
             interface_type* c = (interface_type*)items;
             type = new InterfaceType(c->package ? c->package : "",
                             c->name.data, false, c->oneway,
@@ -331,30 +325,17 @@
                 string name = c->name.data;
                 name += ".Stub";
                 Type* stub = new Type(c->package ? c->package : "",
-                                        name, Type::GENERATED, false, false, false,
+                                        name, Type::GENERATED, false, false,
                                         filename, c->name.lineno);
                 NAMES.Add(stub);
 
                 name = c->name.data;
                 name += ".Stub.Proxy";
                 Type* proxy = new Type(c->package ? c->package : "",
-                                        name, Type::GENERATED, false, false, false,
+                                        name, Type::GENERATED, false, false,
                                         filename, c->name.lineno);
                 NAMES.Add(proxy);
             }
-            else if (items->item_type == INTERFACE_TYPE_RPC) {
-                // for interfaces, also add the service base type, we don't
-                // bother checking these for duplicates, because the parser
-                // won't let us do it.
-                interface_type* c = (interface_type*)items;
-
-                string name = c->name.data;
-                name += ".ServiceBase";
-                Type* base = new Type(c->package ? c->package : "",
-                                        name, Type::GENERATED, false, false, false,
-                                        filename, c->name.lineno);
-                NAMES.Add(base);
-            }
         } else {
             if (old->Kind() == Type::BUILT_IN) {
                 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
@@ -406,7 +387,7 @@
 }
 
 static int
-check_method(const char* filename, int kind, method_type* m)
+check_method(const char* filename, method_type* m)
 {
     int err = 0;
 
@@ -419,19 +400,10 @@
         return err;
     }
 
-    if (returnType == EVENT_FAKE_TYPE) {
-        if (kind != INTERFACE_TYPE_RPC) {
-            fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
-                    filename, m->type.type.lineno);
-            err = 1;
-        }
-    } else {
-        if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
-                    : returnType->CanWriteToRpcData())) {
-            fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
+    if (!returnType->CanWriteToParcel()) {
+        fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
                         m->type.type.lineno, m->type.type.data);
-            err = 1;
-        }
+        err = 1;
     }
 
     if (m->type.dimension > 0 && !returnType->CanBeArray()) {
@@ -464,30 +436,13 @@
             goto next;
         }
 
-        if (t == EVENT_FAKE_TYPE) {
-            fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
-                    filename, m->type.type.lineno, arg->name.data, index,
-                    arg->type.type.data);
-            err = 1;
-            goto next;
-        }
-        
-        if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
+        if (!t->CanWriteToParcel()) {
             fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
                         filename, m->type.type.lineno, index,
                         arg->type.type.data, arg->name.data);
             err = 1;
         }
 
-        if (returnType == EVENT_FAKE_TYPE
-                && convert_direction(arg->direction.data) != IN_PARAMETER) {
-            fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
-                    filename, m->type.type.lineno, index,
-                    arg->type.type.data, arg->name.data);
-            err = 1;
-            goto next;
-        }
-
         if (arg->direction.data == NULL
                 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
             fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
@@ -549,8 +504,7 @@
     int err = 0;
     while (items) {
         // (nothing to check for USER_DATA_TYPE)
-        if (items->item_type == INTERFACE_TYPE_BINDER
-                || items->item_type == INTERFACE_TYPE_RPC) {
+        if (items->item_type == INTERFACE_TYPE_BINDER) {
             map<string,method_type*> methodNames;
             interface_type* c = (interface_type*)items;
 
@@ -559,7 +513,7 @@
                 if (member->item_type == METHOD_TYPE) {
                     method_type* m = (method_type*)member;
 
-                    err |= check_method(filename, items->item_type, m);
+                    err |= check_method(filename, m);
 
                     // prevent duplicate methods
                     if (methodNames.find(m->name.data) == methodNames.end()) {
@@ -600,9 +554,6 @@
         if (next->item_type == INTERFACE_TYPE_BINDER) {
             lineno = ((interface_type*)next)->interface_token.lineno;
         }
-        else if (next->item_type == INTERFACE_TYPE_RPC) {
-            lineno = ((interface_type*)next)->interface_token.lineno;
-        }
         fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
                             filename, lineno);
         return 1;
@@ -612,9 +563,9 @@
         *onlyParcelable = true;
         if (options.failOnParcelable) {
             fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
-                            " parcelables or flattenables,\n", filename,
+                            " parcelables,\n", filename,
                             ((user_data_type*)items)->keyword_token.lineno);
-            fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
+            fprintf(stderr, "%s:%d .aidl files that only declare parcelables"
                             "may not go in the Makefile.\n", filename,
                             ((user_data_type*)items)->keyword_token.lineno);
             return 1;
@@ -651,7 +602,7 @@
         slash = "";
     }
 
-    if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
+    if (items->item_type == INTERFACE_TYPE_BINDER) {
         fprintf(to, "%s: \\\n", options.outputFileName.c_str());
     } else {
         // parcelable: there's no output file.
@@ -725,7 +676,7 @@
 generate_outputFileName(const Options& options, const document_item_type* items)
 {
     // items has already been checked to have only one interface.
-    if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
+    if (items->item_type == INTERFACE_TYPE_BINDER) {
         interface_type* type = (interface_type*)items;
 
         return generate_outputFileName2(options, type->name, type->package);
@@ -812,22 +763,7 @@
             parcl->name.data = strdup(classname);
             parcl->semicolon_token.lineno = lineno;
             parcl->semicolon_token.data = strdup(";");
-            parcl->flattening_methods = PARCELABLE_DATA;
-            doc = (document_item_type*)parcl;
-        }
-        else if (0 == strcmp("flattenable", type)) {
-            user_data_type* parcl = (user_data_type*)malloc(
-                    sizeof(user_data_type));
-            memset(parcl, 0, sizeof(user_data_type));
-            parcl->document_item.item_type = USER_DATA_TYPE;
-            parcl->keyword_token.lineno = lineno;
-            parcl->keyword_token.data = strdup(type);
-            parcl->package = packagename ? strdup(packagename) : NULL;
-            parcl->name.lineno = lineno;
-            parcl->name.data = strdup(classname);
-            parcl->semicolon_token.lineno = lineno;
-            parcl->semicolon_token.data = strdup(";");
-            parcl->flattening_methods = RPC_DATA;
+            parcl->parcelable = true;
             doc = (document_item_type*)parcl;
         }
         else if (0 == strcmp("interface", type)) {
@@ -1081,12 +1017,9 @@
         string line;
         if (doc->item_type == USER_DATA_TYPE) {
             user_data_type* parcelable = (user_data_type*)doc;
-            if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
+            if (parcelable->parcelable) {
                 line = "parcelable ";
             }
-            if ((parcelable->flattening_methods & RPC_DATA) != 0) {
-                line = "flattenable ";
-            }
             if (parcelable->package) {
                 line += parcelable->package;
                 line += '.';
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
index 1be5a9b..a3b1efc 100644
--- a/tools/aidl/aidl_language.h
+++ b/tools/aidl/aidl_language.h
@@ -68,8 +68,7 @@
 
 enum {
     USER_DATA_TYPE = 12,
-    INTERFACE_TYPE_BINDER,
-    INTERFACE_TYPE_RPC
+    INTERFACE_TYPE_BINDER
 };
 
 typedef struct document_item_type {
@@ -78,19 +77,13 @@
 } document_item_type;
 
 
-// for user_data_type.flattening_methods
-enum {
-    PARCELABLE_DATA = 0x1,
-    RPC_DATA = 0x2
-};
-
 typedef struct user_data_type {
     document_item_type document_item;
     buffer_type keyword_token; // only the first one
     char* package;
     buffer_type name;
     buffer_type semicolon_token;
-    int flattening_methods;
+    bool parcelable;
 } user_data_type;
 
 typedef struct interface_type {
diff --git a/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l
index 3d33e7a..aa42f2e 100644
--- a/tools/aidl/aidl_language_l.l
+++ b/tools/aidl/aidl_language_l.l
@@ -83,8 +83,6 @@
     /* keywords */
 parcelable      { SET_BUFFER(PARCELABLE); return PARCELABLE; }
 interface       { SET_BUFFER(INTERFACE); return INTERFACE; }
-flattenable     { SET_BUFFER(FLATTENABLE); return FLATTENABLE; }
-rpc             { SET_BUFFER(INTERFACE); return RPC; }
 in              { SET_BUFFER(IN); return IN; }
 out             { SET_BUFFER(OUT); return OUT; }
 inout           { SET_BUFFER(INOUT); return INOUT; }
diff --git a/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y
index 9b40d28..9c5d10e 100644
--- a/tools/aidl/aidl_language_y.y
+++ b/tools/aidl/aidl_language_y.y
@@ -20,8 +20,6 @@
 %token ARRAY
 %token PARCELABLE
 %token INTERFACE
-%token FLATTENABLE
-%token RPC
 %token IN
 %token OUT
 %token INOUT
@@ -88,7 +86,7 @@
                                                         b->name = $2.buffer;
                                                         b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
                                                         b->semicolon_token = $3.buffer;
-                                                        b->flattening_methods = PARCELABLE_DATA;
+                                                        b->parcelable = true;
                                                         $$.user_data = b;
                                                     }
     |   PARCELABLE ';'                              {
@@ -101,28 +99,6 @@
                                                                      g_currentFilename, $2.buffer.lineno, $2.buffer.data);
                                                         $$.user_data = NULL;
                                                     }
-    |   FLATTENABLE IDENTIFIER ';'                  {
-                                                        user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
-                                                        b->document_item.item_type = USER_DATA_TYPE;
-                                                        b->document_item.next = NULL;
-                                                        b->keyword_token = $1.buffer;
-                                                        b->name = $2.buffer;
-                                                        b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
-                                                        b->semicolon_token = $3.buffer;
-                                                        b->flattening_methods = PARCELABLE_DATA | RPC_DATA;
-                                                        $$.user_data = b;
-                                                    }
-    |   FLATTENABLE ';'                             {
-                                                        fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name.\n",
-                                                                     g_currentFilename, $1.buffer.lineno);
-                                                        $$.user_data = NULL;
-                                                    }
-    |   FLATTENABLE error ';'                       {
-                                                        fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name, saw \"%s\".\n",
-                                                                     g_currentFilename, $2.buffer.lineno, $2.buffer.data);
-                                                        $$.user_data = NULL;
-                                                    }
-
     ;
 
 interface_header:
@@ -146,21 +122,6 @@
                                                         c->comments_token = &c->oneway_token;
                                                         $$.interface_obj = c;
                                                    }
-    |   RPC                                        {
-                                                        interface_type* c = (interface_type*)malloc(sizeof(interface_type));
-                                                        c->document_item.item_type = INTERFACE_TYPE_RPC;
-                                                        c->document_item.next = NULL;
-                                                        c->interface_token = $1.buffer;
-                                                        c->oneway = false;
-                                                        memset(&c->oneway_token, 0, sizeof(buffer_type));
-                                                        c->comments_token = &c->interface_token;
-                                                        $$.interface_obj = c;
-                                                   }
-    ;
-
-interface_keywords:
-        INTERFACE
-    |   RPC
     ;
 
 interface_decl:
@@ -173,12 +134,12 @@
                                                         c->close_brace_token = $5.buffer;
                                                         $$.interface_obj = c;
                                                     }
-    |   interface_keywords error '{' interface_items '}'     {
+    |   INTERFACE error '{' interface_items '}'     {
                                                         fprintf(stderr, "%s:%d: syntax error in interface declaration.  Expected type name, saw \"%s\"\n",
                                                                     g_currentFilename, $2.buffer.lineno, $2.buffer.data);
                                                         $$.document_item = NULL;
                                                     }
-    |   interface_keywords error '}'                {
+    |   INTERFACE error '}'                {
                                                         fprintf(stderr, "%s:%d: syntax error in interface declaration.  Expected type name, saw \"%s\"\n",
                                                                     g_currentFilename, $2.buffer.lineno, $2.buffer.data);
                                                         $$.document_item = NULL;
diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
index 9e57407..1509340 100644
--- a/tools/aidl/generate_java.cpp
+++ b/tools/aidl/generate_java.cpp
@@ -66,9 +66,6 @@
     if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) {
         cl = generate_binder_interface_class(iface);
     }
-    else if (iface->document_item.item_type == INTERFACE_TYPE_RPC) {
-        cl = generate_rpc_interface_class(iface);
-    }
 
     Document* document = new Document;
         document->comment = "";
diff --git a/tools/aidl/generate_java.h b/tools/aidl/generate_java.h
index ae7983f..4e79743 100644
--- a/tools/aidl/generate_java.h
+++ b/tools/aidl/generate_java.h
@@ -12,7 +12,6 @@
                 interface_type* iface);
 
 Class* generate_binder_interface_class(const interface_type* iface);
-Class* generate_rpc_interface_class(const interface_type* iface);
 
 string gather_comments(extra_text_type* extra);
 string append(const char* a, const char* b);
diff --git a/tools/aidl/generate_java_rpc.cpp b/tools/aidl/generate_java_rpc.cpp
deleted file mode 100644
index 5e4dacc..0000000
--- a/tools/aidl/generate_java_rpc.cpp
+++ /dev/null
@@ -1,1001 +0,0 @@
-#include "generate_java.h"
-#include "Type.h"
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-Type* SERVICE_CONTEXT_TYPE = new Type("android.content",
-        "Context", Type::BUILT_IN, false, false, false);
-Type* PRESENTER_BASE_TYPE = new Type("android.support.place.connector",
-        "EventListener", Type::BUILT_IN, false, false, false);
-Type* PRESENTER_LISTENER_BASE_TYPE = new Type("android.support.place.connector",
-        "EventListener.Listener", Type::BUILT_IN, false, false, false);
-Type* RPC_BROKER_TYPE = new Type("android.support.place.connector", "Broker",
-        Type::BUILT_IN, false, false, false);
-Type* RPC_CONTAINER_TYPE = new Type("com.android.athome.connector", "ConnectorContainer",
-        Type::BUILT_IN, false, false, false);
-Type* PLACE_INFO_TYPE = new Type("android.support.place.connector", "PlaceInfo",
-        Type::BUILT_IN, false, false, false);
-// TODO: Just use Endpoint, so this works for all endpoints.
-Type* RPC_CONNECTOR_TYPE = new Type("android.support.place.connector", "Connector",
-        Type::BUILT_IN, false, false, false);
-Type* RPC_ENDPOINT_INFO_TYPE = new UserDataType("android.support.place.rpc",
-        "EndpointInfo", true, __FILE__, __LINE__);
-Type* RPC_RESULT_HANDLER_TYPE = new UserDataType("android.support.place.rpc", "RpcResultHandler",
-        true, __FILE__, __LINE__);
-Type* RPC_ERROR_LISTENER_TYPE = new Type("android.support.place.rpc", "RpcErrorHandler",
-        Type::BUILT_IN, false, false, false);
-Type* RPC_CONTEXT_TYPE = new UserDataType("android.support.place.rpc", "RpcContext", true,
-        __FILE__, __LINE__);
-
-static void generate_create_from_data(Type* t, StatementBlock* addTo, const string& key,
-        Variable* v, Variable* data, Variable** cl);
-static void generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from);
-static void generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data);
-
-static string
-format_int(int n)
-{
-    char str[20];
-    sprintf(str, "%d", n);
-    return string(str);
-}
-
-static string
-class_name_leaf(const string& str)
-{
-    string::size_type pos = str.rfind('.');
-    if (pos == string::npos) {
-        return str;
-    } else {
-        return string(str, pos+1);
-    }
-}
-
-static string
-results_class_name(const string& n)
-{
-    string str = n;
-    str[0] = toupper(str[0]);
-    str.insert(0, "On");
-    return str;
-}
-
-static string
-results_method_name(const string& n)
-{
-    string str = n;
-    str[0] = toupper(str[0]);
-    str.insert(0, "on");
-    return str;
-}
-
-static string
-push_method_name(const string& n)
-{
-    string str = n;
-    str[0] = toupper(str[0]);
-    str.insert(0, "push");
-    return str;
-}
-
-// =================================================
-class DispatcherClass : public Class
-{
-public:
-    DispatcherClass(const interface_type* iface, Expression* target);
-    virtual ~DispatcherClass();
-
-    void AddMethod(const method_type* method);
-    void DoneWithMethods();
-
-    Method* processMethod;
-    Variable* actionParam;
-    Variable* requestParam;
-    Variable* rpcContextParam;
-    Variable* errorParam;
-    Variable* requestData;
-    Variable* resultData;
-    IfStatement* dispatchIfStatement;
-    Expression* targetExpression;
-
-private:
-    void generate_process();
-};
-
-DispatcherClass::DispatcherClass(const interface_type* iface, Expression* target)
-    :Class(),
-     dispatchIfStatement(NULL),
-     targetExpression(target)
-{
-    generate_process();
-}
-
-DispatcherClass::~DispatcherClass()
-{
-}
-
-void
-DispatcherClass::generate_process()
-{
-    // byte[] process(String action, byte[] params, RpcContext context, RpcError status)
-    this->processMethod = new Method;
-        this->processMethod->modifiers = PUBLIC;
-        this->processMethod->returnType = BYTE_TYPE;
-        this->processMethod->returnTypeDimension = 1;
-        this->processMethod->name = "process";
-        this->processMethod->statements = new StatementBlock;
-
-    this->actionParam = new Variable(STRING_TYPE, "action");
-    this->processMethod->parameters.push_back(this->actionParam);
-
-    this->requestParam = new Variable(BYTE_TYPE, "requestParam", 1);
-    this->processMethod->parameters.push_back(this->requestParam);
-
-    this->rpcContextParam = new Variable(RPC_CONTEXT_TYPE, "context", 0);
-    this->processMethod->parameters.push_back(this->rpcContextParam);    
-
-    this->errorParam = new Variable(RPC_ERROR_TYPE, "errorParam", 0);
-    this->processMethod->parameters.push_back(this->errorParam);
-
-    this->requestData = new Variable(RPC_DATA_TYPE, "request");
-    this->processMethod->statements->Add(new VariableDeclaration(requestData,
-                new NewExpression(RPC_DATA_TYPE, 1, this->requestParam)));
-
-    this->resultData = new Variable(RPC_DATA_TYPE, "resultData");
-    this->processMethod->statements->Add(new VariableDeclaration(this->resultData,
-                NULL_VALUE));
-}
-
-void
-DispatcherClass::AddMethod(const method_type* method)
-{
-    arg_type* arg;
-
-    // The if/switch statement
-    IfStatement* ifs = new IfStatement();
-        ifs->expression = new MethodCall(new StringLiteralExpression(method->name.data), "equals",
-                1, this->actionParam);
-    StatementBlock* block = ifs->statements = new StatementBlock;
-    if (this->dispatchIfStatement == NULL) {
-        this->dispatchIfStatement = ifs;
-        this->processMethod->statements->Add(dispatchIfStatement);
-    } else {
-        this->dispatchIfStatement->elseif = ifs;
-        this->dispatchIfStatement = ifs;
-    }
-    
-    // The call to decl (from above)
-    MethodCall* realCall = new MethodCall(this->targetExpression, method->name.data);
-
-    // args
-    Variable* classLoader = NULL;
-    VariableFactory stubArgs("_arg");
-    arg = method->args;
-    while (arg != NULL) {
-        Type* t = NAMES.Search(arg->type.type.data);
-        Variable* v = stubArgs.Get(t);
-        v->dimension = arg->type.dimension;
-
-        // Unmarshall the parameter
-        block->Add(new VariableDeclaration(v));
-        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
-            generate_create_from_data(t, block, arg->name.data, v,
-                    this->requestData, &classLoader);
-        } else {
-            if (arg->type.dimension == 0) {
-                block->Add(new Assignment(v, new NewExpression(v->type)));
-            }
-            else if (arg->type.dimension == 1) {
-                generate_new_array(v->type, block, v, this->requestData);
-            }
-            else {
-                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
-                        __LINE__);
-            }
-        }
-
-        // Add that parameter to the method call
-        realCall->arguments.push_back(v);
-
-        arg = arg->next;
-    }
-
-    // Add a final parameter: RpcContext. Contains data about
-    // incoming request (e.g., certificate)
-    realCall->arguments.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
-
-    Type* returnType = NAMES.Search(method->type.type.data);
-    if (returnType == EVENT_FAKE_TYPE) {
-        returnType = VOID_TYPE;
-    }
-    
-    // the real call
-    bool first = true;
-    Variable* _result = NULL;
-    if (returnType == VOID_TYPE) {
-        block->Add(realCall);
-    } else {
-        _result = new Variable(returnType, "_result",
-                                method->type.dimension);
-        block->Add(new VariableDeclaration(_result, realCall));
-
-        // need the result RpcData
-        if (first) {
-            block->Add(new Assignment(this->resultData,
-                        new NewExpression(RPC_DATA_TYPE)));
-            first = false;
-        }
-
-        // marshall the return value
-        generate_write_to_data(returnType, block,
-                new StringLiteralExpression("_result"), _result, this->resultData);
-    }
-
-    // out parameters
-    int i = 0;
-    arg = method->args;
-    while (arg != NULL) {
-        Type* t = NAMES.Search(arg->type.type.data);
-        Variable* v = stubArgs.Get(i++);
-
-        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
-            // need the result RpcData
-            if (first) {
-                block->Add(new Assignment(this->resultData, new NewExpression(RPC_DATA_TYPE)));
-                first = false;
-            }
-
-            generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
-                    v, this->resultData);
-        }
-
-        arg = arg->next;
-    }
-}
-
-void
-DispatcherClass::DoneWithMethods()
-{
-    if (this->dispatchIfStatement == NULL) {
-        return;
-    }
-
-    this->elements.push_back(this->processMethod);
-
-    IfStatement* fallthrough = new IfStatement();
-        fallthrough->statements = new StatementBlock;
-        fallthrough->statements->Add(new ReturnStatement(
-                    new MethodCall(SUPER_VALUE, "process", 4, 
-                    this->actionParam, this->requestParam, 
-                    this->rpcContextParam,
-                    this->errorParam)));
-    this->dispatchIfStatement->elseif = fallthrough;
-    IfStatement* s = new IfStatement;
-        s->statements = new StatementBlock;
-    this->processMethod->statements->Add(s);
-    s->expression = new Comparison(this->resultData, "!=", NULL_VALUE);
-    s->statements->Add(new ReturnStatement(new MethodCall(this->resultData, "serialize")));
-    s->elseif = new IfStatement;
-    s = s->elseif;
-    s->statements->Add(new ReturnStatement(NULL_VALUE));
-}
-
-// =================================================
-class RpcProxyClass : public Class
-{
-public:
-    RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType);
-    virtual ~RpcProxyClass();
-
-    Variable* endpoint;
-    Variable* broker;
-
-private:
-    void generate_ctor();
-    void generate_get_endpoint_info();
-};
-
-RpcProxyClass::RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType)
-    :Class()
-{
-    this->comment = gather_comments(iface->comments_token->extra);
-    this->modifiers = PUBLIC;
-    this->what = Class::CLASS;
-    this->type = interfaceType;
-
-    // broker
-    this->broker = new Variable(RPC_BROKER_TYPE, "_broker");
-    this->elements.push_back(new Field(PRIVATE, this->broker));
-    // endpoint
-    this->endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "_endpoint");
-    this->elements.push_back(new Field(PRIVATE, this->endpoint));
-
-    // methods
-    generate_ctor();
-    generate_get_endpoint_info();
-}
-
-RpcProxyClass::~RpcProxyClass()
-{
-}
-
-void
-RpcProxyClass::generate_ctor()
-{
-    Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
-    Variable* endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "endpoint");
-    Method* ctor = new Method;
-        ctor->modifiers = PUBLIC;
-        ctor->name = class_name_leaf(this->type->Name());
-        ctor->statements = new StatementBlock;
-        ctor->parameters.push_back(broker);
-        ctor->parameters.push_back(endpoint);
-    this->elements.push_back(ctor);
-
-    ctor->statements->Add(new Assignment(this->broker, broker));
-    ctor->statements->Add(new Assignment(this->endpoint, endpoint));
-}
-
-void
-RpcProxyClass::generate_get_endpoint_info()
-{
-    Method* get = new Method;
-    get->modifiers = PUBLIC;
-    get->returnType = RPC_ENDPOINT_INFO_TYPE;
-    get->name = "getEndpointInfo";
-    get->statements = new StatementBlock;
-    this->elements.push_back(get);
-
-    get->statements->Add(new ReturnStatement(this->endpoint));
-}
-
-// =================================================
-class EventListenerClass : public DispatcherClass
-{
-public:
-    EventListenerClass(const interface_type* iface, Type* listenerType);
-    virtual ~EventListenerClass();
-
-    Variable* _listener;
-
-private:
-    void generate_ctor();
-};
-
-Expression*
-generate_get_listener_expression(Type* cast)
-{
-    return new Cast(cast, new MethodCall(THIS_VALUE, "getView"));
-}
-
-EventListenerClass::EventListenerClass(const interface_type* iface, Type* listenerType)
-    :DispatcherClass(iface, new FieldVariable(THIS_VALUE, "_listener"))
-{
-    this->modifiers = PRIVATE;
-    this->what = Class::CLASS;
-    this->type = new Type(iface->package ? iface->package : "",
-                        append(iface->name.data, ".Presenter"),
-                        Type::GENERATED, false, false, false);
-    this->extends = PRESENTER_BASE_TYPE;
-
-    this->_listener = new Variable(listenerType, "_listener");
-    this->elements.push_back(new Field(PRIVATE, this->_listener));
-
-    // methods
-    generate_ctor();
-}
-
-EventListenerClass::~EventListenerClass()
-{
-}
-
-void
-EventListenerClass::generate_ctor()
-{
-    Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
-    Variable* listener = new Variable(this->_listener->type, "listener");
-    Method* ctor = new Method;
-        ctor->modifiers = PUBLIC;
-        ctor->name = class_name_leaf(this->type->Name());
-        ctor->statements = new StatementBlock;
-        ctor->parameters.push_back(broker);
-        ctor->parameters.push_back(listener);
-    this->elements.push_back(ctor);
-
-    ctor->statements->Add(new MethodCall("super", 2, broker, listener));
-    ctor->statements->Add(new Assignment(this->_listener, listener));
-}
-
-// =================================================
-class ListenerClass : public Class
-{
-public:
-    ListenerClass(const interface_type* iface);
-    virtual ~ListenerClass();
-
-    bool needed;
-
-private:
-    void generate_ctor();
-};
-
-ListenerClass::ListenerClass(const interface_type* iface)
-    :Class(),
-     needed(false)
-{
-    this->comment = "/** Extend this to listen to the events from this class. */";
-    this->modifiers = STATIC | PUBLIC ;
-    this->what = Class::CLASS;
-    this->type = new Type(iface->package ? iface->package : "",
-                        append(iface->name.data, ".Listener"),
-                        Type::GENERATED, false, false, false);
-    this->extends = PRESENTER_LISTENER_BASE_TYPE;
-}
-
-ListenerClass::~ListenerClass()
-{
-}
-
-// =================================================
-class EndpointBaseClass : public DispatcherClass
-{
-public:
-    EndpointBaseClass(const interface_type* iface);
-    virtual ~EndpointBaseClass();
-
-    bool needed;
-
-private:
-    void generate_ctor();
-};
-
-EndpointBaseClass::EndpointBaseClass(const interface_type* iface)
-    :DispatcherClass(iface, THIS_VALUE),
-     needed(false)
-{
-    this->comment = "/** Extend this to implement a link service. */";
-    this->modifiers = STATIC | PUBLIC | ABSTRACT;
-    this->what = Class::CLASS;
-    this->type = new Type(iface->package ? iface->package : "",
-                        append(iface->name.data, ".EndpointBase"),
-                        Type::GENERATED, false, false, false);
-    this->extends = RPC_CONNECTOR_TYPE;
-
-    // methods
-    generate_ctor();
-}
-
-EndpointBaseClass::~EndpointBaseClass()
-{
-}
-
-void
-EndpointBaseClass::generate_ctor()
-{
-    Variable* container = new Variable(RPC_CONTAINER_TYPE, "container");
-    Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
-	Variable* place = new Variable(PLACE_INFO_TYPE, "placeInfo");
-    Method* ctor = new Method;
-        ctor->modifiers = PUBLIC;
-        ctor->name = class_name_leaf(this->type->Name());
-        ctor->statements = new StatementBlock;
-        ctor->parameters.push_back(container);
-        ctor->parameters.push_back(broker);
-        ctor->parameters.push_back(place);
-    this->elements.push_back(ctor);
-
-    ctor->statements->Add(new MethodCall("super", 3, container, broker, place));
-}
-
-// =================================================
-class ResultDispatcherClass : public Class
-{
-public:
-    ResultDispatcherClass();
-    virtual ~ResultDispatcherClass();
-
-    void AddMethod(int index, const string& name, Method** method, Variable** param);
-
-    bool needed;
-    Variable* methodId;
-    Variable* callback;
-    Method* onResultMethod;
-    Variable* resultParam;
-    SwitchStatement* methodSwitch;
-
-private:
-    void generate_ctor();
-    void generate_onResult();
-};
-
-ResultDispatcherClass::ResultDispatcherClass()
-    :Class(),
-     needed(false)
-{
-    this->modifiers = PRIVATE | FINAL;
-    this->what = Class::CLASS;
-    this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false, false);
-    this->interfaces.push_back(RPC_RESULT_HANDLER_TYPE);
-
-    // methodId
-    this->methodId = new Variable(INT_TYPE, "methodId");
-    this->elements.push_back(new Field(PRIVATE, this->methodId));
-    this->callback = new Variable(OBJECT_TYPE, "callback");
-    this->elements.push_back(new Field(PRIVATE, this->callback));
-
-    // methods
-    generate_ctor();
-    generate_onResult();
-}
-
-ResultDispatcherClass::~ResultDispatcherClass()
-{
-}
-
-void
-ResultDispatcherClass::generate_ctor()
-{
-    Variable* methodIdParam = new Variable(INT_TYPE, "methId");
-    Variable* callbackParam = new Variable(OBJECT_TYPE, "cbObj");
-    Method* ctor = new Method;
-        ctor->modifiers = PUBLIC;
-        ctor->name = class_name_leaf(this->type->Name());
-        ctor->statements = new StatementBlock;
-        ctor->parameters.push_back(methodIdParam);
-        ctor->parameters.push_back(callbackParam);
-    this->elements.push_back(ctor);
-
-    ctor->statements->Add(new Assignment(this->methodId, methodIdParam));
-    ctor->statements->Add(new Assignment(this->callback, callbackParam));
-}
-
-void
-ResultDispatcherClass::generate_onResult()
-{
-    this->onResultMethod = new Method;
-        this->onResultMethod->modifiers = PUBLIC;
-        this->onResultMethod->returnType = VOID_TYPE;
-        this->onResultMethod->returnTypeDimension = 0;
-        this->onResultMethod->name = "onResult";
-        this->onResultMethod->statements = new StatementBlock;
-    this->elements.push_back(this->onResultMethod);
-
-    this->resultParam = new Variable(BYTE_TYPE, "result", 1);
-    this->onResultMethod->parameters.push_back(this->resultParam);
-
-    this->methodSwitch = new SwitchStatement(this->methodId);
-    this->onResultMethod->statements->Add(this->methodSwitch);
-}
-
-void
-ResultDispatcherClass::AddMethod(int index, const string& name, Method** method, Variable** param)
-{
-    Method* m = new Method;
-        m->modifiers = PUBLIC;
-        m->returnType = VOID_TYPE;
-        m->returnTypeDimension = 0;
-        m->name = name;
-        m->statements = new StatementBlock;
-    *param = new Variable(BYTE_TYPE, "result", 1);
-    m->parameters.push_back(*param);
-    this->elements.push_back(m);
-    *method = m;
-
-    Case* c = new Case(format_int(index));
-    c->statements->Add(new MethodCall(new LiteralExpression("this"), name, 1, this->resultParam));
-    c->statements->Add(new Break());
-
-    this->methodSwitch->cases.push_back(c);
-}
-
-// =================================================
-static void
-generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from)
-{
-    fprintf(stderr, "aidl: implement generate_new_array %s:%d\n", __FILE__, __LINE__);
-    exit(1);
-}
-
-static void
-generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, Variable* v,
-                            Variable* data, Variable** cl)
-{
-    Expression* k = new StringLiteralExpression(key);
-    if (v->dimension == 0) {
-        t->CreateFromRpcData(addTo, k, v, data, cl);
-    }
-    if (v->dimension == 1) {
-        //t->ReadArrayFromRpcData(addTo, v, data, cl);
-        fprintf(stderr, "aidl: implement generate_create_from_data for arrays%s:%d\n",
-                __FILE__, __LINE__);
-    }
-}
-
-static void
-generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, Variable* data)
-{
-    if (v->dimension == 0) {
-        t->WriteToRpcData(addTo, k, v, data, 0);
-    }
-    if (v->dimension == 1) {
-        //t->WriteArrayToParcel(addTo, v, data);
-        fprintf(stderr, "aidl: implement generate_write_to_data for arrays%s:%d\n",
-                __FILE__, __LINE__);
-    }
-}
-
-// =================================================
-static Type*
-generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
-{
-    arg_type* arg;
-
-    string resultsMethodName = results_method_name(method->name.data);
-    Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
-            Type::GENERATED, false, false, false);
-
-    if (!method->oneway) {
-        Class* resultsClass = new Class;
-            resultsClass->modifiers = STATIC | PUBLIC;
-            resultsClass->what = Class::INTERFACE;
-            resultsClass->type = resultsInterfaceType;
-
-        Method* resultMethod = new Method;
-            resultMethod->comment = gather_comments(method->comments_token->extra);
-            resultMethod->modifiers = PUBLIC;
-            resultMethod->returnType = VOID_TYPE;
-            resultMethod->returnTypeDimension = 0;
-            resultMethod->name = resultsMethodName;
-        if (0 != strcmp("void", method->type.type.data)) {
-            resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data),
-                        "_result", method->type.dimension));
-        }
-        arg = method->args;
-        while (arg != NULL) {
-            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
-                resultMethod->parameters.push_back(new Variable(
-                                    NAMES.Search(arg->type.type.data), arg->name.data,
-                                    arg->type.dimension));
-            }
-            arg = arg->next;
-        }
-        resultsClass->elements.push_back(resultMethod);
-
-        if (resultMethod->parameters.size() > 0) {
-            proxyClass->elements.push_back(resultsClass);
-            return resultsInterfaceType;
-        } 
-    }
-    //delete resultsInterfaceType;
-    return NULL;
-}
-
-static void
-generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass,
-        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
-{
-    arg_type* arg;
-    Method* proxyMethod = new Method;
-        proxyMethod->comment = gather_comments(method->comments_token->extra);
-        proxyMethod->modifiers = PUBLIC;
-        proxyMethod->returnType = VOID_TYPE;
-        proxyMethod->returnTypeDimension = 0;
-        proxyMethod->name = method->name.data;
-        proxyMethod->statements = new StatementBlock;
-    proxyClass->elements.push_back(proxyMethod);
-
-    // The local variables
-    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
-    proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
-
-    // Add the arguments
-    arg = method->args;
-    while (arg != NULL) {
-        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
-            // Function signature
-            Type* t = NAMES.Search(arg->type.type.data);
-            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
-            proxyMethod->parameters.push_back(v);
-
-            // Input parameter marshalling
-            generate_write_to_data(t, proxyMethod->statements,
-                    new StringLiteralExpression(arg->name.data), v, _data);
-        }
-        arg = arg->next;
-    }
-
-    // If there is a results interface for this class
-    Expression* resultParameter;
-    if (resultsInterfaceType != NULL) {
-        // Result interface parameter
-        Variable* resultListener = new Variable(resultsInterfaceType, "_result");
-        proxyMethod->parameters.push_back(resultListener);
-
-        // Add the results dispatcher callback
-        resultsDispatcherClass->needed = true;
-        resultParameter = new NewExpression(resultsDispatcherClass->type, 2,
-                new LiteralExpression(format_int(index)), resultListener);
-    } else {
-        resultParameter = NULL_VALUE;
-    }
-
-    // All proxy methods take an error parameter
-    Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors");
-    proxyMethod->parameters.push_back(errorListener);
-
-    // Call the broker
-    proxyMethod->statements->Add(new MethodCall(new FieldVariable(THIS_VALUE, "_broker"),
-                "sendRpc", 5,
-                proxyClass->endpoint,
-                new StringLiteralExpression(method->name.data),
-                new MethodCall(_data, "serialize"),
-                resultParameter,
-                errorListener));
-}
-
-static void
-generate_result_dispatcher_method(const method_type* method,
-        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
-{
-    arg_type* arg;
-    Method* dispatchMethod;
-    Variable* dispatchParam;
-    resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam);
-
-    Variable* classLoader = NULL;
-    Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData");
-    dispatchMethod->statements->Add(new VariableDeclaration(resultData,
-                new NewExpression(RPC_DATA_TYPE, 1, dispatchParam)));
-
-    // The callback method itself
-    MethodCall* realCall = new MethodCall(
-            new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")),
-            results_method_name(method->name.data));
-
-    // The return value
-    {
-        Type* t = NAMES.Search(method->type.type.data);
-        if (t != VOID_TYPE) {
-            Variable* rv = new Variable(t, "rv");
-            dispatchMethod->statements->Add(new VariableDeclaration(rv));
-            generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
-                    resultData, &classLoader);
-            realCall->arguments.push_back(rv);
-        }
-    }
-
-    VariableFactory stubArgs("arg");
-    arg = method->args;
-    while (arg != NULL) {
-        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
-            // Unmarshall the results
-            Type* t = NAMES.Search(arg->type.type.data);
-            Variable* v = stubArgs.Get(t);
-            dispatchMethod->statements->Add(new VariableDeclaration(v));
-
-            generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v,
-                    resultData, &classLoader);
-
-            // Add the argument to the callback
-            realCall->arguments.push_back(v);
-        }
-        arg = arg->next;
-    }
-
-    // Call the callback method
-    IfStatement* ifst = new IfStatement;
-        ifst->expression = new Comparison(new FieldVariable(THIS_VALUE, "callback"), "!=", NULL_VALUE);
-    dispatchMethod->statements->Add(ifst);
-    ifst->statements->Add(realCall);
-}
-
-static void
-generate_regular_method(const method_type* method, RpcProxyClass* proxyClass,
-        EndpointBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
-        int index)
-{
-    arg_type* arg;
-
-    // == the callback interface for results ================================
-    // the service base class
-    Type* resultsInterfaceType = generate_results_method(method, proxyClass);
-    
-    // == the method in the proxy class =====================================
-    generate_proxy_method(method, proxyClass, resultsDispatcherClass, resultsInterfaceType, index);
-
-    // == the method in the result dispatcher class =========================
-    if (resultsInterfaceType != NULL) {
-        generate_result_dispatcher_method(method, resultsDispatcherClass, resultsInterfaceType,
-                index);
-    }
-
-    // == The abstract method that the service developers implement ==========
-    Method* decl = new Method;
-        decl->comment = gather_comments(method->comments_token->extra);
-        decl->modifiers = PUBLIC | ABSTRACT;
-        decl->returnType = NAMES.Search(method->type.type.data);
-        decl->returnTypeDimension = method->type.dimension;
-        decl->name = method->name.data;
-    arg = method->args;
-    while (arg != NULL) {
-        decl->parameters.push_back(new Variable(
-                            NAMES.Search(arg->type.type.data), arg->name.data,
-                            arg->type.dimension));
-        arg = arg->next;
-    }
-
-    // Add the default RpcContext param to all methods
-    decl->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
-	
-    serviceBaseClass->elements.push_back(decl);
-    
-
-    // == the dispatch method in the service base class ======================
-    serviceBaseClass->AddMethod(method);
-}
-
-static void
-generate_event_method(const method_type* method, RpcProxyClass* proxyClass,
-        EndpointBaseClass* serviceBaseClass, ListenerClass* listenerClass,
-        EventListenerClass* presenterClass, int index)
-{
-    arg_type* arg;
-    listenerClass->needed = true;
-
-    // == the push method in the service base class =========================
-    Method* push = new Method;
-        push->modifiers = PUBLIC;
-        push->name = push_method_name(method->name.data);
-        push->statements = new StatementBlock;
-        push->returnType = VOID_TYPE;
-    serviceBaseClass->elements.push_back(push);
-
-    // The local variables
-    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
-    push->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
-
-    // Add the arguments
-    arg = method->args;
-    while (arg != NULL) {
-        // Function signature
-        Type* t = NAMES.Search(arg->type.type.data);
-        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
-        push->parameters.push_back(v);
-
-        // Input parameter marshalling
-        generate_write_to_data(t, push->statements,
-                new StringLiteralExpression(arg->name.data), v, _data);
-
-        arg = arg->next;
-    }
-
-    // Send the notifications
-    push->statements->Add(new MethodCall("pushEvent", 2,
-                new StringLiteralExpression(method->name.data),
-                new MethodCall(_data, "serialize")));
-
-    // == the event callback dispatcher method  ====================================
-    presenterClass->AddMethod(method);
-
-    // == the event method in the listener base class =====================
-    Method* event = new Method;
-        event->modifiers = PUBLIC;
-        event->name = method->name.data;
-        event->statements = new StatementBlock;
-        event->returnType = VOID_TYPE;
-    listenerClass->elements.push_back(event);
-    arg = method->args;
-    while (arg != NULL) {
-        event->parameters.push_back(new Variable(
-                            NAMES.Search(arg->type.type.data), arg->name.data,
-                            arg->type.dimension));
-        arg = arg->next;
-    }
-
-    // Add a final parameter: RpcContext. Contains data about
-    // incoming request (e.g., certificate)
-    event->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
-}
-
-static void
-generate_listener_methods(RpcProxyClass* proxyClass, Type* presenterType, Type* listenerType)
-{
-    // AndroidAtHomePresenter _presenter;
-    // void startListening(Listener listener) {
-    //     stopListening();
-    //     _presenter = new Presenter(_broker, listener);
-    //     _presenter.startListening(_endpoint);
-    // }
-    // void stopListening() {
-    //     if (_presenter != null) {
-    //         _presenter.stopListening();
-    //     }
-    // }
-
-    Variable* _presenter = new Variable(presenterType, "_presenter");
-    proxyClass->elements.push_back(new Field(PRIVATE, _presenter));
-
-    Variable* listener = new Variable(listenerType, "listener");
-
-    Method* startListeningMethod = new Method;
-        startListeningMethod->modifiers = PUBLIC;
-        startListeningMethod->returnType = VOID_TYPE;
-        startListeningMethod->name = "startListening";
-        startListeningMethod->statements = new StatementBlock;
-        startListeningMethod->parameters.push_back(listener);
-    proxyClass->elements.push_back(startListeningMethod);
-
-    startListeningMethod->statements->Add(new MethodCall(THIS_VALUE, "stopListening"));
-    startListeningMethod->statements->Add(new Assignment(_presenter,
-                new NewExpression(presenterType, 2, proxyClass->broker, listener)));
-    startListeningMethod->statements->Add(new MethodCall(_presenter,
-                "startListening", 1, proxyClass->endpoint));
-
-    Method* stopListeningMethod = new Method;
-        stopListeningMethod->modifiers = PUBLIC;
-        stopListeningMethod->returnType = VOID_TYPE;
-        stopListeningMethod->name = "stopListening";
-        stopListeningMethod->statements = new StatementBlock;
-    proxyClass->elements.push_back(stopListeningMethod);
-
-    IfStatement* ifst = new IfStatement;
-        ifst->expression = new Comparison(_presenter, "!=", NULL_VALUE);
-    stopListeningMethod->statements->Add(ifst);
-
-    ifst->statements->Add(new MethodCall(_presenter, "stopListening"));
-    ifst->statements->Add(new Assignment(_presenter, NULL_VALUE));
-}
-
-Class*
-generate_rpc_interface_class(const interface_type* iface)
-{
-    // the proxy class
-    InterfaceType* interfaceType = static_cast<InterfaceType*>(
-        NAMES.Find(iface->package, iface->name.data));
-    RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType);
-
-    // the listener class
-    ListenerClass* listener = new ListenerClass(iface);
-
-    // the presenter class
-    EventListenerClass* presenter = new EventListenerClass(iface, listener->type);
-
-    // the service base class
-    EndpointBaseClass* base = new EndpointBaseClass(iface);
-    proxy->elements.push_back(base);
-
-    // the result dispatcher
-    ResultDispatcherClass* results = new ResultDispatcherClass();
-
-    // all the declared methods of the proxy
-    int index = 0;
-    interface_item_type* item = iface->interface_items;
-    while (item != NULL) {
-        if (item->item_type == METHOD_TYPE) {
-            if (NAMES.Search(((method_type*)item)->type.type.data) == EVENT_FAKE_TYPE) {
-                generate_event_method((method_type*)item, proxy, base, listener, presenter, index);
-            } else {
-                generate_regular_method((method_type*)item, proxy, base, results, index);
-            }
-        }
-        item = item->next;
-        index++;
-    }
-    presenter->DoneWithMethods();
-    base->DoneWithMethods();
-
-    // only add this if there are methods with results / out parameters
-    if (results->needed) {
-        proxy->elements.push_back(results);
-    }
-    if (listener->needed) {
-        proxy->elements.push_back(listener);
-        proxy->elements.push_back(presenter);
-        generate_listener_methods(proxy, presenter->type, listener->type);
-    }
-
-    return proxy;
-}
diff --git a/tools/aidl/options_test.cpp b/tools/aidl/options_test.cpp
deleted file mode 100644
index bd106ce..0000000
--- a/tools/aidl/options_test.cpp
+++ /dev/null
@@ -1,291 +0,0 @@
-#include <iostream>
-#include "options.h"
-
-const bool VERBOSE = false;
-
-using namespace std;
-
-struct Answer {
-    const char* argv[8];
-    int result;
-    const char* systemSearchPath[8];
-    const char* localSearchPath[8];
-    const char* inputFileName;
-    language_t nativeLanguage;
-    const char* outputH;
-    const char* outputCPP;
-    const char* outputJava;
-};
-
-bool
-match_arrays(const char* const*expected, const vector<string> &got)
-{
-    int count = 0;
-    while (expected[count] != NULL) {
-        count++;
-    }
-    if (got.size() != count) {
-        return false;
-    }
-    for (int i=0; i<count; i++) {
-        if (got[i] != expected[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-void
-print_array(const char* prefix, const char* const*expected)
-{
-    while (*expected) {
-        cout << prefix << *expected << endl;
-        expected++;
-    }
-}
-
-void
-print_array(const char* prefix, const vector<string> &got)
-{
-    size_t count = got.size();
-    for (size_t i=0; i<count; i++) {
-        cout << prefix << got[i] << endl;
-    }
-}
-
-static int
-test(const Answer& answer)
-{
-    int argc = 0;
-    while (answer.argv[argc]) {
-        argc++;
-    }
-
-    int err = 0;
-
-    Options options;
-    int result = parse_options(argc, answer.argv, &options);
-
-    // result
-    if (((bool)result) != ((bool)answer.result)) {
-        cout << "mismatch: result: got " << result << " expected " <<
-            answer.result << endl;
-        err = 1;
-    }
-
-    if (result != 0) {
-        // if it failed, everything is invalid
-        return err;
-    }
-
-    // systemSearchPath
-    if (!match_arrays(answer.systemSearchPath, options.systemSearchPath)) {
-        cout << "mismatch: systemSearchPath: got" << endl;
-        print_array("        ", options.systemSearchPath);
-        cout << "    expected" << endl;
-        print_array("        ", answer.systemSearchPath);
-        err = 1;
-    }
-
-    // localSearchPath
-    if (!match_arrays(answer.localSearchPath, options.localSearchPath)) {
-        cout << "mismatch: localSearchPath: got" << endl;
-        print_array("        ", options.localSearchPath);
-        cout << "    expected" << endl;
-        print_array("        ", answer.localSearchPath);
-        err = 1;
-    }
-
-    // inputFileName
-    if (answer.inputFileName != options.inputFileName) {
-        cout << "mismatch: inputFileName: got " << options.inputFileName
-            << " expected " << answer.inputFileName << endl;
-        err = 1;
-    }
-
-    // nativeLanguage
-    if (answer.nativeLanguage != options.nativeLanguage) {
-        cout << "mismatch: nativeLanguage: got " << options.nativeLanguage
-            << " expected " << answer.nativeLanguage << endl;
-        err = 1;
-    }
-
-    // outputH
-    if (answer.outputH != options.outputH) {
-        cout << "mismatch: outputH: got " << options.outputH
-            << " expected " << answer.outputH << endl;
-        err = 1;
-    }
-
-    // outputCPP
-    if (answer.outputCPP != options.outputCPP) {
-        cout << "mismatch: outputCPP: got " << options.outputCPP
-            << " expected " << answer.outputCPP << endl;
-        err = 1;
-    }
-
-    // outputJava
-    if (answer.outputJava != options.outputJava) {
-        cout << "mismatch: outputJava: got " << options.outputJava
-            << " expected " << answer.outputJava << endl;
-        err = 1;
-    }
-
-    return err;
-}
-
-const Answer g_tests[] = {
-
-    {
-        /* argv */              { "test", "-i/moof", "-I/blah", "-Ibleh", "-imoo", "inputFileName.aidl_cpp", NULL, NULL },
-        /* result */            0,
-        /* systemSearchPath */  { "/blah", "bleh", NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { "/moof", "moo", NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "inputFileName.aidl_cpp",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "",
-        /* outputCPP */         "",
-        /* outputJava */        ""
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-oh", "outputH", NULL, NULL, NULL, NULL },
-        /* result */            0,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "inputFileName.aidl_cpp",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "outputH",
-        /* outputCPP */         "",
-        /* outputJava */        ""
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-ocpp", "outputCPP", NULL, NULL, NULL, NULL },
-        /* result */            0,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "inputFileName.aidl_cpp",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "",
-        /* outputCPP */         "outputCPP",
-        /* outputJava */        ""
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-ojava", "outputJava", NULL, NULL, NULL, NULL },
-        /* result */            0,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "inputFileName.aidl_cpp",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "",
-        /* outputCPP */         "",
-        /* outputJava */        "outputJava"
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-oh", "outputH", "-ocpp", "outputCPP", "-ojava", "outputJava" },
-        /* result */            0,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "inputFileName.aidl_cpp",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "outputH",
-        /* outputCPP */         "outputCPP",
-        /* outputJava */        "outputJava"
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-oh", "outputH", "-oh", "outputH1", NULL, NULL },
-        /* result */            1,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "",
-        /* outputCPP */         "",
-        /* outputJava */        ""
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-ocpp", "outputCPP", "-ocpp", "outputCPP1", NULL, NULL },
-        /* result */            1,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "",
-        /* outputCPP */         "",
-        /* outputJava */        ""
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-ojava", "outputJava", "-ojava", "outputJava1", NULL, NULL },
-        /* result */            1,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "",
-        /* outputCPP */         "",
-        /* outputJava */        ""
-    },
-
-};
-
-int
-main(int argc, const char** argv)
-{
-    const int count = sizeof(g_tests)/sizeof(g_tests[0]);
-    int matches[count];
-
-    int result = 0;
-    for (int i=0; i<count; i++) {
-        if (VERBOSE) {
-            cout << endl;
-            cout << "---------------------------------------------" << endl;
-            const char* const* p = g_tests[i].argv;
-            while (*p) {
-                cout << " " << *p;
-                p++;
-            }
-            cout << endl;
-            cout << "---------------------------------------------" << endl;
-        }
-        matches[i] = test(g_tests[i]);
-        if (VERBOSE) {
-            if (0 == matches[i]) {
-                cout << "passed" << endl;
-            } else {
-                cout << "failed" << endl;
-            }
-            result |= matches[i];
-        }
-    }
-
-    cout << endl;
-    cout << "=============================================" << endl;
-    cout << "options_test summary" << endl;
-    cout << "=============================================" << endl;
-
-    if (!result) {
-        cout << "passed" << endl;
-    } else {
-        cout << "failed the following tests:" << endl;
-        for (int i=0; i<count; i++) {
-            if (matches[i]) {
-                cout << "   ";
-                const char* const* p = g_tests[i].argv;
-                while (*p) {
-                    cout << " " << *p;
-                    p++;
-                }
-                cout << endl;
-            }
-        }
-    }
-
-    return result;
-}
-
diff --git a/tools/aidl/tests/end_to_end_tests.cpp b/tools/aidl/tests/end_to_end_tests.cpp
new file mode 100644
index 0000000..54ca603
--- /dev/null
+++ b/tools/aidl/tests/end_to_end_tests.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <gtest/gtest.h>
+
+#include "aidl.h"
+#include "options.h"
+#include "tests/test_data.h"
+
+using base::FilePath;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+using namespace aidl::test_data;
+
+namespace {
+
+const char kDiffTemplate[] = "diff %s %s";
+const char kStubInterfaceTemplate[] = "package %s;\ninterface %s { }";
+const char kStubParcelableTemplate[] = "package %s;\nparcelable %s;";
+
+FilePath GetPathForPackageClass(const char* package_class,
+                                const char* extension) {
+  string rel_path{package_class};
+  for (char& c : rel_path) {
+    if (c == '.') {
+      c = FilePath::kSeparators[0];
+    }
+  }
+  rel_path += extension;
+  return FilePath(rel_path);
+}
+
+void SplitPackageClass(const string& package_class,
+                       FilePath* rel_path,
+                       string* package,
+                       string* class_name) {
+  *package = string{package_class, 0, package_class.rfind('.')};
+  *class_name = string{package_class, package_class.rfind('.') + 1};
+  *rel_path = GetPathForPackageClass(package_class.c_str(), ".aidl");
+}
+
+}  // namespace
+
+class EndToEndTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    ASSERT_TRUE(base::CreateNewTempDirectory(
+        string{"end_to_end_testsyyyy"}, &tmpDir_));
+    inputDir_ = tmpDir_.Append("input");
+    outputDir_ = tmpDir_.Append("output");
+    ASSERT_TRUE(base::CreateDirectory(inputDir_));
+    ASSERT_TRUE(base::CreateDirectory(outputDir_));
+  }
+
+  virtual void TearDown() {
+    ASSERT_TRUE(DeleteFile(tmpDir_, true))
+        << "Failed to remove temp directory: " << tmpDir_.value();
+  }
+
+  FilePath CreateInputFile(const FilePath& relative_path,
+                           const char contents[],
+                           int size) {
+    const FilePath created_file = inputDir_.Append(relative_path);
+    EXPECT_TRUE(base::CreateDirectory(created_file.DirName()));
+    EXPECT_TRUE(base::WriteFile(created_file, contents, size));
+    return created_file;
+  }
+
+  void CreateStubAidlFile(const string& package_class,
+                          const char* file_template) {
+    string package, class_name;
+    FilePath rel_path;
+    SplitPackageClass(package_class, &rel_path, &package, &class_name);
+    const size_t buf_len =
+        strlen(file_template) + package.length() + class_name.length() + 1;
+    unique_ptr<char[]> contents(new char[buf_len]);
+    const int written = snprintf(contents.get(), buf_len, file_template,
+                                 package.c_str(), class_name.c_str());
+    EXPECT_GT(written, 0);
+    CreateInputFile(rel_path, contents.get(), written);
+  }
+
+  void WriteStubAidls(const char** parcelables, const char** interfaces) {
+    while (*parcelables) {
+      CreateStubAidlFile(string{*parcelables}, kStubParcelableTemplate);
+      ++parcelables;
+    }
+    while (*interfaces) {
+      CreateStubAidlFile(string{*interfaces}, kStubInterfaceTemplate);
+      ++interfaces;
+    }
+  }
+
+  void CheckFileContents(const FilePath& rel_path,
+                         const string& expected_content) {
+    string actual_contents;
+    FilePath actual_path = outputDir_.Append(rel_path);
+    if (!ReadFileToString(actual_path, &actual_contents)) {
+      FAIL() << "Failed to read expected output file: " << rel_path.value();
+    }
+    // Generated .java files mention the "original" file as part of their
+    // comment header.  Thus we look for expected_content being a substring.
+    if (actual_contents.find(expected_content) == string::npos) {
+      // When the match fails, display a diff of what's wrong.  This greatly
+      // aids in debugging.
+      FilePath expected_path;
+      EXPECT_TRUE(CreateTemporaryFileInDir(tmpDir_, &expected_path));
+      base::WriteFile(expected_path, expected_content.c_str(),
+                      expected_content.length());
+      const size_t buf_len =
+          strlen(kDiffTemplate) + actual_path.value().length() +
+          expected_path.value().length() + 1;
+      unique_ptr<char[]> diff_cmd(new char[buf_len]);
+      EXPECT_GT(snprintf(diff_cmd.get(), buf_len, kDiffTemplate,
+                         expected_path.value().c_str(),
+                         actual_path.value().c_str()), 0);
+      system(diff_cmd.get());
+      FAIL() << "Actual contents of " << rel_path.value()
+             << " did not match expected content";
+    }
+  }
+
+  FilePath tmpDir_;
+  FilePath inputDir_;
+  FilePath outputDir_;
+};
+
+TEST_F(EndToEndTest, IExampleInterface) {
+  Options options;
+  options.failOnParcelable = true;
+  options.importPaths.push_back(inputDir_.value());
+  options.inputFileName =
+      CreateInputFile(GetPathForPackageClass(kIExampleInterfaceClass, ".aidl"),
+                      kIExampleInterfaceContents,
+                      strlen(kIExampleInterfaceContents)).value();
+  options.autoDepFile = true;
+  options.outputBaseFolder = outputDir_.value();
+  WriteStubAidls(kIExampleInterfaceParcelables, kIExampleInterfaceInterfaces);
+  EXPECT_EQ(compile_aidl(options), 0);
+  CheckFileContents(GetPathForPackageClass(kIExampleInterfaceClass, ".java"),
+                    kIExampleInterfaceJava);
+  // We'd like to check the depends file, but it mentions unique file paths.
+}
diff --git a/tools/aidl/tests/example_interface_test_data.cpp b/tools/aidl/tests/example_interface_test_data.cpp
new file mode 100644
index 0000000..b17a800
--- /dev/null
+++ b/tools/aidl/tests/example_interface_test_data.cpp
@@ -0,0 +1,404 @@
+/*
+ * 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.
+ */
+
+#include "tests/test_data.h"
+
+namespace aidl {
+namespace test_data {
+
+const char kIExampleInterfaceClass[] = "android.test.IExampleInterface";
+
+const char* kIExampleInterfaceParcelables[] = {
+  "android.foo.ExampleParcelable",
+  "android.test.ExampleParcelable2",
+  nullptr,
+};
+
+const char* kIExampleInterfaceInterfaces[] = {
+  "android.bar.IAuxInterface",
+  "android.test.IAuxInterface2",
+  nullptr,
+};
+
+const char kIExampleInterfaceContents[] = R"(
+package android.test;
+
+import android.foo.ExampleParcelable;
+import android.test.ExampleParcelable2;
+import android.bar.IAuxInterface;
+import android.test.IAuxInterface2;
+
+interface IExampleInterface {
+    boolean isEnabled();
+    int getState();
+    String getAddress();
+
+    ExampleParcelable[] getParcelables();
+
+    boolean setScanMode(int mode, int duration);
+
+    void registerBinder(IAuxInterface foo);
+    IExampleInterface getRecursiveBinder();
+
+    int takesAnInterface(in IAuxInterface2 arg);
+    int takesAParcelable(in ExampleParcelable2 arg);
+}
+)";
+
+const char kIExampleInterfaceDeps[] =
+R"(/tmp/.org.chromium.Chromium.Cdq7YZ/output/android/test/IExampleInterface.java: \
+  /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IExampleInterface.aidl \
+  /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/foo/ExampleParcelable.aidl \
+  /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/ExampleParcelable2.aidl \
+  /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/bar/IAuxInterface.aidl \
+  /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IAuxInterface2.aidl 
+
+/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IExampleInterface.aidl :
+/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/foo/ExampleParcelable.aidl :
+/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/ExampleParcelable2.aidl :
+/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/bar/IAuxInterface.aidl :
+/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IAuxInterface2.aidl :)";
+
+const char kIExampleInterfaceJava[] =
+R"(package android.test;
+public interface IExampleInterface extends android.os.IInterface
+{
+/** Local-side IPC implementation stub class. */
+public static abstract class Stub extends android.os.Binder implements android.test.IExampleInterface
+{
+private static final java.lang.String DESCRIPTOR = "android.test.IExampleInterface";
+/** Construct the stub at attach it to the interface. */
+public Stub()
+{
+this.attachInterface(this, DESCRIPTOR);
+}
+/**
+ * Cast an IBinder object into an android.test.IExampleInterface interface,
+ * generating a proxy if needed.
+ */
+public static android.test.IExampleInterface asInterface(android.os.IBinder obj)
+{
+if ((obj==null)) {
+return null;
+}
+android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
+if (((iin!=null)&&(iin instanceof android.test.IExampleInterface))) {
+return ((android.test.IExampleInterface)iin);
+}
+return new android.test.IExampleInterface.Stub.Proxy(obj);
+}
+@Override public android.os.IBinder asBinder()
+{
+return this;
+}
+@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
+{
+switch (code)
+{
+case INTERFACE_TRANSACTION:
+{
+reply.writeString(DESCRIPTOR);
+return true;
+}
+case TRANSACTION_isEnabled:
+{
+data.enforceInterface(DESCRIPTOR);
+boolean _result = this.isEnabled();
+reply.writeNoException();
+reply.writeInt(((_result)?(1):(0)));
+return true;
+}
+case TRANSACTION_getState:
+{
+data.enforceInterface(DESCRIPTOR);
+int _result = this.getState();
+reply.writeNoException();
+reply.writeInt(_result);
+return true;
+}
+case TRANSACTION_getAddress:
+{
+data.enforceInterface(DESCRIPTOR);
+java.lang.String _result = this.getAddress();
+reply.writeNoException();
+reply.writeString(_result);
+return true;
+}
+case TRANSACTION_getParcelables:
+{
+data.enforceInterface(DESCRIPTOR);
+android.foo.ExampleParcelable[] _result = this.getParcelables();
+reply.writeNoException();
+reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+return true;
+}
+case TRANSACTION_setScanMode:
+{
+data.enforceInterface(DESCRIPTOR);
+int _arg0;
+_arg0 = data.readInt();
+int _arg1;
+_arg1 = data.readInt();
+boolean _result = this.setScanMode(_arg0, _arg1);
+reply.writeNoException();
+reply.writeInt(((_result)?(1):(0)));
+return true;
+}
+case TRANSACTION_registerBinder:
+{
+data.enforceInterface(DESCRIPTOR);
+android.bar.IAuxInterface _arg0;
+_arg0 = android.bar.IAuxInterface.Stub.asInterface(data.readStrongBinder());
+this.registerBinder(_arg0);
+reply.writeNoException();
+return true;
+}
+case TRANSACTION_getRecursiveBinder:
+{
+data.enforceInterface(DESCRIPTOR);
+android.test.IExampleInterface _result = this.getRecursiveBinder();
+reply.writeNoException();
+reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null)));
+return true;
+}
+case TRANSACTION_takesAnInterface:
+{
+data.enforceInterface(DESCRIPTOR);
+android.test.IAuxInterface2 _arg0;
+_arg0 = android.test.IAuxInterface2.Stub.asInterface(data.readStrongBinder());
+int _result = this.takesAnInterface(_arg0);
+reply.writeNoException();
+reply.writeInt(_result);
+return true;
+}
+case TRANSACTION_takesAParcelable:
+{
+data.enforceInterface(DESCRIPTOR);
+android.test.ExampleParcelable2 _arg0;
+if ((0!=data.readInt())) {
+_arg0 = android.test.ExampleParcelable2.CREATOR.createFromParcel(data);
+}
+else {
+_arg0 = null;
+}
+int _result = this.takesAParcelable(_arg0);
+reply.writeNoException();
+reply.writeInt(_result);
+return true;
+}
+}
+return super.onTransact(code, data, reply, flags);
+}
+private static class Proxy implements android.test.IExampleInterface
+{
+private android.os.IBinder mRemote;
+Proxy(android.os.IBinder remote)
+{
+mRemote = remote;
+}
+@Override public android.os.IBinder asBinder()
+{
+return mRemote;
+}
+public java.lang.String getInterfaceDescriptor()
+{
+return DESCRIPTOR;
+}
+@Override public boolean isEnabled() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+boolean _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_isEnabled, _data, _reply, 0);
+_reply.readException();
+_result = (0!=_reply.readInt());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public int getState() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getState, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public java.lang.String getAddress() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+java.lang.String _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getAddress, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readString();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+android.foo.ExampleParcelable[] _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getParcelables, _data, _reply, 0);
+_reply.readException();
+_result = _reply.createTypedArray(android.foo.ExampleParcelable.CREATOR);
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public boolean setScanMode(int mode, int duration) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+boolean _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeInt(mode);
+_data.writeInt(duration);
+mRemote.transact(Stub.TRANSACTION_setScanMode, _data, _reply, 0);
+_reply.readException();
+_result = (0!=_reply.readInt());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeStrongBinder((((foo!=null))?(foo.asBinder()):(null)));
+mRemote.transact(Stub.TRANSACTION_registerBinder, _data, _reply, 0);
+_reply.readException();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+}
+@Override public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+android.test.IExampleInterface _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getRecursiveBinder, _data, _reply, 0);
+_reply.readException();
+_result = android.test.IExampleInterface.Stub.asInterface(_reply.readStrongBinder());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeStrongBinder((((arg!=null))?(arg.asBinder()):(null)));
+mRemote.transact(Stub.TRANSACTION_takesAnInterface, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public int takesAParcelable(android.test.ExampleParcelable2 arg) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+if ((arg!=null)) {
+_data.writeInt(1);
+arg.writeToParcel(_data, 0);
+}
+else {
+_data.writeInt(0);
+}
+mRemote.transact(Stub.TRANSACTION_takesAParcelable, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+}
+static final int TRANSACTION_isEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
+static final int TRANSACTION_getState = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
+static final int TRANSACTION_getAddress = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
+static final int TRANSACTION_getParcelables = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
+static final int TRANSACTION_setScanMode = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
+static final int TRANSACTION_registerBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
+static final int TRANSACTION_getRecursiveBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
+static final int TRANSACTION_takesAnInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
+static final int TRANSACTION_takesAParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
+}
+public boolean isEnabled() throws android.os.RemoteException;
+public int getState() throws android.os.RemoteException;
+public java.lang.String getAddress() throws android.os.RemoteException;
+public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException;
+public boolean setScanMode(int mode, int duration) throws android.os.RemoteException;
+public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException;
+public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException;
+public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException;
+public int takesAParcelable(android.test.ExampleParcelable2 arg) throws android.os.RemoteException;
+})";
+
+}  // namespace test_data
+}  // namespace aidl
diff --git a/tools/aidl/tests/test.cpp b/tools/aidl/tests/test.cpp
deleted file mode 100644
index 15ae294..0000000
--- a/tools/aidl/tests/test.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#include <gtest/gtest.h>
-
-TEST(DummyCase, DummyTest) {}
diff --git a/tools/aidl/tests/test_data.h b/tools/aidl/tests/test_data.h
new file mode 100644
index 0000000..cd8887f
--- /dev/null
+++ b/tools/aidl/tests/test_data.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifndef AIDL_TESTS_TEST_DATA_H_
+#define AIDL_TESTS_TEST_DATA_H_
+
+namespace aidl {
+namespace test_data {
+
+extern const char kIExampleInterfaceClass[];
+extern const char kIExampleInterfaceContents[];
+extern const char* kIExampleInterfaceParcelables[];
+extern const char* kIExampleInterfaceInterfaces[];
+
+extern const char kIExampleInterfaceDeps[];
+extern const char kIExampleInterfaceJava[];
+
+}  // namespace test_data
+}  // namespace aidl
+#endif // AIDL_TESTS_TEST_DATA_H_
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 1f3802e..689e359 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -36,8 +36,8 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.annotation.Nullable;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -139,8 +139,9 @@
     private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap;
     private int mDynamicIdGenerator = 0x02030000; // Base id for R.style in custom namespace
 
-    // cache for TypedArray generated from IStyleResourceValue object
-    private Map<int[], Map<Integer, BridgeTypedArray>> mTypedArrayCache;
+    // cache for TypedArray generated from StyleResourceValue object
+    private Map<int[], Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>>
+            mTypedArrayCache;
     private BridgeInflater mBridgeInflater;
 
     private BridgeContentResolver mContentResolver;
@@ -621,31 +622,38 @@
             }
         }
 
+        // The map is from
+        // attrs (int[]) -> context's current themes (List<StyleRV>) -> resid (int) -> typed array.
         if (mTypedArrayCache == null) {
-            mTypedArrayCache = new HashMap<int[], Map<Integer,BridgeTypedArray>>();
-
-            Map<Integer, BridgeTypedArray> map = new HashMap<Integer, BridgeTypedArray>();
-            mTypedArrayCache.put(attrs, map);
-
-            BridgeTypedArray ta = createStyleBasedTypedArray(style, attrs);
-            map.put(resid, ta);
-
-            return ta;
+            mTypedArrayCache = new IdentityHashMap<int[],
+                    Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>>();
         }
 
         // get the 2nd map
-        Map<Integer, BridgeTypedArray> map = mTypedArrayCache.get(attrs);
-        if (map == null) {
-            map = new HashMap<Integer, BridgeTypedArray>();
-            mTypedArrayCache.put(attrs, map);
+        Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>> map2 =
+                mTypedArrayCache.get(attrs);
+        if (map2 == null) {
+            map2 = new HashMap<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>();
+            mTypedArrayCache.put(attrs, map2);
         }
 
-        // get the array from the 2nd map
-        BridgeTypedArray ta = map.get(resid);
+        // get the 3rd map
+        List<StyleResourceValue> currentThemes = mRenderResources.getAllThemes();
+        Map<Integer, BridgeTypedArray> map3 = map2.get(currentThemes);
+        if (map3 == null) {
+            map3 = new HashMap<Integer, BridgeTypedArray>();
+            // Create a copy of the list before adding it to the map. This allows reusing the
+            // existing list.
+            currentThemes = new ArrayList<StyleResourceValue>(currentThemes);
+            map2.put(currentThemes, map3);
+        }
+
+        // get the array from the 3rd map
+        BridgeTypedArray ta = map3.get(resid);
 
         if (ta == null) {
             ta = createStyleBasedTypedArray(style, attrs);
-            map.put(resid, ta);
+            map3.put(resid, ta);
         }
 
         return ta;