Merge "Ensure entering and exiting views don't match in Fragment Transitions."
diff --git a/api/current.txt b/api/current.txt
index 991756a..7e6f445 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12303,7 +12303,6 @@
     method public int getIntrinsicWidth();
     method public int getLayoutDirection();
     method public final int getLevel();
-    method public final float getLevelFloat();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
     method public abstract int getOpacity();
@@ -12323,7 +12322,6 @@
     method protected void onBoundsChange(android.graphics.Rect);
     method public boolean onLayoutDirectionChanged(int);
     method protected boolean onLevelChange(int);
-    method protected boolean onLevelChange(float);
     method protected boolean onStateChange(int[]);
     method public static int resolveOpacity(int, int);
     method public void scheduleSelf(java.lang.Runnable, long);
@@ -12341,15 +12339,12 @@
     method public void setHotspotBounds(int, int, int, int);
     method public final boolean setLayoutDirection(int);
     method public final boolean setLevel(int);
-    method public final boolean setLevel(float);
     method public boolean setState(int[]);
     method public void setTint(int);
     method public void setTintList(android.content.res.ColorStateList);
     method public void setTintMode(android.graphics.PorterDuff.Mode);
     method public boolean setVisible(boolean, boolean);
     method public void unscheduleSelf(java.lang.Runnable);
-    field public static final int MAX_LEVEL = 10000; // 0x2710
-    field public static final float MAX_LEVEL_FLOAT = 10000.0f;
   }
 
   public static abstract interface Drawable.Callback {
@@ -35370,6 +35365,7 @@
     field public static final int KEYCODE_SLEEP = 223; // 0xdf
     field public static final int KEYCODE_SOFT_LEFT = 1; // 0x1
     field public static final int KEYCODE_SOFT_RIGHT = 2; // 0x2
+    field public static final int KEYCODE_SOFT_SLEEP = 276; // 0x114
     field public static final int KEYCODE_SPACE = 62; // 0x3e
     field public static final int KEYCODE_STAR = 17; // 0x11
     field public static final int KEYCODE_STB_INPUT = 180; // 0xb4
diff --git a/api/system-current.txt b/api/system-current.txt
index b8e5600..0a2a521 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -12640,7 +12640,6 @@
     method public int getIntrinsicWidth();
     method public int getLayoutDirection();
     method public final int getLevel();
-    method public final float getLevelFloat();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
     method public abstract int getOpacity();
@@ -12660,7 +12659,6 @@
     method protected void onBoundsChange(android.graphics.Rect);
     method public boolean onLayoutDirectionChanged(int);
     method protected boolean onLevelChange(int);
-    method protected boolean onLevelChange(float);
     method protected boolean onStateChange(int[]);
     method public static int resolveOpacity(int, int);
     method public void scheduleSelf(java.lang.Runnable, long);
@@ -12678,15 +12676,12 @@
     method public void setHotspotBounds(int, int, int, int);
     method public final boolean setLayoutDirection(int);
     method public final boolean setLevel(int);
-    method public final boolean setLevel(float);
     method public boolean setState(int[]);
     method public void setTint(int);
     method public void setTintList(android.content.res.ColorStateList);
     method public void setTintMode(android.graphics.PorterDuff.Mode);
     method public boolean setVisible(boolean, boolean);
     method public void unscheduleSelf(java.lang.Runnable);
-    field public static final int MAX_LEVEL = 10000; // 0x2710
-    field public static final float MAX_LEVEL_FLOAT = 10000.0f;
   }
 
   public static abstract interface Drawable.Callback {
@@ -37664,6 +37659,7 @@
     field public static final int KEYCODE_SLEEP = 223; // 0xdf
     field public static final int KEYCODE_SOFT_LEFT = 1; // 0x1
     field public static final int KEYCODE_SOFT_RIGHT = 2; // 0x2
+    field public static final int KEYCODE_SOFT_SLEEP = 276; // 0x114
     field public static final int KEYCODE_SPACE = 62; // 0x3e
     field public static final int KEYCODE_STAR = 17; // 0x11
     field public static final int KEYCODE_STB_INPUT = 180; // 0xb4
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index a475041..d751f96f 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -426,7 +426,7 @@
     @RequiresPermission(GET_ACCOUNTS)
     public Account[] getAccounts() {
         try {
-            return mService.getAccounts(null);
+            return mService.getAccounts(null, mContext.getOpPackageName());
         } catch (RemoteException e) {
             // won't ever happen
             throw new RuntimeException(e);
@@ -451,7 +451,7 @@
     @RequiresPermission(GET_ACCOUNTS)
     public Account[] getAccountsAsUser(int userId) {
         try {
-            return mService.getAccountsAsUser(null, userId);
+            return mService.getAccountsAsUser(null, userId, mContext.getOpPackageName());
         } catch (RemoteException e) {
             // won't ever happen
             throw new RuntimeException(e);
@@ -468,7 +468,7 @@
      */
     public Account[] getAccountsForPackage(String packageName, int uid) {
         try {
-            return mService.getAccountsForPackage(packageName, uid);
+            return mService.getAccountsForPackage(packageName, uid, mContext.getOpPackageName());
         } catch (RemoteException re) {
             // won't ever happen
             throw new RuntimeException(re);
@@ -485,7 +485,8 @@
      */
     public Account[] getAccountsByTypeForPackage(String type, String packageName) {
         try {
-            return mService.getAccountsByTypeForPackage(type, packageName);
+            return mService.getAccountsByTypeForPackage(type, packageName,
+                    mContext.getOpPackageName());
         } catch (RemoteException re) {
             // won't ever happen
             throw new RuntimeException(re);
@@ -522,7 +523,8 @@
     /** @hide Same as {@link #getAccountsByType(String)} but for a specific user. */
     public Account[] getAccountsByTypeAsUser(String type, UserHandle userHandle) {
         try {
-            return mService.getAccountsAsUser(type, userHandle.getIdentifier());
+            return mService.getAccountsAsUser(type, userHandle.getIdentifier(),
+                    mContext.getOpPackageName());
         } catch (RemoteException e) {
             // won't ever happen
             throw new RuntimeException(e);
@@ -610,7 +612,7 @@
         if (features == null) throw new IllegalArgumentException("features is null");
         return new Future2Task<Boolean>(handler, callback) {
             public void doWork() throws RemoteException {
-                mService.hasFeatures(mResponse, account, features);
+                mService.hasFeatures(mResponse, account, features, mContext.getOpPackageName());
             }
             public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
                 if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
@@ -662,7 +664,8 @@
         if (type == null) throw new IllegalArgumentException("type is null");
         return new Future2Task<Account[]>(handler, callback) {
             public void doWork() throws RemoteException {
-                mService.getAccountsByFeatures(mResponse, type, features);
+                mService.getAccountsByFeatures(mResponse, type, features,
+                        mContext.getOpPackageName());
             }
             public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
                 if (!bundle.containsKey(KEY_ACCOUNTS)) {
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 04b3c88..4378df4 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -30,12 +30,14 @@
     String getPassword(in Account account);
     String getUserData(in Account account, String key);
     AuthenticatorDescription[] getAuthenticatorTypes(int userId);
-    Account[] getAccounts(String accountType);
-    Account[] getAccountsForPackage(String packageName, int uid);
-    Account[] getAccountsByTypeForPackage(String type, String packageName);
-    Account[] getAccountsAsUser(String accountType, int userId);
-    void hasFeatures(in IAccountManagerResponse response, in Account account, in String[] features);
-    void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features);
+    Account[] getAccounts(String accountType, String opPackageName);
+    Account[] getAccountsForPackage(String packageName, int uid, String opPackageName);
+    Account[] getAccountsByTypeForPackage(String type, String packageName, String opPackageName);
+    Account[] getAccountsAsUser(String accountType, int userId, String opPackageName);
+    void hasFeatures(in IAccountManagerResponse response, in Account account, in String[] features,
+        String opPackageName);
+    void getAccountsByFeatures(in IAccountManagerResponse response, String accountType,
+        in String[] features, String opPackageName);
     boolean addAccountExplicitly(in Account account, String password, in Bundle extras);
     void removeAccount(in IAccountManagerResponse response, in Account account,
         boolean expectActivityLaunch);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 73c3786..f7dcf02 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2736,40 +2736,6 @@
     }
 
     /**
-     * Returns the bounds of the task that contains this activity.
-     *
-     * @return Rect The bounds that contains the activity.
-     * @hide
-     */
-    @Override
-    public Rect getActivityBounds() throws RemoteException {
-        return ActivityManagerNative.getDefault().getActivityBounds(mToken);
-    }
-
-    /**
-     * Sets the bounds (size and position) of the task or stack that contains this
-     * activity.
-     * NOTE: The requested bounds might not the fully honored by the system depending
-     * on the window placement policy.
-     *
-     * @param newBounds The new target bounds of the activity in task or stack.
-     * @hide
-     */
-    @Override
-    public void setActivityBounds(Rect newBounds) throws RemoteException {
-        ActivityManagerNative.getDefault().setActivityBounds(mToken, newBounds);
-    }
-
-    /**
-     * Activates this activity, hence bringing it to the top and giving it focus.
-     * Note: This will only work for activities which are located on the freeform desktop.
-     * @hide
-     */
-    public void activateActivity() throws RemoteException {
-        ActivityManagerNative.getDefault().activateActivity(mToken);
-    }
-
-    /**
      * Called to process key events.  You can override this to intercept all
      * key events before they are dispatched to the window.  Be sure to call
      * this implementation for key events that should be handled normally.
@@ -3839,6 +3805,12 @@
      * #checkSelfPermission(String)}.
      * </p>
      * <p>
+     * Calling this API for permissions already granted to your app would show UI
+     * to the user to decide whether the app can still hold these permissions. This
+     * can be useful if the way your app uses data guarded by the permissions
+     * changes significantly.
+     * </p>
+     * <p>
      * You cannot request a permission if your activity sets {@link
      * android.R.styleable#AndroidManifestActivity_noHistory noHistory} to
      * <code>true</code> because in this case the activity would not receive
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1f1f356..d1c73bc 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -752,24 +752,6 @@
             return true;
         }
 
-        case GET_ACTIVITY_BOUNDS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            Rect r = getActivityBounds(token);
-            reply.writeNoException();
-            r.writeToParcel(reply, 0);
-            return true;
-        }
-
-        case SET_ACTIVITY_BOUNDS_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            Rect r = Rect.CREATOR.createFromParcel(data);
-            setActivityBounds(token, r);
-            reply.writeNoException();
-            return true;
-        }
-
         case POSITION_TASK_IN_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int taskId = data.readInt();
@@ -827,14 +809,6 @@
             return true;
         }
 
-        case ACTIVATE_ACTIVITY_TRANSACTION: {
-            data.enforceInterface(IActivityManager.descriptor);
-            IBinder token = data.readStrongBinder();
-            activateActivity(token);
-            reply.writeNoException();
-            return true;
-        }
-
         case SET_FOCUSED_TASK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int taskId = data.readInt();
@@ -3631,18 +3605,6 @@
         return focusedStackId;
     }
     @Override
-    public void activateActivity(IBinder token) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(ACTIVATE_ACTIVITY_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-    @Override
     public void setFocusedTask(int taskId) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -5941,35 +5903,6 @@
     }
 
     @Override
-    public void setActivityBounds(IBinder token, Rect r) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        r.writeToParcel(data, 0);
-        mRemote.transact(SET_ACTIVITY_BOUNDS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        data.recycle();
-        reply.recycle();
-    }
-
-    @Override
-    public Rect getActivityBounds(IBinder token) throws RemoteException
-    {
-        Parcel data = Parcel.obtain();
-        Parcel reply = Parcel.obtain();
-        data.writeInterfaceToken(IActivityManager.descriptor);
-        data.writeStrongBinder(token);
-        mRemote.transact(GET_ACTIVITY_BOUNDS_TRANSACTION, data, reply, 0);
-        reply.readException();
-        Rect rect = Rect.CREATOR.createFromParcel(reply);
-        data.recycle();
-        reply.recycle();
-        return rect;
-    }
-
-    @Override
     public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 5c6fe46..38562da 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -150,7 +150,13 @@
     }
 
     public void setEnterActivityOptions(Activity activity, ActivityOptions options) {
-        if (activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
+        final Window window = activity.getWindow();
+        if (window == null) {
+            return;
+        }
+        // ensure Decor View has been created so that the window features are activated
+        window.getDecorView();
+        if (window.hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
                 && options != null && mEnterActivityOptions == null
                 && mEnterTransitionCoordinator == null
                 && options.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 42ac67c..09c0a6e 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -235,8 +235,10 @@
     public static final int OP_WRITE_EXTERNAL_STORAGE = 60;
     /** @hide Turned on the screen. */
     public static final int OP_TURN_SCREEN_ON = 61;
+    /** @hide Get device accounts. */
+    public static final int OP_GET_ACCOUNTS = 62;
     /** @hide */
-    public static final int _NUM_OP = 62;
+    public static final int _NUM_OP = 63;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -331,6 +333,9 @@
     /** Required to write/modify/update system settingss. */
     public static final String OPSTR_WRITE_SETTINGS
             = "android:write_settings";
+    /** @hide Get device accounts. */
+    public static final String OPSTR_GET_ACCOUNTS
+            = "android:get_accounts";
 
     /**
      * This maps each operation to the operation that serves as the
@@ -403,6 +408,7 @@
             OP_READ_EXTERNAL_STORAGE,
             OP_WRITE_EXTERNAL_STORAGE,
             OP_TURN_SCREEN_ON,
+            OP_GET_ACCOUNTS,
     };
 
     /**
@@ -472,6 +478,7 @@
             OPSTR_READ_EXTERNAL_STORAGE,
             OPSTR_WRITE_EXTERNAL_STORAGE,
             null,
+            OPSTR_GET_ACCOUNTS
     };
 
     /**
@@ -541,6 +548,7 @@
             "READ_EXTERNAL_STORAGE",
             "WRITE_EXTERNAL_STORAGE",
             "TURN_ON_SCREEN",
+            "GET_ACCOUNTS",
     };
 
     /**
@@ -610,6 +618,7 @@
             Manifest.permission.READ_EXTERNAL_STORAGE,
             Manifest.permission.WRITE_EXTERNAL_STORAGE,
             null, // no permission for turning the screen on
+            Manifest.permission.GET_ACCOUNTS
     };
 
     /**
@@ -680,6 +689,7 @@
             null, // READ_EXTERNAL_STORAGE
             null, // WRITE_EXTERNAL_STORAGE
             null, // TURN_ON_SCREEN
+            null, // GET_ACCOUNTS
     };
 
     /**
@@ -749,6 +759,7 @@
             false, // READ_EXTERNAL_STORAGE
             false, // WRITE_EXTERNAL_STORAGE
             false, // TURN_ON_SCREEN
+            false, // GET_ACCOUNTS
     };
 
     /**
@@ -817,6 +828,7 @@
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,  // OP_TURN_ON_SCREEN
+            AppOpsManager.MODE_ALLOWED,
     };
 
     /**
@@ -889,6 +901,7 @@
             false,
             false,
             false,
+            false
     };
 
     /**
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 82206ea..f70423f 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1166,6 +1166,12 @@
      * android.content.Context#checkSelfPermission(String)}.
      * </p>
      * <p>
+     * Calling this API for permissions already granted to your app would show UI
+     * to the user to decide whether the app can still hold these permissions. This
+     * can be useful if the way your app uses data guarded by the permissions
+     * changes significantly.
+     * </p>
+     * <p>
      * You cannot request a permission if your activity sets {@link
      * android.R.styleable#AndroidManifestActivity_noHistory noHistory} to
      * <code>true</code> because in this case the activity would not receive
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 47abf26..66fa796 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -147,7 +147,6 @@
     public boolean isInHomeStack(int taskId) throws RemoteException;
     public void setFocusedStack(int stackId) throws RemoteException;
     public int getFocusedStackId() throws RemoteException;
-    public void activateActivity(IBinder token) throws RemoteException;
     public void setFocusedTask(int taskId) throws RemoteException;
     public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException;
     public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
@@ -491,8 +490,6 @@
             throws RemoteException;
     public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException;
     public void resizeTask(int taskId, Rect bounds) throws RemoteException;
-    public void setActivityBounds(IBinder token, Rect bounds) throws RemoteException;
-    public Rect getActivityBounds(IBinder token) throws RemoteException;
 
     public Rect getTaskBounds(int taskId) throws RemoteException;
     public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException;
@@ -891,7 +888,4 @@
     int GET_ACTIVITY_STACK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 343;
     int MOVE_ACTIVITY_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344;
     int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345;
-    int GET_ACTIVITY_BOUNDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
-    int SET_ACTIVITY_BOUNDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
-    int ACTIVATE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 348;
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9381327..55aec59 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -953,6 +953,9 @@
         private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
                 RemoteInput[] remoteInputs) {
             this.mIcon = icon;
+            if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
+                this.icon = icon.getResId();
+            }
             this.title = title;
             this.actionIntent = intent;
             this.mExtras = extras != null ? extras : new Bundle();
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index cc06b67..f27fc2a 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -18,6 +18,7 @@
 
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
+import android.os.Parcelable;
 import android.util.Printer;
 
 /**
@@ -160,7 +161,12 @@
     
     public void writeToParcel(Parcel dest, int parcelableFlags) {
         super.writeToParcel(dest, parcelableFlags);
-        applicationInfo.writeToParcel(dest, parcelableFlags);
+        if ((parcelableFlags & Parcelable.PARCELABLE_ELIDE_DUPLICATES) != 0) {
+            dest.writeInt(0);
+        } else {
+            dest.writeInt(1);
+            applicationInfo.writeToParcel(dest, parcelableFlags);
+        }
         dest.writeString(processName);
         dest.writeInt(descriptionRes);
         dest.writeInt(enabled ? 1 : 0);
@@ -169,7 +175,10 @@
     
     protected ComponentInfo(Parcel source) {
         super(source);
-        applicationInfo = ApplicationInfo.CREATOR.createFromParcel(source);
+        final boolean hasApplicationInfo = (source.readInt() != 0);
+        if (hasApplicationInfo) {
+            applicationInfo = ApplicationInfo.CREATOR.createFromParcel(source);
+        }
         processName = source.readString();
         descriptionRes = source.readInt();
         enabled = (source.readInt() != 0);
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 9e6c6b5..d40bab5 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -305,10 +305,10 @@
         dest.writeLong(firstInstallTime);
         dest.writeLong(lastUpdateTime);
         dest.writeIntArray(gids);
-        dest.writeTypedArray(activities, parcelableFlags);
-        dest.writeTypedArray(receivers, parcelableFlags);
-        dest.writeTypedArray(services, parcelableFlags);
-        dest.writeTypedArray(providers, parcelableFlags);
+        dest.writeTypedArray(activities, parcelableFlags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
+        dest.writeTypedArray(receivers, parcelableFlags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
+        dest.writeTypedArray(services, parcelableFlags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
+        dest.writeTypedArray(providers, parcelableFlags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
         dest.writeTypedArray(instrumentation, parcelableFlags);
         dest.writeTypedArray(permissions, parcelableFlags);
         dest.writeStringArray(requestedPermissions);
@@ -372,5 +372,22 @@
         restrictedAccountType = source.readString();
         requiredAccountType = source.readString();
         overlayTarget = source.readString();
+
+        // The component lists were flattened with the redundant ApplicationInfo
+        // instances omitted.  Distribute the canonical one here as appropriate.
+        if (applicationInfo != null) {
+            propagateApplicationInfo(applicationInfo, activities);
+            propagateApplicationInfo(applicationInfo, receivers);
+            propagateApplicationInfo(applicationInfo, services);
+            propagateApplicationInfo(applicationInfo, providers);
+        }
+    }
+
+    private void propagateApplicationInfo(ApplicationInfo appInfo, ComponentInfo[] components) {
+        if (components != null) {
+            for (ComponentInfo ci : components) {
+                ci.applicationInfo = appInfo;
+            }
+        }
     }
 }
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index c248a9e..04c690b 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -610,14 +610,28 @@
      * {@hide}
      */
     public final int addAssetPath(String path) {
+        return  addAssetPathInternal(path, false);
+    }
+
+    /**
+     * Add an application assets to the asset manager and loading it as shared library.
+     * This can be either a directory or ZIP file.  Not for use by applications.  Returns
+     * the cookie of the added asset, or 0 on failure.
+     * {@hide}
+     */
+    public final int addAssetPathAsSharedLibrary(String path) {
+        return addAssetPathInternal(path, true);
+    }
+
+    private final int addAssetPathInternal(String path, boolean appAsLib) {
         synchronized (this) {
-            int res = addAssetPathNative(path);
+            int res = addAssetPathNative(path, appAsLib);
             makeStringBlocks(mStringBlocks);
             return res;
         }
     }
 
-    private native final int addAssetPathNative(String path);
+    private native final int addAssetPathNative(String path, boolean appAsLib);
 
      /**
      * Add a set of assets to overlay an already added set of assets.
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 1f23c0a..7fef5e1 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -27,6 +27,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.security.keystore.AndroidKeyStoreProvider;
@@ -705,15 +706,23 @@
     public void addLockoutResetCallback(final LockoutResetCallback callback) {
         if (mService != null) {
             try {
+                final PowerManager powerManager = mContext.getSystemService(PowerManager.class);
                 mService.addLockoutResetCallback(
                         new IFingerprintServiceLockoutResetCallback.Stub() {
 
                     @Override
                     public void onLockoutReset(long deviceId) throws RemoteException {
+                        final PowerManager.WakeLock wakeLock = powerManager.newWakeLock(
+                                PowerManager.PARTIAL_WAKE_LOCK, "lockoutResetCallback");
+                        wakeLock.acquire();
                         mHandler.post(new Runnable() {
                             @Override
                             public void run() {
-                                callback.onLockoutReset();
+                                try {
+                                    callback.onLockoutReset();
+                                } finally {
+                                    wakeLock.release();
+                                }
                             }
                         });
                     }
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
index c9a5d59..e027a2b3 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
@@ -23,6 +23,8 @@
  * Callback when lockout period expired and clients are allowed to authenticate again.
  * @hide
  */
-oneway interface IFingerprintServiceLockoutResetCallback {
+interface IFingerprintServiceLockoutResetCallback {
+
+    /** Method is synchronous so wakelock is held when this is called from a WAKEUP alarm. */
     void onLockoutReset(long deviceId);
 }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 112ae10..6e28982 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1456,15 +1456,9 @@
         final int previousImeWindowStatus =
                 (mWindowVisible ? IME_ACTIVE : 0) | (isInputViewShown() ? IME_VISIBLE : 0);
         mWindowVisible = true;
-        if (!mShowInputRequested) {
-            if (mInputStarted) {
-                if (showInput) {
-                    doShowInput = true;
-                    mShowInputRequested = true;
-                }
-            }
-        } else {
-            showInput = true;
+        if (!mShowInputRequested && mInputStarted && showInput) {
+            doShowInput = true;
+            mShowInputRequested = true;
         }
 
         if (DEBUG) Log.v(TAG, "showWindow: updating UI");
@@ -1985,31 +1979,25 @@
                 // We want our own movement method to handle the key, so the
                 // cursor will properly move in our own word wrapping.
                 if (count == MOVEMENT_DOWN) {
-                    if (movement.onKeyDown(eet,
-                            (Spannable)eet.getText(), keyCode, event)) {
+                    if (movement.onKeyDown(eet, eet.getText(), keyCode, event)) {
                         reportExtractedMovement(keyCode, 1);
                         return true;
                     }
                 } else if (count == MOVEMENT_UP) {
-                    if (movement.onKeyUp(eet,
-                            (Spannable)eet.getText(), keyCode, event)) {
+                    if (movement.onKeyUp(eet, eet.getText(), keyCode, event)) {
                         return true;
                     }
                 } else {
-                    if (movement.onKeyOther(eet, (Spannable)eet.getText(), event)) {
+                    if (movement.onKeyOther(eet, eet.getText(), event)) {
                         reportExtractedMovement(keyCode, count);
                     } else {
                         KeyEvent down = KeyEvent.changeAction(event, KeyEvent.ACTION_DOWN);
-                        if (movement.onKeyDown(eet,
-                                (Spannable)eet.getText(), keyCode, down)) {
+                        if (movement.onKeyDown(eet, eet.getText(), keyCode, down)) {
                             KeyEvent up = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
-                            movement.onKeyUp(eet,
-                                    (Spannable)eet.getText(), keyCode, up);
+                            movement.onKeyUp(eet, eet.getText(), keyCode, up);
                             while (--count > 0) {
-                                movement.onKeyDown(eet,
-                                        (Spannable)eet.getText(), keyCode, down);
-                                movement.onKeyUp(eet,
-                                        (Spannable)eet.getText(), keyCode, up);
+                                movement.onKeyDown(eet, eet.getText(), keyCode, down);
+                                movement.onKeyUp(eet, eet.getText(), keyCode, up);
                             }
                             reportExtractedMovement(keyCode, count);
                         }
@@ -2125,7 +2113,7 @@
                 } else {
                     InputConnection ic = getCurrentInputConnection();
                     if (ic != null) {
-                        ic.commitText(String.valueOf((char) charCode), 1);
+                        ic.commitText(String.valueOf(charCode), 1);
                     }
                 }
                 break;
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index 4407c9d..78a9401 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -1,3 +1,19 @@
+/*
+ * 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 android.nfc.cardemulation;
 
 import java.io.IOException;
diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/core/java/android/nfc/cardemulation/HostApduService.java
index ad34e61..a299479 100644
--- a/core/java/android/nfc/cardemulation/HostApduService.java
+++ b/core/java/android/nfc/cardemulation/HostApduService.java
@@ -1,3 +1,19 @@
+/*
+ * 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 android.nfc.cardemulation;
 
 import android.annotation.SdkConstant;
diff --git a/core/java/android/nfc/cardemulation/OffHostApduService.java b/core/java/android/nfc/cardemulation/OffHostApduService.java
index 0d01762..6a8aeee 100644
--- a/core/java/android/nfc/cardemulation/OffHostApduService.java
+++ b/core/java/android/nfc/cardemulation/OffHostApduService.java
@@ -1,3 +1,19 @@
+/*
+ * 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 android.nfc.cardemulation;
 
 import android.annotation.SdkConstant;
diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java
index 448b591..13b5de9 100644
--- a/core/java/android/os/Parcelable.java
+++ b/core/java/android/os/Parcelable.java
@@ -62,7 +62,17 @@
      * may want to release resources at this point.
      */
     public static final int PARCELABLE_WRITE_RETURN_VALUE = 0x0001;
-    
+
+    /**
+     * Flag for use with {@link #writeToParcel}: a parent object will take
+     * care of managing duplicate state/data that is nominally replicated
+     * across its inner data members.  This flag instructs the inner data
+     * types to omit that data during marshaling.  Exact behavior may vary
+     * on a case by case basis.
+     * @hide
+     */
+    public static final int PARCELABLE_ELIDE_DUPLICATES = 0x0002;
+
     /**
      * Bit masks for use with {@link #describeContents}: each bit represents a
      * kind of object considered to have potential special significance when
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d1744b4..a038b0d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5719,6 +5719,15 @@
         public static final String CAMERA_GESTURE_DISABLED = "camera_gesture_disabled";
 
         /**
+         * Whether the camera launch gesture to double tap the power button when the screen is off
+         * should be disabled.
+         *
+         * @hide
+         */
+        public static final String CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED =
+                "camera_double_tap_power_gesture_disabled";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
index 409542d..7cf1d71 100644
--- a/core/java/android/security/IKeystoreService.aidl
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -31,7 +31,7 @@
  */
 interface IKeystoreService {
     int getState(int userId);
-    byte[] get(String name);
+    byte[] get(String name, int uid);
     int insert(String name, in byte[] item, int uid, int flags);
     int del(String name, int uid);
     int exist(String name, int uid);
@@ -49,7 +49,7 @@
     byte[] get_pubkey(String name);
     int grant(String name, int granteeUid);
     int ungrant(String name, int granteeUid);
-    long getmtime(String name);
+    long getmtime(String name, int uid);
     int duplicate(String srcKey, int srcUid, String destKey, int destUid);
     int is_hardware_backed(String string);
     int clear_uid(long uid);
@@ -59,13 +59,13 @@
     int generateKey(String alias, in KeymasterArguments arguments, in byte[] entropy, int uid,
         int flags, out KeyCharacteristics characteristics);
     int getKeyCharacteristics(String alias, in KeymasterBlob clientId, in KeymasterBlob appId,
-        out KeyCharacteristics characteristics);
+        int uid, out KeyCharacteristics characteristics);
     int importKey(String alias, in KeymasterArguments arguments, int format,
         in byte[] keyData, int uid, int flags, out KeyCharacteristics characteristics);
     ExportResult exportKey(String alias, int format, in KeymasterBlob clientId,
-        in KeymasterBlob appId);
+        in KeymasterBlob appId, int uid);
     OperationResult begin(IBinder appToken, String alias, int purpose, boolean pruneable,
-        in KeymasterArguments params, in byte[] entropy);
+        in KeymasterArguments params, in byte[] entropy, int uid);
     OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input);
     OperationResult finish(IBinder token, in KeymasterArguments params, in byte[] signature,
         in byte[] entropy);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 73b4a6e..017364a 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -211,4 +211,12 @@
      * The assumption is that this method will be called rather infrequently.
      */
     void pokeDrawLock(IBinder window);
+
+    /**
+     * Starts a task window move with {startX, startY} as starting point. The amount of move
+     * will be the offset between {startX, startY} and the new cursor position.
+     *
+     * Returns true if the move started successfully; false otherwise.
+     */
+    boolean startMovingTask(IWindow window, float startX, float startY);
 }
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 61ba590..1c20cab 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -788,8 +788,7 @@
     /** Key code constant: Step backward media key.
      * Steps media backward, one frame at a time. */
     public static final int KEYCODE_MEDIA_STEP_BACKWARD = 275;
-    /** Key code constant: put device to sleep unless a wakelock is held.
-     * @hide */
+    /** Key code constant: put device to sleep unless a wakelock is held. */
     public static final int KEYCODE_SOFT_SLEEP = 276;
 
     private static final int LAST_KEYCODE = KEYCODE_SOFT_SLEEP;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f4fc6e7..eb591c1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -19750,6 +19750,26 @@
     }
 
     /**
+     * Starts a move from {startX, startY}, the amount of the movement will be the offset
+     * between {startX, startY} and the new cursor positon.
+     * @param startX horizontal coordinate where the move started.
+     * @param startY vertical coordinate where the move started.
+     * @return whether moving was started successfully.
+     * @hide
+     */
+    public final boolean startMovingTask(float startX, float startY) {
+        if (ViewDebug.DEBUG_POSITIONING) {
+            Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}");
+        }
+        try {
+            return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY);
+        } catch (RemoteException e) {
+            Log.e(VIEW_LOG_TAG, "Unable to start moving", e);
+        }
+        return false;
+    }
+
+    /**
      * Handles drag events sent by the system following a call to
      * {@link android.view.View#startDrag(ClipData,DragShadowBuilder,Object,int) startDrag()}.
      *<p>
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 8bf53a8..8278335 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -78,6 +78,12 @@
     public static final boolean DEBUG_DRAG = false;
 
     /**
+     * Enables detailed logging of task positioning operations.
+     * @hide
+     */
+    public static final boolean DEBUG_POSITIONING = false;
+
+    /**
      * This annotation can be used to mark fields and methods to be dumped by
      * the view server. Only non-void methods with no arguments can be annotated
      * by this annotation.
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 5893f4a..b146a51 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -562,28 +562,6 @@
 
         /** Returns the current stack Id for the window. */
         int getWindowStackId() throws RemoteException;
-
-        /**
-         * Returns the bounds of the task that contains this activity.
-         *
-         * @return Rect The bounds that contains the activity.
-         */
-        Rect getActivityBounds() throws RemoteException;
-
-        /**
-         * Sets the bounds (size and position) of the task or stack that contains this
-         * activity.
-         * NOTE: The requested bounds might not the fully honored by the system depending
-         * on the window placement policy.
-         *
-         * @param newBounds The new target bounds of the activity in task or stack.
-         */
-        void setActivityBounds(Rect newBounds) throws RemoteException;
-
-        /**
-         * Activates this activity, hence bringing it to the top and giving it focus.
-         */
-        void activateActivity() throws RemoteException;
     }
 
     public Window(Context context) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 389fc0a..5724f52 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2398,6 +2398,7 @@
             lp.itemId = mAdapter.getItemId(position);
         }
         lp.viewType = mAdapter.getItemViewType(position);
+        lp.isEnabled = mAdapter.isEnabled(position);
         if (lp != vlp) {
           child.setLayoutParams(lp);
         }
@@ -2419,19 +2420,33 @@
             }
 
             final int position = getPositionForView(host);
-            final ListAdapter adapter = getAdapter();
-
-            if ((position == INVALID_POSITION) || (adapter == null)) {
+            if (position == INVALID_POSITION || mAdapter == null) {
                 // Cannot perform actions on invalid items.
                 return false;
             }
 
-            if (!isEnabled() || !adapter.isEnabled(position)) {
-                // Cannot perform actions on disabled items.
+            if (position >= mAdapter.getCount()) {
+                // The position is no longer valid, likely due to a data set
+                // change. We could fail here for all data set changes, since
+                // there is a chance that the data bound to the view may no
+                // longer exist at the same position within the adapter, but
+                // it's more consistent with the standard touch interaction to
+                // click at whatever may have moved into that position.
                 return false;
             }
 
-            final long id = getItemIdAtPosition(position);
+            final boolean isItemEnabled;
+            final ViewGroup.LayoutParams lp = host.getLayoutParams();
+            if (lp instanceof AbsListView.LayoutParams) {
+                isItemEnabled = ((AbsListView.LayoutParams) lp).isEnabled;
+            } else {
+                isItemEnabled = false;
+            }
+
+            if (!isEnabled() || !isItemEnabled) {
+                // Cannot perform actions on disabled items.
+                return false;
+            }
 
             switch (action) {
                 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: {
@@ -2447,12 +2462,14 @@
                     }
                 } return false;
                 case AccessibilityNodeInfo.ACTION_CLICK: {
-                    if (isItemClickable(host, position)) {
+                    if (isItemClickable(host)) {
+                        final long id = getItemIdAtPosition(position);
                         return performItemClick(host, position, id);
                     }
                 } return false;
                 case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
                     if (isLongClickable()) {
+                        final long id = getItemIdAtPosition(position);
                         return performLongPress(host, position, id);
                     }
                 } return false;
@@ -2472,13 +2489,20 @@
      */
     public void onInitializeAccessibilityNodeInfoForItem(
             View view, int position, AccessibilityNodeInfo info) {
-        final ListAdapter adapter = getAdapter();
-        if (position == INVALID_POSITION || adapter == null) {
+        if (position == INVALID_POSITION) {
             // The item doesn't exist, so there's not much we can do here.
             return;
         }
 
-        if (!isEnabled() || !adapter.isEnabled(position)) {
+        final boolean isItemEnabled;
+        final ViewGroup.LayoutParams lp = view.getLayoutParams();
+        if (lp instanceof AbsListView.LayoutParams) {
+            isItemEnabled = ((AbsListView.LayoutParams) lp).isEnabled;
+        } else {
+            isItemEnabled = false;
+        }
+
+        if (!isEnabled() || !isItemEnabled) {
             info.setEnabled(false);
             return;
         }
@@ -2490,7 +2514,7 @@
             info.addAction(AccessibilityAction.ACTION_SELECT);
         }
 
-        if (isItemClickable(view, position)) {
+        if (isItemClickable(view)) {
             info.addAction(AccessibilityAction.ACTION_CLICK);
             info.setClickable(true);
         }
@@ -2501,9 +2525,8 @@
         }
     }
 
-    private boolean isItemClickable(View view, int position) {
-        return mAdapter != null && view != null &&
-                mAdapter.isEnabled(position) && !view.hasFocusable();
+    private boolean isItemClickable(View view) {
+        return !view.hasFocusable();
     }
 
     /**
@@ -6326,6 +6349,9 @@
          */
         long itemId = -1;
 
+        /** Whether the adapter considers the item enabled. */
+        boolean isEnabled;
+
         public LayoutParams(Context c, AttributeSet attrs) {
             super(c, attrs);
         }
@@ -6351,6 +6377,7 @@
             encoder.addProperty("list:viewType", viewType);
             encoder.addProperty("list:recycledHeaderFooter", recycledHeaderFooter);
             encoder.addProperty("list:forceAdd", forceAdd);
+            encoder.addProperty("list:isEnabled", isEnabled);
         }
     }
 
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index 64c4103..2dd84e3 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -85,6 +85,8 @@
     private OpenOverflowRunnable mPostedOpenRunnable;
     private ActionMenuPopupCallback mPopupCallback;
 
+    private final boolean mShowCascadingMenus;
+
     final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
     int mOpenSubMenuId;
 
@@ -126,6 +128,9 @@
     public ActionMenuPresenter(Context context) {
         super(context, com.android.internal.R.layout.action_menu_layout,
                 com.android.internal.R.layout.action_menu_item_layout);
+
+        mShowCascadingMenus = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableCascadingSubmenus);
     }
 
     @Override
@@ -500,14 +505,29 @@
         }
         View anchor = findViewForItem(topSubMenu.getItem());
         if (anchor == null) {
-            if (mOverflowButton == null) return false;
-            anchor = mOverflowButton;
+            // This means the submenu was opened from an overflow menu item, indicating the
+            // MenuPopupHelper will handle opening the submenu via its MenuPopup. Return false to
+            // ensure that the MenuPopup acts as presenter for the submenu, and acts on its
+            // responsibility to display the new submenu.
+            return false;
         }
 
         mOpenSubMenuId = subMenu.getItem().getItemId();
-        mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu);
-        mActionButtonPopup.setAnchorView(anchor);
+
+        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;
+            }
+        }
+
+        mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu, anchor);
+        mActionButtonPopup.setForceShowIcon(preserveIconSpacing);
         mActionButtonPopup.show();
+
         super.onSubMenuSelected(subMenu);
         return true;
     }
@@ -926,12 +946,9 @@
     }
 
     private class ActionButtonSubmenu extends MenuPopupHelper {
-        private SubMenuBuilder mSubMenu;
-
-        public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) {
-            super(context, subMenu, null, false,
+        public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu, View anchorView) {
+            super(context, subMenu, anchorView, false,
                     com.android.internal.R.attr.actionOverflowMenuStyle);
-            mSubMenu = subMenu;
 
             MenuItemImpl item = (MenuItemImpl) subMenu.getItem();
             if (!item.isActionButton()) {
@@ -940,17 +957,6 @@
             }
 
             setCallback(mPopupPresenterCallback);
-
-            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;
-                }
-            }
-            setForceShowIcon(preserveIconSpacing);
         }
 
         @Override
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 0cc1b25..2cfefba 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -600,13 +600,20 @@
     }
 
     /**
-     * Get the position within the adapter's data set for the view, where view is a an adapter item
-     * or a descendant of an adapter item.
+     * Returns the position within the adapter's data set for the view, where
+     * view is a an adapter item or a descendant of an adapter item.
+     * <p>
+     * <strong>Note:</strong> The result of this method only reflects the
+     * position of the data bound to <var>view</var> during the most recent
+     * layout pass. If the adapter's data set has changed without a subsequent
+     * layout pass, the position returned by this method may not match the
+     * current position of the data within the adapter.
      *
-     * @param view an adapter item, or a descendant of an adapter item. This must be visible in this
-     *        AdapterView at the time of the call.
-     * @return the position within the adapter's data set of the view, or {@link #INVALID_POSITION}
-     *         if the view does not correspond to a list item (or it is not currently visible).
+     * @param view an adapter item, or a descendant of an adapter item. This
+     *             must be visible in this AdapterView at the time of the call.
+     * @return the position within the adapter's data set of the view, or
+     *         {@link #INVALID_POSITION} if the view does not correspond to a
+     *         list item (or it is not currently visible)
      */
     public int getPositionForView(View view) {
         View listItem = view;
diff --git a/core/java/android/widget/DropDownListView.java b/core/java/android/widget/DropDownListView.java
index 5536513..bcbafc9 100644
--- a/core/java/android/widget/DropDownListView.java
+++ b/core/java/android/widget/DropDownListView.java
@@ -25,10 +25,8 @@
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.util.IntProperty;
-import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.widget.TextView;
 import android.widget.ListView;
@@ -128,6 +126,61 @@
         setCacheColorHint(0); // Transparent, since the background drawable could be anything.
     }
 
+    @Override
+    protected boolean shouldShowSelector() {
+        View selectedView = getSelectedView();
+        return selectedView != null && selectedView.isEnabled() || super.shouldShowSelector();
+    }
+
+    protected void clearSelection() {
+        setSelectedPositionInt(-1);
+        setNextSelectedPositionInt(-1);
+    }
+
+    @Override
+    public boolean onHoverEvent(MotionEvent ev) {
+        final int action = ev.getActionMasked();
+        if (action == MotionEvent.ACTION_HOVER_ENTER
+                || action == MotionEvent.ACTION_HOVER_MOVE) {
+            final int position = pointToPosition((int) ev.getX(), (int) ev.getY());
+            if (position != INVALID_POSITION && position != mSelectedPosition) {
+                final View hoveredItem = getChildAt(position - getFirstVisiblePosition());
+                if (hoveredItem.isEnabled()) {
+                    // Force a focus so that the proper selector state gets used when we update.
+                    requestFocus();
+
+                    positionSelector(position, hoveredItem);
+                    setSelectedPositionInt(position);
+                    setNextSelectedPositionInt(position);
+                }
+                updateSelectorState();
+            }
+        } else {
+            // Do not cancel the selected position if the selection is visible by other reasons.
+            if (!super.shouldShowSelector()) {
+                setSelectedPositionInt(INVALID_POSITION);
+            }
+        }
+        return super.onHoverEvent(ev);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        final int x = (int) event.getX();
+        final int y = (int) event.getY();
+        final int position = pointToPosition(x, y);
+        if (position == INVALID_POSITION) {
+            return super.onTouchEvent(event);
+        }
+
+        if (position != mSelectedPosition) {
+            setSelectedPositionInt(position);
+            setNextSelectedPositionInt(position);
+        }
+
+        return super.onTouchEvent(event);
+    }
+
     /**
      * Handles forwarded events.
      *
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index f994d4a..607e955 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1070,6 +1070,7 @@
                 child.setLayoutParams(p);
             }
             p.viewType = mAdapter.getItemViewType(0);
+            p.isEnabled = mAdapter.isEnabled(0);
             p.forceAdd = true;
 
             int childHeightSpec = getChildMeasureSpec(
@@ -1480,6 +1481,7 @@
             p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
         }
         p.viewType = mAdapter.getItemViewType(position);
+        p.isEnabled = mAdapter.isEnabled(position);
 
         if (recycled && !p.forceAdd) {
             attachViewToParent(child, where, p);
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 3d07d87..b95bc28 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -69,7 +69,6 @@
     private static final int EXPAND_LIST_TIMEOUT = 250;
 
     private Context mContext;
-    private PopupWindow mPopup;
     private ListAdapter mAdapter;
     private DropDownListView mDropDownList;
 
@@ -112,6 +111,8 @@
 
     private int mLayoutDirection;
 
+    PopupWindow mPopup;
+
     /**
      * The provided prompt view should appear above list content.
      * 
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index be83974..53ca6d1 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1200,6 +1200,7 @@
             child.setLayoutParams(p);
         }
         p.viewType = mAdapter.getItemViewType(position);
+        p.isEnabled = mAdapter.isEnabled(position);
         p.forceAdd = true;
 
         final int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
@@ -1913,6 +1914,7 @@
             p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
         }
         p.viewType = mAdapter.getItemViewType(position);
+        p.isEnabled = mAdapter.isEnabled(position);
 
         if ((recycled && !p.forceAdd) || (p.recycledHeaderFooter
                 && p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) {
diff --git a/core/java/android/widget/MenuPopupWindow.java b/core/java/android/widget/MenuPopupWindow.java
index 9e47e85..900aa32 100644
--- a/core/java/android/widget/MenuPopupWindow.java
+++ b/core/java/android/widget/MenuPopupWindow.java
@@ -17,10 +17,17 @@
 package android.widget;
 
 import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.transition.Transition;
 import android.util.AttributeSet;
-import android.view.MotionEvent;
+import android.view.KeyEvent;
 import android.view.View;
-import android.view.accessibility.AccessibilityManager;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+
+import com.android.internal.view.menu.ListMenuItemView;
+import com.android.internal.view.menu.MenuAdapter;
 
 /**
  * A MenuPopupWindow represents the popup window for menu.
@@ -40,52 +47,58 @@
         return new MenuDropDownListView(context, hijackFocus);
     }
 
-    static class MenuDropDownListView extends DropDownListView {
-        private boolean mHoveredOnDisabledItem = false;
-        private AccessibilityManager mAccessibilityManager;
-
-        MenuDropDownListView(Context context, boolean hijackFocus) {
-            super(context, hijackFocus);
-            mAccessibilityManager = (AccessibilityManager) getContext().getSystemService(
-                    Context.ACCESSIBILITY_SERVICE);
-        }
-
-        @Override
-        protected boolean shouldShowSelector() {
-            return (isHovered() && !mHoveredOnDisabledItem) || super.shouldShowSelector();
-        }
-
-        @Override
-        public boolean onHoverEvent(MotionEvent ev) {
-            mHoveredOnDisabledItem = false;
-
-            // Accessibility system should already handle hover events and selections, menu does
-            // not have to handle it by itself.
-            if (mAccessibilityManager.isTouchExplorationEnabled()) {
-                return super.onHoverEvent(ev);
-            }
-
-            final int action = ev.getActionMasked();
-            if (action == MotionEvent.ACTION_HOVER_ENTER
-                    || action == MotionEvent.ACTION_HOVER_MOVE) {
-                final int position = pointToPosition((int) ev.getX(), (int) ev.getY());
-                if (position != INVALID_POSITION && position != mSelectedPosition) {
-                    final View hoveredItem = getChildAt(position - getFirstVisiblePosition());
-                    if (hoveredItem.isEnabled()) {
-                        positionSelector(position, hoveredItem);
-                        setSelectedPositionInt(position);
-                    } else {
-                        mHoveredOnDisabledItem = true;
-                    }
-                    updateSelectorState();
-                }
-            } else {
-                // Do not cancel the selected position if the selection is visible by other reasons.
-                if (!super.shouldShowSelector()) {
-                    setSelectedPositionInt(INVALID_POSITION);
-                }
-            }
-            return super.onHoverEvent(ev);
-        }
+    public void setEnterTransition(Transition enterTransition) {
+        mPopup.setEnterTransition(enterTransition);
     }
-}
+
+    /**
+     * Set whether this window is touch modal or if outside touches will be sent to
+     * other windows behind it.
+     */
+    public void setTouchModal(boolean touchModal) {
+        mPopup.setTouchModal(touchModal);
+    }
+
+    private static class MenuDropDownListView extends DropDownListView {
+        final int mAdvanceKey;
+        final int mRetreatKey;
+
+        public MenuDropDownListView(Context context, boolean hijackFocus) {
+            super(context, hijackFocus);
+
+            final Resources res = context.getResources();
+            final Configuration config = res.getConfiguration();
+            if (config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+                mAdvanceKey = KeyEvent.KEYCODE_DPAD_LEFT;
+                mRetreatKey = KeyEvent.KEYCODE_DPAD_RIGHT;
+            } else {
+                mAdvanceKey = KeyEvent.KEYCODE_DPAD_RIGHT;
+                mRetreatKey = KeyEvent.KEYCODE_DPAD_LEFT;
+            }
+        }
+
+        @Override
+        public boolean onKeyDown(int keyCode, KeyEvent event) {
+            ListMenuItemView selectedItem = (ListMenuItemView) getSelectedView();
+            if (selectedItem != null && keyCode == mAdvanceKey) {
+                if (selectedItem.isEnabled() &&
+                        ((ListMenuItemView) selectedItem).getItemData().hasSubMenu()) {
+                    performItemClick(
+                            selectedItem,
+                            getSelectedItemPosition(),
+                            getSelectedItemId());
+                }
+                return true;
+            } else if (selectedItem != null && keyCode == mRetreatKey) {
+                setSelectedPositionInt(-1);
+                setNextSelectedPositionInt(-1);
+
+                ((MenuAdapter) getAdapter()).getAdapterMenu().close();
+                return true;
+            }
+            return super.onKeyDown(keyCode, event);
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index 3b2d60d..bd1fbb8 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -43,6 +43,7 @@
     private final MenuBuilder mMenu;
     private final View mAnchor;
     private final MenuPopupHelper mPopup;
+    private final boolean mShowCascadingMenus;
 
     private OnMenuItemClickListener mMenuItemClickListener;
     private OnDismissListener mDismissListener;
@@ -107,6 +108,8 @@
     public PopupMenu(Context context, View anchor, int gravity, int popupStyleAttr,
             int popupStyleRes) {
         mContext = context;
+        mShowCascadingMenus = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableCascadingSubmenus);
         mMenu = new MenuBuilder(context);
         mMenu.setCallback(this);
         mAnchor = anchor;
@@ -273,8 +276,12 @@
             return true;
         }
 
-        // Current menu will be dismissed by the normal helper, submenu will be shown in its place.
-        new MenuPopupHelper(mContext, subMenu, mAnchor).show();
+        if (!mShowCascadingMenus) {
+            // Current menu will be dismissed by the normal helper, submenu will be shown in its
+            // place. (If cascading menus are enabled, the cascading implementation will show the
+            // submenu itself).
+            new MenuPopupHelper(mContext, subMenu, mAnchor).show();
+        }
         return true;
     }
 
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 5fc8c7a..5b19edf 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -104,6 +104,7 @@
                                 sri.resultTargets);
                     }
                     unbindService(sri.connection);
+                    sri.connection.destroy();
                     mServiceConnections.remove(sri.connection);
                     if (mServiceConnections.isEmpty()) {
                         mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
@@ -208,6 +209,8 @@
             mRefinementResultReceiver.destroy();
             mRefinementResultReceiver = null;
         }
+        unbindRemainingServices();
+        mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_RESULT);
     }
 
     @Override
@@ -265,6 +268,11 @@
         return true;
     }
 
+    @Override
+    boolean shouldAutoLaunchSingleChoice() {
+        return false;
+    }
+
     private void modifyTargetIntent(Intent in) {
         final String action = in.getAction();
         if (Intent.ACTION_SEND.equals(action) ||
@@ -371,7 +379,8 @@
                     continue;
                 }
 
-                final ChooserTargetServiceConnection conn = new ChooserTargetServiceConnection(dri);
+                final ChooserTargetServiceConnection conn =
+                        new ChooserTargetServiceConnection(this, dri);
                 if (bindServiceAsUser(serviceIntent, conn, BIND_AUTO_CREATE | BIND_NOT_FOREGROUND,
                         UserHandle.CURRENT)) {
                     if (DEBUG) {
@@ -425,6 +434,7 @@
             final ChooserTargetServiceConnection conn = mServiceConnections.get(i);
             if (DEBUG) Log.d(TAG, "unbinding " + conn);
             unbindService(conn);
+            conn.destroy();
         }
         mServiceConnections.clear();
         mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
@@ -1024,54 +1034,93 @@
         }
     }
 
-    class ChooserTargetServiceConnection implements ServiceConnection {
+    static class ChooserTargetServiceConnection implements ServiceConnection {
         private final DisplayResolveInfo mOriginalTarget;
+        private ComponentName mConnectedComponent;
+        private ChooserActivity mChooserActivity;
+        private final Object mLock = new Object();
 
         private final IChooserTargetResult mChooserTargetResult = new IChooserTargetResult.Stub() {
             @Override
             public void sendResult(List<ChooserTarget> targets) throws RemoteException {
-                filterServiceTargets(mOriginalTarget.getResolveInfo().activityInfo.packageName,
-                        targets);
-                final Message msg = Message.obtain();
-                msg.what = CHOOSER_TARGET_SERVICE_RESULT;
-                msg.obj = new ServiceResultInfo(mOriginalTarget, targets,
-                        ChooserTargetServiceConnection.this);
-                mChooserHandler.sendMessage(msg);
+                synchronized (mLock) {
+                    if (mChooserActivity == null) {
+                        Log.e(TAG, "destroyed ChooserTargetServiceConnection received result from "
+                                + mConnectedComponent + "; ignoring...");
+                        return;
+                    }
+                    mChooserActivity.filterServiceTargets(
+                            mOriginalTarget.getResolveInfo().activityInfo.packageName, targets);
+                    final Message msg = Message.obtain();
+                    msg.what = CHOOSER_TARGET_SERVICE_RESULT;
+                    msg.obj = new ServiceResultInfo(mOriginalTarget, targets,
+                            ChooserTargetServiceConnection.this);
+                    mChooserActivity.mChooserHandler.sendMessage(msg);
+                }
             }
         };
 
-        public ChooserTargetServiceConnection(DisplayResolveInfo dri) {
+        public ChooserTargetServiceConnection(ChooserActivity chooserActivity,
+                DisplayResolveInfo dri) {
+            mChooserActivity = chooserActivity;
             mOriginalTarget = dri;
         }
 
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             if (DEBUG) Log.d(TAG, "onServiceConnected: " + name);
-            final IChooserTargetService icts = IChooserTargetService.Stub.asInterface(service);
-            try {
-                icts.getChooserTargets(mOriginalTarget.getResolvedComponentName(),
-                        mOriginalTarget.getResolveInfo().filter, mChooserTargetResult);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Querying ChooserTargetService " + name + " failed.", e);
-                unbindService(this);
-                mServiceConnections.remove(this);
+            synchronized (mLock) {
+                if (mChooserActivity == null) {
+                    Log.e(TAG, "destroyed ChooserTargetServiceConnection got onServiceConnected");
+                    return;
+                }
+
+                final IChooserTargetService icts = IChooserTargetService.Stub.asInterface(service);
+                try {
+                    icts.getChooserTargets(mOriginalTarget.getResolvedComponentName(),
+                            mOriginalTarget.getResolveInfo().filter, mChooserTargetResult);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Querying ChooserTargetService " + name + " failed.", e);
+                    mChooserActivity.unbindService(this);
+                    destroy();
+                    mChooserActivity.mServiceConnections.remove(this);
+                }
             }
         }
 
         @Override
         public void onServiceDisconnected(ComponentName name) {
             if (DEBUG) Log.d(TAG, "onServiceDisconnected: " + name);
-            unbindService(this);
-            mServiceConnections.remove(this);
-            if (mServiceConnections.isEmpty()) {
-                mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
-                sendVoiceChoicesIfNeeded();
+            synchronized (mLock) {
+                if (mChooserActivity == null) {
+                    Log.e(TAG,
+                            "destroyed ChooserTargetServiceConnection got onServiceDisconnected");
+                    return;
+                }
+
+                mChooserActivity.unbindService(this);
+                destroy();
+                mChooserActivity.mServiceConnections.remove(this);
+                if (mChooserActivity.mServiceConnections.isEmpty()) {
+                    mChooserActivity.mChooserHandler.removeMessages(
+                            CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
+                    mChooserActivity.sendVoiceChoicesIfNeeded();
+                }
+                mConnectedComponent = null;
+            }
+        }
+
+        public void destroy() {
+            synchronized (mLock) {
+                mChooserActivity = null;
             }
         }
 
         @Override
         public String toString() {
-            return mOriginalTarget.getResolveInfo().activityInfo.toString();
+            return "ChooserTargetServiceConnection{service="
+                    + mConnectedComponent + ", activity="
+                    + mOriginalTarget.getResolveInfo().activityInfo.toString() + "}";
         }
     }
 
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 7dd3bed..9272193 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -234,7 +234,9 @@
 
         mResolverComparator = new ResolverComparator(this, getTargetIntent(), referrerPackage);
 
-        configureContentView(mIntents, initialIntents, rList, alwaysUseOption);
+        if (configureContentView(mIntents, initialIntents, rList, alwaysUseOption)) {
+            return;
+        }
 
         // Prevent the Resolver window from becoming the top fullscreen window and thus from taking
         // control of the system bars.
@@ -794,6 +796,10 @@
         return false;
     }
 
+    boolean shouldAutoLaunchSingleChoice() {
+        return true;
+    }
+
     void showAppDetails(ResolveInfo ri) {
         Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                 .setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
@@ -808,7 +814,10 @@
                 launchedFromUid, filterLastUsed);
     }
 
-    void configureContentView(List<Intent> payloadIntents, Intent[] initialIntents,
+    /**
+     * Returns true if the activity is finishing and creation should halt
+     */
+    boolean configureContentView(List<Intent> payloadIntents, Intent[] initialIntents,
             List<ResolveInfo> rList, boolean alwaysUseOption) {
         // The last argument of createAdapter is whether to do special handling
         // of the last used choice to highlight it in the list.  We need to always
@@ -828,7 +837,9 @@
         mAlwaysUseOption = alwaysUseOption;
 
         int count = mAdapter.getUnfilteredCount();
-        if (count > 1 || (count == 1 && mAdapter.getOtherProfile() != null)) {
+        if ((!shouldAutoLaunchSingleChoice() && count > 0)
+                || count > 1
+                || (count == 1 && mAdapter.getOtherProfile() != null)) {
             setContentView(layoutId);
             mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
             onPrepareAdapterView(mAdapterView, mAdapter, alwaysUseOption);
@@ -837,7 +848,7 @@
             mPackageMonitor.unregister();
             mRegistered = false;
             finish();
-            return;
+            return true;
         } else {
             setContentView(R.layout.resolver_list);
 
@@ -847,6 +858,7 @@
             mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
             mAdapterView.setVisibility(View.GONE);
         }
+        return false;
     }
 
     void onPrepareAdapterView(AbsListView adapterView, ResolveListAdapter adapter,
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 6da0f63..b6240e4 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -44,6 +44,8 @@
     public static final int ACTION_FINGERPRINT_AUTH = 252;
     public static final int ACTION_FINGERPRINT_DELETE = 253;
     public static final int ACTION_FINGERPRINT_RENAME = 254;
+    public static final int ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255;
+    public static final int ACTION_WIGGLE_CAMERA_GESTURE = 256;
 
     public static void visible(Context context, int category) throws IllegalArgumentException {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 55e23b1..7f01841 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -174,6 +174,7 @@
     // buttons. The visibility of this decor depends on the workspace and the window type.
     // If the window type does not require such a view, this member might be null.
     NonClientDecorView mNonClientDecorView;
+
     // The non client decor needs to adapt to the used workspace. Since querying and changing the
     // workspace is expensive, this is the workspace value the window is currently set up for.
     int mWorkspaceId;
@@ -2495,6 +2496,10 @@
             return onInterceptTouchEvent(event);
         }
 
+        private boolean isOutOfInnerBounds(int x, int y) {
+            return x < 0 || y < 0 || x > getWidth() || y > getHeight();
+        }
+
         private boolean isOutOfBounds(int x, int y) {
             return x < -5 || y < -5 || x > (getWidth() + 5)
                     || y > (getHeight() + 5);
@@ -2503,6 +2508,24 @@
         @Override
         public boolean onInterceptTouchEvent(MotionEvent event) {
             int action = event.getAction();
+            if (mHasNonClientDecor && mNonClientDecorView.mVisible) {
+                // Don't dispatch ACTION_DOWN to the non client decor if the window is
+                // resizable and the event was (starting) outside the window.
+                // Window resizing events should be handled by WindowManager.
+                // TODO: Investigate how to handle the outside touch in window manager
+                //       without generating these events.
+                //       Currently we receive these because we need to enlarge the window's
+                //       touch region so that the monitor channel receives the events
+                //       in the outside touch area.
+                if (action == MotionEvent.ACTION_DOWN) {
+                    final int x = (int) event.getX();
+                    final int y = (int) event.getY();
+                    if (isOutOfInnerBounds(x, y)) {
+                        return true;
+                    }
+                }
+            }
+
             if (mFeatureId >= 0) {
                 if (action == MotionEvent.ACTION_DOWN) {
                     int x = (int)event.getX();
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
new file mode 100644
index 0000000..4c829a2
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -0,0 +1,394 @@
+package com.android.internal.view.menu;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.annotation.IntDef;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.os.Parcelable;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnKeyListener;
+import android.widget.AdapterView;
+import android.widget.DropDownListView;
+import android.widget.ListView;
+import android.widget.MenuPopupWindow;
+import android.widget.PopupWindow;
+import android.widget.PopupWindow.OnDismissListener;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A popup for a menu which will allow multiple submenus to appear in a cascading fashion, side by
+ * side.
+ * @hide
+ */
+final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemClickListener,
+        MenuPresenter, OnKeyListener, PopupWindow.OnDismissListener {
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({HORIZ_POSITION_LEFT, HORIZ_POSITION_RIGHT})
+    public @interface HorizPosition {}
+
+    private static final int HORIZ_POSITION_LEFT = 0;
+    private static final int HORIZ_POSITION_RIGHT = 1;
+
+    private final Context mContext;
+    private final int mMenuMaxWidth;
+    private final int mPopupStyleAttr;
+    private final int mPopupStyleRes;
+    private final boolean mOverflowOnly;
+    private final int mLayoutDirection;
+
+    private int mDropDownGravity = Gravity.NO_GRAVITY;
+    private View mAnchor;
+    private List<DropDownListView> mListViews;
+    private List<MenuPopupWindow> mPopupWindows;
+    private List<int[]> mOffsets;
+    private int mPreferredPosition;
+    private boolean mForceShowIcon;
+    private Callback mPresenterCallback;
+    private PopupWindow.OnDismissListener mOnDismissListener;
+
+    /**
+     * Initializes a new cascading-capable menu popup.
+     *
+     * @param parent A parent view to get the {@link android.view.View#getWindowToken()} token from.
+     */
+    public CascadingMenuPopup(Context context, View anchor, int popupStyleAttr,
+            int popupStyleRes, boolean overflowOnly) {
+        mContext = Preconditions.checkNotNull(context);
+        mAnchor = Preconditions.checkNotNull(anchor);
+        mPopupStyleAttr = popupStyleAttr;
+        mPopupStyleRes = popupStyleRes;
+        mOverflowOnly = overflowOnly;
+
+        mForceShowIcon = false;
+
+        final Resources res = context.getResources();
+        final Configuration config = res.getConfiguration();
+        mLayoutDirection = config.getLayoutDirection();
+        mPreferredPosition = mLayoutDirection == View.LAYOUT_DIRECTION_RTL ? HORIZ_POSITION_LEFT :
+                HORIZ_POSITION_RIGHT;
+        mMenuMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
+                res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
+
+        mPopupWindows = new ArrayList<MenuPopupWindow>();
+        mListViews = new ArrayList<DropDownListView>();
+        mOffsets = new ArrayList<int[]>();
+    }
+
+    @Override
+    public void setForceShowIcon(boolean forceShow) {
+        mForceShowIcon = forceShow;
+    }
+
+    private MenuPopupWindow createPopupWindow() {
+        MenuPopupWindow popupWindow = new MenuPopupWindow(
+                mContext, null, mPopupStyleAttr, mPopupStyleRes);
+        popupWindow.setOnItemClickListener(this);
+        popupWindow.setOnDismissListener(this);
+        popupWindow.setAnchorView(mAnchor);
+        popupWindow.setDropDownGravity(mDropDownGravity);
+        popupWindow.setModal(true);
+        popupWindow.setTouchModal(false);
+        return popupWindow;
+    }
+
+    @Override
+    public void show() {
+        if (isShowing()) {
+            return;
+        }
+
+        // Show any menus that have been added via #addMenu(MenuBuilder) but which have not yet been
+        // shown.
+        // In a typical use case, #addMenu(MenuBuilder) would be called once, followed by a call to
+        // this #show() method -- which would actually show the popup on the screen.
+        for (int i = 0; i < mPopupWindows.size(); i++) {
+            MenuPopupWindow popupWindow = mPopupWindows.get(i);
+            popupWindow.show();
+            mListViews.add((DropDownListView) popupWindow.getListView());
+        }
+    }
+
+    @Override
+    public void dismiss() {
+        // Need to make another list to avoid a concurrent modification exception, as #onDismiss
+        // may clear mPopupWindows while we are iterating.
+        List<MenuPopupWindow> popupWindows = new ArrayList<MenuPopupWindow>(mPopupWindows);
+        for (MenuPopupWindow popupWindow : popupWindows) {
+            if (popupWindow != null && popupWindow.isShowing()) {
+                popupWindow.dismiss();
+            }
+        }
+    }
+
+    @Override
+    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        MenuAdapter adapter = (MenuAdapter) parent.getAdapter();
+        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;
+    }
+
+    /**
+     * Determines whether the next submenu (of the given width) should display on the right or on
+     * the left of the most recent menu.
+     *
+     * @param nextMenuWidth Width of the next submenu to display.
+     * @return The position to display it.
+     */
+    @HorizPosition
+    private int getNextMenuPosition(int nextMenuWidth) {
+        ListView lastListView = mListViews.get(mListViews.size() - 1);
+
+        final int[] screenLocation = new int[2];
+        lastListView.getLocationOnScreen(screenLocation);
+
+        final Rect displayFrame = new Rect();
+        mAnchor.getWindowVisibleDisplayFrame(displayFrame);
+
+        if (mPreferredPosition == HORIZ_POSITION_RIGHT) {
+            final int right = screenLocation[0] + lastListView.getWidth() + nextMenuWidth;
+            if (right > displayFrame.right) {
+                return HORIZ_POSITION_LEFT;
+            }
+            return HORIZ_POSITION_RIGHT;
+        } else { // LEFT
+            final int left = screenLocation[0] - nextMenuWidth;
+            if (left < 0) {
+                return HORIZ_POSITION_RIGHT;
+            }
+            return HORIZ_POSITION_LEFT;
+        }
+    }
+
+    @Override
+    public void addMenu(MenuBuilder menu) {
+        boolean addSubMenu = mListViews.size() > 0;
+
+        menu.addMenuPresenter(this, mContext);
+
+        MenuPopupWindow popupWindow = createPopupWindow();
+
+        MenuAdapter adapter = new MenuAdapter(menu, LayoutInflater.from(mContext), mOverflowOnly);
+        adapter.setForceShowIcon(mForceShowIcon);
+
+        popupWindow.setAdapter(adapter);
+
+        int menuWidth = measureIndividualMenuWidth(adapter, null, mContext, mMenuMaxWidth);
+
+        int x = 0;
+        int y = 0;
+
+        if (addSubMenu) {
+            popupWindow.setEnterTransition(null);
+
+            ListView lastListView = mListViews.get(mListViews.size() - 1);
+            @HorizPosition int nextMenuPosition = getNextMenuPosition(menuWidth);
+            boolean showOnRight = nextMenuPosition == HORIZ_POSITION_RIGHT;
+            mPreferredPosition = nextMenuPosition;
+
+            int[] lastLocation = new int[2];
+            lastListView.getLocationOnScreen(lastLocation);
+
+            int[] lastOffset = mOffsets.get(mOffsets.size() - 1);
+
+            // Note: By now, mDropDownGravity is the absolute gravity, so this should work in both
+            // LTR and RTL.
+            if ((mDropDownGravity & Gravity.RIGHT) == Gravity.RIGHT) {
+                if (showOnRight) {
+                    x = lastOffset[0] + menuWidth;
+                } else {
+                    x = lastOffset[0] - lastListView.getWidth();
+                }
+            } else {
+                if (showOnRight) {
+                    x = lastOffset[0] + lastListView.getWidth();
+                } else {
+                    x = lastOffset[0] - menuWidth;
+                }
+            }
+
+            y = lastOffset[1] + lastListView.getSelectedView().getTop() -
+                    lastListView.getChildAt(0).getTop();
+        }
+
+        popupWindow.setWidth(menuWidth);
+        popupWindow.setHorizontalOffset(x);
+        popupWindow.setVerticalOffset(y);
+        mPopupWindows.add(popupWindow);
+
+        // NOTE: This case handles showing submenus once the CascadingMenuPopup has already
+        // been shown via a call to its #show() method. If it hasn't yet been show()n, then
+        // we deliberately do not yet show the popupWindow, as #show() will do that later.
+        if (isShowing()) {
+            popupWindow.show();
+            mListViews.add((DropDownListView) popupWindow.getListView());
+        }
+
+        int[] offsets = {x, y};
+        mOffsets.add(offsets);
+    }
+
+    /**
+     * @return {@code true} if the popup is currently showing, {@code false} otherwise.
+     */
+    @Override
+    public boolean isShowing() {
+        return mPopupWindows.size() > 0 && mPopupWindows.get(0).isShowing();
+    }
+
+    /**
+     * Called when one or more of the popup windows was dismissed.
+     */
+    @Override
+    public void onDismiss() {
+        int dismissedIndex = -1;
+        for (int i = 0; i < mPopupWindows.size(); i++) {
+            if (!mPopupWindows.get(i).isShowing()) {
+                dismissedIndex = i;
+                break;
+            }
+        }
+
+        if (dismissedIndex != -1) {
+            for (int i = dismissedIndex; i < mListViews.size(); i++) {
+                ListView view = mListViews.get(i);
+                MenuAdapter adapter = (MenuAdapter) view.getAdapter();
+                adapter.mAdapterMenu.close();
+            }
+        }
+    }
+
+    @Override
+    public void updateMenuView(boolean cleared) {
+        for (ListView view : mListViews) {
+            ((MenuAdapter) view.getAdapter()).notifyDataSetChanged();
+        }
+    }
+
+    @Override
+    public void setCallback(Callback cb) {
+        mPresenterCallback = cb;
+    }
+
+    @Override
+    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+        // Don't allow double-opening of the same submenu.
+        for (ListView view : mListViews) {
+            if (((MenuAdapter) view.getAdapter()).mAdapterMenu.equals(subMenu)) {
+                // Just re-focus that one.
+                view.requestFocus();
+                return true;
+            }
+        }
+
+        if (subMenu.hasVisibleItems()) {
+            this.addMenu(subMenu);
+            if (mPresenterCallback != null) {
+                mPresenterCallback.onOpenSubMenu(subMenu);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+        int menuIndex = -1;
+        boolean wasSelected = false;
+
+        for (int i = 0; i < mListViews.size(); i++) {
+            ListView view = mListViews.get(i);
+            MenuAdapter adapter = (MenuAdapter) view.getAdapter();
+
+            if (menuIndex == -1 && menu == adapter.mAdapterMenu) {
+                menuIndex = i;
+                wasSelected = view.getSelectedItem() != null;
+            }
+
+            // Once the menu has been found, remove it and all submenus beneath it from the
+            // container view. Also remove the presenter.
+            if (menuIndex != -1) {
+                adapter.mAdapterMenu.removeMenuPresenter(this);
+            }
+        }
+
+        // Then, actually remove the views for these [sub]menu(s) from our list of views.
+        if (menuIndex != -1) {
+            for (int i = menuIndex; i < mPopupWindows.size(); i++) {
+                mPopupWindows.get(i).dismiss();
+            }
+            mPopupWindows.subList(menuIndex, mPopupWindows.size()).clear();
+            mListViews.subList(menuIndex, mListViews.size()).clear();
+            mOffsets.subList(menuIndex, mOffsets.size()).clear();
+
+            // If there's still a menu open, refocus the new leaf [sub]menu.
+            if (mListViews.size() > 0) {
+                mListViews.get(mListViews.size() - 1).requestFocus();
+            }
+        }
+
+        if (mListViews.size() == 0 || wasSelected) {
+            dismiss();
+            if (mPresenterCallback != null) {
+                mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
+            }
+        }
+
+        if (mPopupWindows.size() == 0) {
+            // If every [sub]menu was dismissed, that means the whole thing was dismissed, so notify
+            // the owner.
+            mOnDismissListener.onDismiss();
+        }
+    }
+
+    @Override
+    public boolean flagActionItems() {
+        return false;
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        return null;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+    }
+
+    @Override
+    public void setGravity(int dropDownGravity) {
+        mDropDownGravity = Gravity.getAbsoluteGravity(dropDownGravity, mLayoutDirection);
+    }
+
+    @Override
+    public void setAnchorView(View anchor) {
+        mAnchor = anchor;
+    }
+
+    @Override
+    public void setOnDismissListener(OnDismissListener listener) {
+        mOnDismissListener = listener;
+    }
+
+    @Override
+    public ListView getListView() {
+        return mListViews.size() > 0 ? mListViews.get(mListViews.size() - 1) : null;
+    }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index e8d1ead..1673928 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -64,6 +64,7 @@
 
     private final Context mContext;
     private final Resources mResources;
+    private final boolean mShowCascadingMenus;
 
     /**
      * Whether the shortcuts should be qwerty-accessible. Use isQwertyMode()
@@ -186,6 +187,8 @@
     public MenuBuilder(Context context) {
         mContext = context;
         mResources = context.getResources();
+        mShowCascadingMenus = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableCascadingSubmenus);
         
         mItems = new ArrayList<MenuItemImpl>();
         
@@ -909,7 +912,9 @@
             invoked |= itemImpl.expandActionView();
             if (invoked) close(true);
         } else if (itemImpl.hasSubMenu() || providerHasSubMenu) {
-            close(false);
+            if (!mShowCascadingMenus) {
+                close(false);
+            }
 
             if (!itemImpl.hasSubMenu()) {
                 itemImpl.setSubMenu(new SubMenuBuilder(getContext(), this, itemImpl));
diff --git a/core/java/com/android/internal/view/menu/MenuPopup.java b/core/java/com/android/internal/view/menu/MenuPopup.java
index 91788ca..b43e8ad 100644
--- a/core/java/com/android/internal/view/menu/MenuPopup.java
+++ b/core/java/com/android/internal/view/menu/MenuPopup.java
@@ -35,9 +35,11 @@
     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).
+     * Adds the given menu to the popup, if it is capable of displaying submenus within itself.
+     * If menu is the first menu shown, it won't be displayed until show() is called.
+     * If the popup was already showing, adding a submenu via this method will cause that new
+     * submenu to be shown immediately (that is, if this MenuPopup implementation is capable of
+     * showing its own submenus).
      *
      * @param menu
      */
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 9a47fc1..e0d7fee 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -17,10 +17,8 @@
 package com.android.internal.view.menu;
 
 import android.content.Context;
-import android.os.Parcelable;
 import android.view.Gravity;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.widget.PopupWindow;
 
@@ -30,7 +28,7 @@
  * @hide
  */
 public class MenuPopupHelper implements ViewTreeObserver.OnGlobalLayoutListener,
-        PopupWindow.OnDismissListener, View.OnAttachStateChangeListener, MenuPresenter {
+        PopupWindow.OnDismissListener, View.OnAttachStateChangeListener {
     private final Context mContext;
     private final MenuBuilder mMenu;
     private final boolean mOverflowOnly;
@@ -70,9 +68,8 @@
     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 CascadingMenuPopup(mContext, mAnchorView, mPopupStyleAttr, mPopupStyleRes,
+                    mOverflowOnly);
         }
         return new StandardMenuPopup(
                 mContext, mMenu, mAnchorView, mPopupStyleAttr, mPopupStyleRes, mOverflowOnly);
@@ -187,62 +184,7 @@
         v.removeOnAttachStateChangeListener(this);
     }
 
-    @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("MenuPopupHelpers manage their own views");
-    }
-
-    @Override
-    public void updateMenuView(boolean cleared) {
-        mPopup.updateMenuView(cleared);
-    }
-
-    @Override
-    public void setCallback(Callback cb) {
+    public void setCallback(MenuPresenter.Callback cb) {
         mPopup.setCallback(cb);
     }
-
-    @Override
-    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
-        return mPopup.onSubMenuSelected(subMenu);
-    }
-
-    @Override
-    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
-        mPopup.onCloseMenu(menu, allMenusAreClosing);
-    }
-
-    @Override
-    public boolean flagActionItems() {
-        return false;
-    }
-
-    @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;
-    }
-
-    @Override
-    public Parcelable onSaveInstanceState() {
-        return null;
-    }
-
-    @Override
-    public void onRestoreInstanceState(Parcelable state) {
-    }
 }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index d96a909..6a98ec7 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1178,7 +1178,7 @@
      * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
      */
     public void requireCredentialEntry(int userId) {
-        requireStrongAuth(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
+        requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
     }
 
     /**
@@ -1260,7 +1260,7 @@
                 value = { STRONG_AUTH_NOT_REQUIRED,
                         STRONG_AUTH_REQUIRED_AFTER_BOOT,
                         STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
-                        STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST})
+                        SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
         @Retention(RetentionPolicy.SOURCE)
         public @interface StrongAuthFlags {}
 
@@ -1275,14 +1275,14 @@
         public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
 
         /**
-         * Strong authentication is required because a device admin has temporarily requested it.
+         * Strong authentication is required because a device admin has requested it.
          */
         public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
 
         /**
-         * Strong authentication is required because the user has temporarily requested it.
+         * Some authentication is required because the user has temporarily disabled trust.
          */
-        public static final int STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
+        public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
 
         /**
          * Strong authentication is required because the user has been locked out after too many
@@ -1298,6 +1298,7 @@
         public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT;
 
         private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
+                | SOME_AUTH_REQUIRED_AFTER_USER_REQUEST
                 | SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL;
 
         private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java
index 491b323..6ab306c 100644
--- a/core/java/com/android/internal/widget/NonClientDecorView.java
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -26,7 +26,6 @@
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
 import android.view.Window;
-import android.view.WindowInsets;
 import android.util.Log;
 import android.util.TypedValue;
 
@@ -71,16 +70,11 @@
     // True if the window is being dragged.
     private boolean mDragging = false;
 
-    // The bounds of the window and the absolute mouse pointer coordinates from before we started to
-    // drag the window. They will be used to determine the next window position.
-    private final Rect mWindowOriginalBounds = new Rect();
-    private float mStartDragX;
-    private float mStartDragY;
     // True when the left mouse button got released while dragging.
     private boolean mLeftMouseButtonReleased;
 
-    // Avoiding re-creation of Rect's by keeping a temporary window drag bound.
-    private final Rect mWindowDragBounds = new Rect();
+    // True if this window is resizable (which is currently only true when the decor is shown).
+    public boolean mVisible = false;
 
     // The current focus state of the window for updating the window elevation.
     private boolean mWindowHasFocus = true;
@@ -128,18 +122,14 @@
                     // When there is no decor we should not react to anything.
                     return false;
                 }
-                // Ensure that the activity is active.
-                activateActivity();
                 // A drag action is started if we aren't dragging already and the starting event is
                 // either a left mouse button or any other input device.
                 if (!mDragging &&
                         (e.getToolType(e.getActionIndex()) != MotionEvent.TOOL_TYPE_MOUSE ||
                                 (e.getButtonState() & MotionEvent.BUTTON_PRIMARY) != 0)) {
                     mDragging = true;
-                    mWindowOriginalBounds.set(getActivityBounds());
                     mLeftMouseButtonReleased = false;
-                    mStartDragX = e.getRawX();
-                    mStartDragY = e.getRawY();
+                    startMovingTask(e.getRawX(), e.getRawY());
                 }
                 break;
 
@@ -152,29 +142,17 @@
                         mLeftMouseButtonReleased = true;
                         break;
                     }
-                    mWindowDragBounds.set(mWindowOriginalBounds);
-                    mWindowDragBounds.offset(Math.round(e.getRawX() - mStartDragX),
-                            Math.round(e.getRawY() - mStartDragY));
-                    setActivityBounds(mWindowDragBounds);
                 }
                 break;
 
             case MotionEvent.ACTION_UP:
-                if (mDragging) {
-                    // Since the window is already where it should be we don't have to do anything
-                    // special at this time.
-                    mDragging = false;
-                    return true;
-                }
-                break;
-
             case MotionEvent.ACTION_CANCEL:
-                if (mDragging) {
-                    mDragging = false;
-                    setActivityBounds(mWindowOriginalBounds);
-                    return true;
+                if (!mDragging) {
+                    break;
                 }
-                break;
+                // Abort the ongoing dragging.
+                mDragging = false;
+                return true;
         }
         return mDragging;
     }
@@ -246,6 +224,7 @@
         boolean invisible = isFillingScreen() || !mShowDecor;
         View caption = getChildAt(0);
         caption.setVisibility(invisible ? GONE : VISIBLE);
+        mVisible = !invisible;
     }
 
     /**
@@ -312,54 +291,4 @@
             }
         }
     }
-
-    /**
-     * Returns the bounds of this activity.
-     * @return Returns bounds of the activity. It will return null if either the window is
-     *     fullscreen or the bounds could not be retrieved.
-     */
-    private Rect getActivityBounds() {
-        Window.WindowControllerCallback callback = mOwner.getWindowControllerCallback();
-        if (callback != null) {
-            try {
-                return callback.getActivityBounds();
-            } catch (RemoteException ex) {
-                Log.e(TAG, "Failed to get the activity bounds.");
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Sets the bounds of this Activity on the stack.
-     * @param newBounds The bounds of the activity. Passing null is not allowed.
-     */
-    private void setActivityBounds(Rect newBounds) {
-        if (newBounds == null) {
-            Log.e(TAG, "Failed to set null bounds to the activity.");
-            return;
-        }
-        Window.WindowControllerCallback callback = mOwner.getWindowControllerCallback();
-        if (callback != null) {
-            try {
-                callback.setActivityBounds(newBounds);
-            } catch (RemoteException ex) {
-                Log.e(TAG, "Failed to set the activity bounds.");
-            }
-        }
-    }
-
-    /**
-     * Activates the activity - means setting the focus and moving it to the top of the stack.
-     */
-    private void activateActivity() {
-        Window.WindowControllerCallback callback = mOwner.getWindowControllerCallback();
-        if (callback != null) {
-            try {
-                callback.activateActivity();
-            } catch (RemoteException ex) {
-                Log.e(TAG, "Failed to activate the activity.");
-            }
-        }
-    }
 }
diff --git a/core/java/com/android/server/backup/NotificationBackupHelper.java b/core/java/com/android/server/backup/NotificationBackupHelper.java
index 6f5c7e8..0d225e8 100644
--- a/core/java/com/android/server/backup/NotificationBackupHelper.java
+++ b/core/java/com/android/server/backup/NotificationBackupHelper.java
@@ -46,7 +46,8 @@
             try {
                 INotificationManager nm = INotificationManager.Stub.asInterface(
                         ServiceManager.getService("notification"));
-                newPayload = nm.getBackupPayload(UserHandle.USER_OWNER);
+                // TODO: http://b/22388012
+                newPayload = nm.getBackupPayload(UserHandle.USER_SYSTEM);
             } catch (Exception e) {
                 // Treat as no data
                 Slog.e(TAG, "Couldn't communicate with notification manager");
@@ -66,7 +67,8 @@
             try {
                 INotificationManager nm = INotificationManager.Stub.asInterface(
                         ServiceManager.getService("notification"));
-                nm.applyRestore(payload, UserHandle.USER_OWNER);
+                // TODO: http://b/22388012
+                nm.applyRestore(payload, UserHandle.USER_SYSTEM);
             } catch (Exception e) {
                 Slog.e(TAG, "Couldn't communicate with notification manager");
             }
diff --git a/core/java/com/android/server/backup/PreferredActivityBackupHelper.java b/core/java/com/android/server/backup/PreferredActivityBackupHelper.java
index 458a2ca..8063670 100644
--- a/core/java/com/android/server/backup/PreferredActivityBackupHelper.java
+++ b/core/java/com/android/server/backup/PreferredActivityBackupHelper.java
@@ -52,13 +52,14 @@
             Slog.d(TAG, "Handling backup of " + key);
         }
         try {
+            // TODO: http://b/22388012
             switch (key) {
                 case KEY_PREFERRED:
-                    return pm.getPreferredActivityBackup(UserHandle.USER_OWNER);
+                    return pm.getPreferredActivityBackup(UserHandle.USER_SYSTEM);
                 case KEY_DEFAULT_APPS:
-                    return pm.getDefaultAppsBackup(UserHandle.USER_OWNER);
+                    return pm.getDefaultAppsBackup(UserHandle.USER_SYSTEM);
                 case KEY_INTENT_VERIFICATION:
-                    return pm.getIntentFilterVerificationBackup(UserHandle.USER_OWNER);
+                    return pm.getIntentFilterVerificationBackup(UserHandle.USER_SYSTEM);
                 default:
                     Slog.w(TAG, "Unexpected backup key " + key);
             }
@@ -75,15 +76,16 @@
             Slog.d(TAG, "Handling restore of " + key);
         }
         try {
+            // TODO: http://b/22388012
             switch (key) {
                 case KEY_PREFERRED:
-                    pm.restorePreferredActivities(payload, UserHandle.USER_OWNER);
+                    pm.restorePreferredActivities(payload, UserHandle.USER_SYSTEM);
                     break;
                 case KEY_DEFAULT_APPS:
-                    pm.restoreDefaultApps(payload, UserHandle.USER_OWNER);
+                    pm.restoreDefaultApps(payload, UserHandle.USER_SYSTEM);
                     break;
                 case KEY_INTENT_VERIFICATION:
-                    pm.restoreIntentFilterVerification(payload, UserHandle.USER_OWNER);
+                    pm.restoreIntentFilterVerification(payload, UserHandle.USER_SYSTEM);
                     break;
                 default:
                     Slog.w(TAG, "Unexpected restore key " + key);
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index f485460b..234815f 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -54,13 +54,15 @@
     private static final String WALLPAPER_INFO_FILENAME = "wallpaper_info.xml";
 
     // TODO: Will need to change if backing up non-primary user's wallpaper
+    // TODO: http://b/22388012
     private static final String WALLPAPER_IMAGE_DIR =
-            Environment.getUserSystemDirectory(UserHandle.USER_OWNER).getAbsolutePath();
+            Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM).getAbsolutePath();
     private static final String WALLPAPER_IMAGE = WallpaperBackupHelper.WALLPAPER_IMAGE;
 
     // TODO: Will need to change if backing up non-primary user's wallpaper
+    // TODO: http://b/22388012
     private static final String WALLPAPER_INFO_DIR =
-            Environment.getUserSystemDirectory(UserHandle.USER_OWNER).getAbsolutePath();
+            Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM).getAbsolutePath();
     private static final String WALLPAPER_INFO = WallpaperBackupHelper.WALLPAPER_INFO;
     // Use old keys to keep legacy data compatibility and avoid writing two wallpapers
     private static final String WALLPAPER_IMAGE_KEY = WallpaperBackupHelper.WALLPAPER_IMAGE_KEY;
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 9aa544f..7ca0654 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -510,7 +510,7 @@
 }
 
 static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
-                                                       jstring path)
+                                                       jstring path, jboolean appAsLib)
 {
     ScopedUtfChars path8(env, path);
     if (path8.c_str() == NULL) {
@@ -523,7 +523,7 @@
     }
 
     int32_t cookie;
-    bool res = am->addAssetPath(String8(path8.c_str()), &cookie);
+    bool res = am->addAssetPath(String8(path8.c_str()), &cookie, appAsLib);
 
     return (res) ? static_cast<jint>(cookie) : 0;
 }
@@ -2138,7 +2138,7 @@
         (void*) android_content_AssetManager_getAssetLength },
     { "getAssetRemainingLength", "(J)J",
         (void*) android_content_AssetManager_getAssetRemainingLength },
-    { "addAssetPathNative", "(Ljava/lang/String;)I",
+    { "addAssetPathNative", "(Ljava/lang/String;Z)I",
         (void*) android_content_AssetManager_addAssetPath },
     { "addOverlayPathNative",   "(Ljava/lang/String;)I",
         (void*) android_content_AssetManager_addOverlayPath },
diff --git a/core/res/res/layout/calendar_view.xml b/core/res/res/layout/calendar_view.xml
index bccb056..5b32a392 100644
--- a/core/res/res/layout/calendar_view.xml
+++ b/core/res/res/layout/calendar_view.xml
@@ -28,7 +28,7 @@
         android:layout_gravity="center_horizontal"
         android:paddingTop="10dip"
         android:paddingBottom="10dip"
-        style="@android:style/TextAppearance.Medium" />
+        style="?android:attr/textAppearanceMedium" />
 
     <LinearLayout android:id="@+android:id/day_names"
         android:orientation="horizontal"
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 9b65882..bb44ed30 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -890,7 +890,7 @@
     <string name="whichHomeApplication" msgid="4307587691506919691">"Selecciona una aplicación de inicio"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Usar %1$s como aplicación de inicio"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Usar siempre para esta acción"</string>
-    <string name="use_a_different_app" msgid="8134926230585710243">"Uitliza otra aplicación"</string>
+    <string name="use_a_different_app" msgid="8134926230585710243">"Utiliza otra aplicación"</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Para borrar los valores predeterminados, accede a Ajustes del sistema &gt; Aplicaciones &gt; Descargadas."</string>
     <string name="chooseActivity" msgid="7486876147751803333">"Selecciona una acción"</string>
     <string name="chooseUsbActivity" msgid="6894748416073583509">"Elegir una aplicación para el dispositivo USB"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 2e3c569..6c03159 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1436,7 +1436,7 @@
     <string name="package_installed_device_owner" msgid="8420696545959087545">"توسط سرپرستتان نصب شد"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"توسط سرپرست شما به‌روزرسانی شد"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"توسط سرپرستتان حذف شد"</string>
-    <string name="battery_saver_description" msgid="1960431123816253034">"برای کمک به بهبود ماندگاری باتری، ذخیره کننده باتری عملکرد دستگاهتان را کاهش می‌دهد و لرزش، سرویس‌های مبتنی بر مکان، و دسترسی به اکثر داده‌ها در پس‌زمینه را محدود می‌کند. ایمیل، پیام‌رسانی و برنامه‌های دیگری که به همگام‌سازی متکی هستند، تا زمانی‌که آن‌ها را باز نکنید نمی‌توانند به‌روز شوند.\n\nذخیره کننده باتری به‌صورت خودکار در هنگام شارژ شدن دستگاه خاموش می‌شود."</string>
+    <string name="battery_saver_description" msgid="1960431123816253034">"برای کمک به بهبود عمر باتری، بهینه‌سازی باتری عملکرد دستگاهتان را کاهش می‌دهد و لرزش، سرویس‌های مبتنی بر مکان، و دسترسی به اکثر داده‌ها در پس‌زمینه را محدود می‌کند. ایمیل، پیام‌رسانی و برنامه‌های دیگری که به همگام‌سازی وابسته‌اند، تا زمانی‌که آن‌ها را باز نکنید نمی‌توانند به‌روز شوند.\n\nبهینه‌سازی باتری به‌صورت خودکار در هنگام شارژ شدن دستگاه خاموش می‌شود."</string>
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">‏به مدت %1$d دقیقه (تا <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="other">‏به مدت %1$d دقیقه (تا <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 37d9bac..bf046e3 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -350,8 +350,8 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Uygulamaya kamerayla fotoğraf ve video çekme izni verir. Bu izin, uygulamanın sizin onayınız olmadan istediği zaman kamerayı kullanmasına olanak sağlar."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"titreşimi denetleme"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Uygulamaya, titreşimi denetleme izni verir."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"flaşı denetle"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Uygulamaya, flaş ışığını denetleme izni verir."</string>
+    <string name="permlab_flashlight" msgid="2155920810121984215">"el fenerini denetle"</string>
+    <string name="permdesc_flashlight" msgid="6522284794568368310">"Uygulamaya, el fenerini denetleme izni verir."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefon numaralarına doğrudan çağrı yap"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Uygulamaya sizin müdahaleniz olmadan telefon numaralarına çağrı yapma izni verir. Bu durum beklenmeyen ödemelere veya çağrılara neden olabilir. Ancak bu iznin, uygulamanın acil numaralara çağrı yapmasına olanak sağlamadığını unutmayın. Kötü amaçlı uygulamalar onayınız olmadan çağrılar yaparak sizi zarara sokabilir."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS çağrı hizmetine erişme"</string>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 9044802..41b05ea 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -51,4 +51,7 @@
     <!-- Scale factor threshold used by the screen magnifier to determine when to switch from
          panning to scaling the magnification viewport. -->
     <item name="config_screen_magnification_scaling_threshold" format="float" type="dimen">0.1</item>
+
+    <!-- Do not show the message saying USB is connected in charging mode. -->
+    <bool name="config_usbChargingMessage">false</bool>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
old mode 100755
new mode 100644
index 3599b5b..a5960a9
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -252,7 +252,7 @@
     <integer name="config_networkTransitionTimeout">60000</integer>
 
     <!-- List of regexpressions describing the interface (if any) that represent tetherable
-         USB interfaces.  If the device doesn't want to support tething over USB this should
+         USB interfaces.  If the device doesn't want to support tethering over USB this should
          be empty.  An example would be "usb.*" -->
     <string-array translatable="false" name="config_tether_usb_regexs">
     </string-array>
@@ -543,6 +543,9 @@
     <!-- If this is true, the screen will come on when you unplug usb/power/whatever. -->
     <bool name="config_unplugTurnsOnScreen">false</bool>
 
+    <!-- If this is true, the message that USB is only being used for charging will be shown. -->
+    <bool name="config_usbChargingMessage">true</bool>
+
     <!-- Set this true only if the device has separate attention and notification lights. -->
     <bool name="config_useAttentionLight">false</bool>
 
@@ -2297,6 +2300,9 @@
     <string-array name="config_cell_retries_per_error_code">
     </string-array>
 
+    <!-- Set initial MaxRetry value for operators -->
+    <integer name="config_mdc_initial_max_retry">1</integer>
+
     <!-- The OEM specified sensor type for the gesture to launch the camear app. -->
     <integer name="config_cameraLaunchGestureSensorType">-1</integer>
     <!-- The OEM specified sensor string type for the gesture to launch camera app, this value
@@ -2306,4 +2312,12 @@
     <!-- 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>
+
+    <!-- Allow the gesture to double tap the power button twice to start the camera while the device
+         is non-interactive. -->
+    <bool name="config_cameraDoubleTapPowerGestureEnabled">true</bool>
+
+    <!-- Name of the component to handle network policy notifications. If present,
+         disables NetworkPolicyManagerService's presentation of data-usage notifications. -->
+    <string translatable="false" name="config_networkPolicyNotificationComponent"></string>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 09c1e6f..8635a4f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -37,7 +37,7 @@
     <!-- Height of the bottom navigation bar in portrait; often the same as @dimen/navigation_bar_height -->
     <dimen name="navigation_bar_height_landscape">48dp</dimen>
     <!-- Width of the navigation bar when it is placed vertically on the screen -->
-    <dimen name="navigation_bar_width">42dp</dimen>
+    <dimen name="navigation_bar_width">48dp</dimen>
     <!-- Height of notification icons in the status bar -->
     <dimen name="status_bar_icon_size">24dip</dimen>
     <!-- Size of the giant number (unread count) in the notifications -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
old mode 100755
new mode 100644
index ed4391b..16e44b86
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -408,6 +408,7 @@
   <java-symbol type="integer" name="config_volte_replacement_rat"/>
   <java-symbol type="integer" name="config_valid_wappush_index" />
   <java-symbol type="integer" name="config_overrideHasPermanentMenuKey" />
+  <java-symbol type="integer" name="config_mdc_initial_max_retry" />
   <java-symbol type="bool" name="config_hasPermanentDpad" />
 
   <java-symbol type="color" name="tab_indicator_text_v4" />
@@ -1632,6 +1633,7 @@
   <java-symbol type="bool" name="config_enableNetworkLocationOverlay" />
   <java-symbol type="bool" name="config_sf_limitedAlpha" />
   <java-symbol type="bool" name="config_unplugTurnsOnScreen" />
+  <java-symbol type="bool" name="config_usbChargingMessage" />
   <java-symbol type="bool" name="config_allowAutoBrightnessWhileDozing" />
   <java-symbol type="bool" name="config_allowTheaterModeWakeFromUnplug" />
   <java-symbol type="bool" name="config_allowTheaterModeWakeFromGesture" />
@@ -2315,6 +2317,7 @@
   <!-- Gesture -->
   <java-symbol type="integer" name="config_cameraLaunchGestureSensorType" />
   <java-symbol type="string" name="config_cameraLaunchGestureSensorStringType" />
+  <java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" />
 
   <java-symbol type="drawable" name="platlogo_m" />
 </resources>
diff --git a/docs/html/guide/topics/renderscript/reference/rs_math.jd b/docs/html/guide/topics/renderscript/reference/rs_math.jd
index 13513e9..e1e7805 100644
--- a/docs/html/guide/topics/renderscript/reference/rs_math.jd
+++ b/docs/html/guide/topics/renderscript/reference/rs_math.jd
@@ -3968,16 +3968,31 @@
         <td>        </td>
       </tr>
       <tr>
+        <td><a href='rs_value_types.html#android_rs:float2'>float2</a> max(<a href='rs_value_types.html#android_rs:float2'>float2</a> a, float b);
+</td>
+        <td>        </td>
+      </tr>
+      <tr>
         <td><a href='rs_value_types.html#android_rs:float2'>float2</a> max(<a href='rs_value_types.html#android_rs:float2'>float2</a> a, <a href='rs_value_types.html#android_rs:float2'>float2</a> b);
 </td>
         <td>        </td>
       </tr>
       <tr>
+        <td><a href='rs_value_types.html#android_rs:float3'>float3</a> max(<a href='rs_value_types.html#android_rs:float3'>float3</a> a, float b);
+</td>
+        <td>        </td>
+      </tr>
+      <tr>
         <td><a href='rs_value_types.html#android_rs:float3'>float3</a> max(<a href='rs_value_types.html#android_rs:float3'>float3</a> a, <a href='rs_value_types.html#android_rs:float3'>float3</a> b);
 </td>
         <td>        </td>
       </tr>
       <tr>
+        <td><a href='rs_value_types.html#android_rs:float4'>float4</a> max(<a href='rs_value_types.html#android_rs:float4'>float4</a> a, float b);
+</td>
+        <td>        </td>
+      </tr>
+      <tr>
         <td><a href='rs_value_types.html#android_rs:float4'>float4</a> max(<a href='rs_value_types.html#android_rs:float4'>float4</a> a, <a href='rs_value_types.html#android_rs:float4'>float4</a> b);
 </td>
         <td>        </td>
@@ -4172,16 +4187,31 @@
         <td>        </td>
       </tr>
       <tr>
+        <td><a href='rs_value_types.html#android_rs:float2'>float2</a> min(<a href='rs_value_types.html#android_rs:float2'>float2</a> a, float b);
+</td>
+        <td>        </td>
+      </tr>
+      <tr>
         <td><a href='rs_value_types.html#android_rs:float2'>float2</a> min(<a href='rs_value_types.html#android_rs:float2'>float2</a> a, <a href='rs_value_types.html#android_rs:float2'>float2</a> b);
 </td>
         <td>        </td>
       </tr>
       <tr>
+        <td><a href='rs_value_types.html#android_rs:float3'>float3</a> min(<a href='rs_value_types.html#android_rs:float3'>float3</a> a, float b);
+</td>
+        <td>        </td>
+      </tr>
+      <tr>
         <td><a href='rs_value_types.html#android_rs:float3'>float3</a> min(<a href='rs_value_types.html#android_rs:float3'>float3</a> a, <a href='rs_value_types.html#android_rs:float3'>float3</a> b);
 </td>
         <td>        </td>
       </tr>
       <tr>
+        <td><a href='rs_value_types.html#android_rs:float4'>float4</a> min(<a href='rs_value_types.html#android_rs:float4'>float4</a> a, float b);
+</td>
+        <td>        </td>
+      </tr>
+      <tr>
         <td><a href='rs_value_types.html#android_rs:float4'>float4</a> min(<a href='rs_value_types.html#android_rs:float4'>float4</a> a, <a href='rs_value_types.html#android_rs:float4'>float4</a> b);
 </td>
         <td>        </td>
diff --git a/docs/html/guide/topics/renderscript/reference/rs_value_types.jd b/docs/html/guide/topics/renderscript/reference/rs_value_types.jd
index 85c7a5c..d53caf9 100644
--- a/docs/html/guide/topics/renderscript/reference/rs_value_types.jd
+++ b/docs/html/guide/topics/renderscript/reference/rs_value_types.jd
@@ -25,7 +25,7 @@
 </p>
 
 <p> To create vector literals, use the vector type followed by the values enclosed
-between parentheses, e.g. <code>(float3)(1.0f, 2.0f, 3.0f)</code>.
+between curly braces, e.g. <code>(float3){1.0f, 2.0f, 3.0f}</code>.
 </p>
 
 <p> Entries of a vector can be accessed using different naming styles.
diff --git a/graphics/java/android/graphics/Interpolator.java b/graphics/java/android/graphics/Interpolator.java
index f695a9e..1045464 100644
--- a/graphics/java/android/graphics/Interpolator.java
+++ b/graphics/java/android/graphics/Interpolator.java
@@ -147,11 +147,12 @@
     @Override
     protected void finalize() throws Throwable {
         nativeDestructor(native_instance);
+        native_instance = 0;  // Other finalizers can still call us.
     }
     
     private int mValueCount;
     private int mFrameCount;
-    private final long native_instance;
+    private long native_instance;
 
     private static native long nativeConstructor(int valueCount, int frameCount);
     private static native void nativeDestructor(long native_instance);
diff --git a/graphics/java/android/graphics/MaskFilter.java b/graphics/java/android/graphics/MaskFilter.java
index 27a7dda..d474315 100644
--- a/graphics/java/android/graphics/MaskFilter.java
+++ b/graphics/java/android/graphics/MaskFilter.java
@@ -25,6 +25,7 @@
 
     protected void finalize() throws Throwable {
         nativeDestructor(native_instance);
+        native_instance = 0;  // Other finalizers can still call us.
     }
 
     private static native void nativeDestructor(long native_filter);
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index 90e5a4e..1e8f11b 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -827,6 +827,7 @@
     protected void finalize() throws Throwable {
         try {
             finalizer(native_instance);
+            native_instance = 0;  // Other finalizers can still call us.
         } finally {
             super.finalize();
         }
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index b9a1eda..5efc00c 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -71,7 +71,7 @@
      *
      * @hide
      */
-    public final long mNativeChunk;
+    public long mNativeChunk;
 
     private Paint mPaint;
     private String mSrcName;
@@ -121,6 +121,7 @@
             if (mNativeChunk != 0) {
                 // only attempt to destroy correctly initilized chunks
                 nativeFinalize(mNativeChunk);
+                mNativeChunk = 0;
             }
         } finally {
             super.finalize();
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index ce35b87..6582b7e 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -2471,6 +2471,7 @@
     protected void finalize() throws Throwable {
         try {
             finalizer(mNativePaint);
+            mNativePaint = 0;
         } finally {
             super.finalize();
         }
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 91e704a..da3deff 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -27,7 +27,7 @@
     /**
      * @hide
      */
-    public final long mNativePath;
+    public long mNativePath;
 
     /**
      * @hide
@@ -746,6 +746,7 @@
     protected void finalize() throws Throwable {
         try {
             finalizer(mNativePath);
+            mNativePath = 0;  //  Other finalizers can still call us.
         } finally {
             super.finalize();
         }
diff --git a/graphics/java/android/graphics/PathEffect.java b/graphics/java/android/graphics/PathEffect.java
index 617dfca..3292501 100644
--- a/graphics/java/android/graphics/PathEffect.java
+++ b/graphics/java/android/graphics/PathEffect.java
@@ -25,6 +25,7 @@
 
     protected void finalize() throws Throwable {
         nativeDestructor(native_instance);
+        native_instance = 0;  // Other finalizers can still call us.
     }
 
     private static native void nativeDestructor(long native_patheffect);
diff --git a/graphics/java/android/graphics/PathMeasure.java b/graphics/java/android/graphics/PathMeasure.java
index 7cc9765..0416159 100644
--- a/graphics/java/android/graphics/PathMeasure.java
+++ b/graphics/java/android/graphics/PathMeasure.java
@@ -142,6 +142,7 @@
 
     protected void finalize() throws Throwable {
         native_destroy(native_instance);
+        native_instance = 0;  // Other finalizers can still call us.
     }
 
     private static native long native_create(long native_path, boolean forceClosed);
@@ -154,6 +155,6 @@
     private static native boolean native_nextContour(long native_instance);
     private static native void native_destroy(long native_instance);
 
-    /* package */private final long native_instance;
+    /* package */private long native_instance;
 }
 
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index 0e55089..28d8690 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -29,7 +29,7 @@
  */
 public class Picture {
     private Canvas mRecordingCanvas;
-    private final long mNativePicture;
+    private long mNativePicture;
 
     private static final int WORKING_STREAM_STORAGE = 16 * 1024;
 
@@ -60,6 +60,7 @@
     protected void finalize() throws Throwable {
         try {
             nativeDestructor(mNativePicture);
+            mNativePicture = 0;
         } finally {
             super.finalize();
         }
diff --git a/graphics/java/android/graphics/Region.java b/graphics/java/android/graphics/Region.java
index 727723d..de89ad0 100644
--- a/graphics/java/android/graphics/Region.java
+++ b/graphics/java/android/graphics/Region.java
@@ -30,7 +30,7 @@
     /**
      * @hide
      */
-    public final long mNativeRegion;
+    public long mNativeRegion;
 
     // the native values for these must match up with the enum in SkRegion.h
     public enum Op {
@@ -380,6 +380,7 @@
     protected void finalize() throws Throwable {
         try {
             nativeDestructor(mNativeRegion);
+            mNativeRegion = 0;
         } finally {
             super.finalize();
         }
diff --git a/graphics/java/android/graphics/RegionIterator.java b/graphics/java/android/graphics/RegionIterator.java
index 8401adb..443b23c 100644
--- a/graphics/java/android/graphics/RegionIterator.java
+++ b/graphics/java/android/graphics/RegionIterator.java
@@ -43,12 +43,13 @@
     
     protected void finalize() throws Throwable {
         nativeDestructor(mNativeIter);
+        mNativeIter = 0;  // Other finalizers can still call us.
     }
     
     private static native long nativeConstructor(long native_region);
     private static native void nativeDestructor(long native_iter);
     private static native boolean nativeNext(long native_iter, Rect r);
 
-    private final long mNativeIter;
+    private long mNativeIter;
 }
 
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index a96d2cb..adb282f 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -91,6 +91,7 @@
             super.finalize();
         } finally {
             nativeDestructor(native_instance);
+            native_instance = 0;  // Other finalizers can still call us.
         }
     }
 
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index db42314..7eb5584 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -358,6 +358,7 @@
     protected void finalize() throws Throwable {
         try {
             nativeUnref(native_instance);
+            native_instance = 0;  // Other finalizers can still call us.
         } finally {
             super.finalize();
         }
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index abb51db..1857345 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -217,7 +217,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(float level) {
+    protected boolean onLevelChange(int level) {
         return mAnimatedVectorState.mVectorDrawable.setLevel(level);
     }
 
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 3b92507..31fccd0 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -52,6 +52,8 @@
     public static final int HORIZONTAL = 1;
     public static final int VERTICAL = 2;
 
+    private static final int MAX_LEVEL = 10000;
+
     private final Rect mTmpRect = new Rect();
 
     private ClipState mState;
@@ -141,7 +143,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(float level) {
+    protected boolean onLevelChange(int level) {
         super.onLevelChange(level);
         invalidateSelf();
         return true;
@@ -151,12 +153,12 @@
     public int getOpacity() {
         final Drawable dr = getDrawable();
         final int opacity = dr.getOpacity();
-        if (opacity == PixelFormat.TRANSPARENT || dr.getLevelFloat() == 0) {
+        if (opacity == PixelFormat.TRANSPARENT || dr.getLevel() == 0) {
             return PixelFormat.TRANSPARENT;
         }
 
-        final float level = getLevelFloat();
-        if (level >= MAX_LEVEL_FLOAT) {
+        final int level = getLevel();
+        if (level >= MAX_LEVEL) {
             return dr.getOpacity();
         }
 
@@ -167,24 +169,24 @@
     @Override
     public void draw(Canvas canvas) {
         final Drawable dr = getDrawable();
-        if (dr.getLevelFloat() == 0) {
+        if (dr.getLevel() == 0) {
             return;
         }
 
         final Rect r = mTmpRect;
         final Rect bounds = getBounds();
-        final float level = getLevelFloat();
+        final int level = getLevel();
 
         int w = bounds.width();
-        final int iw = 0;
+        final int iw = 0; //mState.mDrawable.getIntrinsicWidth();
         if ((mState.mOrientation & HORIZONTAL) != 0) {
-            w -= Math.round((w - iw) * (MAX_LEVEL_FLOAT - level) / MAX_LEVEL_FLOAT);
+            w -= (w - iw) * (MAX_LEVEL - level) / MAX_LEVEL;
         }
 
         int h = bounds.height();
-        final int ih = 0;
+        final int ih = 0; //mState.mDrawable.getIntrinsicHeight();
         if ((mState.mOrientation & VERTICAL) != 0) {
-            h -= Math.round((h - ih) * (MAX_LEVEL_FLOAT - level) / MAX_LEVEL_FLOAT);
+            h -= (h - ih) * (MAX_LEVEL - level) / MAX_LEVEL;
         }
 
         final int layoutDirection = getLayoutDirection();
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index fb771550..b95c183 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -41,7 +41,6 @@
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
-import android.util.FloatProperty;
 import android.util.StateSet;
 import android.util.TypedValue;
 import android.util.Xml;
@@ -127,19 +126,12 @@
  * document.</p></div>
  */
 public abstract class Drawable {
-
     private static final Rect ZERO_BOUNDS_RECT = new Rect();
 
     static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN;
 
-    /** The standard maximum value for calls to {@link #setLevel(int)}. */
-    public static final int MAX_LEVEL = 10000;
-
-    /** The standard maximum value for calls to {@link #setLevel(float)}. */
-    public static final float MAX_LEVEL_FLOAT = 10000.0f;
-
     private int[] mStateSet = StateSet.WILD_CARD;
-    private float mLevel = 0.0f;
+    private int mLevel = 0;
     private int mChangingConfigurations = 0;
     private Rect mBounds = ZERO_BOUNDS_RECT;  // lazily becomes a new Rect()
     private WeakReference<Callback> mCallback = null;
@@ -719,63 +711,22 @@
     }
 
     /**
-     * Sets the level for the drawable as an integer value where typically the
-     * minimum level is 0 and the maximum is 10000 {@link #MAX_LEVEL}; however,
-     * the range may vary based on the Drawable implementation and is not
-     * clamped.
-     * <p>
-     * This allows a drawable to vary its imagery based on a continuous
-     * controller. For example, it may be used to show progress or volume
-     * level.
-     * <p>
-     * Use #setLevelFloat(float) to set the level as a high-precision
-     * floating-point value.
+     * Specify the level for the drawable.  This allows a drawable to vary its
+     * imagery based on a continuous controller, for example to show progress
+     * or volume level.
      *
-     * @param level the new level, typically between 0 and 10000
-     * @return {@code true} if this change in level has caused the appearance
-     *         of the drawable to change and will require a subsequent call to
-     *         invalidate, {@code false} otherwise
-     * @see #getLevel()
-     * @see #setLevel(float)
-     * @see #onLevelChange(int)
+     * <p>If the new level you are supplying causes the appearance of the
+     * Drawable to change, then it is responsible for calling
+     * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em>
+     * true will be returned from this function.
+     *
+     * @param level The new level, from 0 (minimum) to 10000 (maximum).
+     *
+     * @return Returns true if this change in level has caused the appearance
+     * of the Drawable to change (hence requiring an invalidate), otherwise
+     * returns false.
      */
     public final boolean setLevel(int level) {
-        return setLevel((float) level);
-    }
-
-    /**
-     * Returns the current level as a rounded integer value.
-     * <p>
-     * Use #getLevelFloat() to return the level as a high-precision
-     * floating-point value.
-     *
-     * @return the current level, typically between 0 and 10000
-     * @see #setLevel(int)
-     * @see #getLevelFloat()
-     */
-    public final int getLevel() {
-        return Math.round(mLevel);
-    }
-
-    /**
-     * Sets the level for the drawable as a floating-point value where
-     * typically the minimum level is 0.0 and the maximum is 10000.0
-     * {@link #MAX_LEVEL_FLOAT}; however, the range may vary based on the
-     * Drawable implementation and is not clamped.
-     * <p>
-     * This allows a drawable to vary its imagery based on a continuous
-     * controller. For example, it may be used to show progress or volume
-     * level.
-     *
-     * @param level the new level, typically between 0.0 and 10000.0
-     *              ({@link #MAX_LEVEL_FLOAT})
-     * @return {@code true} if this change in level has caused the appearance
-     *         of the drawable to change and will require a subsequent call to
-     *         invalidate, {@code false} otherwise
-     * @see #getLevelFloat()
-     * @see #onLevelChange(float)
-     */
-    public final boolean setLevel(float level) {
         if (mLevel != level) {
             mLevel = level;
             return onLevelChange(level);
@@ -784,13 +735,11 @@
     }
 
     /**
-     * Returns the current level as a floating-point value.
+     * Retrieve the current level.
      *
-     * @return the current level, typically between 0.0 and 10000.0
-     *         ({@link #MAX_LEVEL_FLOAT})
-     * @see #setLevel(float)
+     * @return int Current level, from 0 (minimum) to 10000 (maximum).
      */
-    public final float getLevelFloat() {
+    public final int getLevel() {
         return mLevel;
     }
 
@@ -945,47 +894,14 @@
      * last state.
      */
     protected boolean onStateChange(int[] state) { return false; }
-
-    /**
-     * Called when the drawable level changes.
-     * <p>
-     * Override this in your subclass to change appearance if you vary based on
-     * level and do not need floating-point accuracy. To handle changes with
-     * higher accuracy, override {@link #onLevelChange(float)} instead.
-     * <p>
-     * <strong>Note:</strong> Do not override both this method and
-     * {@link #onLevelChange(float)}. Only override one method.
-     *
-     * @param level the level as an integer value, typically between 0
-     *              (minimum) and 10000 ({@link #MAX_LEVEL})
-     * @return {@code true} if the level change has caused the appearance of
-     *         the drawable to change such that it needs to be redrawn, or
-     *         {@code false} if there is no need to redraw
+    /** Override this in your subclass to change appearance if you vary based
+     *  on level.
+     * @return Returns true if the level change has caused the appearance of
+     * the Drawable to change (that is, it needs to be drawn), else false
+     * if it looks the same and there is no need to redraw it since its
+     * last level.
      */
     protected boolean onLevelChange(int level) { return false; }
-
-    /**
-     * Called when the drawable level changes.
-     * <p>
-     * Override this in your subclass to change appearance if you vary based on
-     * level and need floating-point accuracy.
-     * <p>
-     * <strong>Note:</strong> Do not override both this method and
-     * {@link #onLevelChange(int)}. Only override one method. If your app
-     * targets SDK <= 23 ({@link android.os.Build.VERSION_CODES#M M}), you
-     * will need to override {@link #onLevelChange(int)} to receive callbacks
-     * on devices running Android M and below.
-     *
-     * @param level the level as a floating-point value, typically between 0.0
-     *              and 10000.0 ({@link #MAX_LEVEL_FLOAT})
-     * @return {@code true} if the level change has caused the appearance of
-     *         the drawable to change such that it needs to be redrawn, or
-     *         {@code false} if there is no need to redraw
-     */
-    protected boolean onLevelChange(float level) {
-        return onLevelChange(Math.round(level));
-    }
-
     /**
      * Override this in your subclass to change appearance if you vary based on
      * the bounds.
@@ -1412,23 +1328,6 @@
     }
 
     /**
-     * Animatable property for Drawable level.
-     *
-     * @hide Until Drawable animations have been cleaned up.
-     */
-    public static final FloatProperty<Drawable> LEVEL = new FloatProperty<Drawable>("levelFloat") {
-        @Override
-        public Float get(Drawable object) {
-            return object.getLevelFloat();
-        }
-
-        @Override
-        public void setValue(Drawable object, float value) {
-            object.setLevel(value);
-        }
-    };
-
-    /**
      * Obtains styled attributes from the theme, if available, or unstyled
      * resources if the theme is null.
      */
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 0210ddb..1915dd7 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -322,7 +322,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(float level) {
+    protected boolean onLevelChange(int level) {
         if (mLastDrawable != null) {
             return mLastDrawable.setLevel(level);
         }
@@ -510,7 +510,7 @@
         d.setVisible(isVisible(), true);
         d.setDither(mDrawableContainerState.mDither);
         d.setState(getState());
-        d.setLevel(getLevelFloat());
+        d.setLevel(getLevel());
         d.setBounds(getBounds());
         d.setLayoutDirection(getLayoutDirection());
         d.setAutoMirrored(mDrawableContainerState.mAutoMirrored);
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index 57b4db2..9185e1a 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -92,7 +92,7 @@
             // Only call setters for data that's stored in the base Drawable.
             dr.setVisible(isVisible(), true);
             dr.setState(getState());
-            dr.setLevel(getLevelFloat());
+            dr.setLevel(getLevel());
             dr.setBounds(getBounds());
             dr.setLayoutDirection(getLayoutDirection());
 
@@ -286,7 +286,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(float level) {
+    protected boolean onLevelChange(int level) {
         return mDrawable != null && mDrawable.setLevel(level);
     }
 
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 15295a0..d7fd8a5 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -530,8 +530,8 @@
      *                 {@code false} otherwise
      *
      * @see #mutate()
-     * @see #setLevel(float)
-     * @see #getLevelFloat()
+     * @see #setLevel(int)
+     * @see #getLevel()
      * @see #isUseLevel()
      */
     public void setUseLevel(boolean useLevel) {
@@ -764,7 +764,7 @@
         if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) return mRingPath;
         mPathIsDirty = false;
 
-        float sweep = st.mUseLevelForShape ? (360.0f * getLevelFloat() / MAX_LEVEL_FLOAT) : 360f;
+        float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f;
 
         RectF bounds = new RectF(mRect);
 
@@ -990,7 +990,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(float level) {
+    protected boolean onLevelChange(int level) {
         super.onLevelChange(level);
         mGradientIsDirty = true;
         mPathIsDirty = true;
@@ -1026,7 +1026,7 @@
                 final float x0, x1, y0, y1;
 
                 if (st.mGradient == LINEAR_GRADIENT) {
-                    final float level = st.mUseLevel ? getLevelFloat() / MAX_LEVEL_FLOAT : 1.0f;
+                    final float level = st.mUseLevel ? getLevel() / 10000.0f : 1.0f;
                     switch (st.mOrientation) {
                     case TOP_BOTTOM:
                         x0 = r.left;            y0 = r.top;
@@ -1080,7 +1080,7 @@
                     }
 
                     if (st.mUseLevel) {
-                        radius *= getLevelFloat() / MAX_LEVEL_FLOAT;
+                        radius *= getLevel() / 10000.0f;
                     }
 
                     mGradientRadius = radius;
@@ -1115,7 +1115,7 @@
                             tempPositions = st.mTempPositions = new float[length + 1];
                         }
 
-                        final float level = getLevelFloat() / MAX_LEVEL_FLOAT;
+                        final float level = getLevel() / 10000.0f;
                         for (int i = 0; i < length; i++) {
                             tempPositions[i] = i * fraction * level;
                         }
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index c9e38b9..1a0ba6f 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -1400,7 +1400,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(float level) {
+    protected boolean onLevelChange(int level) {
         boolean changed = false;
 
         final ChildDrawable[] array = mLayerState.mChildren;
@@ -1733,7 +1733,7 @@
                 clone.setCallback(owner);
                 clone.setLayoutDirection(dr.getLayoutDirection());
                 clone.setBounds(dr.getBounds());
-                clone.setLevel(dr.getLevelFloat());
+                clone.setLevel(dr.getLevel());
             } else {
                 clone = null;
             }
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index 09d8b6f..b01c643 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -69,16 +69,15 @@
         if (drawable != null) {
             mLevelListState.addLevel(low, high, drawable);
             // in case the new state matches our current state...
-            onLevelChange(getLevelFloat());
+            onLevelChange(getLevel());
         }
     }
 
     // overrides from Drawable
 
     @Override
-    protected boolean onLevelChange(float level) {
-        final int nearestLevel = Math.round(level);
-        final int idx = mLevelListState.indexOfLevel(nearestLevel);
+    protected boolean onLevelChange(int level) {
+        int idx = mLevelListState.indexOfLevel(level);
         if (selectDrawable(idx)) {
             return true;
         }
@@ -142,7 +141,7 @@
             mLevelListState.addLevel(low, high, dr);
         }
 
-        onLevelChange(getLevelFloat());
+        onLevelChange(getLevel());
     }
 
     @Override
@@ -241,7 +240,7 @@
     private LevelListDrawable(LevelListState state, Resources res) {
         final LevelListState as = new LevelListState(state, this, res);
         setConstantState(as);
-        onLevelChange(getLevelFloat());
+        onLevelChange(getLevel());
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 71c9977..036a078 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -303,10 +303,10 @@
     }
 
     @Override
-    protected boolean onLevelChange(float level) {
+    protected boolean onLevelChange(int level) {
         super.onLevelChange(level);
 
-        final float value = level / (float) MAX_LEVEL_FLOAT;
+        final float value = level / (float) MAX_LEVEL;
         final float degrees = MathUtils.lerp(mState.mFromDegrees, mState.mToDegrees, value);
         mState.mCurrentDegrees = degrees;
 
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index 38c6b80..0acbeda 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -50,6 +50,8 @@
  * @attr ref android.R.styleable#ScaleDrawable_drawable
  */
 public class ScaleDrawable extends DrawableWrapper {
+    private static final int MAX_LEVEL = 10000;
+
     private final Rect mTmpRect = new Rect();
 
     private ScaleState mState;
@@ -168,7 +170,7 @@
     @Override
     public void draw(Canvas canvas) {
         final Drawable d = getDrawable();
-        if (d != null && d.getLevelFloat() != 0) {
+        if (d != null && d.getLevel() != 0) {
             d.draw(canvas);
         }
     }
@@ -176,12 +178,12 @@
     @Override
     public int getOpacity() {
         final Drawable d = getDrawable();
-        if (d.getLevelFloat() == 0) {
+        if (d.getLevel() == 0) {
             return PixelFormat.TRANSPARENT;
         }
 
         final int opacity = d.getOpacity();
-        if (opacity == PixelFormat.OPAQUE && d.getLevelFloat() < MAX_LEVEL_FLOAT) {
+        if (opacity == PixelFormat.OPAQUE && d.getLevel() < MAX_LEVEL) {
             return PixelFormat.TRANSLUCENT;
         }
 
@@ -189,7 +191,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(float level) {
+    protected boolean onLevelChange(int level) {
         super.onLevelChange(level);
         onBoundsChange(getBounds());
         invalidateSelf();
@@ -201,20 +203,18 @@
         final Drawable d = getDrawable();
         final Rect r = mTmpRect;
         final boolean min = mState.mUseIntrinsicSizeAsMin;
-        final float level = getLevelFloat();
+        final int level = getLevel();
 
         int w = bounds.width();
         if (mState.mScaleWidth > 0) {
             final int iw = min ? d.getIntrinsicWidth() : 0;
-            w -= (int) ((w - iw) * (MAX_LEVEL_FLOAT - level)
-                    * mState.mScaleWidth / MAX_LEVEL_FLOAT);
+            w -= (int) ((w - iw) * (MAX_LEVEL - level) * mState.mScaleWidth / MAX_LEVEL);
         }
 
         int h = bounds.height();
         if (mState.mScaleHeight > 0) {
             final int ih = min ? d.getIntrinsicHeight() : 0;
-            h -= (int) ((h - ih) * (MAX_LEVEL_FLOAT - level)
-                    * mState.mScaleHeight / MAX_LEVEL_FLOAT);
+            h -= (int) ((h - ih) * (MAX_LEVEL - level) * mState.mScaleHeight / MAX_LEVEL);
         }
 
         final int layoutDirection = getLayoutDirection();
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index 0cfd2b1..3d4e47d 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -93,13 +93,14 @@
      * look in multiple places for assets.  It can be either a directory (for
      * finding assets as raw files on the disk) or a ZIP file.  This newly
      * added asset path will be examined first when searching for assets,
-     * before any that were previously added.
+     * before any that were previously added, the assets are added as shared
+     * library if appAsLib is true.
      *
      * Returns "true" on success, "false" on failure.  If 'cookie' is non-NULL,
      * then on success, *cookie is set to the value corresponding to the
      * newly-added asset source.
      */
-    bool addAssetPath(const String8& path, int32_t* cookie);
+    bool addAssetPath(const String8& path, int32_t* cookie, bool appAsLib=false);
     bool addOverlayPath(const String8& path, int32_t* cookie);
 
     /*                                                                       
@@ -280,7 +281,7 @@
     const ResTable* getResTable(bool required = true) const;
     void setLocaleLocked(const char* locale);
     void updateResourceParamsLocked() const;
-    bool appendPathToResTable(const asset_path& ap) const;
+    bool appendPathToResTable(const asset_path& ap, bool appAsLib=false) const;
 
     Asset* openIdmapLocked(const struct asset_path& ap) const;
 
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index eff1f5f..49b6333 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -1505,7 +1505,7 @@
 class DynamicRefTable
 {
 public:
-    DynamicRefTable(uint8_t packageId);
+    DynamicRefTable(uint8_t packageId, bool appAsLib);
 
     // Loads an unmapped reference table from the package.
     status_t load(const ResTable_lib_header* const header);
@@ -1530,6 +1530,7 @@
     const uint8_t                   mAssignedPackageId;
     uint8_t                         mLookupTable[256];
     KeyedVector<String16, uint8_t>  mEntries;
+    bool                            mAppAsLib;
 };
 
 bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue);
@@ -1547,10 +1548,11 @@
 
     status_t add(const void* data, size_t size, const int32_t cookie=-1, bool copyData=false);
     status_t add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
-            const int32_t cookie=-1, bool copyData=false);
+            const int32_t cookie=-1, bool copyData=false, bool appAsLib=false);
 
     status_t add(Asset* asset, const int32_t cookie=-1, bool copyData=false);
-    status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false);
+    status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false,
+            bool appAsLib=false);
 
     status_t add(ResTable* src);
     status_t addEmpty(const int32_t cookie);
@@ -1858,7 +1860,7 @@
     typedef Vector<Type*> TypeList;
 
     status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
-            const int32_t cookie, bool copyData);
+            bool appAsLib, const int32_t cookie, bool copyData);
 
     ssize_t getResourcePackageIndex(uint32_t resID) const;
 
@@ -1871,7 +1873,7 @@
             size_t nameLen, uint32_t* outTypeSpecFlags) const;
 
     status_t parsePackage(
-        const ResTable_package* const pkg, const Header* const header);
+        const ResTable_package* const pkg, const Header* const header, bool appAsLib);
 
     void print_value(const Package* pkg, const Res_value& value) const;
     
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 5d777b0..c8333c8 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -217,13 +217,22 @@
      * Returns {@code true} if there was at least one of those types.
      */
     public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias) {
+        return deleteAllTypesForAlias(keystore, alias, KeyStore.UID_SELF);
+    }
+
+    /**
+     * Delete all types (private key, certificate, CA certificate) for a
+     * particular {@code alias}. All three can exist for any given alias.
+     * Returns {@code true} if there was at least one of those types.
+     */
+    public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias, int uid) {
         /*
          * Make sure every type is deleted. There can be all three types, so
          * don't use a conditional here.
          */
-        return keystore.delete(Credentials.USER_PRIVATE_KEY + alias)
-                | keystore.delete(Credentials.USER_SECRET_KEY + alias)
-                | deleteCertificateTypesForAlias(keystore, alias);
+        return keystore.delete(Credentials.USER_PRIVATE_KEY + alias, uid)
+                | keystore.delete(Credentials.USER_SECRET_KEY + alias, uid)
+                | deleteCertificateTypesForAlias(keystore, alias, uid);
     }
 
     /**
@@ -232,12 +241,21 @@
      * Returns {@code true} if there was at least one of those types.
      */
     public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias) {
+        return deleteCertificateTypesForAlias(keystore, alias, KeyStore.UID_SELF);
+    }
+
+    /**
+     * Delete all types (private key, certificate, CA certificate) for a
+     * particular {@code alias}. All three can exist for any given alias.
+     * Returns {@code true} if there was at least one of those types.
+     */
+    public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias, int uid) {
         /*
          * Make sure every certificate type is deleted. There can be two types,
          * so don't use a conditional here.
          */
-        return keystore.delete(Credentials.USER_CERTIFICATE + alias)
-                | keystore.delete(Credentials.CA_CERTIFICATE + alias);
+        return keystore.delete(Credentials.USER_CERTIFICATE + alias, uid)
+                | keystore.delete(Credentials.CA_CERTIFICATE + alias, uid);
     }
 
     /**
@@ -245,7 +263,15 @@
      * Returns {@code true} if an entry was was deleted.
      */
     static boolean deletePrivateKeyTypeForAlias(KeyStore keystore, String alias) {
-        return keystore.delete(Credentials.USER_PRIVATE_KEY + alias);
+        return deletePrivateKeyTypeForAlias(keystore, alias, KeyStore.UID_SELF);
+    }
+
+    /**
+     * Delete private key for a particular {@code alias}.
+     * Returns {@code true} if an entry was was deleted.
+     */
+    static boolean deletePrivateKeyTypeForAlias(KeyStore keystore, String alias, int uid) {
+        return keystore.delete(Credentials.USER_PRIVATE_KEY + alias, uid);
     }
 
     /**
@@ -253,6 +279,14 @@
      * Returns {@code true} if an entry was was deleted.
      */
     public static boolean deleteSecretKeyTypeForAlias(KeyStore keystore, String alias) {
-        return keystore.delete(Credentials.USER_SECRET_KEY + alias);
+        return deleteSecretKeyTypeForAlias(keystore, alias, KeyStore.UID_SELF);
+    }
+
+    /**
+     * Delete secret key for a particular {@code alias}.
+     * Returns {@code true} if an entry was was deleted.
+     */
+    public static boolean deleteSecretKeyTypeForAlias(KeyStore keystore, String alias, int uid) {
+        return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
     }
 }
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 7de26d6..5b2594d 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -374,7 +374,7 @@
                 throw new KeyChainException("keystore had a problem");
             }
             return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
-                    KeyStore.getInstance(), keyId);
+                    KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
         } catch (RemoteException e) {
             throw new KeyChainException(e);
         } catch (RuntimeException e) {
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 98b44dc..1b87a41 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -155,15 +155,19 @@
         return state() == State.UNLOCKED;
     }
 
-    public byte[] get(String key) {
+    public byte[] get(String key, int uid) {
         try {
-            return mBinder.get(key);
+            return mBinder.get(key, uid);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return null;
         }
     }
 
+    public byte[] get(String key) {
+        return get(key, UID_SELF);
+    }
+
     public boolean put(String key, byte[] value, int uid, int flags) {
         return insert(key, value, uid, flags) == NO_ERROR;
     }
@@ -348,9 +352,9 @@
      * Returns the last modification time of the key in milliseconds since the
      * epoch. Will return -1L if the key could not be found or other error.
      */
-    public long getmtime(String key) {
+    public long getmtime(String key, int uid) {
         try {
-            final long millis = mBinder.getmtime(key);
+            final long millis = mBinder.getmtime(key, uid);
             if (millis == -1L) {
                 return -1L;
             }
@@ -362,6 +366,10 @@
         }
     }
 
+    public long getmtime(String key) {
+        return getmtime(key, UID_SELF);
+    }
+
     public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) {
         try {
             return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR;
@@ -423,15 +431,20 @@
     }
 
     public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
-            KeyCharacteristics outCharacteristics) {
+            int uid, KeyCharacteristics outCharacteristics) {
         try {
-            return mBinder.getKeyCharacteristics(alias, clientId, appId, outCharacteristics);
+            return mBinder.getKeyCharacteristics(alias, clientId, appId, uid, outCharacteristics);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return SYSTEM_ERROR;
         }
     }
 
+    public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
+            KeyCharacteristics outCharacteristics) {
+        return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
+    }
+
     public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
             int uid, int flags, KeyCharacteristics outCharacteristics) {
         try {
@@ -449,9 +462,23 @@
     }
 
     public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
-            KeymasterBlob appId) {
+            KeymasterBlob appId, int uid) {
         try {
-            return mBinder.exportKey(alias, format, clientId, appId);
+            return mBinder.exportKey(alias, format, clientId, appId, uid);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return null;
+        }
+    }
+    public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
+            KeymasterBlob appId) {
+        return exportKey(alias, format, clientId, appId, UID_SELF);
+    }
+
+    public OperationResult begin(String alias, int purpose, boolean pruneable,
+            KeymasterArguments args, byte[] entropy, int uid) {
+        try {
+            return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return null;
@@ -460,12 +487,7 @@
 
     public OperationResult begin(String alias, int purpose, boolean pruneable,
             KeymasterArguments args, byte[] entropy) {
-        try {
-            return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Cannot connect to keystore", e);
-            return null;
-        }
+        return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
     }
 
     public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
@@ -640,7 +662,7 @@
      * {@link KeyStoreException}.
      */
     public InvalidKeyException getInvalidKeyException(
-            String keystoreKeyAlias, KeyStoreException e) {
+            String keystoreKeyAlias, int uid, KeyStoreException e) {
         switch (e.getErrorCode()) {
             case LOCKED:
                 return new UserNotAuthenticatedException();
@@ -658,7 +680,8 @@
                 // to authenticate.
                 KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
                 int getKeyCharacteristicsErrorCode =
-                        getKeyCharacteristics(keystoreKeyAlias, null, null, keyCharacteristics);
+                        getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
+                                keyCharacteristics);
                 if (getKeyCharacteristicsErrorCode != NO_ERROR) {
                     return new InvalidKeyException(
                             "Failed to obtained key characteristics",
@@ -708,7 +731,8 @@
      * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
      * code.
      */
-    public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int errorCode) {
-        return getInvalidKeyException(keystoreKeyAlias, getKeyStoreException(errorCode));
+    public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
+            int errorCode) {
+        return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
     }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
index 38cacd0..042dc83 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
@@ -249,7 +249,8 @@
                 purpose,
                 true, // permit aborting this operation if keystore runs out of resources
                 keymasterInputArgs,
-                additionalEntropy);
+                additionalEntropy,
+                mKey.getUid());
         if (opResult == null) {
             throw new KeyStoreConnectException();
         }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
index 10aab7e..45f2110 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
@@ -155,9 +155,9 @@
 
         KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
         int errorCode = getKeyStore().getKeyCharacteristics(
-                key.getAlias(), null, null, keyCharacteristics);
+                key.getAlias(), null, null, key.getUid(), keyCharacteristics);
         if (errorCode != KeyStore.NO_ERROR) {
-            throw getKeyStore().getInvalidKeyException(key.getAlias(), errorCode);
+            throw getKeyStore().getInvalidKeyException(key.getAlias(), key.getUid(), errorCode);
         }
         long keySizeBits = keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
         if (keySizeBits == -1) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
index 5dbcd68..aa7bdff 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
@@ -28,8 +28,8 @@
 public class AndroidKeyStoreECPrivateKey extends AndroidKeyStorePrivateKey implements ECKey {
     private final ECParameterSpec mParams;
 
-    public AndroidKeyStoreECPrivateKey(String alias, ECParameterSpec params) {
-        super(alias, KeyProperties.KEY_ALGORITHM_EC);
+    public AndroidKeyStoreECPrivateKey(String alias, int uid, ECParameterSpec params) {
+        super(alias, uid, KeyProperties.KEY_ALGORITHM_EC);
         mParams = params;
     }
 
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java
index 3ed396d..2efaeb6 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java
@@ -30,15 +30,15 @@
     private final ECParameterSpec mParams;
     private final ECPoint mW;
 
-    public AndroidKeyStoreECPublicKey(String alias, byte[] x509EncodedForm, ECParameterSpec params,
+    public AndroidKeyStoreECPublicKey(String alias, int uid, byte[] x509EncodedForm, ECParameterSpec params,
             ECPoint w) {
-        super(alias, KeyProperties.KEY_ALGORITHM_EC, x509EncodedForm);
+        super(alias, uid, KeyProperties.KEY_ALGORITHM_EC, x509EncodedForm);
         mParams = params;
         mW = w;
     }
 
-    public AndroidKeyStoreECPublicKey(String alias, ECPublicKey info) {
-        this(alias, info.getEncoded(), info.getParams(), info.getW());
+    public AndroidKeyStoreECPublicKey(String alias, int uid, ECPublicKey info) {
+        this(alias, uid, info.getEncoded(), info.getParams(), info.getW());
         if (!"X.509".equalsIgnoreCase(info.getFormat())) {
             throw new IllegalArgumentException(
                     "Unsupported key export format: " + info.getFormat());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
index d20e3af..2e8ac32 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
@@ -168,7 +168,8 @@
                 KeymasterDefs.KM_PURPOSE_SIGN,
                 true,
                 keymasterArgs,
-                null); // no additional entropy needed for HMAC because it's deterministic
+                null, // no additional entropy needed for HMAC because it's deterministic
+                mKey.getUid());
 
         if (opResult == null) {
             throw new KeyStoreConnectException();
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
index e76802f..e8e6310 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
@@ -25,10 +25,12 @@
  */
 public class AndroidKeyStoreKey implements Key {
     private final String mAlias;
+    private final int mUid;
     private final String mAlgorithm;
 
-    public AndroidKeyStoreKey(String alias, String algorithm) {
+    public AndroidKeyStoreKey(String alias, int uid, String algorithm) {
         mAlias = alias;
+        mUid = uid;
         mAlgorithm = algorithm;
     }
 
@@ -36,6 +38,10 @@
         return mAlias;
     }
 
+    int getUid() {
+        return mUid;
+    }
+
     @Override
     public String getAlgorithm() {
         return mAlgorithm;
@@ -59,6 +65,7 @@
         int result = 1;
         result = prime * result + ((mAlgorithm == null) ? 0 : mAlgorithm.hashCode());
         result = prime * result + ((mAlias == null) ? 0 : mAlias.hashCode());
+        result = prime * result + mUid;
         return result;
     }
 
@@ -88,6 +95,9 @@
         } else if (!mAlias.equals(other.mAlias)) {
             return false;
         }
+        if (mUid != other.mUid) {
+            return false;
+        }
         return true;
     }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
index 5ce4fd2..303b0f2 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
@@ -62,7 +62,8 @@
                         "Unsupported key type: " + key.getClass().getName()
                         + ". KeyInfo can be obtained only for Android Keystore private keys");
             }
-            String keyAliasInKeystore = ((AndroidKeyStorePrivateKey) key).getAlias();
+            AndroidKeyStorePrivateKey keystorePrivateKey = (AndroidKeyStorePrivateKey) key;
+            String keyAliasInKeystore = keystorePrivateKey.getAlias();
             String entryAlias;
             if (keyAliasInKeystore.startsWith(Credentials.USER_PRIVATE_KEY)) {
                 entryAlias = keyAliasInKeystore.substring(Credentials.USER_PRIVATE_KEY.length());
@@ -71,7 +72,7 @@
             }
             @SuppressWarnings("unchecked")
             T result = (T) AndroidKeyStoreSecretKeyFactorySpi.getKeyInfo(
-                    mKeyStore, entryAlias, keyAliasInKeystore);
+                    mKeyStore, entryAlias, keyAliasInKeystore, keystorePrivateKey.getUid());
             return result;
         } else if (X509EncodedKeySpec.class.equals(keySpecClass)) {
             if (!(key instanceof AndroidKeyStorePublicKey)) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 4c174f1..e6276a4 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -297,11 +297,12 @@
         KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
         boolean success = false;
         try {
-            Credentials.deleteAllTypesForAlias(mKeyStore, spec.getKeystoreAlias());
+            Credentials.deleteAllTypesForAlias(mKeyStore, spec.getKeystoreAlias(), spec.getUid());
             int errorCode = mKeyStore.generateKey(
                     keyAliasInKeystore,
                     args,
                     additionalEntropy,
+                    spec.getUid(),
                     flags,
                     resultingKeyCharacteristics);
             if (errorCode != KeyStore.NO_ERROR) {
@@ -315,12 +316,14 @@
             } catch (IllegalArgumentException e) {
                 throw new ProviderException("Failed to obtain JCA secret key algorithm name", e);
             }
-            SecretKey result = new AndroidKeyStoreSecretKey(keyAliasInKeystore, keyAlgorithmJCA);
+            SecretKey result = new AndroidKeyStoreSecretKey(
+                    keyAliasInKeystore, spec.getUid(), keyAlgorithmJCA);
             success = true;
             return result;
         } finally {
             if (!success) {
-                Credentials.deleteAllTypesForAlias(mKeyStore, spec.getKeystoreAlias());
+                Credentials.deleteAllTypesForAlias(
+                        mKeyStore, spec.getKeystoreAlias(), spec.getUid());
             }
         }
     }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 79095f4..65460b5 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -147,6 +147,7 @@
     private KeyGenParameterSpec mSpec;
 
     private String mEntryAlias;
+    private int mEntryUid;
     private boolean mEncryptionAtRestRequired;
     private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
     private int mKeymasterAlgorithm = -1;
@@ -283,6 +284,7 @@
             }
 
             mEntryAlias = spec.getKeystoreAlias();
+            mEntryUid = spec.getUid();
             mSpec = spec;
             mKeymasterAlgorithm = keymasterAlgorithm;
             mEncryptionAtRestRequired = encryptionAtRestRequired;
@@ -352,6 +354,7 @@
 
     private void resetAll() {
         mEntryAlias = null;
+        mEntryUid = KeyStore.UID_SELF;
         mJcaKeyAlgorithm = null;
         mKeymasterAlgorithm = -1;
         mKeymasterPurposes = null;
@@ -470,12 +473,13 @@
         final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
         boolean success = false;
         try {
-            Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias);
+            Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
             KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
             int errorCode = mKeyStore.generateKey(
                     privateKeyAlias,
                     args,
                     additionalEntropy,
+                    mEntryUid,
                     flags,
                     resultingKeyCharacteristics);
             if (errorCode != KeyStore.NO_ERROR) {
@@ -486,7 +490,7 @@
             KeyPair result;
             try {
                 result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
-                        mKeyStore, privateKeyAlias);
+                        mKeyStore, privateKeyAlias, mEntryUid);
             } catch (UnrecoverableKeyException e) {
                 throw new ProviderException("Failed to load generated key pair from keystore", e);
             }
@@ -515,7 +519,7 @@
             int insertErrorCode = mKeyStore.insert(
                     Credentials.USER_CERTIFICATE + mEntryAlias,
                     certBytes,
-                    KeyStore.UID_SELF,
+                    mEntryUid,
                     flags);
             if (insertErrorCode != KeyStore.NO_ERROR) {
                 throw new ProviderException("Failed to store self-signed certificate",
@@ -526,7 +530,7 @@
             return result;
         } finally {
             if (!success) {
-                Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias);
+                Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
             }
         }
     }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java b/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java
new file mode 100644
index 0000000..45d579e
--- /dev/null
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java
@@ -0,0 +1,38 @@
+/*
+ * 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 android.security.keystore;
+
+import java.security.KeyStore;
+import java.security.KeyStore.ProtectionParameter;
+
+class AndroidKeyStoreLoadStoreParameter implements KeyStore.LoadStoreParameter {
+
+    private final int mUid;
+
+    AndroidKeyStoreLoadStoreParameter(int uid) {
+        mUid = uid;
+    }
+
+    @Override
+    public ProtectionParameter getProtectionParameter() {
+        return null;
+    }
+
+    int getUid() {
+        return mUid;
+    }
+}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java
index b586ad4..06e4c88 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java
@@ -25,7 +25,7 @@
  */
 public class AndroidKeyStorePrivateKey extends AndroidKeyStoreKey implements PrivateKey {
 
-    public AndroidKeyStorePrivateKey(String alias, String algorithm) {
-        super(alias, algorithm);
+    public AndroidKeyStorePrivateKey(String alias, int uid, String algorithm) {
+        super(alias, uid, algorithm);
     }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index ba39ba7..c31a8b7 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -22,15 +22,19 @@
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterDefs;
 
+import java.io.IOException;
 import java.security.KeyFactory;
 import java.security.KeyPair;
+import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
 import java.security.Provider;
 import java.security.ProviderException;
 import java.security.PublicKey;
 import java.security.Security;
 import java.security.Signature;
 import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
 import java.security.interfaces.ECKey;
 import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAKey;
@@ -167,6 +171,7 @@
     @NonNull
     public static AndroidKeyStorePublicKey getAndroidKeyStorePublicKey(
             @NonNull String alias,
+            int uid,
             @NonNull @KeyProperties.KeyAlgorithmEnum String keyAlgorithm,
             @NonNull byte[] x509EncodedForm) {
         PublicKey publicKey;
@@ -180,9 +185,9 @@
             throw new ProviderException("Invalid X.509 encoding of public key", e);
         }
         if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
-            return new AndroidKeyStoreECPublicKey(alias, (ECPublicKey) publicKey);
+            return new AndroidKeyStoreECPublicKey(alias, uid, (ECPublicKey) publicKey);
         } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
-            return new AndroidKeyStoreRSAPublicKey(alias, (RSAPublicKey) publicKey);
+            return new AndroidKeyStoreRSAPublicKey(alias, uid, (RSAPublicKey) publicKey);
         } else {
             throw new ProviderException("Unsupported Android Keystore public key algorithm: "
                     + keyAlgorithm);
@@ -195,10 +200,10 @@
         String keyAlgorithm = publicKey.getAlgorithm();
         if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
             return new AndroidKeyStoreECPrivateKey(
-                    publicKey.getAlias(), ((ECKey) publicKey).getParams());
+                    publicKey.getAlias(), publicKey.getUid(), ((ECKey) publicKey).getParams());
         } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
             return new AndroidKeyStoreRSAPrivateKey(
-                    publicKey.getAlias(), ((RSAKey) publicKey).getModulus());
+                    publicKey.getAlias(), publicKey.getUid(), ((RSAKey) publicKey).getModulus());
         } else {
             throw new ProviderException("Unsupported Android Keystore public key algorithm: "
                     + keyAlgorithm);
@@ -207,18 +212,18 @@
 
     @NonNull
     public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
             throws UnrecoverableKeyException {
         KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
         int errorCode = keyStore.getKeyCharacteristics(
-                privateKeyAlias, null, null, keyCharacteristics);
+                privateKeyAlias, null, null, uid, keyCharacteristics);
         if (errorCode != KeyStore.NO_ERROR) {
             throw (UnrecoverableKeyException)
                     new UnrecoverableKeyException("Failed to obtain information about private key")
                     .initCause(KeyStore.getKeyStoreException(errorCode));
         }
         ExportResult exportResult = keyStore.exportKey(
-                privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
+                privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null, uid);
         if (exportResult.resultCode != KeyStore.NO_ERROR) {
             throw (UnrecoverableKeyException)
                     new UnrecoverableKeyException("Failed to obtain X.509 form of public key")
@@ -242,15 +247,15 @@
         }
 
         return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
-                privateKeyAlias, jcaKeyAlgorithm, x509EncodedPublicKey);
+                privateKeyAlias, uid, jcaKeyAlgorithm, x509EncodedPublicKey);
     }
 
     @NonNull
     public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
             throws UnrecoverableKeyException {
         AndroidKeyStorePublicKey publicKey =
-                loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias);
+                loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias, uid);
         AndroidKeyStorePrivateKey privateKey =
                 AndroidKeyStoreProvider.getAndroidKeyStorePrivateKey(publicKey);
         return new KeyPair(publicKey, privateKey);
@@ -258,19 +263,19 @@
 
     @NonNull
     public static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
             throws UnrecoverableKeyException {
-        KeyPair keyPair = loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias);
+        KeyPair keyPair = loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias, uid);
         return (AndroidKeyStorePrivateKey) keyPair.getPrivate();
     }
 
     @NonNull
     public static AndroidKeyStoreSecretKey loadAndroidKeyStoreSecretKeyFromKeystore(
-            @NonNull KeyStore keyStore, @NonNull String secretKeyAlias)
+            @NonNull KeyStore keyStore, @NonNull String secretKeyAlias, int uid)
             throws UnrecoverableKeyException {
         KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
         int errorCode = keyStore.getKeyCharacteristics(
-                secretKeyAlias, null, null, keyCharacteristics);
+                secretKeyAlias, null, null, uid, keyCharacteristics);
         if (errorCode != KeyStore.NO_ERROR) {
             throw (UnrecoverableKeyException)
                     new UnrecoverableKeyException("Failed to obtain information about key")
@@ -301,6 +306,29 @@
                     new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
         }
 
-        return new AndroidKeyStoreSecretKey(secretKeyAlias, keyAlgorithmString);
+        return new AndroidKeyStoreSecretKey(secretKeyAlias, uid, keyAlgorithmString);
+    }
+
+    /**
+     * Returns an {@code AndroidKeyStore} {@link java.security.KeyStore}} of the specified UID.
+     * The {@code KeyStore} contains keys and certificates owned by that UID. Such cross-UID
+     * access is permitted to a few system UIDs and only to a few other UIDs (e.g., Wi-Fi, VPN)
+     * all of which are system.
+     *
+     * <p>Note: the returned {@code KeyStore} is already initialized/loaded. Thus, there is
+     * no need to invoke {@code load} on it.
+     */
+    @NonNull
+    public static java.security.KeyStore getKeyStoreForUid(int uid)
+            throws KeyStoreException, NoSuchProviderException {
+        java.security.KeyStore result =
+                java.security.KeyStore.getInstance("AndroidKeyStore", PROVIDER_NAME);
+        try {
+            result.load(new AndroidKeyStoreLoadStoreParameter(uid));
+        } catch (NoSuchAlgorithmException | CertificateException | IOException e) {
+            throw new KeyStoreException(
+                    "Failed to load AndroidKeyStore KeyStore for UID " + uid, e);
+        }
+        return result;
     }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
index 9fea30d..4194780 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
@@ -28,8 +28,8 @@
 
     private final byte[] mEncoded;
 
-    public AndroidKeyStorePublicKey(String alias, String algorithm, byte[] x509EncodedForm) {
-        super(alias, algorithm);
+    public AndroidKeyStorePublicKey(String alias, int uid, String algorithm, byte[] x509EncodedForm) {
+        super(alias, uid, algorithm);
         mEncoded = ArrayUtils.cloneIfNotEmpty(x509EncodedForm);
     }
 
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
index 56cc44c..2ae68fa 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
@@ -415,9 +415,10 @@
 
         KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
         int errorCode = getKeyStore().getKeyCharacteristics(
-                keystoreKey.getAlias(), null, null, keyCharacteristics);
+                keystoreKey.getAlias(), null, null, keystoreKey.getUid(), keyCharacteristics);
         if (errorCode != KeyStore.NO_ERROR) {
-            throw getKeyStore().getInvalidKeyException(keystoreKey.getAlias(), errorCode);
+            throw getKeyStore().getInvalidKeyException(
+                    keystoreKey.getAlias(), keystoreKey.getUid(), errorCode);
         }
         long keySizeBits = keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
         if (keySizeBits == -1) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
index 179ffd8..adb3922 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
@@ -29,8 +29,8 @@
 
     private final BigInteger mModulus;
 
-    public AndroidKeyStoreRSAPrivateKey(String alias, BigInteger modulus) {
-        super(alias, KeyProperties.KEY_ALGORITHM_RSA);
+    public AndroidKeyStoreRSAPrivateKey(String alias, int uid, BigInteger modulus) {
+        super(alias, uid, KeyProperties.KEY_ALGORITHM_RSA);
         mModulus = modulus;
     }
 
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
index 08a173e..d85aace 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
@@ -28,15 +28,15 @@
     private final BigInteger mModulus;
     private final BigInteger mPublicExponent;
 
-    public AndroidKeyStoreRSAPublicKey(String alias, byte[] x509EncodedForm, BigInteger modulus,
+    public AndroidKeyStoreRSAPublicKey(String alias, int uid, byte[] x509EncodedForm, BigInteger modulus,
             BigInteger publicExponent) {
-        super(alias, KeyProperties.KEY_ALGORITHM_RSA, x509EncodedForm);
+        super(alias, uid, KeyProperties.KEY_ALGORITHM_RSA, x509EncodedForm);
         mModulus = modulus;
         mPublicExponent = publicExponent;
     }
 
-    public AndroidKeyStoreRSAPublicKey(String alias, RSAPublicKey info) {
-        this(alias, info.getEncoded(), info.getModulus(), info.getPublicExponent());
+    public AndroidKeyStoreRSAPublicKey(String alias, int uid, RSAPublicKey info) {
+        this(alias, uid, info.getEncoded(), info.getModulus(), info.getPublicExponent());
         if (!"X.509".equalsIgnoreCase(info.getFormat())) {
             throw new IllegalArgumentException(
                     "Unsupported key export format: " + info.getFormat());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
index af354ab..b8e6af7 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
@@ -25,7 +25,7 @@
  */
 public class AndroidKeyStoreSecretKey extends AndroidKeyStoreKey implements SecretKey {
 
-    public AndroidKeyStoreSecretKey(String alias, String algorithm) {
-        super(alias, algorithm);
+    public AndroidKeyStoreSecretKey(String alias, int uid, String algorithm) {
+        super(alias, uid, algorithm);
     }
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 11c22a9..8d606bf 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -59,7 +59,8 @@
         if (!KeyInfo.class.equals(keySpecClass)) {
             throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
         }
-        String keyAliasInKeystore = ((AndroidKeyStoreKey) key).getAlias();
+        AndroidKeyStoreKey keystoreKey = (AndroidKeyStoreKey) key;
+        String keyAliasInKeystore = keystoreKey.getAlias();
         String entryAlias;
         if (keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)) {
             entryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
@@ -67,13 +68,14 @@
             throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
         }
 
-        return getKeyInfo(mKeyStore, entryAlias, keyAliasInKeystore);
+        return getKeyInfo(mKeyStore, entryAlias, keyAliasInKeystore, keystoreKey.getUid());
     }
 
-    static KeyInfo getKeyInfo(KeyStore keyStore, String entryAlias, String keyAliasInKeystore) {
+    static KeyInfo getKeyInfo(KeyStore keyStore, String entryAlias, String keyAliasInKeystore,
+            int keyUid) {
         KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
-        int errorCode =
-                keyStore.getKeyCharacteristics(keyAliasInKeystore, null, null, keyCharacteristics);
+        int errorCode = keyStore.getKeyCharacteristics(
+                keyAliasInKeystore, null, null, keyUid, keyCharacteristics);
         if (errorCode != KeyStore.NO_ERROR) {
             throw new ProviderException("Failed to obtain information about key."
                     + " Keystore error: " + errorCode);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
index 76240dd..da47b6b 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
@@ -204,8 +204,8 @@
                 mSigning ? KeymasterDefs.KM_PURPOSE_SIGN : KeymasterDefs.KM_PURPOSE_VERIFY,
                 true, // permit aborting this operation if keystore runs out of resources
                 keymasterInputArgs,
-                null // no additional entropy for begin -- only finish might need some
-                );
+                null, // no additional entropy for begin -- only finish might need some
+                mKey.getUid());
         if (opResult == null) {
             throw new KeyStoreConnectException();
         }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index d300a92..cdcc7a2 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -17,7 +17,6 @@
 package android.security.keystore;
 
 import libcore.util.EmptyArray;
-
 import android.security.Credentials;
 import android.security.KeyStore;
 import android.security.KeyStoreParameter;
@@ -34,6 +33,7 @@
 import java.io.OutputStream;
 import java.security.Key;
 import java.security.KeyStore.Entry;
+import java.security.KeyStore.LoadStoreParameter;
 import java.security.KeyStore.PrivateKeyEntry;
 import java.security.KeyStore.ProtectionParameter;
 import java.security.KeyStore.SecretKeyEntry;
@@ -84,6 +84,7 @@
     public static final String NAME = "AndroidKeyStore";
 
     private KeyStore mKeyStore;
+    private int mUid = KeyStore.UID_SELF;
 
     @Override
     public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException,
@@ -91,11 +92,11 @@
         if (isPrivateKeyEntry(alias)) {
             String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
             return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
-                    mKeyStore, privateKeyAlias);
+                    mKeyStore, privateKeyAlias, mUid);
         } else if (isSecretKeyEntry(alias)) {
             String secretKeyAlias = Credentials.USER_SECRET_KEY + alias;
             return AndroidKeyStoreProvider.loadAndroidKeyStoreSecretKeyFromKeystore(
-                    mKeyStore, secretKeyAlias);
+                    mKeyStore, secretKeyAlias, mUid);
         } else {
             // Key not found
             return null;
@@ -115,7 +116,7 @@
 
         final Certificate[] caList;
 
-        final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+        final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
         if (caBytes != null) {
             final Collection<X509Certificate> caChain = toCertificates(caBytes);
 
@@ -141,12 +142,12 @@
             throw new NullPointerException("alias == null");
         }
 
-        byte[] encodedCert = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
+        byte[] encodedCert = mKeyStore.get(Credentials.USER_CERTIFICATE + alias, mUid);
         if (encodedCert != null) {
             return getCertificateForPrivateKeyEntry(alias, encodedCert);
         }
 
-        encodedCert = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+        encodedCert = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
         if (encodedCert != null) {
             return getCertificateForTrustedCertificateEntry(encodedCert);
         }
@@ -183,13 +184,13 @@
         }
 
         String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
-        if (mKeyStore.contains(privateKeyAlias)) {
+        if (mKeyStore.contains(privateKeyAlias, mUid)) {
             // As expected, keystore contains the private key corresponding to this public key. Wrap
             // the certificate so that its getPublicKey method returns an Android Keystore
             // PublicKey. This key will delegate crypto operations involving this public key to
             // Android Keystore when higher-priority providers do not offer these crypto
             // operations for this key.
-            return wrapIntoKeyStoreCertificate(privateKeyAlias, cert);
+            return wrapIntoKeyStoreCertificate(privateKeyAlias, mUid, cert);
         } else {
             // This KeyStore entry/alias is supposed to contain the private key corresponding to
             // the public key in this certificate, but it does not for some reason. It's probably a
@@ -206,9 +207,9 @@
      * find out which key alias to use. These operations cannot work without an alias.
      */
     private static KeyStoreX509Certificate wrapIntoKeyStoreCertificate(
-            String privateKeyAlias, X509Certificate certificate) {
+            String privateKeyAlias, int uid, X509Certificate certificate) {
         return (certificate != null)
-                ? new KeyStoreX509Certificate(privateKeyAlias, certificate) : null;
+                ? new KeyStoreX509Certificate(privateKeyAlias, uid, certificate) : null;
     }
 
     private static X509Certificate toCertificate(byte[] bytes) {
@@ -235,7 +236,7 @@
     }
 
     private Date getModificationDate(String alias) {
-        final long epochMillis = mKeyStore.getmtime(alias);
+        final long epochMillis = mKeyStore.getmtime(alias, mUid);
         if (epochMillis == -1L) {
             return null;
         }
@@ -516,13 +517,14 @@
             if (shouldReplacePrivateKey) {
                 // Delete the stored private key and any related entries before importing the
                 // provided key
-                Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+                Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
                 KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
                 int errorCode = mKeyStore.importKey(
                         Credentials.USER_PRIVATE_KEY + alias,
                         importArgs,
                         KeymasterDefs.KM_KEY_FORMAT_PKCS8,
                         pkcs8EncodedPrivateKeyBytes,
+                        mUid,
                         flags,
                         resultingKeyCharacteristics);
                 if (errorCode != KeyStore.NO_ERROR) {
@@ -531,13 +533,13 @@
                 }
             } else {
                 // Keep the stored private key around -- delete all other entry types
-                Credentials.deleteCertificateTypesForAlias(mKeyStore, alias);
-                Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias);
+                Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
+                Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias, mUid);
             }
 
             // Store the leaf certificate
             int errorCode = mKeyStore.insert(Credentials.USER_CERTIFICATE + alias, userCertBytes,
-                    KeyStore.UID_SELF, flags);
+                    mUid, flags);
             if (errorCode != KeyStore.NO_ERROR) {
                 throw new KeyStoreException("Failed to store certificate #0",
                         KeyStore.getKeyStoreException(errorCode));
@@ -545,7 +547,7 @@
 
             // Store the certificate chain
             errorCode = mKeyStore.insert(Credentials.CA_CERTIFICATE + alias, chainBytes,
-                    KeyStore.UID_SELF, flags);
+                    mUid, flags);
             if (errorCode != KeyStore.NO_ERROR) {
                 throw new KeyStoreException("Failed to store certificate chain",
                         KeyStore.getKeyStoreException(errorCode));
@@ -554,10 +556,10 @@
         } finally {
             if (!success) {
                 if (shouldReplacePrivateKey) {
-                    Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+                    Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
                 } else {
-                    Credentials.deleteCertificateTypesForAlias(mKeyStore, alias);
-                    Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias);
+                    Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
+                    Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias, mUid);
                 }
             }
         }
@@ -712,13 +714,14 @@
             throw new KeyStoreException(e);
         }
 
-        Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias);
+        Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias, mUid);
         String keyAliasInKeystore = Credentials.USER_SECRET_KEY + entryAlias;
         int errorCode = mKeyStore.importKey(
                 keyAliasInKeystore,
                 args,
                 KeymasterDefs.KM_KEY_FORMAT_RAW,
                 keyMaterial,
+                mUid,
                 0, // flags
                 new KeyCharacteristics());
         if (errorCode != KeyStore.NO_ERROR) {
@@ -751,8 +754,7 @@
             throw new KeyStoreException(e);
         }
 
-        if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, encoded,
-                KeyStore.UID_SELF, KeyStore.FLAG_NONE)) {
+        if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, encoded, mUid, KeyStore.FLAG_NONE)) {
             throw new KeyStoreException("Couldn't insert certificate; is KeyStore initialized?");
         }
     }
@@ -764,13 +766,13 @@
         }
         // At least one entry corresponding to this alias exists in keystore
 
-        if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias)) {
+        if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid)) {
             throw new KeyStoreException("Failed to delete entry: " + alias);
         }
     }
 
     private Set<String> getUniqueAliases() {
-        final String[] rawAliases = mKeyStore.list("");
+        final String[] rawAliases = mKeyStore.list("", mUid);
         if (rawAliases == null) {
             return new HashSet<String>();
         }
@@ -800,10 +802,10 @@
             throw new NullPointerException("alias == null");
         }
 
-        return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias)
-                || mKeyStore.contains(Credentials.USER_SECRET_KEY + alias)
-                || mKeyStore.contains(Credentials.USER_CERTIFICATE + alias)
-                || mKeyStore.contains(Credentials.CA_CERTIFICATE + alias);
+        return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias, mUid)
+                || mKeyStore.contains(Credentials.USER_SECRET_KEY + alias, mUid)
+                || mKeyStore.contains(Credentials.USER_CERTIFICATE + alias, mUid)
+                || mKeyStore.contains(Credentials.CA_CERTIFICATE + alias, mUid);
     }
 
     @Override
@@ -825,7 +827,7 @@
             throw new NullPointerException("alias == null");
         }
 
-        return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias);
+        return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias, mUid);
     }
 
     private boolean isSecretKeyEntry(String alias) {
@@ -833,7 +835,7 @@
             throw new NullPointerException("alias == null");
         }
 
-        return mKeyStore.contains(Credentials.USER_SECRET_KEY + alias);
+        return mKeyStore.contains(Credentials.USER_SECRET_KEY + alias, mUid);
     }
 
     private boolean isCertificateEntry(String alias) {
@@ -841,7 +843,7 @@
             throw new NullPointerException("alias == null");
         }
 
-        return mKeyStore.contains(Credentials.CA_CERTIFICATE + alias);
+        return mKeyStore.contains(Credentials.CA_CERTIFICATE + alias, mUid);
     }
 
     @Override
@@ -876,10 +878,10 @@
          * equivalent to the USER_CERTIFICATE prefix for the Android keystore
          * convention.
          */
-        final String[] certAliases = mKeyStore.list(Credentials.USER_CERTIFICATE);
+        final String[] certAliases = mKeyStore.list(Credentials.USER_CERTIFICATE, mUid);
         if (certAliases != null) {
             for (String alias : certAliases) {
-                final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
+                final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias, mUid);
                 if (certBytes == null) {
                     continue;
                 }
@@ -896,14 +898,14 @@
          * Look at all the TrustedCertificateEntry types. Skip all the
          * PrivateKeyEntry we looked at above.
          */
-        final String[] caAliases = mKeyStore.list(Credentials.CA_CERTIFICATE);
+        final String[] caAliases = mKeyStore.list(Credentials.CA_CERTIFICATE, mUid);
         if (certAliases != null) {
             for (String alias : caAliases) {
                 if (nonCaEntries.contains(alias)) {
                     continue;
                 }
 
-                final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+                final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
                 if (certBytes == null) {
                     continue;
                 }
@@ -936,6 +938,23 @@
 
         // Unfortunate name collision.
         mKeyStore = KeyStore.getInstance();
+        mUid = KeyStore.UID_SELF;
+    }
+
+    @Override
+    public void engineLoad(LoadStoreParameter param) throws IOException,
+            NoSuchAlgorithmException, CertificateException {
+        int uid = KeyStore.UID_SELF;
+        if (param != null) {
+            if (param instanceof AndroidKeyStoreLoadStoreParameter) {
+                uid = ((AndroidKeyStoreLoadStoreParameter) param).getUid();
+            } else {
+                throw new IllegalArgumentException(
+                        "Unsupported param type: " + param.getClass());
+            }
+        }
+        mKeyStore = KeyStore.getInstance();
+        mUid = uid;
     }
 
     @Override
@@ -945,7 +964,7 @@
             throw new KeyStoreException("entry == null");
         }
 
-        Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+        Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
 
         if (entry instanceof java.security.KeyStore.TrustedCertificateEntry) {
             java.security.KeyStore.TrustedCertificateEntry trE =
@@ -976,16 +995,20 @@
      */
     static class KeyStoreX509Certificate extends DelegatingX509Certificate {
         private final String mPrivateKeyAlias;
-        KeyStoreX509Certificate(String privateKeyAlias, X509Certificate delegate) {
+        private final int mPrivateKeyUid;
+        KeyStoreX509Certificate(String privateKeyAlias, int privateKeyUid,
+                X509Certificate delegate) {
             super(delegate);
             mPrivateKeyAlias = privateKeyAlias;
+            mPrivateKeyUid = privateKeyUid;
         }
 
         @Override
         public PublicKey getPublicKey() {
             PublicKey original = super.getPublicKey();
             return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
-                    mPrivateKeyAlias, original.getAlgorithm(), original.getEncoded());
+                    mPrivateKeyAlias, mPrivateKeyUid,
+                    original.getAlgorithm(), original.getEncoded());
         }
     }
 }
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index f42d750..add199f 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.app.KeyguardManager;
 import android.hardware.fingerprint.FingerprintManager;
+import android.security.KeyStore;
 import android.text.TextUtils;
 
 import java.math.BigInteger;
@@ -231,6 +232,7 @@
     private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
 
     private final String mKeystoreAlias;
+    private final int mUid;
     private final int mKeySize;
     private final AlgorithmParameterSpec mSpec;
     private final X500Principal mCertificateSubject;
@@ -254,6 +256,7 @@
      */
     public KeyGenParameterSpec(
             String keyStoreAlias,
+            int uid,
             int keySize,
             AlgorithmParameterSpec spec,
             X500Principal certificateSubject,
@@ -293,6 +296,7 @@
         }
 
         mKeystoreAlias = keyStoreAlias;
+        mUid = uid;
         mKeySize = keySize;
         mSpec = spec;
         mCertificateSubject = certificateSubject;
@@ -323,6 +327,16 @@
     }
 
     /**
+     * Returns the UID which will own the key. {@code -1} is an alias for the UID of the current
+     * process.
+     *
+     * @hide
+     */
+    public int getUid() {
+        return mUid;
+    }
+
+    /**
      * Returns the requested key size. If {@code -1}, the size should be looked up from
      * {@link #getAlgorithmParameterSpec()}, if provided, otherwise an algorithm-specific default
      * size should be used.
@@ -531,6 +545,7 @@
         private final String mKeystoreAlias;
         private @KeyProperties.PurposeEnum int mPurposes;
 
+        private int mUid = KeyStore.UID_SELF;
         private int mKeySize = -1;
         private AlgorithmParameterSpec mSpec;
         private X500Principal mCertificateSubject;
@@ -575,6 +590,19 @@
         }
 
         /**
+         * Sets the UID which will own the key.
+         *
+         * @param uid UID or {@code -1} for the UID of the current process.
+         *
+         * @hide
+         */
+        @NonNull
+        public Builder setUid(int uid) {
+            mUid = uid;
+            return this;
+        }
+
+        /**
          * Sets the size (in bits) of the key to be generated. For instance, for RSA keys this sets
          * the modulus size, for EC keys this selects a curve with a matching field size, and for
          * symmetric keys this sets the size of the bitstring which is their key material.
@@ -936,6 +964,7 @@
         public KeyGenParameterSpec build() {
             return new KeyGenParameterSpec(
                     mKeystoreAlias,
+                    mUid,
                     mKeySize,
                     mSpec,
                     mCertificateSubject,
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java
index 27c1b2a..773729e 100644
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java
+++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java
@@ -51,7 +51,7 @@
         // An error occured. However, some errors should not lead to init throwing an exception.
         // See below.
         InvalidKeyException e =
-                keyStore.getInvalidKeyException(key.getAlias(), beginOpResultCode);
+                keyStore.getInvalidKeyException(key.getAlias(), key.getUid(), beginOpResultCode);
         switch (beginOpResultCode) {
             case KeyStore.OP_AUTH_NEEDED:
                 // Operation needs to be authorized by authenticating the user. Don't throw an
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
index e5c15c5..1af0b7d 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
@@ -384,6 +384,7 @@
                 pubKey,
                 AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
                         Credentials.USER_PRIVATE_KEY + alias,
+                        KeyStore.UID_SELF,
                         x509userCert.getPublicKey().getAlgorithm(),
                         x509userCert.getPublicKey().getEncoded()));
 
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
index c3b731b..aa718dc 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
@@ -1918,7 +1918,7 @@
         final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
 
         KeyPair keyPair = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
-                keyStore, privateKeyAlias);
+                keyStore, privateKeyAlias, KeyStore.UID_SELF);
 
         final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
         certGen.setPublicKey(keyPair.getPublic());
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 623ea89..8a03b94 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -176,7 +176,7 @@
     delete[] mVendor;
 }
 
-bool AssetManager::addAssetPath(const String8& path, int32_t* cookie)
+bool AssetManager::addAssetPath(const String8& path, int32_t* cookie, bool appAsLib)
 {
     AutoMutex _l(mLock);
 
@@ -238,7 +238,7 @@
 #endif
 
     if (mResources != NULL) {
-        appendPathToResTable(ap);
+        appendPathToResTable(ap, appAsLib);
     }
 
     return true;
@@ -610,7 +610,7 @@
         return kFileTypeRegular;
 }
 
-bool AssetManager::appendPathToResTable(const asset_path& ap) const {
+bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) const {
     // skip those ap's that correspond to system overlays
     if (ap.isSystemOverlay) {
         return true;
@@ -685,7 +685,7 @@
             mResources->add(sharedRes);
         } else {
             ALOGV("Parsing resources for %s", ap.path.string());
-            mResources->add(ass, idmap, nextEntryIdx + 1, !shared);
+            mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib);
         }
         onlyEmptyResources = false;
 
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 37de89a..21b543e 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3080,13 +3080,13 @@
 // table that defined the package); the ones after are skins on top of it.
 struct ResTable::PackageGroup
 {
-    PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id)
+    PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id, bool appAsLib)
         : owner(_owner)
         , name(_name)
         , id(_id)
         , largestTypeId(0)
         , bags(NULL)
-        , dynamicRefTable(static_cast<uint8_t>(_id))
+        , dynamicRefTable(static_cast<uint8_t>(_id), appAsLib)
     { }
 
     ~PackageGroup() {
@@ -3532,7 +3532,7 @@
 {
     memset(&mParams, 0, sizeof(mParams));
     memset(mPackageMap, 0, sizeof(mPackageMap));
-    addInternal(data, size, NULL, 0, cookie, copyData);
+    addInternal(data, size, NULL, 0, false, cookie, copyData);
     LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
     if (kDebugTableSuperNoisy) {
         ALOGI("Creating ResTable %p\n", this);
@@ -3553,12 +3553,12 @@
 }
 
 status_t ResTable::add(const void* data, size_t size, const int32_t cookie, bool copyData) {
-    return addInternal(data, size, NULL, 0, cookie, copyData);
+    return addInternal(data, size, NULL, 0, false, cookie, copyData);
 }
 
 status_t ResTable::add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
-        const int32_t cookie, bool copyData) {
-    return addInternal(data, size, idmapData, idmapDataSize, cookie, copyData);
+        const int32_t cookie, bool copyData, bool appAsLib) {
+    return addInternal(data, size, idmapData, idmapDataSize, appAsLib, cookie, copyData);
 }
 
 status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) {
@@ -3568,10 +3568,12 @@
         return UNKNOWN_ERROR;
     }
 
-    return addInternal(data, static_cast<size_t>(asset->getLength()), NULL, 0, cookie, copyData);
+    return addInternal(data, static_cast<size_t>(asset->getLength()), NULL, false, 0, cookie,
+            copyData);
 }
 
-status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData) {
+status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
+        bool appAsLib) {
     const void* data = asset->getBuffer(true);
     if (data == NULL) {
         ALOGW("Unable to get buffer of resource asset file");
@@ -3590,7 +3592,7 @@
     }
 
     return addInternal(data, static_cast<size_t>(asset->getLength()),
-            idmapData, idmapSize, cookie, copyData);
+            idmapData, idmapSize, appAsLib, cookie, copyData);
 }
 
 status_t ResTable::add(ResTable* src)
@@ -3603,7 +3605,7 @@
 
     for (size_t i=0; i<src->mPackageGroups.size(); i++) {
         PackageGroup* srcPg = src->mPackageGroups[i];
-        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id);
+        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id, false);
         for (size_t j=0; j<srcPg->packages.size(); j++) {
             pg->packages.add(srcPg->packages[j]);
         }
@@ -3644,7 +3646,7 @@
 }
 
 status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize,
-        const int32_t cookie, bool copyData)
+        bool appAsLib, const int32_t cookie, bool copyData)
 {
     if (!data) {
         return NO_ERROR;
@@ -3747,7 +3749,7 @@
                 return (mError=BAD_TYPE);
             }
 
-            if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
+            if (parsePackage((ResTable_package*)chunk, header, appAsLib) != NO_ERROR) {
                 return mError;
             }
             curPackage++;
@@ -5935,7 +5937,7 @@
 }
 
 status_t ResTable::parsePackage(const ResTable_package* const pkg,
-                                const Header* const header)
+                                const Header* const header, bool appAsLib)
 {
     const uint8_t* base = (const uint8_t*)pkg;
     status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
@@ -5983,7 +5985,7 @@
     if (id >= 256) {
         LOG_ALWAYS_FATAL("Package id out of range");
         return NO_ERROR;
-    } else if (id == 0) {
+    } else if (id == 0 || appAsLib) {
         // This is a library so assign an ID
         id = mNextPackageId++;
     }
@@ -6016,7 +6018,7 @@
 
         char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
         strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
-        group = new PackageGroup(this, String16(tmpName), id);
+        group = new PackageGroup(this, String16(tmpName), id, appAsLib);
         if (group == NULL) {
             delete package;
             return (mError=NO_MEMORY);
@@ -6228,8 +6230,9 @@
     return NO_ERROR;
 }
 
-DynamicRefTable::DynamicRefTable(uint8_t packageId)
+DynamicRefTable::DynamicRefTable(uint8_t packageId, bool appAsLib)
     : mAssignedPackageId(packageId)
+    , mAppAsLib(appAsLib)
 {
     memset(mLookupTable, 0, sizeof(mLookupTable));
 
@@ -6314,16 +6317,18 @@
     uint32_t res = *resId;
     size_t packageId = Res_GETPACKAGE(res) + 1;
 
-    if (packageId == APP_PACKAGE_ID) {
+    if (packageId == APP_PACKAGE_ID && !mAppAsLib) {
         // No lookup needs to be done, app package IDs are absolute.
         return NO_ERROR;
     }
 
-    if (packageId == 0) {
+    if (packageId == 0 || (packageId == APP_PACKAGE_ID && mAppAsLib)) {
         // The package ID is 0x00. That means that a shared library is accessing
-        // its own local resource, so we fix up the resource with the calling
-        // package ID.
-        *resId |= ((uint32_t) mAssignedPackageId) << 24;
+        // its own local resource.
+        // Or if app resource is loaded as shared library, the resource which has
+        // app package Id is local resources.
+        // so we fix up those resources with the calling package ID.
+        *resId = (0xFFFFFF & (*resId)) | (((uint32_t) mAssignedPackageId) << 24);
         return NO_ERROR;
     }
 
@@ -6345,7 +6350,10 @@
 }
 
 status_t DynamicRefTable::lookupResourceValue(Res_value* value) const {
-    if (value->dataType != Res_value::TYPE_DYNAMIC_REFERENCE) {
+    if (value->dataType != Res_value::TYPE_DYNAMIC_REFERENCE &&
+        (value->dataType != Res_value::TYPE_REFERENCE || !mAppAsLib)) {
+        // If the package is loaded as shared library, the resource reference
+        // also need to be fixed.
         return NO_ERROR;
     }
 
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index a353575..2bc026b7 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -21,6 +21,7 @@
 LOCAL_PATH:= $(call my-dir)
 
 testFiles := \
+    AppAsLib_test.cpp \
     AttributeFinder_test.cpp \
     ByteBucketArray_test.cpp \
     Config_test.cpp \
diff --git a/libs/androidfw/tests/AppAsLib_test.cpp b/libs/androidfw/tests/AppAsLib_test.cpp
new file mode 100644
index 0000000..bdb0c3d
--- /dev/null
+++ b/libs/androidfw/tests/AppAsLib_test.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 <androidfw/ResourceTypes.h>
+
+#include "data/basic/R.h"
+#include "data/appaslib/R.h"
+
+#include <gtest/gtest.h>
+
+using namespace android;
+
+namespace {
+
+#include "data/basic/basic_arsc.h"
+
+TEST(AppAsLibTest, loadedAsApp) {
+  ResTable table;
+  ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+
+  Res_value val;
+  ssize_t block = table.getResource(base::R::integer::number2, &val);
+  ASSERT_GE(block, 0);
+  ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
+  ASSERT_EQ(base::R::array::integerArray1, val.data);
+}
+
+TEST(AppAsLibTest, loadedAsSharedLib) {
+  ResTable table;
+  // Load as shared library.
+  ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len, NULL, 0, -1, false, true));
+
+  Res_value val;
+  ssize_t block = table.getResource(appaslib::R::integer::number2, &val);
+  ASSERT_GE(block, 0);
+  ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType);
+  ASSERT_EQ(appaslib::R::array::integerArray1, val.data);
+}
+
+}
diff --git a/libs/androidfw/tests/data/appaslib/R.h b/libs/androidfw/tests/data/appaslib/R.h
new file mode 100644
index 0000000..f89d4bf
--- /dev/null
+++ b/libs/androidfw/tests/data/appaslib/R.h
@@ -0,0 +1,38 @@
+/*
+ * 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 __APPASLIB_R_H
+#define __APPASLIB_R_H
+
+namespace appaslib {
+namespace R {
+
+namespace integer {
+    enum {
+        number2     = 0x02040001,   // default
+    };
+}
+
+namespace array {
+    enum {
+        integerArray1 = 0x02060000,   // default
+    };
+}
+
+} // namespace R
+} // namespace appaslib
+
+#endif // __APPASLIB_R_H
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index e307ad9..c128ca7 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -34,12 +34,17 @@
 
 }
 
-CanvasState::~CanvasState() {
-
-}
-
-void CanvasState::initializeSaveStack(float clipLeft, float clipTop,
+void CanvasState::initializeSaveStack(
+        int viewportWidth, int viewportHeight,
+        float clipLeft, float clipTop,
         float clipRight, float clipBottom, const Vector3& lightCenter) {
+    if (mWidth != viewportWidth || mHeight != viewportHeight) {
+        mWidth = viewportWidth;
+        mHeight = viewportHeight;
+        mFirstSnapshot->initializeViewport(viewportWidth, viewportHeight);
+        mCanvas.onViewportInitialized();
+    }
+
     mSnapshot = new Snapshot(mFirstSnapshot,
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
@@ -48,20 +53,6 @@
     mSaveCount = 1;
 }
 
-void CanvasState::setViewport(int width, int height) {
-    mWidth = width;
-    mHeight = height;
-    mFirstSnapshot->initializeViewport(width, height);
-    mCanvas.onViewportInitialized();
-
-    // create a temporary 1st snapshot, so old snapshots are released,
-    // and viewport can be queried safely.
-    // TODO: remove, combine viewport + save stack initialization
-    mSnapshot = new Snapshot(mFirstSnapshot,
-            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
-    mSaveCount = 1;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Save (layer)
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
index b35db28..f0fb9ba 100644
--- a/libs/hwui/CanvasState.h
+++ b/libs/hwui/CanvasState.h
@@ -71,20 +71,18 @@
  * (getClip/Matrix), but so that quickRejection can also be used.
  */
 
-class ANDROID_API CanvasState {
+class CanvasState {
 public:
     CanvasState(CanvasStateClient& renderer);
-    ~CanvasState();
 
     /**
      * Initializes the first snapshot, computing the projection matrix,
      * and stores the dimensions of the render target.
      */
-    void initializeSaveStack(float clipLeft, float clipTop, float clipRight, float clipBottom,
+    void initializeSaveStack(int viewportWidth, int viewportHeight,
+            float clipLeft, float clipTop, float clipRight, float clipBottom,
             const Vector3& lightCenter);
 
-    void setViewport(int width, int height);
-
     bool hasRectToRectTransform() const {
         return CC_LIKELY(currentTransform()->rectToRect());
     }
@@ -159,16 +157,11 @@
     int getHeight() const { return mHeight; }
     bool clipIsSimple() const { return currentSnapshot()->clipIsSimple(); }
 
-    inline const Snapshot* currentSnapshot() const {
-        return mSnapshot != nullptr ? mSnapshot.get() : mFirstSnapshot.get();
-    }
+    inline const Snapshot* currentSnapshot() const { return mSnapshot.get(); }
     inline Snapshot* writableSnapshot() { return mSnapshot.get(); }
     inline const Snapshot* firstSnapshot() const { return mFirstSnapshot.get(); }
 
 private:
-    /// No default constructor - must supply a CanvasStateClient (mCanvas).
-    CanvasState();
-
     /// indicates that the clip has been changed since the last time it was consumed
     bool mDirtyClip;
 
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index 506bfad..77bde86 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -54,8 +54,8 @@
             "prepareDirty called a second time during a recording!");
     mDisplayListData = new DisplayListData();
 
-    mState.setViewport(width, height);
-    mState.initializeSaveStack(0, 0, mState.getWidth(), mState.getHeight(), Vector3());
+    mState.initializeSaveStack(width, height,
+            0, 0, width, height, Vector3());
 
     mDeferredBarrierType = kBarrier_InOrder;
     mState.setDirtyClip(false);
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index e748221..8d85289 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -236,8 +236,7 @@
     DeferStateStruct deferredState(*deferredList, *renderer,
             RenderNode::kReplayFlag_ClipChildren);
 
-    renderer->setViewport(width, height);
-    renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
+    renderer->setupFrameState(width, height, dirtyRect.left, dirtyRect.top,
             dirtyRect.right, dirtyRect.bottom, !isBlend());
 
     renderNode->computeOrdering();
@@ -258,9 +257,8 @@
         ATRACE_LAYER_WORK("Issue");
         renderer->startMark((renderNode.get() != nullptr) ? renderNode->getName() : "Layer");
 
-        renderer->setViewport(layer.getWidth(), layer.getHeight());
-        renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
-                !isBlend());
+        renderer->prepareDirty(layer.getWidth(), layer.getHeight(),
+                dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, !isBlend());
 
         deferredList->flush(*renderer, dirtyRect);
 
@@ -277,9 +275,8 @@
     ATRACE_LAYER_WORK("Direct-Issue");
 
     updateLightPosFromRenderer(rootRenderer);
-    renderer->setViewport(layer.getWidth(), layer.getHeight());
-    renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom,
-            !isBlend());
+    renderer->prepareDirty(layer.getWidth(), layer.getHeight(),
+            dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, !isBlend());
 
     renderer->drawRenderNode(renderNode.get(), dirtyRect, RenderNode::kReplayFlag_ClipChildren);
 
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index d8e6392..c63b559 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -43,8 +43,8 @@
 LayerRenderer::~LayerRenderer() {
 }
 
-void LayerRenderer::prepareDirty(float left, float top, float right, float bottom,
-        bool opaque) {
+void LayerRenderer::prepareDirty(int viewportWidth, int viewportHeight,
+        float left, float top, float right, float bottom, bool opaque) {
     LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
 
     mRenderState.bindFramebuffer(mLayer->getFbo());
@@ -64,7 +64,8 @@
     }
     mLayer->clipRect.set(dirty);
 
-    OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque);
+    OpenGLRenderer::prepareDirty(viewportWidth, viewportHeight,
+            dirty.left, dirty.top, dirty.right, dirty.bottom, opaque);
 }
 
 void LayerRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
@@ -430,9 +431,8 @@
 
         {
             LayerRenderer renderer(renderState, layer);
-            renderer.setViewport(bitmap->width(), bitmap->height());
-            renderer.OpenGLRenderer::prepareDirty(0.0f, 0.0f,
-                    bitmap->width(), bitmap->height(), !layer->isBlend());
+            renderer.OpenGLRenderer::prepareDirty(bitmap->width(), bitmap->height(),
+                    0.0f, 0.0f, bitmap->width(), bitmap->height(), !layer->isBlend());
 
             renderState.scissor().setEnabled(false);
             renderer.translate(0.0f, bitmap->height());
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index 47ded7e..e4a54b0 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -50,8 +50,8 @@
     virtual ~LayerRenderer();
 
     virtual void onViewportInitialized() override { /* do nothing */ }
-    virtual void prepareDirty(float left, float top, float right, float bottom,
-            bool opaque) override;
+    virtual void prepareDirty(int viewportWidth, int viewportHeight,
+            float left, float top, float right, float bottom, bool opaque) override;
     virtual void clear(float left, float top, float right, float bottom, bool opaque) override;
     virtual bool finish() override;
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 5692d7e..e06e348 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -113,10 +113,11 @@
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 }
 
-void OpenGLRenderer::setupFrameState(float left, float top,
-        float right, float bottom, bool opaque) {
+void OpenGLRenderer::setupFrameState(int viewportWidth, int viewportHeight,
+        float left, float top, float right, float bottom, bool opaque) {
     mCaches.clearGarbage();
-    mState.initializeSaveStack(left, top, right, bottom, mLightCenter);
+    mState.initializeSaveStack(viewportWidth, viewportHeight,
+            left, top, right, bottom, mLightCenter);
     mOpaque = opaque;
     mTilingClip.set(left, top, right, bottom);
 }
@@ -137,10 +138,10 @@
             mTilingClip.right, mTilingClip.bottom, mOpaque);
 }
 
-void OpenGLRenderer::prepareDirty(float left, float top,
-        float right, float bottom, bool opaque) {
+void OpenGLRenderer::prepareDirty(int viewportWidth, int viewportHeight,
+        float left, float top, float right, float bottom, bool opaque) {
 
-    setupFrameState(left, top, right, bottom, opaque);
+    setupFrameState(viewportWidth, viewportHeight, left, top, right, bottom, opaque);
 
     // Layer renderers will start the frame immediately
     // The framebuffer renderer will first defer the display list
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index af85e8c..910af57 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -119,15 +119,6 @@
     OpenGLRenderer(RenderState& renderState);
     virtual ~OpenGLRenderer();
 
-    /**
-     * Sets the dimension of the underlying drawing surface. This method must
-     * be called at least once every time the drawing surface changes size.
-     *
-     * @param width The width in pixels of the underlysing surface
-     * @param height The height in pixels of the underlysing surface
-     */
-    void setViewport(int width, int height) { mState.setViewport(width, height); }
-
     void initProperties();
     void initLight(float lightRadius, uint8_t ambientShadowAlpha,
             uint8_t spotShadowAlpha);
@@ -143,21 +134,8 @@
      *               and will not be cleared. If false, the target surface
      *               will be cleared
      */
-    virtual void prepareDirty(float left, float top, float right, float bottom,
-            bool opaque);
-
-    /**
-     * Prepares the renderer to draw a frame. This method must be invoked
-     * at the beginning of each frame. When this method is invoked, the
-     * entire drawing surface is assumed to be redrawn.
-     *
-     * @param opaque If true, the target surface is considered opaque
-     *               and will not be cleared. If false, the target surface
-     *               will be cleared
-     */
-    void prepare(bool opaque) {
-        prepareDirty(0.0f, 0.0f, mState.getWidth(), mState.getHeight(), opaque);
-    }
+    virtual void prepareDirty(int viewportWidth, int viewportHeight,
+            float left, float top, float right, float bottom, bool opaque);
 
     /**
      * Indicates the end of a frame. This method must be invoked whenever
@@ -430,7 +408,8 @@
      * Perform the setup specific to a frame. This method does not
      * issue any OpenGL commands.
      */
-    void setupFrameState(float left, float top, float right, float bottom, bool opaque);
+    void setupFrameState(int viewportWidth, int viewportHeight,
+            float left, float top, float right, float bottom, bool opaque);
 
     /**
      * Indicates the start of rendering. This method will setup the
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 1673802..b74b508 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -248,7 +248,7 @@
     Frame frame = mEglManager.beginFrame(mEglSurface);
     if (frame.width() != mCanvas->getViewportWidth()
             || frame.height() != mCanvas->getViewportHeight()) {
-        mCanvas->setViewport(frame.width(), frame.height());
+        // can't rely on prior content of window if viewport size changes
         dirty.setEmpty();
     } else if (mHaveNewSurface || frame.bufferAge() == 0) {
         // New surface needs a full draw
@@ -295,8 +295,8 @@
     mDamageHistory.next() = screenDirty;
 
     mEglManager.damageFrame(frame, dirty);
-    mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,
-            dirty.fRight, dirty.fBottom, mOpaque);
+    mCanvas->prepareDirty(frame.width(), frame.height(),
+            dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque);
 
     Rect outBounds;
     mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);
diff --git a/libs/hwui/unit_tests/CanvasStateTests.cpp b/libs/hwui/unit_tests/CanvasStateTests.cpp
index 79852be..dfbf6d3 100644
--- a/libs/hwui/unit_tests/CanvasStateTests.cpp
+++ b/libs/hwui/unit_tests/CanvasStateTests.cpp
@@ -47,8 +47,8 @@
 
 TEST(CanvasState, gettersAndSetters) {
     CanvasState state(sNullClient);
-    state.setViewport(200, 200);
-    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+    state.initializeSaveStack(200, 200,
+            0, 0, 200, 200, Vector3());
 
     ASSERT_EQ(state.getWidth(), 200);
     ASSERT_EQ(state.getHeight(), 200);
@@ -65,8 +65,8 @@
 
 TEST(CanvasState, simpleClipping) {
     CanvasState state(sNullClient);
-    state.setViewport(200, 200);
-    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+    state.initializeSaveStack(200, 200,
+            0, 0, 200, 200, Vector3());
 
     state.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
     ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 100, 100));
@@ -80,8 +80,8 @@
 
 TEST(CanvasState, complexClipping) {
     CanvasState state(sNullClient);
-    state.setViewport(200, 200);
-    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+    state.initializeSaveStack(200, 200,
+            0, 0, 200, 200, Vector3());
 
     state.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
     {
@@ -116,8 +116,8 @@
 
 TEST(CanvasState, saveAndRestore) {
     CanvasState state(sNullClient);
-    state.setViewport(200, 200);
-    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+    state.initializeSaveStack(200, 200,
+            0, 0, 200, 200, Vector3());
 
     state.save(SkCanvas::kClip_SaveFlag);
     {
@@ -140,10 +140,10 @@
 
 TEST(CanvasState, saveAndRestoreButNotTooMuch) {
     CanvasState state(sNullClient);
-    state.setViewport(200, 200);
-    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+    state.initializeSaveStack(200, 200,
+            0, 0, 200, 200, Vector3());
 
-    state.save(SkCanvas::kMatrix_SaveFlag); // Note: clip not saved
+    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));
diff --git a/packages/BackupRestoreConfirmation/res/values-nl/strings.xml b/packages/BackupRestoreConfirmation/res/values-nl/strings.xml
index f483b14..81f2712 100644
--- a/packages/BackupRestoreConfirmation/res/values-nl/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-nl/strings.xml
@@ -18,18 +18,18 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Volledige back-up"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Volledig herstel"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"Er is een volledige back-up van alle gegevens naar een verbonden desktopcomputer aangevraagd. Wilt u dit toestaan?\n\nAls u de back-up zelf niet heeft aangevraagd, moet u niet toestaan dat de bewerking wordt uitgevoerd."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"Er is een volledige back-up van alle gegevens naar een verbonden desktopcomputer aangevraagd. Wil je dit toestaan?\n\nAls je de back-up niet zelf hebt aangevraagd, moet je niet toestaan dat de bewerking wordt uitgevoerd."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Back-up maken van mijn gegevens"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Geen back-up maken"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"Er is volledig herstel van alle gegevens van een verbonden desktopcomputer aangevraagd. Wilt u dit toestaan?\n\nAls u het herstel zelf niet heeft aangevraagd, moet u niet toestaan dat de bewerking wordt uitgevoerd. Bij herstel worden alle gegevens op het apparaat vervangen."</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"Er is volledig herstel van alle gegevens van een verbonden desktopcomputer aangevraagd. Wil je dit toestaan?\n\nAls je het herstel niet zelf hebt aangevraagd, moet je niet toestaan dat de bewerking wordt uitgevoerd. Bij herstel worden alle gegevens op het apparaat vervangen."</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Mijn gegevens herstellen"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Niet herstellen"</string>
-    <string name="current_password_text" msgid="8268189555578298067">"Geef hieronder uw huidige back-upwachtwoord op:"</string>
-    <string name="device_encryption_restore_text" msgid="1570864916855208992">"Geef hieronder uw wachtwoord voor apparaatcodering op."</string>
-    <string name="device_encryption_backup_text" msgid="5866590762672844664">"Geef hieronder uw wachtwoord voor apparaatversleuteling op. Dit wordt ook gebruikt om het back-uparchief te versleutelen."</string>
-    <string name="backup_enc_password_text" msgid="4981585714795233099">"Geef een wachtwoord op dat u wilt gebruiken voor het coderen van de gegevens van de volledige back-up. Als u dit leeg laat, wordt uw huidige back-upwachtwoord gebruikt:"</string>
+    <string name="current_password_text" msgid="8268189555578298067">"Geef hieronder je huidige back-upwachtwoord op:"</string>
+    <string name="device_encryption_restore_text" msgid="1570864916855208992">"Geef hieronder je wachtwoord voor apparaatcodering op."</string>
+    <string name="device_encryption_backup_text" msgid="5866590762672844664">"Geef hieronder je wachtwoord voor apparaatversleuteling op. Dit wordt ook gebruikt om het back-uparchief te versleutelen."</string>
+    <string name="backup_enc_password_text" msgid="4981585714795233099">"Geef een wachtwoord op dat u wilt gebruiken voor het coderen van de gegevens van de volledige back-up. Als u dit leeg laat, wordt je huidige back-upwachtwoord gebruikt:"</string>
     <string name="backup_enc_password_optional" msgid="1350137345907579306">"Als u de gegevens van de volledige back-up wilt versleutelen, geeft u daarvoor hieronder een wachtwoord op:"</string>
-    <string name="backup_enc_password_required" msgid="7889652203371654149">"Aangezien uw apparaat is gecodeerd, moet u uw back-up coderen. Geef hieronder een wachtwoord op:"</string>
+    <string name="backup_enc_password_required" msgid="7889652203371654149">"Aangezien je apparaat is gecodeerd, moet u je back-up coderen. Geef hieronder een wachtwoord op:"</string>
     <string name="restore_enc_password_text" msgid="6140898525580710823">"Als deze herstelgegevens zijn gecodeerd, geeft u hieronder het wachtwoord op:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"Back-up starten..."</string>
     <string name="toast_backup_ended" msgid="3818080769548726424">"Back-up voltooid"</string>
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index d578769..97bc8fd 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -36,12 +36,18 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
             <intent-filter>
-                <action android:name="android.provider.action.MANAGE_ROOT" />
+                <action android:name="android.provider.action.BROWSE_DOCUMENT_ROOT" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <data android:mimeType="vnd.android.document/root" />
             </intent-filter>
+        </activity>
+
+        <activity
+            android:name=".ManageRootActivity"
+            android:theme="@style/DocumentsNonDialogTheme"
+            android:icon="@drawable/ic_doc_text">
             <intent-filter>
-                <action android:name="android.provider.action.BROWSE_DOCUMENT_ROOT" />
+                <action android:name="android.provider.action.MANAGE_ROOT" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <data android:mimeType="vnd.android.document/root" />
             </intent-filter>
diff --git a/packages/DocumentsUI/res/layout/directory_cluster.xml b/packages/DocumentsUI/res/layout/directory_cluster.xml
new file mode 100644
index 0000000..e47e196
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/directory_cluster.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <com.android.documentsui.DirectoryContainerView
+        android:id="@+id/container_directory"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <FrameLayout
+        android:id="@+id/container_save"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@color/material_grey_50"
+        android:elevation="8dp" />
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/drawer_layout.xml b/packages/DocumentsUI/res/layout/drawer_layout.xml
index 32431e3..dec4e92 100644
--- a/packages/DocumentsUI/res/layout/drawer_layout.xml
+++ b/packages/DocumentsUI/res/layout/drawer_layout.xml
@@ -30,7 +30,8 @@
             android:layout_height="?android:attr/actionBarSize"
             android:background="?android:attr/colorPrimary"
             android:elevation="8dp"
-            android:theme="?android:attr/actionBarTheme">
+            android:theme="?actionBarTheme"
+            android:popupTheme="?actionBarPopupTheme">
 
             <Spinner
                 android:id="@+id/stack"
@@ -41,18 +42,7 @@
 
         </com.android.documentsui.DocumentsToolBar>
 
-        <com.android.documentsui.DirectoryContainerView
-            android:id="@+id/container_directory"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_weight="1" />
-
-        <FrameLayout
-            android:id="@+id/container_save"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:background="@color/material_grey_50"
-            android:elevation="8dp" />
+        <include layout="@layout/directory_cluster"/>
 
     </LinearLayout>
 
@@ -71,7 +61,8 @@
             android:layout_height="?android:attr/actionBarSize"
             android:background="?android:attr/colorPrimary"
             android:elevation="8dp"
-            android:theme="?android:attr/actionBarTheme" />
+            android:theme="?actionBarTheme"
+            android:popupTheme="?actionBarPopupTheme" />
 
         <FrameLayout
             android:id="@+id/container_roots"
diff --git a/packages/DocumentsUI/res/layout/fixed_layout.xml b/packages/DocumentsUI/res/layout/fixed_layout.xml
index 9769f26..eba9af4 100644
--- a/packages/DocumentsUI/res/layout/fixed_layout.xml
+++ b/packages/DocumentsUI/res/layout/fixed_layout.xml
@@ -51,28 +51,11 @@
             android:layout_width="256dp"
             android:layout_height="match_parent" />
 
-        <LinearLayout
+        <include layout="@layout/directory_cluster"
             android:layout_width="0dp"
-            android:layout_height="match_parent"
             android:layout_weight="1"
-            android:orientation="vertical"
-            android:background="@color/material_grey_50"
-            android:elevation="8dp">
-
-            <com.android.documentsui.DirectoryContainerView
-                android:id="@+id/container_directory"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_weight="1" />
-
-            <FrameLayout
-                android:id="@+id/container_save"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:background="@color/material_grey_50"
-                android:elevation="8dp" />
-
-        </LinearLayout>
+            android:elevation="8dp"
+            android:background="@color/material_grey_50" />
 
     </LinearLayout>
 
diff --git a/packages/DocumentsUI/res/layout/single_pane_layout.xml b/packages/DocumentsUI/res/layout/single_pane_layout.xml
new file mode 100644
index 0000000..20c3232
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/single_pane_layout.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <com.android.documentsui.DocumentsToolBar
+        android:id="@+id/toolbar"
+        android:layout_width="match_parent"
+        android:layout_height="?android:attr/actionBarSize"
+        android:background="?android:attr/colorPrimary"
+        android:elevation="8dp"
+        android:theme="?actionBarTheme"
+        android:popupTheme="?actionBarPopupTheme">
+
+        <Spinner
+            android:id="@+id/stack"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="4dp"
+            android:overlapAnchor="true" />
+
+    </com.android.documentsui.DocumentsToolBar>
+
+    <include layout="@layout/directory_cluster"/>
+
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index e1f6562..7df152f 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -26,7 +26,8 @@
         android:id="@+id/menu_create_dir"
         android:title="@string/menu_create_dir"
         android:icon="@drawable/ic_menu_new_folder"
-        android:showAsAction="always" />
+        android:showAsAction="always"
+        android:visible="false" />
     <item
         android:id="@+id/menu_sort"
         android:title="@string/menu_sort"
@@ -62,10 +63,12 @@
         android:visible="false" />
     <item
         android:id="@+id/menu_advanced"
-        android:showAsAction="never" />
+        android:showAsAction="never"
+        android:visible="false" />
     <item
         android:id="@+id/menu_file_size"
-        android:showAsAction="never" />
+        android:showAsAction="never"
+        android:visible="false" />
     <item
         android:id="@+id/menu_settings"
         android:title="@string/menu_settings"
diff --git a/packages/DocumentsUI/res/values/layouts.xml b/packages/DocumentsUI/res/values/layouts.xml
index c73a1cb..8ac1ac2 100644
--- a/packages/DocumentsUI/res/values/layouts.xml
+++ b/packages/DocumentsUI/res/values/layouts.xml
@@ -17,4 +17,5 @@
 <resources>
     <item name="docs_activity" type="layout">@layout/drawer_layout</item>
     <item name="files_activity" type="layout">@layout/drawer_layout</item>
+    <item name="manage_roots_activity" type="layout">@layout/single_pane_layout</item>
 </resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index 22add98..e67f956 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -57,6 +57,10 @@
         <item name="android:colorPrimaryDark">@color/primary_dark</item>
         <item name="android:colorPrimary">@color/primary</item>
         <item name="android:colorAccent">@color/accent</item>
+
+        <item name="android:actionModeStyle">@style/ActionModeStyle</item>
+
+        <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
     </style>
 
     <style name="ActionModeStyle" parent="@android:style/Widget.Material.Light.ActionMode">
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 2835106..1e7a42f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -16,6 +16,13 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE;
+import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
+import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
+import static com.android.documentsui.BaseActivity.State.ACTION_OPEN;
+import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION;
+import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
 import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
 import static com.android.documentsui.DirectoryFragment.ANIM_SIDE;
@@ -47,7 +54,6 @@
 import android.view.MenuItem.OnActionExpandListener;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewStub;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.BaseAdapter;
@@ -85,7 +91,6 @@
     private int mLayoutId;
     private final String mTag;
 
-    public abstract State getDisplayState();
     public abstract void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings);
     public abstract void onDocumentsPicked(List<DocumentInfo> docs);
 
@@ -93,7 +98,7 @@
     abstract void onDirectoryChanged(int anim);
     abstract void updateActionBar();
     abstract void saveStackBlocking();
-    abstract State buildDefaultState();
+    abstract State buildState();
 
     public BaseActivity(@LayoutRes int layoutId, String tag) {
         mLayoutId = layoutId;
@@ -106,7 +111,7 @@
 
         mState = (icicle != null)
                 ? icicle.<State>getParcelable(EXTRA_STATE)
-                        : buildDefaultState();
+                        : buildState();
 
         setContentView(mLayoutId);
 
@@ -154,30 +159,46 @@
         final MenuItem sortSize = menu.findItem(R.id.menu_sort_size);
         final MenuItem grid = menu.findItem(R.id.menu_grid);
         final MenuItem list = menu.findItem(R.id.menu_list);
-
         final MenuItem advanced = menu.findItem(R.id.menu_advanced);
         final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
+        final MenuItem settings = menu.findItem(R.id.menu_settings);
 
         mSearchManager.update(root);
 
         // Search uses backend ranking; no sorting
         sort.setVisible(cwd != null && !mSearchManager.isSearching());
 
-        State state = getDisplayState();
-        grid.setVisible(state.derivedMode != State.MODE_GRID);
-        list.setVisible(state.derivedMode != State.MODE_LIST);
-
-        // Only sort by size when visible
-        sortSize.setVisible(state.showSize);
-
         advanced.setTitle(LocalPreferences.getDisplayAdvancedDevices(this)
                 ? R.string.menu_advanced_hide : R.string.menu_advanced_show);
         fileSize.setTitle(LocalPreferences.getDisplayFileSize(this)
                 ? R.string.menu_file_size_hide : R.string.menu_file_size_show);
 
+        State state = getDisplayState();
+
+        sortSize.setVisible(state.showSize); // Only sort by size when visible
+        grid.setVisible(state.derivedMode != State.MODE_GRID);
+        list.setVisible(state.derivedMode != State.MODE_LIST);
+        settings.setVisible((root.flags & Root.FLAG_HAS_SETTINGS) != 0);
+
         return shown;
     }
 
+    State buildDefaultState() {
+        State state = new State();
+
+        final Intent intent = getIntent();
+        final String action = intent.getAction();
+
+        state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
+        state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
+        state.showAdvanced = state.forceAdvanced ||
+                LocalPreferences.getDisplayAdvancedDevices(this);
+
+        state.excludedAuthorities = getExcludedAuthorities();
+
+        return state;
+    }
+
     void onStackRestored(boolean restored, boolean external) {}
 
     void onRootPicked(RootInfo root) {
@@ -344,6 +365,10 @@
         return (BaseActivity) fragment.getActivity();
     }
 
+    public State getDisplayState() {
+        return mState;
+    }
+
     public static abstract class DocumentsIntent {
         /** Intent action name to open copy destination. */
         public static String ACTION_OPEN_COPY_DESTINATION =
@@ -664,6 +689,33 @@
         }
     }
 
+    final class RestoreRootTask extends AsyncTask<Void, Void, RootInfo> {
+        private Uri mRootUri;
+
+        public RestoreRootTask(Uri rootUri) {
+            mRootUri = rootUri;
+        }
+
+        @Override
+        protected RootInfo doInBackground(Void... params) {
+            final String rootId = DocumentsContract.getRootId(mRootUri);
+            return mRoots.getRootOneshot(mRootUri.getAuthority(), rootId);
+        }
+
+        @Override
+        protected void onPostExecute(RootInfo root) {
+            if (isDestroyed()) return;
+            mState.restored = true;
+
+            if (root != null) {
+                onRootPicked(root);
+            } else {
+                Log.w(mTag, "Failed to find root: " + mRootUri);
+                finish();
+            }
+        }
+    }
+
     final class ItemSelectedListener implements OnItemSelectedListener {
 
         boolean mIgnoreNextNavigation;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 93921dd..cfd4ecb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -77,6 +77,7 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.TypedValue;
 import android.view.ActionMode;
 import android.view.DragEvent;
 import android.view.GestureDetector;
@@ -650,8 +651,12 @@
                 if (mActionMode != null) {
                     mActionMode.finish();
                 }
-                getActivity().getWindow().setStatusBarColor(
-                    getResources().getColor(R.color.status_bar_background));
+                // Obtain the original status bar color from the theme, and restore it.
+                TypedValue color = new TypedValue();
+                getActivity().getTheme().resolveAttribute(
+                    android.R.attr.colorPrimaryDark, color, true);
+                getActivity().getWindow().setStatusBarColor(color.data);
+
             }
 
             if (mActionMode != null) {
@@ -827,8 +832,18 @@
                                 if (event == Snackbar.Callback.DISMISS_EVENT_ACTION) {
                                     mModel.undoDeletion();
                                 } else {
-                                    // TODO: Use a listener rather than pushing the view.
-                                    mModel.finalizeDeletion(DirectoryFragment.this.getView());
+                                    mModel.finalizeDeletion(
+                                            new Runnable() {
+                                                @Override
+                                                public void run() {
+                                                    Snackbar.make(
+                                                            DirectoryFragment.this.getView(),
+                                                            R.string.toast_failed_delete,
+                                                            Snackbar.LENGTH_LONG)
+                                                            .show();
+
+                                                }
+                                            });
                                 }
                             }
                         })
@@ -1809,13 +1824,13 @@
                 info = null;
                 error = null;
                 mIsLoading = false;
-                if (mUpdateListener != null)  mUpdateListener.onModelUpdate(this);
+                mUpdateListener.onModelUpdate(this);
                 return;
             }
 
             if (result.exception != null) {
                 Log.e(TAG, "Error while loading directory contents", result.exception);
-                if (mUpdateListener != null)  mUpdateListener.onModelUpdateFailed(result.exception);
+                mUpdateListener.onModelUpdateFailed(result.exception);
                 return;
             }
 
@@ -1829,7 +1844,7 @@
                 mIsLoading = extras.getBoolean(DocumentsContract.EXTRA_LOADING, false);
             }
 
-            if (mUpdateListener != null)  mUpdateListener.onModelUpdate(this);
+            mUpdateListener.onModelUpdate(this);
         }
 
         int getItemCount() {
@@ -1842,7 +1857,7 @@
             // position by 1.
             final int originalPos = position;
             final int size = mMarkedForDeletion.size();
-            for (int i = 0; i <= size; ++i) {
+            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)) {
@@ -1930,7 +1945,7 @@
                 int position = selected.get(i);
                 if (DEBUG) Log.d(TAG, "Marked position " + position + " for deletion");
                 mMarkedForDeletion.append(position, true);
-                if (mUpdateListener != null)  mUpdateListener.notifyItemRemoved(position);
+                mUpdateListener.notifyItemRemoved(position);
             }
         }
 
@@ -1945,7 +1960,7 @@
             for (int i = 0; i < size; ++i) {
                 final int position = mMarkedForDeletion.keyAt(i);
                 mMarkedForDeletion.put(position, false);
-                if (mUpdateListener != null)  mUpdateListener.notifyItemInserted(position);
+                mUpdateListener.notifyItemInserted(position);
             }
 
             // Then, clear the deletion list.
@@ -1959,21 +1974,9 @@
          * @param view The view which will be used to interact with the user (e.g. surfacing
          * snackbars) for errors, info, etc.
          */
-        void finalizeDeletion(final View view) {
+        void finalizeDeletion(Runnable errorCallback) {
             final ContentResolver resolver = mContext.getContentResolver();
-            DeleteFilesTask task = new DeleteFilesTask(
-                    resolver,
-                    new Runnable() {
-                        @Override
-                        public void run() {
-                            Snackbar.make(
-                                    view,
-                                    R.string.toast_failed_delete,
-                                    Snackbar.LENGTH_LONG)
-                                    .show();
-
-                        }
-                    });
+            DeleteFilesTask task = new DeleteFilesTask(resolver, errorCallback);
             task.execute();
         }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index fdc4bb0..1de1c6a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -19,7 +19,6 @@
 import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE;
 import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
 import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT;
-import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
 import static com.android.documentsui.BaseActivity.State.ACTION_OPEN;
 import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION;
 import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
@@ -67,7 +66,7 @@
 
 public class DocumentsActivity extends BaseActivity {
     private static final int CODE_FORWARD = 42;
-    public static final String TAG = "Documents";
+    private static final String TAG = "DocumentsActivity";
 
     private boolean mShowAsDialog;
 
@@ -90,8 +89,7 @@
         super.onCreate(icicle);
 
         final Resources res = getResources();
-        mShowAsDialog = res.getBoolean(R.bool.show_as_dialog) && mState.action != ACTION_MANAGE &&
-                mState.action != ACTION_BROWSE;
+        mShowAsDialog = res.getBoolean(R.bool.show_as_dialog) && mState.action != ACTION_BROWSE;
 
         if (!mShowAsDialog) {
             setTheme(R.style.DocumentsNonDialogTheme);
@@ -119,8 +117,6 @@
         mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
 
         mToolbar = (Toolbar) findViewById(R.id.toolbar);
-        mToolbar.setTitleTextAppearance(context,
-                android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
 
         mStackAdapter = new StackAdapter();
         mStackListener = new ItemSelectedListener();
@@ -128,15 +124,11 @@
         mToolbarStack.setOnItemSelectedListener(mStackListener);
 
         mRootsToolbar = (Toolbar) findViewById(R.id.roots_toolbar);
-        if (mRootsToolbar != null) {
-            mRootsToolbar.setTitleTextAppearance(context,
-                    android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
-        }
 
         setActionBar(mToolbar);
 
         // Hide roots when we're managing a specific root
-        if (mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE) {
+        if (mState.action == ACTION_BROWSE) {
             mDrawer.lockClosed();
             if (mShowAsDialog) {
                 findViewById(R.id.container_roots).setVisibility(View.GONE);
@@ -168,7 +160,7 @@
             // In this case, we set the activity title in AsyncTask.onPostExecute().  To prevent
             // talkback from reading aloud the default title, we clear it here.
             setTitle("");
-            if (mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE) {
+            if (mState.action == ACTION_BROWSE) {
                 final Uri rootUri = getIntent().getData();
                 new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor());
             } else {
@@ -180,8 +172,8 @@
     }
 
     @Override
-    State buildDefaultState() {
-        State state = new State();
+    State buildState() {
+        State state = buildDefaultState();
 
         final Intent intent = getIntent();
         final String action = intent.getAction();
@@ -193,8 +185,6 @@
             state.action = ACTION_GET_CONTENT;
         } else if (Intent.ACTION_OPEN_DOCUMENT_TREE.equals(action)) {
             state.action = ACTION_OPEN_TREE;
-        } else if (DocumentsContract.ACTION_MANAGE_ROOT.equals(action)) {
-            state.action = ACTION_MANAGE;
         } else if (DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT.equals(action)) {
             state.action = ACTION_BROWSE;
         } else if (DocumentsIntent.ACTION_OPEN_COPY_DESTINATION.equals(action)) {
@@ -206,7 +196,7 @@
                     Intent.EXTRA_ALLOW_MULTIPLE, false);
         }
 
-        if (state.action == ACTION_MANAGE || state.action == ACTION_BROWSE) {
+        if (state.action == ACTION_BROWSE) {
             state.acceptMimes = new String[] { "*/*" };
             state.allowMultiple = true;
         } else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
@@ -215,12 +205,7 @@
             state.acceptMimes = new String[] { intent.getType() };
         }
 
-        state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
-        state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
-        state.showAdvanced = state.forceAdvanced
-                | LocalPreferences.getDisplayAdvancedDevices(this);
-
-        if (state.action == ACTION_MANAGE || state.action == ACTION_BROWSE) {
+        if (state.action == ACTION_BROWSE) {
             state.showSize = true;
         } else {
             state.showSize = LocalPreferences.getDisplayFileSize(this);
@@ -232,38 +217,9 @@
                     CopyService.TRANSFER_MODE_NONE);
         }
 
-        state.excludedAuthorities = getExcludedAuthorities();
-
         return state;
     }
 
-    private class RestoreRootTask extends AsyncTask<Void, Void, RootInfo> {
-        private Uri mRootUri;
-
-        public RestoreRootTask(Uri rootUri) {
-            mRootUri = rootUri;
-        }
-
-        @Override
-        protected RootInfo doInBackground(Void... params) {
-            final String rootId = DocumentsContract.getRootId(mRootUri);
-            return mRoots.getRootOneshot(mRootUri.getAuthority(), rootId);
-        }
-
-        @Override
-        protected void onPostExecute(RootInfo root) {
-            if (isDestroyed()) return;
-            mState.restored = true;
-
-            if (root != null) {
-                onRootPicked(root);
-            } else {
-                Log.w(TAG, "Failed to find root: " + mRootUri);
-                finish();
-            }
-        }
-    }
-
     @Override
     void onStackRestored(boolean restored, boolean external) {
         // Show drawer when no stack restored, but only when requesting
@@ -405,8 +361,11 @@
         final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
         final MenuItem settings = menu.findItem(R.id.menu_settings);
 
-        boolean fileSizeVisible = !(mState.action == ACTION_MANAGE
-                || mState.action == ACTION_BROWSE);
+        // File size is locked visible for browse because that is the action triggered by Settings,
+        // where the user is trying to find large files to clean up.
+        // TODO: instead of setting this according to the action, use a local preference, but
+        // provide a @hide extra to let callers like Settings force-enable size visibility.
+        boolean fileSizeVisible = mState.action != ACTION_BROWSE;
         if (mState.action == ACTION_CREATE
                 || mState.action == ACTION_OPEN_TREE
                 || mState.action == ACTION_OPEN_COPY_DESTINATION) {
@@ -428,11 +387,10 @@
             createDir.setVisible(false);
         }
 
-        advanced.setVisible(!(mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE) &&
-                !mState.forceAdvanced);
+        advanced.setVisible(mState.action != ACTION_BROWSE && !mState.forceAdvanced);
         fileSize.setVisible(fileSizeVisible);
 
-        settings.setVisible((mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE)
+        settings.setVisible(mState.action == ACTION_BROWSE
                 && (root.flags & Root.FLAG_HAS_SETTINGS) != 0);
 
         return true;
@@ -444,11 +402,6 @@
     }
 
     @Override
-    public State getDisplayState() {
-        return mState;
-    }
-
-    @Override
     void onDirectoryChanged(int anim) {
         final FragmentManager fm = getFragmentManager();
         final RootInfo root = getCurrentRoot();
@@ -523,26 +476,6 @@
         } else if (mState.action == ACTION_CREATE) {
             // Replace selected file
             SaveFragment.get(fm).setReplaceTarget(doc);
-        } else if (mState.action == ACTION_MANAGE) {
-            // First try managing the document; we expect manager to filter
-            // based on authority, so we don't grant.
-            final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
-            manage.setData(doc.derivedUri);
-
-            try {
-                startActivity(manage);
-            } catch (ActivityNotFoundException ex) {
-                // Fall back to viewing
-                final Intent view = new Intent(Intent.ACTION_VIEW);
-                view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                view.setData(doc.derivedUri);
-
-                try {
-                    startActivity(view);
-                } catch (ActivityNotFoundException ex2) {
-                    Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
-                }
-            }
         } else if (mState.action == ACTION_BROWSE) {
             // Go straight to viewing
             final Intent view = new Intent(Intent.ACTION_VIEW);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 7c445bf..8f9025a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -30,7 +30,6 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Root;
 import android.support.annotation.Nullable;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -58,12 +57,11 @@
  */
 public class FilesActivity extends BaseActivity {
 
-    public static final String TAG = "StandaloneFileManagement";
+    public static final String TAG = "FilesActivity";
     static final boolean DEBUG = false;
 
     private Toolbar mToolbar;
     private Spinner mToolbarStack;
-    private Toolbar mRootsToolbar;
     private DirectoryContainerView mDirectoryContainer;
     private ItemSelectedListener mStackListener;
     private BaseAdapter mStackAdapter;
@@ -82,20 +80,12 @@
         mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
 
         mToolbar = (Toolbar) findViewById(R.id.toolbar);
-        mToolbar.setTitleTextAppearance(context,
-                android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
 
         mStackAdapter = new StackAdapter();
         mStackListener = new ItemSelectedListener();
         mToolbarStack = (Spinner) findViewById(R.id.stack);
         mToolbarStack.setOnItemSelectedListener(mStackListener);
 
-        mRootsToolbar = (Toolbar) findViewById(R.id.roots_toolbar);
-        if (mRootsToolbar != null) {
-            mRootsToolbar.setTitleTextAppearance(context,
-                    android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
-        }
-
         setActionBar(mToolbar);
 
         mClipper = new DocumentClipper(this);
@@ -127,14 +117,14 @@
     }
 
     @Override
-    State buildDefaultState() {
-        State state = new State();
+    State buildState() {
+        State state = buildDefaultState();
 
         final Intent intent = getIntent();
+
         state.action = State.ACTION_BROWSE_ALL;
-        state.acceptMimes = new String[] { "*/*" };
-        state.allowMultiple = true;
         state.acceptMimes = new String[] { intent.getType() };
+        state.allowMultiple = true;
 
         // These options are specific to the DocumentsActivity.
         Preconditions.checkArgument(
@@ -223,8 +213,6 @@
         createDir.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
         createDir.setVisible(canCreateDir);
 
-        settings.setVisible((getCurrentRoot().flags & Root.FLAG_HAS_SETTINGS) != 0);
-
         pasteFromCb.setVisible(true);
         pasteFromCb.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
         pasteFromCb.setEnabled(mClipper.hasItemsToPaste());
@@ -246,11 +234,6 @@
     }
 
     @Override
-    public State getDisplayState() {
-        return mState;
-    }
-
-    @Override
     void onDirectoryChanged(int anim) {
         final FragmentManager fm = getFragmentManager();
         final RootInfo root = getCurrentRoot();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index 9959265..ec1cb1d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -222,7 +222,7 @@
                 return context.getDrawable(R.drawable.ic_doc_album);
             }
 
-            if (mode == DocumentsActivity.State.MODE_GRID) {
+            if (mode == BaseActivity.State.MODE_GRID) {
                 return context.getDrawable(R.drawable.ic_grid_folder);
             } else {
                 return context.getDrawable(R.drawable.ic_doc_folder);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
new file mode 100644
index 0000000..7401578
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2013 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.documentsui;
+
+import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
+import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
+import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.ActivityNotFoundException;
+import android.content.ClipData;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.util.Log;
+import android.view.Menu;
+import android.view.View;
+import android.widget.BaseAdapter;
+import android.widget.Spinner;
+import android.widget.Toast;
+import android.widget.Toolbar;
+
+import com.android.documentsui.RecentsProvider.ResumeColumns;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DurableUtils;
+import com.android.documentsui.model.RootInfo;
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class ManageRootActivity extends BaseActivity {
+    private static final int CODE_FORWARD = 42;
+    private static final String TAG = "ManageRootsActivity";
+
+    private Toolbar mToolbar;
+    private Spinner mToolbarStack;
+
+    private DirectoryContainerView mDirectoryContainer;
+
+    private ItemSelectedListener mStackListener;
+    private BaseAdapter mStackAdapter;
+
+    public ManageRootActivity() {
+        super(R.layout.manage_roots_activity, TAG);
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        final Context context = this;
+
+        mDrawer = DrawerController.createDummy();
+
+        mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
+
+        mToolbar = (Toolbar) findViewById(R.id.toolbar);
+        mToolbar.setTitleTextAppearance(context,
+                android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
+
+        mStackAdapter = new StackAdapter();
+        mStackListener = new ItemSelectedListener();
+        mToolbarStack = (Spinner) findViewById(R.id.stack);
+        mToolbarStack.setOnItemSelectedListener(mStackListener);
+
+        setActionBar(mToolbar);
+
+        if (!mState.restored) {
+            // In this case, we set the activity title in AsyncTask.onPostExecute(). To prevent
+            // talkback from reading aloud the default title, we clear it here.
+            setTitle("");
+            final Uri rootUri = getIntent().getData();
+            new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor());
+        } else {
+            onCurrentDirectoryChanged(ANIM_NONE);
+        }
+    }
+
+    @Override
+    State buildState() {
+        State state = buildDefaultState();
+
+        state.action = ACTION_MANAGE;
+        state.acceptMimes = new String[] { "*/*" };
+        state.allowMultiple = true;
+        state.showSize = true;
+        state.excludedAuthorities = getExcludedAuthorities();
+
+        return state;
+    }
+
+    @Override
+    protected void onPostCreate(Bundle savedInstanceState) {
+        super.onPostCreate(savedInstanceState);
+        updateActionBar();
+    }
+
+    @Override
+    public void updateActionBar() {
+        // No navigation in manage root mode.
+        mToolbar.setNavigationIcon(null);
+        mToolbar.setNavigationOnClickListener(null);
+
+        if (mSearchManager.isExpanded()) {
+            mToolbar.setTitle(null);
+            mToolbarStack.setVisibility(View.GONE);
+            mToolbarStack.setAdapter(null);
+        } else {
+            if (mState.stack.size() <= 1) {
+                mToolbar.setTitle(getCurrentRoot().title);
+                mToolbarStack.setVisibility(View.GONE);
+                mToolbarStack.setAdapter(null);
+            } else {
+                mToolbar.setTitle(null);
+                mToolbarStack.setVisibility(View.VISIBLE);
+                mToolbarStack.setAdapter(mStackAdapter);
+
+                mStackListener.mIgnoreNextNavigation = true;
+                mToolbarStack.setSelection(mStackAdapter.getCount() - 1);
+            }
+        }
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        super.onPrepareOptionsMenu(menu);
+        return true;
+    }
+
+    @Override
+    void onDirectoryChanged(int anim) {
+        final FragmentManager fm = getFragmentManager();
+        final RootInfo root = getCurrentRoot();
+        final DocumentInfo cwd = getCurrentDirectory();
+
+        // If started in manage roots mode, there has to be a cwd (i.e. the root dir of the managed
+        // root).
+        Preconditions.checkNotNull(cwd);
+        mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN);
+
+        if (mState.currentSearch != null) {
+            // Ongoing search
+            DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
+        } else {
+            // Normal boring directory
+            DirectoryFragment.showNormal(fm, root, cwd, anim);
+        }
+    }
+
+    @Override
+    public void onDocumentPicked(DocumentInfo doc, DocumentContext context) {
+        final FragmentManager fm = getFragmentManager();
+        if (doc.isDirectory()) {
+            openDirectory(doc);
+        } else {
+            // First try managing the document; we expect manager to filter
+            // based on authority, so we don't grant.
+            final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
+            manage.setData(doc.derivedUri);
+
+            try {
+                startActivity(manage);
+            } catch (ActivityNotFoundException ex) {
+                // Fall back to viewing
+                final Intent view = new Intent(Intent.ACTION_VIEW);
+                view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                view.setData(doc.derivedUri);
+
+                try {
+                    startActivity(view);
+                } catch (ActivityNotFoundException ex2) {
+                    Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onDocumentsPicked(List<DocumentInfo> docs) {}
+
+    @Override
+    void saveStackBlocking() {
+        final ContentResolver resolver = getContentResolver();
+        final ContentValues values = new ContentValues();
+
+        final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack);
+
+        // Remember location for next app launch
+        final String packageName = getCallingPackageMaybeExtra();
+        values.clear();
+        values.put(ResumeColumns.STACK, rawStack);
+        values.put(ResumeColumns.EXTERNAL, 0);
+        resolver.insert(RecentsProvider.buildResume(packageName), values);
+    }
+
+    @Override
+    void onTaskFinished(Uri... uris) {
+        Log.d(TAG, "onFinished() " + Arrays.toString(uris));
+
+        final Intent intent = new Intent();
+        if (uris.length == 1) {
+            intent.setData(uris[0]);
+        } else if (uris.length > 1) {
+            final ClipData clipData = new ClipData(
+                    null, mState.acceptMimes, new ClipData.Item(uris[0]));
+            for (int i = 1; i < uris.length; i++) {
+                clipData.addItem(new ClipData.Item(uris[i]));
+            }
+            intent.setClipData(clipData);
+        }
+
+        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
+
+        setResult(Activity.RESULT_OK, intent);
+        finish();
+    }
+
+    public static ManageRootActivity get(Fragment fragment) {
+        return (ManageRootActivity) fragment.getActivity();
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index f9f308d..5930056 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -73,10 +73,10 @@
     private final List<MultiSelectManager.Callback> mCallbacks = new ArrayList<>(1);
 
     private Adapter<?> mAdapter;
-    private MultiSelectHelper mHelper;
+    private ItemFinder mHelper;
     private boolean mSingleSelect;
 
-    @Nullable private BandSelectManager mBandManager;
+    @Nullable private BandController mBandManager;
 
     /**
      * @param recyclerView
@@ -90,11 +90,13 @@
 
         this(
                 recyclerView.getAdapter(),
-                new RuntimeRecyclerViewHelper(recyclerView),
+                new RuntimeItemFinder(recyclerView),
                 mode);
 
         if (mode == MODE_MULTIPLE) {
-            mBandManager = new BandSelectManager((RuntimeRecyclerViewHelper) mHelper);
+            mBandManager = new BandController(
+                    mHelper,
+                    new RuntimeBandEnvironment(recyclerView));
         }
 
         GestureDetector.SimpleOnGestureListener listener =
@@ -167,7 +169,7 @@
      * @hide
      */
     @VisibleForTesting
-    MultiSelectManager(Adapter<?> adapter, MultiSelectHelper helper, int mode) {
+    MultiSelectManager(Adapter<?> adapter, ItemFinder helper, int mode) {
         checkNotNull(adapter, "'adapter' cannot be null.");
         checkNotNull(helper, "'helper' cannot be null.");
 
@@ -730,16 +732,6 @@
             mTotalSelection = mSavedSelection.clone();
         }
 
-        private boolean flip(int position) {
-            if (contains(position)) {
-                remove(position);
-                return false;
-            } else {
-                add(position);
-                return true;
-            }
-        }
-
         /** @hide */
         @VisibleForTesting
         boolean add(int position) {
@@ -873,109 +865,114 @@
     }
 
     /**
-     * Provides functionality for MultiSelectManager. In practice, use RuntimeRecyclerViewHelper;
-     * this interface exists only for mocking in tests.
+     * Provides functionality for MultiSelectManager. Exists primarily to tests that are
+     * fully isolated from RecyclerView.
      */
-    interface MultiSelectHelper {
-        int findEventPosition(MotionEvent e);
+    interface ItemFinder {
+        int findItemPosition(MotionEvent e);
+    }
+
+    /** ItemFinder implementation backed by good ol' RecyclerView. */
+    private static final class RuntimeItemFinder implements ItemFinder {
+
+        private final RecyclerView mView;
+
+        RuntimeItemFinder(RecyclerView view) {
+            mView = view;
+        }
+
+        @Override
+        public int findItemPosition(MotionEvent e) {
+            View view = mView.findChildViewUnder(e.getX(), e.getY());
+            return view != null
+                    ? mView.getChildAdapterPosition(view)
+                    : RecyclerView.NO_POSITION;
+        }
     }
 
     /**
-     * Provides functionality for BandSelectManager. In practice, use RuntimeRecyclerViewHelper;
-     * this interface exists only for mocking in tests.
+     * Provides functionality for BandController. Exists primarily to tests that are
+     * fully isolated from RecyclerView.
      */
-    interface BandManagerHelper {
-        void drawBand(Rect rect);
-        void addOnScrollListener(RecyclerView.OnScrollListener listener);
-        int findEventPosition(MotionEvent e);
-        int getHeight();
+    interface BandEnvironment {
+        void showBand(Rect rect);
         void hideBand();
-        void invalidateView();
-        void postRunnable(Runnable r);
-        void removeCallback(Runnable r);
-        void scrollBy(int dy);
-    }
-
-    /**
-     * Provides functionality for BandSelectModel. In practice, use RuntimeRecyclerViewHelper;
-     * this interface exists only for mocking in tests.
-     */
-    interface BandModelHelper {
         void addOnScrollListener(RecyclerView.OnScrollListener listener);
+        void removeOnScrollListener(RecyclerView.OnScrollListener listener);
+        void scrollBy(int dy);
+        int getHeight();
+        void invalidateView();
+        void runAtNextFrame(Runnable r);
+        void removeCallback(Runnable r);
         Point createAbsolutePoint(Point relativePoint);
         Rect getAbsoluteRectForChildViewAt(int index);
         int getAdapterPositionAt(int index);
-        int getNumColumns();
-        int getNumRows();
-        int getTotalChildCount();
+        int getColumnCount();
+        int getRowCount();
+        int getChildCount();
         int getVisibleChildCount();
-        void removeOnScrollListener(RecyclerView.OnScrollListener listener);
     }
 
-    /**
-     * Concrete RecyclerViewHelper implementation for use within the Files app.
-     */
-    private static final class RuntimeRecyclerViewHelper implements MultiSelectHelper,
-            BandManagerHelper, BandModelHelper {
+    /** RvFacade implementation backed by good ol' RecyclerView. */
+    private static final class RuntimeBandEnvironment implements BandEnvironment {
 
-        private final RecyclerView mRecyclerView;
-        private final Drawable mBandSelectRect;
+        private final RecyclerView mView;
+        private final Drawable mBand;
 
         private boolean mIsOverlayShown = false;
 
-        RuntimeRecyclerViewHelper(RecyclerView rv) {
-            mRecyclerView = rv;
-            mBandSelectRect = mRecyclerView.getContext().getTheme().getDrawable(
-                    R.drawable.band_select_overlay);
+        RuntimeBandEnvironment(RecyclerView rv) {
+            mView = rv;
+            mBand = mView.getContext().getTheme().getDrawable(R.drawable.band_select_overlay);
         }
 
         @Override
         public int getAdapterPositionAt(int index) {
-            View child = mRecyclerView.getChildAt(index);
-            return mRecyclerView.getChildViewHolder(child).getAdapterPosition();
+            View child = mView.getChildAt(index);
+            return mView.getChildViewHolder(child).getAdapterPosition();
         }
 
         @Override
         public void addOnScrollListener(OnScrollListener listener) {
-            mRecyclerView.addOnScrollListener(listener);
+            mView.addOnScrollListener(listener);
         }
 
         @Override
         public void removeOnScrollListener(OnScrollListener listener) {
-            mRecyclerView.removeOnScrollListener(listener);
+            mView.removeOnScrollListener(listener);
         }
 
         @Override
         public Point createAbsolutePoint(Point relativePoint) {
-            return new Point(relativePoint.x + mRecyclerView.computeHorizontalScrollOffset(),
-                    relativePoint.y + mRecyclerView.computeVerticalScrollOffset());
+            return new Point(relativePoint.x + mView.computeHorizontalScrollOffset(),
+                    relativePoint.y + mView.computeVerticalScrollOffset());
         }
 
         @Override
         public Rect getAbsoluteRectForChildViewAt(int index) {
-            final View child = mRecyclerView.getChildAt(index);
+            final View child = mView.getChildAt(index);
             final Rect childRect = new Rect();
             child.getHitRect(childRect);
-            childRect.left += mRecyclerView.computeHorizontalScrollOffset();
-            childRect.right += mRecyclerView.computeHorizontalScrollOffset();
-            childRect.top += mRecyclerView.computeVerticalScrollOffset();
-            childRect.bottom += mRecyclerView.computeVerticalScrollOffset();
+            childRect.left += mView.computeHorizontalScrollOffset();
+            childRect.right += mView.computeHorizontalScrollOffset();
+            childRect.top += mView.computeVerticalScrollOffset();
+            childRect.bottom += mView.computeVerticalScrollOffset();
             return childRect;
         }
 
         @Override
+        public int getChildCount() {
+            return mView.getAdapter().getItemCount();
+        }
+
+        @Override
         public int getVisibleChildCount() {
-            return mRecyclerView.getChildCount();
+            return mView.getChildCount();
         }
 
         @Override
-        public int getTotalChildCount() {
-            return mRecyclerView.getAdapter().getItemCount();
-        }
-
-        @Override
-        public int getNumColumns() {
-            LayoutManager layoutManager = mRecyclerView.getLayoutManager();
+        public int getColumnCount() {
+            LayoutManager layoutManager = mView.getLayoutManager();
             if (layoutManager instanceof GridLayoutManager) {
                 return ((GridLayoutManager) layoutManager).getSpanCount();
             }
@@ -985,57 +982,49 @@
         }
 
         @Override
-        public int getNumRows() {
-            int numFullColumns = getTotalChildCount() / getNumColumns();
-            boolean hasPartiallyFullColumn = getTotalChildCount() % getNumColumns() != 0;
+        public int getRowCount() {
+            int numFullColumns = getChildCount() / getColumnCount();
+            boolean hasPartiallyFullColumn = getChildCount() % getColumnCount() != 0;
             return numFullColumns + (hasPartiallyFullColumn ? 1 : 0);
         }
 
         @Override
-        public int findEventPosition(MotionEvent e) {
-            View view = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
-            return view != null
-                    ? mRecyclerView.getChildAdapterPosition(view)
-                    : RecyclerView.NO_POSITION;
-        }
-
-        @Override
         public int getHeight() {
-            return mRecyclerView.getHeight();
+            return mView.getHeight();
         }
 
         @Override
         public void invalidateView() {
-            mRecyclerView.invalidate();
+            mView.invalidate();
         }
 
         @Override
-        public void postRunnable(Runnable r) {
-            mRecyclerView.postOnAnimation(r);
+        public void runAtNextFrame(Runnable r) {
+            mView.postOnAnimation(r);
         }
 
         @Override
         public void removeCallback(Runnable r) {
-            mRecyclerView.removeCallbacks(r);
+            mView.removeCallbacks(r);
         }
 
         @Override
         public void scrollBy(int dy) {
-            mRecyclerView.scrollBy(0, dy);
+            mView.scrollBy(0, dy);
         }
 
         @Override
-        public void drawBand(Rect rect) {
-            mBandSelectRect.setBounds(rect);
+        public void showBand(Rect rect) {
+            mBand.setBounds(rect);
 
             if (!mIsOverlayShown) {
-                mRecyclerView.getOverlay().add(mBandSelectRect);
+                mView.getOverlay().add(mBand);
             }
         }
 
         @Override
         public void hideBand() {
-            mRecyclerView.getOverlay().remove(mBandSelectRect);
+            mView.getOverlay().remove(mBand);
         }
     }
 
@@ -1172,34 +1161,35 @@
      * and {@link MultiSelectManager}. This class is responsible for rendering the band select
      * overlay and selecting overlaid items via MultiSelectManager.
      */
-    public class BandSelectManager extends RecyclerView.OnScrollListener
-            implements BandSelectModel.OnSelectionChangedListener {
+    public class BandController extends RecyclerView.OnScrollListener
+            implements GridModel.OnSelectionChangedListener {
 
         private static final int NOT_SET = -1;
 
-        private final BandManagerHelper mHelper;
+        private final ItemFinder mItemFinder;
+        private final BandEnvironment mEnvironment;
         private final Runnable mModelBuilder;
 
         @Nullable private Rect mBounds;
         @Nullable private Point mCurrentPosition;
         @Nullable private Point mOrigin;
-        @Nullable private BandSelectModel mModel;
+        @Nullable private GridModel mModel;
 
         // The time at which the current band selection-induced scroll began. If no scroll is in
         // progress, the value is NOT_SET.
         private long mScrollStartTime = NOT_SET;
         private final Runnable mViewScroller = new ViewScroller();
 
-        public <T extends BandManagerHelper & BandModelHelper>
-                BandSelectManager(final T helper) {
-            mHelper = helper;
-            mHelper.addOnScrollListener(this);
+        public BandController(ItemFinder finder, final BandEnvironment environment) {
+            mItemFinder = finder;
+            mEnvironment = environment;
+            mEnvironment.addOnScrollListener(this);
 
             mModelBuilder = new Runnable() {
                 @Override
                 public void run() {
-                    mModel = new BandSelectModel(helper);
-                    mModel.addOnSelectionChangedListener(BandSelectManager.this);
+                    mModel = new GridModel(environment);
+                    mModel.addOnSelectionChangedListener(BandController.this);
                 }
             };
         }
@@ -1226,7 +1216,8 @@
             return !isActive()
                     && Events.isMouseEvent(e)  // a mouse
                     && Events.isActionDown(e)  // the initial button press
-                    && mHelper.findEventPosition(e) == RecyclerView.NO_ID;  // in empty space
+                    && mAdapter.getItemCount() > 0
+                    && mItemFinder.findItemPosition(e) == RecyclerView.NO_ID;  // in empty space
         }
 
         boolean shouldStop(InputEvent input) {
@@ -1274,9 +1265,9 @@
          * Scrolls the view if necessary.
          */
         private void scrollViewIfNecessary() {
-            mHelper.removeCallback(mViewScroller);
+            mEnvironment.removeCallback(mViewScroller);
             mViewScroller.run();
-            mHelper.invalidateView();
+            mEnvironment.invalidateView();
         }
 
         /**
@@ -1288,7 +1279,7 @@
                     Math.min(mOrigin.y, mCurrentPosition.y),
                     Math.max(mOrigin.x, mCurrentPosition.x),
                     Math.max(mOrigin.y, mCurrentPosition.y));
-            mHelper.drawBand(mBounds);
+            mEnvironment.showBand(mBounds);
         }
 
         /**
@@ -1297,14 +1288,14 @@
         private void endBandSelect() {
             if (DEBUG) Log.d(TAG, "Ending band select.");
 
-            mHelper.hideBand();
+            mEnvironment.hideBand();
             mSelection.applyProvisionalSelection();
             mModel.endSelection();
             int firstSelected = mModel.getPositionNearestOrigin();
             if (!mSelection.contains(firstSelected)) {
                 Log.w(TAG, "First selected by band is NOT in selection!");
                 // Sadly this is really happening. Need to figure out what's going on.
-            } else if (firstSelected != BandSelectModel.NOT_SET) {
+            } else if (firstSelected != GridModel.NOT_SET) {
                 setSelectionFocusBegin(firstSelected);
             }
 
@@ -1340,8 +1331,8 @@
                 int pixelsPastView = 0;
                 if (mCurrentPosition.y <= 0) {
                     pixelsPastView = mCurrentPosition.y - 1;
-                } else if (mCurrentPosition.y >= mHelper.getHeight() - 1) {
-                    pixelsPastView = mCurrentPosition.y - mHelper.getHeight() + 1;
+                } else if (mCurrentPosition.y >= mEnvironment.getHeight() - 1) {
+                    pixelsPastView = mCurrentPosition.y - mEnvironment.getHeight() + 1;
                 }
 
                 if (!isActive() || pixelsPastView == 0) {
@@ -1360,10 +1351,10 @@
                 // Compute the number of pixels to scroll, and scroll that many pixels.
                 final int numPixels = computeScrollDistance(
                         pixelsPastView, System.currentTimeMillis() - mScrollStartTime);
-                mHelper.scrollBy(numPixels);
+                mEnvironment.scrollBy(numPixels);
 
-                mHelper.removeCallback(mViewScroller);
-                mHelper.postRunnable(this);
+                mEnvironment.removeCallback(mViewScroller);
+                mEnvironment.runAtNextFrame(this);
             }
 
             /**
@@ -1376,14 +1367,14 @@
              * @return
              */
             private int computeScrollDistance(int pixelsPastView, long scrollDuration) {
-                final int maxScrollStep = mHelper.getHeight();
+                final int maxScrollStep = mEnvironment.getHeight();
                 final int direction = (int) Math.signum(pixelsPastView);
                 final int absPastView = Math.abs(pixelsPastView);
 
                 // Calculate the ratio of how far out of the view the pointer currently resides to
                 // the entire height of the view.
                 final float outOfBoundsRatio = Math.min(
-                        1.0f, (float) absPastView / mHelper.getHeight());
+                        1.0f, (float) absPastView / mEnvironment.getHeight());
                 // Interpolate this ratio and use it to compute the maximum scroll that should be
                 // possible for this step.
                 final float cappedScrollStep =
@@ -1446,7 +1437,7 @@
      * RecyclerView to determine where its items are placed; then, once band selection is underway,
      * it alerts listeners of which items are covered by the selections.
      */
-    public static final class BandSelectModel extends RecyclerView.OnScrollListener {
+    public static final class GridModel extends RecyclerView.OnScrollListener {
 
         public static final int NOT_SET = -1;
 
@@ -1460,8 +1451,9 @@
         private static final int LOWER_LEFT = LOWER | LEFT;
         private static final int LOWER_RIGHT = LOWER | RIGHT;
 
-        private final BandModelHelper mHelper;
-        private final List<OnSelectionChangedListener> mOnSelectionChangedListeners = new ArrayList<>();
+        private final BandEnvironment mHelper;
+        private final List<OnSelectionChangedListener> mOnSelectionChangedListeners =
+                new ArrayList<>();
 
         // Map from the x-value of the left side of a SparseBooleanArray of adapter positions, keyed
         // by their y-offset. For example, if the first column of the view starts at an x-value of 5,
@@ -1469,15 +1461,13 @@
         // value for key y is the adapter position for the item whose y-offset is y.
         private final SparseArray<SparseIntArray> mColumns = new SparseArray<>();
 
-        // List of limits along the x-axis. For example, if the view has two columns, this list will
-        // have two elements, each of which lists the lower- and upper-limits of the x-values of the
-        // view items. This list is sorted from furthest left to furthest right.
-        private final List<Limits> mXLimitsList = new ArrayList<>();
+        // List of limits along the x-axis (columns).
+        // This list is sorted from furthest left to furthest right.
+        private final List<Limits> mColumnBounds = new ArrayList<>();
 
-        // Like mXLimitsList, but for y-coordinates. Note that this list only contains items which
-        // have been in the viewport. Thus, limits which exist in an area of the view to which the
-        // view has not scrolled are not present in the list.
-        private final List<Limits> mYLimitsList = new ArrayList<>();
+        // List of limits along the y-axis (rows). Note that this list only contains items which
+        // have been in the viewport.
+        private final List<Limits> mRowBounds = new ArrayList<>();
 
         // The adapter positions which have been recorded so far.
         private final SparseBooleanArray mKnownPositions = new SparseBooleanArray();
@@ -1499,7 +1489,7 @@
         // should expand from when Shift+click is used.
         private int mPositionNearestOrigin = NOT_SET;
 
-        BandSelectModel(BandModelHelper helper) {
+        GridModel(BandEnvironment helper) {
             mHelper = helper;
             mHelper.addOnScrollListener(this);
         }
@@ -1590,16 +1580,16 @@
          * @param adapterPosition The position of the child view being processed.
          */
         private void recordItemData(Rect absoluteChildRect, int adapterPosition) {
-            if (mXLimitsList.size() != mHelper.getNumColumns()) {
+            if (mColumnBounds.size() != mHelper.getColumnCount()) {
                 // If not all x-limits have been recorded, record this one.
                 recordLimits(
-                        mXLimitsList, new Limits(absoluteChildRect.left, absoluteChildRect.right));
+                        mColumnBounds, new Limits(absoluteChildRect.left, absoluteChildRect.right));
             }
 
-            if (mYLimitsList.size() != mHelper.getNumRows()) {
+            if (mRowBounds.size() != mHelper.getRowCount()) {
                 // If not all y-limits have been recorded, record this one.
                 recordLimits(
-                        mYLimitsList, new Limits(absoluteChildRect.top, absoluteChildRect.bottom));
+                        mRowBounds, new Limits(absoluteChildRect.top, absoluteChildRect.bottom));
             }
 
             SparseIntArray columnList = mColumns.get(absoluteChildRect.left);
@@ -1640,7 +1630,7 @@
          * Computes the currently-selected items.
          */
         private void computeCurrentSelection() {
-            if (areItemsCoveredBySelection(mRelativePointer, mRelativeOrigin)) {
+            if (areItemsCoveredByBand(mRelativePointer, mRelativeOrigin)) {
                 updateSelection(computeBounds());
             } else {
                 mSelection.clear();
@@ -1664,17 +1654,17 @@
          */
         private void updateSelection(Rect rect) {
             int columnStartIndex =
-                    Collections.binarySearch(mXLimitsList, new Limits(rect.left, rect.left));
+                    Collections.binarySearch(mColumnBounds, new Limits(rect.left, rect.left));
             checkState(columnStartIndex >= 0);
             int columnEndIndex = columnStartIndex;
 
-            for (int i = columnStartIndex;
-                    i < mXLimitsList.size() && mXLimitsList.get(i).lowerLimit <= rect.right; i++) {
+            for (int i = columnStartIndex; i < mColumnBounds.size()
+                    && mColumnBounds.get(i).lowerLimit <= rect.right; i++) {
                 columnEndIndex = i;
             }
 
             SparseIntArray firstColumn =
-                    mColumns.get(mXLimitsList.get(columnStartIndex).lowerLimit);
+                    mColumns.get(mColumnBounds.get(columnStartIndex).lowerLimit);
             int rowStartIndex = firstColumn.indexOfKey(rect.top);
             if (rowStartIndex < 0) {
                 mPositionNearestOrigin = NOT_SET;
@@ -1698,7 +1688,7 @@
                 int columnStartIndex, int columnEndIndex, int rowStartIndex, int rowEndIndex) {
             mSelection.clear();
             for (int column = columnStartIndex; column <= columnEndIndex; column++) {
-                SparseIntArray items = mColumns.get(mXLimitsList.get(column).lowerLimit);
+                SparseIntArray items = mColumns.get(mColumnBounds.get(column).lowerLimit);
                 for (int row = rowStartIndex; row <= rowEndIndex; row++) {
                     int position = items.get(items.keyAt(row));
                     mSelection.append(position, true);
@@ -1760,7 +1750,7 @@
          * of item columns and the top- and bottom sides of item rows so that it can be determined
          * whether the pointer is located within the bounds of an item.
          */
-        private class Limits implements Comparable<Limits> {
+        private static class Limits implements Comparable<Limits> {
             int lowerLimit;
             int upperLimit;
 
@@ -1798,7 +1788,7 @@
          * selection of items within those Limits as opposed to a search through every item to see if a
          * given coordinate value falls within those Limits.
          */
-        private class RelativeCoordinate
+        private static class RelativeCoordinate
                 implements Comparable<RelativeCoordinate> {
             /**
              * Location describing points after the last known item.
@@ -1849,8 +1839,7 @@
              * @param value The coordinate value.
              */
             RelativeCoordinate(List<Limits> limitsList, int value) {
-                Limits dummyLimits = new Limits(value, value);
-                int index = Collections.binarySearch(limitsList, dummyLimits);
+                int index = Collections.binarySearch(limitsList, new Limits(value, value));
 
                 if (index >= 0) {
                     this.type = WITHIN_LIMITS;
@@ -1917,8 +1906,8 @@
             final RelativeCoordinate yLocation;
 
             RelativePoint(Point point) {
-                this.xLocation = new RelativeCoordinate(mXLimitsList, point.x);
-                this.yLocation = new RelativeCoordinate(mYLimitsList, point.y);
+                this.xLocation = new RelativeCoordinate(mColumnBounds, point.x);
+                this.yLocation = new RelativeCoordinate(mRowBounds, point.y);
             }
 
             @Override
@@ -1940,19 +1929,19 @@
             Rect rect = new Rect();
             rect.left = getCoordinateValue(
                     min(mRelativeOrigin.xLocation, mRelativePointer.xLocation),
-                    mXLimitsList,
+                    mColumnBounds,
                     true);
             rect.right = getCoordinateValue(
                     max(mRelativeOrigin.xLocation, mRelativePointer.xLocation),
-                    mXLimitsList,
+                    mColumnBounds,
                     false);
             rect.top = getCoordinateValue(
                     min(mRelativeOrigin.yLocation, mRelativePointer.yLocation),
-                    mYLimitsList,
+                    mRowBounds,
                     true);
             rect.bottom = getCoordinateValue(
                     max(mRelativeOrigin.yLocation, mRelativePointer.yLocation),
-                    mYLimitsList,
+                    mRowBounds,
                     false);
             return rect;
         }
@@ -2013,7 +2002,7 @@
             throw new RuntimeException("Invalid coordinate value.");
         }
 
-        private boolean areItemsCoveredBySelection(
+        private boolean areItemsCoveredByBand(
                 RelativePoint first, RelativePoint second) {
             return doesCoordinateLocationCoverItems(first.xLocation, second.xLocation) &&
                     doesCoordinateLocationCoverItems(first.yLocation, second.yLocation);
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
index 4331b03..5505f35 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
@@ -58,6 +58,7 @@
         r.cursor = cursor;
 
         model = new Model(mContext, null);
+        model.addUpdateListener(new DummyListener());
         model.update(r);
     }
 
@@ -73,8 +74,12 @@
 
         assertEquals(ITEM_COUNT - 2, model.getItemCount());
 
-        // Finalize the deletion
-        model.finalizeDeletion(null);
+        // Finalize the deletion.  Provide a callback that just ignores errors.
+        model.finalizeDeletion(
+              new Runnable() {
+                  @Override
+                  public void run() {}
+              });
         assertEquals(ITEM_COUNT - 2, model.getItemCount());
     }
 
@@ -154,4 +159,12 @@
         }
         return model.getDocuments(sel);
     }
+
+    private static class DummyListener implements Model.UpdateListener {
+        public void onModelUpdate(Model model) {}
+        public void onModelUpdateFailed(Exception e) {}
+        public void notifyItemRemoved(int position) {}
+        public void notifyItemInserted(int position) {}
+    }
+
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
index 337064c..25d4ed4 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
@@ -285,10 +285,10 @@
         assertEquals(selection.toString(), expected, selection.size());
     }
 
-    private static final class EventHelper implements MultiSelectManager.MultiSelectHelper {
+    private static final class EventHelper implements MultiSelectManager.ItemFinder {
 
         @Override
-        public int findEventPosition(MotionEvent e) {
+        public int findItemPosition(MotionEvent e) {
             throw new UnsupportedOperationException();
         }
     }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/BandSelectModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java
similarity index 80%
rename from packages/DocumentsUI/tests/src/com/android/documentsui/BandSelectModelTest.java
rename to packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java
index 20c4548..87d7e15 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/BandSelectModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java
@@ -16,25 +16,26 @@
 
 package com.android.documentsui;
 
-import static org.junit.Assert.*;
-
-import com.android.documentsui.MultiSelectManager.BandSelectModel;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.support.v7.widget.RecyclerView.OnScrollListener;
 import android.util.SparseBooleanArray;
 
+import com.android.documentsui.MultiSelectManager.GridModel;
+
 import org.junit.After;
 import org.junit.Test;
 
-public class BandSelectModelTest {
+public class MultiSelectManager_GridModelTest {
 
     private static final int VIEW_PADDING_PX = 5;
     private static final int CHILD_VIEW_EDGE_PX = 100;
     private static final int VIEWPORT_HEIGHT = 500;
 
-    private static BandSelectModel model;
+    private static GridModel model;
     private static TestHelper helper;
     private static SparseBooleanArray lastSelection;
     private static int viewWidth;
@@ -42,14 +43,14 @@
     private static void setUp(int numChildren, int numColumns) {
         helper = new TestHelper(numChildren, numColumns);
         viewWidth = VIEW_PADDING_PX + numColumns * (VIEW_PADDING_PX + CHILD_VIEW_EDGE_PX);
-        model = new BandSelectModel(helper);
-        model.addOnSelectionChangedListener(new BandSelectModel.OnSelectionChangedListener() {
-
-            @Override
-            public void onSelectionChanged(SparseBooleanArray updatedSelection) {
-                lastSelection = updatedSelection;
-            }
-        });
+        model = new GridModel(helper);
+        model.addOnSelectionChangedListener(
+                new GridModel.OnSelectionChangedListener() {
+                    @Override
+                    public void onSelectionChanged(SparseBooleanArray updatedSelection) {
+                        lastSelection = updatedSelection;
+                    }
+                });
     }
 
     @After
@@ -65,7 +66,7 @@
         model.startSelection(new Point(0, 10));
         model.resizeSelection(new Point(1, 11));
         assertSelected(new int[0]);
-        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
     @Test
@@ -74,7 +75,7 @@
         model.startSelection(new Point(viewWidth - 1, 10));
         model.resizeSelection(new Point(viewWidth - 2, 11));
         assertSelected(new int[0]);
-        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
     @Test
@@ -83,7 +84,7 @@
         model.startSelection(new Point(10, 0));
         model.resizeSelection(new Point(11, 1));
         assertSelected(new int[0]);
-        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
     @Test
@@ -92,7 +93,7 @@
         model.startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
         model.resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
         assertSelected(new int[0]);
-        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
     @Test
@@ -101,7 +102,7 @@
         model.startSelection(new Point(106, 0));
         model.resizeSelection(new Point(107, 200));
         assertSelected(new int[0]);
-        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
     @Test
@@ -110,7 +111,7 @@
         model.startSelection(new Point(0, 105));
         model.resizeSelection(new Point(200, 106));
         assertSelected(new int[0]);
-        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
     @Test
@@ -141,7 +142,7 @@
         assertSelected(new int[] {0});
         model.resizeSelection(new Point(0, 0));
         assertSelected(new int[0]);
-        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+        assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
     @Test
@@ -191,7 +192,7 @@
         model.onScrolled(null, 0, dy);
     }
 
-    private static final class TestHelper implements MultiSelectManager.BandModelHelper {
+    private static final class TestHelper implements MultiSelectManager.BandEnvironment {
 
         public int horizontalOffset = 0;
         public int verticalOffset = 0;
@@ -269,18 +270,53 @@
         }
 
         @Override
-        public int getTotalChildCount() {
+        public int getChildCount() {
             return mNumChildren;
         }
 
         @Override
-        public int getNumColumns() {
+        public int getColumnCount() {
             return mNumColumns;
         }
 
         @Override
-        public int getNumRows() {
+        public int getRowCount() {
             return mNumRows;
         }
+
+        @Override
+        public void showBand(Rect rect) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void hideBand() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void scrollBy(int dy) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public int getHeight() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void invalidateView() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void runAtNextFrame(Runnable r) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void removeCallback(Runnable r) {
+            throw new UnsupportedOperationException();
+        }
     }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
index d90130f..be3f251 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
@@ -22,7 +22,7 @@
 
 @RunWith(Suite.class)
 @SuiteClasses({
-        BandSelectModelTest.class,
+        MultiSelectManager_GridModelTest.class,
         MultiSelectManager_SelectionTest.class,
         MultiSelectManagerTest.class
 })
diff --git a/packages/Keyguard/res/values-nl/strings.xml b/packages/Keyguard/res/values-nl/strings.xml
index 5413895..35caf77 100644
--- a/packages/Keyguard/res/values-nl/strings.xml
+++ b/packages/Keyguard/res/values-nl/strings.xml
@@ -42,7 +42,7 @@
     <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Plaats een simkaart."</string>
     <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"De simkaart ontbreekt of kan niet worden gelezen. Plaats een simkaart."</string>
     <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"Onbruikbare simkaart."</string>
-    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Uw simkaart is permanent uitgeschakeld.\n Neem contact op met uw mobiele serviceprovider voor een nieuwe simkaart."</string>
+    <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"Je simkaart is permanent uitgeschakeld.\n Neem contact op met je mobiele serviceprovider voor een nieuwe simkaart."</string>
     <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"Simkaart is vergrendeld."</string>
     <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"Simkaart is vergrendeld met PUK-code."</string>
     <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Simkaart ontgrendelen…"</string>
@@ -62,13 +62,13 @@
     <string name="kg_wrong_password" msgid="2333281762128113157">"Onjuist wachtwoord"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Onjuiste pincode"</string>
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Probeer het over <xliff:g id="NUMBER">%d</xliff:g> seconden opnieuw."</string>
-    <string name="kg_pattern_instructions" msgid="398978611683075868">"Teken uw patroon"</string>
+    <string name="kg_pattern_instructions" msgid="398978611683075868">"Teken je patroon"</string>
     <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Geef de pincode van de simkaart op"</string>
     <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"Voer de pincode in voor de simkaart van \'<xliff:g id="CARRIER">%1$s</xliff:g>\'"</string>
     <string name="kg_pin_instructions" msgid="2377242233495111557">"Pincode opgeven"</string>
     <string name="kg_password_instructions" msgid="5753646556186936819">"Wachtwoord invoeren"</string>
     <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"De simkaart is nu uitgeschakeld. Geef de PUK-code op om door te gaan. Neem contact op met de provider voor informatie."</string>
-    <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"Simkaart van \'<xliff:g id="CARRIER">%1$s</xliff:g>\' is nu uitgeschakeld. Voer de PUK-code in om door te gaan. Neem contact op met uw provider voor meer informatie."</string>
+    <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"Simkaart van \'<xliff:g id="CARRIER">%1$s</xliff:g>\' is nu uitgeschakeld. Voer de PUK-code in om door te gaan. Neem contact op met je provider voor meer informatie."</string>
     <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Gewenste pincode opgeven"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Gewenste pincode bevestigen"</string>
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Simkaart ontgrendelen..."</string>
@@ -77,32 +77,32 @@
     <string name="kg_invalid_puk" msgid="3638289409676051243">"Geef de juiste PUK-code opnieuw op. Bij herhaalde pogingen wordt de simkaart permanent uitgeschakeld."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pincodes komen niet overeen"</string>
     <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogingen"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"U heeft uw pincode <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%d</xliff:g> seconden."</string>
-    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"U heeft uw wachtwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%d</xliff:g> seconden."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%d</xliff:g> seconden."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"U heeft <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt deze tablet gereset, waardoor alle gegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"U heeft <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt deze telefoon gereset, waardoor alle gegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"U heeft <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Deze tablet wordt gereset, waardoor alle gegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"U heeft <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Deze telefoon wordt gereset, waardoor alle gegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"U heeft <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"U heeft <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"U heeft <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Deze gebruiker wordt verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"U heeft <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Deze gebruiker wordt verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"U heeft <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt het werkprofiel verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"U heeft <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt het werkprofiel verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"U heeft <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"U heeft <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd uw telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
-    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Onjuiste pincode voor simkaart. U moet nu contact opnemen met uw provider om uw apparaat te ontgrendelen."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Je hebt je pincode <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%d</xliff:g> seconden."</string>
+    <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Je hebt je wachtwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%d</xliff:g> seconden."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%d</xliff:g> seconden."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt deze tablet gereset, waardoor alle gegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt deze telefoon gereset, waardoor alle gegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Deze tablet wordt gereset, waardoor alle gegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Deze telefoon wordt gereset, waardoor alle gegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt deze gebruiker verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Deze gebruiker wordt verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Deze gebruiker wordt verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt het werkprofiel verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt het werkprofiel verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Het werkprofiel wordt verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd je tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+    <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Onjuiste pincode voor simkaart. U moet nu contact opnemen met je provider om je apparaat te ontgrendelen."</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
-      <item quantity="other">Onjuiste pincode voor simkaart. U heeft nog <xliff:g id="NUMBER_1">%d</xliff:g> pogingen over.</item>
-      <item quantity="one">Onjuiste pincode voor simkaart. U heeft nog <xliff:g id="NUMBER_0">%d</xliff:g> poging over voordat u contact met uw provider moet opnemen om uw apparaat te ontgrendelen.</item>
+      <item quantity="other">Onjuiste pincode voor simkaart. Je hebt nog <xliff:g id="NUMBER_1">%d</xliff:g> pogingen over.</item>
+      <item quantity="one">Onjuiste pincode voor simkaart. Je hebt nog <xliff:g id="NUMBER_0">%d</xliff:g> poging over voordat u contact met je provider moet opnemen om je apparaat te ontgrendelen.</item>
     </plurals>
-    <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Simkaart is onbruikbaar. Neem contact op met uw provider."</string>
+    <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"Simkaart is onbruikbaar. Neem contact op met je provider."</string>
     <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
-      <item quantity="other">Onjuiste pukcode voor simkaart. U heeft nog <xliff:g id="NUMBER_1">%d</xliff:g> pogingen over voordat de simkaart definitief onbruikbaar wordt.</item>
-      <item quantity="one">Onjuiste pukcode voor simkaart. U heeft nog <xliff:g id="NUMBER_0">%d</xliff:g> poging over voordat de simkaart definitief onbruikbaar wordt.</item>
+      <item quantity="other">Onjuiste pukcode voor simkaart. Je hebt nog <xliff:g id="NUMBER_1">%d</xliff:g> pogingen over voordat de simkaart definitief onbruikbaar wordt.</item>
+      <item quantity="one">Onjuiste pukcode voor simkaart. Je hebt nog <xliff:g id="NUMBER_0">%d</xliff:g> poging over voordat de simkaart definitief onbruikbaar wordt.</item>
     </plurals>
     <string name="kg_password_pin_failed" msgid="6268288093558031564">"Bewerking met pincode voor simkaart mislukt."</string>
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Bewerking met pukcode voor simkaart is mislukt."</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index b752c9b..47d8e28 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1032,7 +1032,7 @@
     }
 
     private boolean shouldListenForFingerprint() {
-        return (mKeyguardIsVisible || !mDeviceInteractive) && !mSwitchingUser
+        return (mKeyguardIsVisible || !mDeviceInteractive || mBouncer) && !mSwitchingUser
                 && !mFingerprintAlreadyAuthenticated && !isFingerprintDisabled(getCurrentUser());
     }
 
@@ -1365,6 +1365,7 @@
                 cb.onKeyguardBouncerChanged(isBouncer);
             }
         }
+        updateFingerprintListeningState();
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
index f52d755..66233b8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -25,6 +25,7 @@
 import android.os.SystemProperties;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
 
 public class TetherUtil {
 
@@ -62,6 +63,13 @@
         return wifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED;
     }
 
+    private static boolean isEntitlementCheckRequired(Context context) {
+        final CarrierConfigManager configManager = (CarrierConfigManager) context
+             .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        return configManager.getConfig().getBoolean(CarrierConfigManager
+             .KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
+    }
+
     public static boolean isProvisioningNeeded(Context context) {
         // Keep in sync with other usage of config_mobile_hotspot_provision_app.
         // ConnectivityManager#enforceTetherChangePermission
@@ -71,6 +79,10 @@
                 || provisionApp == null) {
             return false;
         }
+        // Check carrier config for entitlement checks
+        if (isEntitlementCheckRequired(context) == false) {
+            return false;
+        }
         return (provisionApp.length == 2);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 632a867..cff8c23 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -771,6 +771,10 @@
         }
     }
 
+    void setRssi(int rssi) {
+        mRssi = rssi;
+    }
+
     public static String getSummary(Context context, String ssid, DetailedState state,
             boolean isEphemeral, String passpointProvider) {
         if (state == DetailedState.CONNECTED && ssid == null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index c28288e..d7dfdf8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -312,6 +312,8 @@
             connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId());
         }
 
+        final Collection<ScanResult> results = fetchScanResults();
+
         final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
         if (configs != null) {
             mSavedNetworksExist = configs.size() != 0;
@@ -326,8 +328,20 @@
                     }
                 }
                 if (mIncludeSaved) {
-                    if (!config.isPasspoint() || mIncludePasspoints)
+                    if (!config.isPasspoint() || mIncludePasspoints) {
+                        // If saved network not present in scan result then set its Rssi to MAX_VALUE
+                        boolean apFound = false;
+                        for (ScanResult result : results) {
+                            if (result.SSID.equals(accessPoint.getSsidStr())) {
+                                apFound = true;
+                                break;
+                            }
+                        }
+                        if (!apFound) {
+                            accessPoint.setRssi(Integer.MAX_VALUE);
+                        }
                         accessPoints.add(accessPoint);
+                    }
 
                     if (config.isPasspoint() == false) {
                         apMap.put(accessPoint.getSsidStr(), accessPoint);
@@ -340,7 +354,6 @@
             }
         }
 
-        final Collection<ScanResult> results = fetchScanResults();
         if (results != null) {
             for (ScanResult result : results) {
                 // Ignore hidden and ad-hoc networks.
diff --git a/packages/Shell/res/values-nl/strings.xml b/packages/Shell/res/values-nl/strings.xml
index 2936387..b0dba4d 100644
--- a/packages/Shell/res/values-nl/strings.xml
+++ b/packages/Shell/res/values-nl/strings.xml
@@ -18,8 +18,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Foutenrapport vastgelegd"</string>
-    <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Veeg naar links om uw bugmelding te delen"</string>
-    <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Raak aan om uw foutenrapport te delen"</string>
+    <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Veeg naar links om je bugmelding te delen"</string>
+    <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Raak aan om je foutenrapport te delen"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Foutenrapporten bevatten gegevens uit de verschillende logbestanden van het systeem, waaronder persoonlijke en privégegevens. Deel foutenrapporten alleen met apps en mensen die u vertrouwt."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Dit bericht de volgende keer weergeven"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Foutenrapporten"</string>
diff --git a/packages/SystemUI/res/anim/fab_elevation.xml b/packages/SystemUI/res/anim/fab_elevation.xml
new file mode 100644
index 0000000..2c76a86
--- /dev/null
+++ b/packages/SystemUI/res/anim/fab_elevation.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="true" android:state_pressed="true">
+        <set>
+            <objectAnimator
+                android:duration="@android:integer/config_shortAnimTime"
+                android:propertyName="translationZ"
+                android:valueTo="@dimen/fab_press_translation_z"
+                android:valueType="floatType" />
+        </set>
+    </item>
+    <item>
+        <set>
+            <objectAnimator
+                android:duration="@android:integer/config_shortAnimTime"
+                android:propertyName="translationZ"
+                android:valueTo="0"
+                android:valueType="floatType" />
+        </set>
+    </item>
+</selector>
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_land.png
deleted file mode 100644
index 165ef4f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
deleted file mode 100644
index f95f09f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png
deleted file mode 100644
index 860a906..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png
deleted file mode 100644
index bcb203e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index bab268e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
deleted file mode 100644
index 2f4dbbe..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
deleted file mode 100644
index d04d84f..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
deleted file mode 100644
index 1500ae5..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
deleted file mode 100644
index a7fec49..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_land.png
deleted file mode 100644
index 0feb405..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
deleted file mode 100644
index cabab0d..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png
deleted file mode 100644
index 16e1bf5..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png
deleted file mode 100644
index 94c9743..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index 40375de..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_land.png
deleted file mode 100644
index b7b8f98..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
deleted file mode 100644
index 69b7449..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png
deleted file mode 100644
index 57d243c..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png
deleted file mode 100644
index 8a7ac4f..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index e53eaff..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_land.png
deleted file mode 100644
index 695e7a4..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
deleted file mode 100644
index 88294c0..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
deleted file mode 100644
index 09d684a..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png
deleted file mode 100644
index 62f44e8..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index e31ea32..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_land.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_land.png
deleted file mode 100644
index 24f12d7..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_land.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_land.png
deleted file mode 100644
index 51482f5..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_land.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_land.png
deleted file mode 100644
index 46c7b18..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent_land.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent_land.png
deleted file mode 100644
index 396ad7d..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent_land.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/fab_background.xml b/packages/SystemUI/res/drawable/fab_background.xml
new file mode 100644
index 0000000..7f23f2b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/fab_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="@color/fab_ripple">
+    <item>
+        <shape>
+            <solid android:color="@color/fab_shape" />
+        </shape>
+    </item>
+</ripple>
diff --git a/packages/SystemUI/res/drawable/ic_add.xml b/packages/SystemUI/res/drawable/ic_add.xml
new file mode 100644
index 0000000..c573592
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_add.xml
@@ -0,0 +1,24 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M38.0,26.0L26.0,26.0l0.0,12.0l-4.0,0.0L22.0,26.0L10.0,26.0l0.0,-4.0l12.0,0.0L22.0,10.0l4.0,0.0l0.0,12.0l12.0,0.0l0.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_close_white.xml b/packages/SystemUI/res/drawable/ic_close_white.xml
new file mode 100644
index 0000000..ce64047
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_close_white.xml
@@ -0,0 +1,24 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
+        android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index c92ba45..d58664f 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -213,7 +213,7 @@
                     android:layout_width="match_parent"
                     android:layout_height="40dp"
                     android:contentDescription="@string/accessibility_menu"
-                    android:src="@drawable/ic_sysbar_menu_land"
+                    android:src="@drawable/ic_sysbar_menu"
                     android:scaleType="centerInside"
                     android:layout_gravity="top"
                     android:visibility="invisible"
@@ -223,7 +223,7 @@
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps"
                 android:layout_height="@dimen/navigation_key_width"
                 android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_recent_land"
+                android:src="@drawable/ic_sysbar_recent"
                 android:scaleType="center"
                 android:layout_weight="0"
                 android:contentDescription="@string/accessibility_recent"
@@ -237,7 +237,7 @@
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
                 android:layout_height="@dimen/navigation_key_width"
                 android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_home_land"
+                android:src="@drawable/ic_sysbar_home"
                 android:scaleType="center"
                 systemui:keyCode="3"
                 systemui:keyRepeat="false"
@@ -253,7 +253,7 @@
             <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
                 android:layout_height="@dimen/navigation_key_width"
                 android:layout_width="match_parent"
-                android:src="@drawable/ic_sysbar_back_land"
+                android:src="@drawable/ic_sysbar_back"
                 android:scaleType="center"
                 systemui:keyCode="4"
                 android:layout_weight="0"
diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index 6beac31..dc928c7 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -19,19 +19,66 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
+    android:paddingBottom="@dimen/navigation_bar_size"
     android:background="?android:attr/windowBackground">
 
-    <Toolbar
-        android:id="@*android:id/action_bar"
+    <FrameLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:navigationContentDescription="@*android:string/action_bar_up_description"
-        android:background="?android:attr/colorPrimary"
-        style="?android:attr/toolbarStyle" />
+        android:background="?android:attr/colorPrimary">
+
+        <LinearLayout
+            android:id="@+id/drag_buttons"
+            android:layout_width="match_parent"
+            android:layout_height="fill_parent"
+            android:orientation="horizontal">
+            <FrameLayout
+                android:layout_width="0dp"
+                android:layout_height="fill_parent"
+                android:layout_weight="1">
+                <com.android.systemui.qs.customize.DropButton
+                    android:id="@+id/info_button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:gravity="center"
+                    android:drawableStart="@drawable/ic_info"
+                    android:drawablePadding="10dp"
+                    android:textAppearance="?android:attr/textAppearanceMedium"
+                    android:textColor="@android:color/white"
+                    android:text="@string/qs_customize_info" />
+            </FrameLayout>
+            <FrameLayout
+                android:layout_width="0dp"
+                android:layout_height="fill_parent"
+                android:layout_weight="1">
+                <com.android.systemui.qs.customize.DropButton
+                    android:id="@+id/remove_button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:gravity="center"
+                    android:drawableStart="@drawable/ic_close_white"
+                    android:drawablePadding="10dp"
+                    android:textAppearance="?android:attr/textAppearanceMedium"
+                    android:textColor="@android:color/white"
+                    android:text="@string/qs_customize_remove" />
+            </FrameLayout>
+        </LinearLayout>
+
+        <Toolbar
+            android:id="@*android:id/action_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:navigationContentDescription="@*android:string/action_bar_up_description"
+            style="?android:attr/toolbarStyle"
+            android:background="?android:attr/colorPrimary" />
+    </FrameLayout>
 
     <com.android.systemui.tuner.AutoScrollView
         android:layout_width="match_parent"
-        android:layout_height="fill_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
         android:paddingTop="8dp"
         android:paddingBottom="8dp"
         android:elevation="2dp">
@@ -44,4 +91,15 @@
 
     </com.android.systemui.tuner.AutoScrollView>
 
+    <com.android.systemui.qs.customize.FloatingActionButton
+        android:id="@+id/fab"
+        android:clickable="true"
+        android:layout_width="@dimen/fab_size"
+        android:layout_height="@dimen/fab_size"
+        android:layout_gravity="bottom|end"
+        android:layout_marginEnd="@dimen/fab_margin"
+        android:layout_marginBottom="@dimen/fab_margin"
+        android:elevation="@dimen/fab_elevation"
+        android:background="@drawable/fab_background" />
+
 </com.android.systemui.qs.customize.QSCustomizer>
diff --git a/packages/SystemUI/res/layout/shelf_menu_anchor.xml b/packages/SystemUI/res/layout/shelf_menu_anchor.xml
new file mode 100644
index 0000000..984f655
--- /dev/null
+++ b/packages/SystemUI/res/layout/shelf_menu_anchor.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent"
+             android:alpha="0">
+    <ImageView android:id="@+id/shelf_menu_anchor_anchor"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:alpha="0"/>
+</FrameLayout>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 7def415f..cc37162 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -354,7 +354,7 @@
     <string name="user_remove_user_title" msgid="4681256956076895559">"Vols suprimir l\'usuari?"</string>
     <string name="user_remove_user_message" msgid="1453218013959498039">"Totes les aplicacions i les dades d\'aquest usuari se suprimiran."</string>
     <string name="user_remove_user_remove" msgid="7479275741742178297">"Suprimeix"</string>
-    <string name="battery_saver_notification_title" msgid="237918726750955859">"Estalvi de bateria activada"</string>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Estalvi de bateria activat"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Redueix el rendiment i l\'ús de les dades en segon pla."</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactiva l\'estalvi de bateria"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contingut amagat"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index fa01c47..7593f46 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -34,14 +34,14 @@
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"اعلان‌ها"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"شارژ باتری کم است"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده است"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده است. ذخیره کننده باتری روشن است."</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"<xliff:g id="PERCENTAGE">%s</xliff:g> باقی مانده است. بهینه‌سازی باتری روشن است."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"‏شارژ USB پشتیبانی نمی‌شود.\nفقط از شارژر ارائه شده استفاده کنید."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"‏شارژ با USB پشتیبانی نمی‌شود."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"فقط از شارژر ارائه شده استفاده کنید."</string>
     <string name="battery_low_why" msgid="4553600287639198111">"تنظیمات"</string>
-    <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"ذخیره‌کننده باتری روشن شود؟"</string>
+    <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"بهینه‌سازی باتری روشن شود؟"</string>
     <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"روشن کردن"</string>
-    <string name="battery_saver_start_action" msgid="5576697451677486320">"ذخیره‌کننده باتری را روشن کنید"</string>
+    <string name="battery_saver_start_action" msgid="5576697451677486320">"بهینه‌سازی باتری را روشن کنید"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"تنظیمات"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"چرخش خودکار صفحه"</string>
@@ -352,9 +352,9 @@
     <string name="user_remove_user_title" msgid="4681256956076895559">"کاربر حذف شود؟"</string>
     <string name="user_remove_user_message" msgid="1453218013959498039">"همه برنامه‌ها و داده‌های این کاربر حذف می‌شود."</string>
     <string name="user_remove_user_remove" msgid="7479275741742178297">"حذف"</string>
-    <string name="battery_saver_notification_title" msgid="237918726750955859">"ذخیره کننده باتری روشن است."</string>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"بهینه‌سازی باتری روشن است."</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"عملکرد و اطلاعات پس‌زمینه را کاهش می‌دهد"</string>
-    <string name="battery_saver_notification_action_text" msgid="109158658238110382">"خاموش کردن ذخیره‌کننده باتری"</string>
+    <string name="battery_saver_notification_action_text" msgid="109158658238110382">"بهینه‌سازی باتری را خاموش کنید"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"محتواها پنهان هستند"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> شروع به ضبط هر چیزی می‌کند که در صفحه‌نمایش شما نمایش داده می‌شود."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"دوباره نشان داده نشود"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 13f02d5..79f3333 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -23,7 +23,7 @@
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Wissen"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Verwijderen uit lijst"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"App-info"</string>
-    <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Uw recente schermen worden hier weergegeven"</string>
+    <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Je recente schermen worden hier weergegeven"</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Recente apps negeren"</string>
     <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
       <item quantity="other">%d schermen in Overzicht</item>
@@ -71,9 +71,9 @@
     <string name="screenshot_saving_title" msgid="8242282144535555697">"Screenshot opslaan..."</string>
     <string name="screenshot_saving_text" msgid="2419718443411738818">"Screenshot wordt opgeslagen."</string>
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot gemaakt."</string>
-    <string name="screenshot_saved_text" msgid="1152839647677558815">"Raak aan om uw screenshot te bekijken."</string>
+    <string name="screenshot_saved_text" msgid="1152839647677558815">"Raak aan om je screenshot te bekijken."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Screenshot is niet gemaakt."</string>
-    <string name="screenshot_failed_text" msgid="1260203058661337274">"Kan geen screenshot maken wegens beperkte opslagruimte of omdat de app of uw organisatie dit niet toestaat."</string>
+    <string name="screenshot_failed_text" msgid="1260203058661337274">"Kan geen screenshot maken wegens beperkte opslagruimte of omdat de app of je organisatie dit niet toestaat."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opties voor USB-bestandsoverdracht"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Koppelen als mediaspeler (MTP)"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"Koppelen als camera (PTP)"</string>
@@ -88,7 +88,7 @@
     <string name="accessibility_voice_assist_button" msgid="487611083884852965">"Spraakassistent"</string>
     <string name="accessibility_unlock_button" msgid="128158454631118828">"Ontgrendelen"</string>
     <string name="accessibility_unlock_button_fingerprint" msgid="8214125623493923751">"Knop Ontgrendelen, wacht op vingerafdruk"</string>
-    <string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"Ontgrendelen zonder uw vingerafdruk te gebruiken"</string>
+    <string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"Ontgrendelen zonder je vingerafdruk te gebruiken"</string>
     <string name="unlock_label" msgid="8779712358041029439">"ontgrendelen"</string>
     <string name="phone_label" msgid="2320074140205331708">"telefoon openen"</string>
     <string name="voice_assist_label" msgid="3956854378310019854">"spraakassistent openen"</string>
@@ -217,7 +217,7 @@
     <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data zijn onderbroken"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele gegevens zijn onderbroken"</string>
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Gegevens zijn onderbroken"</string>
-    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat de ingestelde gegevenslimiet is bereikt, heeft het apparaat het gegevensverbruik onderbroken voor de rest van deze cyclus.\n\nAls u het gegevensverbruik hervat, kan uw provider kosten in rekening brengen."</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat de ingestelde gegevenslimiet is bereikt, heeft het apparaat het gegevensverbruik onderbroken voor de rest van deze cyclus.\n\nAls u het gegevensverbruik hervat, kan je provider kosten in rekening brengen."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervatten"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Verbonden via wifi"</string>
@@ -289,7 +289,7 @@
     <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"<xliff:g id="DATA_USED">%s</xliff:g> gebruikt"</string>
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Limiet van <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Waarschuwing voor <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
-    <string name="recents_empty_message" msgid="8682129509540827999">"Uw recente schermen worden hier weergegeven"</string>
+    <string name="recents_empty_message" msgid="8682129509540827999">"Je recente schermen worden hier weergegeven"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"scherm vastzetten"</string>
     <string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
@@ -338,7 +338,7 @@
     <string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"Alle apps en gegevens in deze sessie worden verwijderd."</string>
     <string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"Verwijderen"</string>
     <string name="guest_wipe_session_title" msgid="6419439912885956132">"Welkom terug, gast!"</string>
-    <string name="guest_wipe_session_message" msgid="8476238178270112811">"Wilt u doorgaan met uw sessie?"</string>
+    <string name="guest_wipe_session_message" msgid="8476238178270112811">"Wilt u doorgaan met je sessie?"</string>
     <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"Opnieuw starten"</string>
     <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"Ja, doorgaan"</string>
     <string name="guest_notification_title" msgid="1585278533840603063">"Gastgebruiker"</string>
@@ -356,7 +356,7 @@
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Vermindert de prestaties en achtergrondgegevens"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Accubesparing uitschakelen"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud verborgen"</string>
-    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> gaat alles vastleggen dat wordt weergegeven op uw scherm."</string>
+    <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> gaat alles vastleggen dat wordt weergegeven op je scherm."</string>
     <string name="media_projection_remember_text" msgid="3103510882172746752">"Niet opnieuw weergeven"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Alles wissen"</string>
     <string name="media_projection_action_text" msgid="8470872969457985954">"Nu starten"</string>
@@ -369,16 +369,16 @@
     <string name="monitoring_title" msgid="169206259253048106">"Netwerkcontrole"</string>
     <string name="disable_vpn" msgid="4435534311510272506">"VPN uitschakelen"</string>
     <string name="disconnect_vpn" msgid="1324915059568548655">"Verbinding met VPN verbreken"</string>
-    <string name="monitoring_description_device_owned" msgid="5780988291898461883">"Uw apparaat wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nUw beheerder kan instellingen, bedrijfstoegang, apps, gegevens voor uw apparaat en locatiegegevens voor uw apparaat controleren en beheren. Neem voor meer informatie contact op met uw beheerder."</string>
-    <string name="monitoring_description_vpn" msgid="4445150119515393526">"U heeft een app toestemming gegeven voor het instellen van een VPN-verbinding.\n\nMet deze app kan uw apparaat- en netwerkactiviteit worden gecontroleerd, inclusief e-mails, apps en websites."</string>
-    <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Uw apparaat wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nUw beheerder kan instellingen, bedrijfstoegang, apps, gegevens voor uw apparaat en locatiegegevens voor uw apparaat controleren en beheren.\n\nU bent verbonden met een VPN, die uw netwerkactiviteit kan controleren, waaronder e-mails, apps en websites.\n\nNeem voor meer informatie contact op met uw beheerder."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Uw werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nUw beheerder kan uw netwerkactiviteit controleren, inclusief e-mails, apps en websites.\n\nNeem contact op met uw beheerder voor meer informatie.\n\nU bent ook verbonden met een VPN waarmee uw netwerkactiviteit kan worden gecontroleerd."</string>
+    <string name="monitoring_description_device_owned" msgid="5780988291898461883">"Je apparaat wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJe beheerder kan instellingen, bedrijfstoegang, apps, gegevens voor je apparaat en locatiegegevens voor je apparaat controleren en beheren. Neem voor meer informatie contact op met je beheerder."</string>
+    <string name="monitoring_description_vpn" msgid="4445150119515393526">"Je hebt een app toestemming gegeven voor het instellen van een VPN-verbinding.\n\nMet deze app kan je apparaat- en netwerkactiviteit worden gecontroleerd, inclusief e-mails, apps en websites."</string>
+    <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Je apparaat wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJe beheerder kan instellingen, bedrijfstoegang, apps, gegevens voor je apparaat en locatiegegevens voor je apparaat controleren en beheren.\n\nU bent verbonden met een VPN, die je netwerkactiviteit kan controleren, waaronder e-mails, apps en websites.\n\nNeem voor meer informatie contact op met je beheerder."</string>
+    <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJe beheerder kan je netwerkactiviteit controleren, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie.\n\nU bent ook verbonden met een VPN waarmee je netwerkactiviteit kan worden gecontroleerd."</string>
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
-    <string name="monitoring_description_app" msgid="6259179342284742878">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee uw netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
-    <string name="monitoring_description_app_personal" msgid="484599052118316268">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee uw persoonlijke netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
-    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Uw werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Deze is verbonden met <xliff:g id="APPLICATION">%2$s</xliff:g>, waarmee uw werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nNeem contact op met uw beheerder voor meer informatie."</string>
-    <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Uw werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Deze is verbonden met <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, waarmee uw werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nU bent ook verbonden met <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, waarmee uw persoonlijke netwerkactiviteit kan worden gecontroleerd."</string>
-    <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Uw apparaat wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nUw beheerder kan instellingen, zakelijke toegang, apps, gekoppelde apparaatgegevens en locatiegegevens voor uw apparaat controleren en beheren.\n\nU bent verbonden met <xliff:g id="APPLICATION">%2$s</xliff:g> waarmee uw netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nNeem contact op met uw beheerder voor meer informatie."</string>
+    <string name="monitoring_description_app" msgid="6259179342284742878">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
+    <string name="monitoring_description_app_personal" msgid="484599052118316268">"U bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites."</string>
+    <string name="monitoring_description_app_work" msgid="1754325860918060897">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Deze is verbonden met <xliff:g id="APPLICATION">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie."</string>
+    <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Deze is verbonden met <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nU bent ook verbonden met <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden gecontroleerd."</string>
+    <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Je apparaat wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJe beheerder kan instellingen, zakelijke toegang, apps, gekoppelde apparaatgegevens en locatiegegevens voor je apparaat controleren en beheren.\n\nU bent verbonden met <xliff:g id="APPLICATION">%2$s</xliff:g> waarmee je netwerkactiviteit kan worden gecontroleerd, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Het apparaat blijft vergrendeld totdat u het handmatig ontgrendelt"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Sneller meldingen ontvangen"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Weergeven voordat u ontgrendelt"</string>
@@ -403,7 +403,7 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Afwijzen"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is het volumedialoogvenster"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Tik hierop om het origineel te herstellen."</string>
-    <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"U gebruikt uw werkprofiel"</string>
+    <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"U gebruikt je werkprofiel"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Systeem-UI-tuner"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Percentage ingebouwde accu weergeven"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Accupercentage weergeven in het pictogram op de statusbalk wanneer er niet wordt opgeladen"</string>
@@ -418,8 +418,8 @@
     <string name="status_bar_airplane" msgid="7057575501472249002">"Vliegtuigmodus"</string>
     <string name="add_tile" msgid="2995389510240786221">"Tegel toevoegen"</string>
     <string name="broadcast_tile" msgid="3894036511763289383">"Tegel \'Uitzenden\'"</string>
-    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"U hoort uw volgende alarm niet <xliff:g id="WHEN">%1$s</xliff:g> tenzij u dit voor die tijd uitschakelt"</string>
-    <string name="zen_alarm_warning" msgid="444533119582244293">"U hoort uw volgende alarm niet <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"U hoort je volgende alarm niet <xliff:g id="WHEN">%1$s</xliff:g> tenzij u dit voor die tijd uitschakelt"</string>
+    <string name="zen_alarm_warning" msgid="444533119582244293">"U hoort je volgende alarm niet <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template" msgid="3980063409350522735">"om <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template_far" msgid="4242179982586714810">"op <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_detail" msgid="2579369091672902101">"Snelle instellingen, <xliff:g id="TITLE">%s</xliff:g>."</string>
@@ -432,7 +432,7 @@
     <string name="tuner_toast" msgid="603429811084428439">"Systeem-UI-tuner is toegevoegd aan Instellingen"</string>
     <string name="remove_from_settings" msgid="8389591916603406378">"Verwijderen uit Instellingen"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Systeem-UI-tuner uit Instellingen verwijderen en het gebruik van alle functies daarvan stopzetten?"</string>
-    <string name="activity_not_found" msgid="348423244327799974">"Deze app is niet geïnstalleerd op uw apparaat"</string>
+    <string name="activity_not_found" msgid="348423244327799974">"Deze app is niet geïnstalleerd op je apparaat"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Klokseconden weergeven"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Klokseconden op de statusbalk weergeven. Kan van invloed zijn op de accuduur."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"Snelle instellingen opnieuw indelen"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index e3f0fb3..2e41b29 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -36,7 +36,7 @@
     <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Upozornenia"</string>
     <string name="battery_low_title" msgid="6456385927409742437">"Batéria je takmer vybitá"</string>
     <string name="battery_low_percent_format" msgid="2900940511201380775">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
-    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g>. Úspora batérie je zapnutá."</string>
+    <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Zostáva <xliff:g id="PERCENTAGE">%s</xliff:g>. Šetrič batérie je zapnutý."</string>
     <string name="invalid_charger" msgid="4549105996740522523">"Nabíjanie pomocou rozhrania USB nie je podporované.\nPoužívajte iba nabíjačku, ktorá bola dodaná spolu so zariadením."</string>
     <string name="invalid_charger_title" msgid="3515740382572798460">"Nabíjanie prostredníctvom USB nie je podporované."</string>
     <string name="invalid_charger_text" msgid="5474997287953892710">"Používajte iba originálnu nabíjačku."</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 195fdb1..1af4ab1 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -98,4 +98,6 @@
          In sw600dp we want the buttons centered so this fills the space,
          (screen_pinning_request_width - 3 * screen_pinning_request_button_width) / 2 -->
     <dimen name="screen_pinning_request_side_width">8dp</dimen>
+
+    <dimen name="fab_margin">24dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index fdad0d5..49edb57 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -203,10 +203,10 @@
     <string name="accessibility_quick_settings_close" msgid="3115847794692516306">"Paneli kapat."</string>
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Daha uzun süre."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Daha kısa süre."</string>
-    <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Flaş ışığı kapalı."</string>
-    <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Flaş ışığı açık."</string>
-    <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Flaş ışığı kapatıldı."</string>
-    <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Flaş ışığı açıldı."</string>
+    <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"El feneri kapalı."</string>
+    <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"El feneri açık."</string>
+    <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"El feneri kapatıldı."</string>
+    <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"El feneri açıldı."</string>
     <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="4406577213290173911">"Renkleri ters çevirme işlevi kapatıldı."</string>
     <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="6897462320184911126">"Renkleri ters çevirme işlevi açıldı."</string>
     <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobil hotspot kapatıldı."</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 0dcbe88..da21084 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -143,4 +143,7 @@
     <color name="volume_icon_color">#ffffffff</color>
     <color name="volume_settings_icon_color">#7fffffff</color>
     <color name="volume_slider_inactive">#FFB0BEC5</color><!-- blue grey 200 -->
+
+    <color name="fab_ripple">#1fffffff</color><!-- 12% white -->
+    <color name="fab_shape">#ff009688</color><!-- Teal 500 -->
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3817741..96a77256 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -590,4 +590,9 @@
 
     <!-- Thickness of the shadows of the assist disclosure beams -->
     <dimen name="assist_disclosure_shadow_thickness">1.5dp</dimen>
+
+    <dimen name="fab_size">56dp</dimen>
+    <dimen name="fab_margin">16dp</dimen>
+    <dimen name="fab_elevation">12dp</dimen>
+    <dimen name="fab_press_translation_z">9dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index da7eadc..db1e688 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1158,5 +1158,7 @@
 
     <string name="save" translatable="false">Save</string>
     <string name="qs_customize" translatable="false">Allow long-press customize in Quick Settings</string>
+    <string name="qs_customize_info" translatable="false">Info</string>
+    <string name="qs_customize_remove" translatable="false">Remove</string>
 
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 9265b63..6f26222 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -1,5 +1,7 @@
 package com.android.systemui.assist;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.SearchManager;
@@ -9,9 +11,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
-import android.database.ContentObserver;
 import android.graphics.PixelFormat;
-import android.media.AudioAttributes;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
@@ -21,7 +21,6 @@
 import android.service.voice.VoiceInteractionSession;
 import android.util.Log;
 import android.view.Gravity;
-import android.view.HapticFeedbackConstants;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -33,10 +32,6 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
 
 /**
  * Class to manage everything related to assist in SystemUI.
@@ -58,8 +53,6 @@
     private final BaseStatusBar mBar;
     private final AssistUtils mAssistUtils;
 
-    private ComponentName mAssistComponent;
-
     private IVoiceInteractionSessionShowCallback mShowCallback =
             new IVoiceInteractionSessionShowCallback.Stub() {
 
@@ -82,23 +75,11 @@
         }
     };
 
-    private final ContentObserver mAssistSettingsObserver = new ContentObserver(new Handler()) {
-        @Override
-        public void onChange(boolean selfChange) {
-            updateAssistInfo();
-        }
-    };
-
     public AssistManager(BaseStatusBar bar, Context context) {
         mContext = context;
         mBar = bar;
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         mAssistUtils = new AssistUtils(context);
-
-        mContext.getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.ASSISTANT), false,
-                mAssistSettingsObserver);
-        mAssistSettingsObserver.onChange(false);
         mAssistDisclosure = new AssistDisclosure(context, new Handler());
     }
 
@@ -123,19 +104,19 @@
     }
 
     public void startAssist(Bundle args) {
-        updateAssistInfo();
-        if (mAssistComponent == null) {
+        final ComponentName assistComponent = getAssistInfo();
+        if (assistComponent == null) {
             return;
         }
 
-        final boolean isService = isAssistantService();
+        final boolean isService = assistComponent.equals(getVoiceInteractorComponentName());
         if (!isService || !isVoiceSessionRunning()) {
-            showOrb();
+            showOrb(assistComponent, isService);
             mView.postDelayed(mHideRunnable, isService
                     ? TIMEOUT_SERVICE
                     : TIMEOUT_ACTIVITY);
         }
-        startAssistInternal(args);
+        startAssistInternal(args, assistComponent, isService);
     }
 
     public void hideAssist() {
@@ -161,22 +142,21 @@
         return lp;
     }
 
-    private void showOrb() {
-        maybeSwapSearchIcon();
+    private void showOrb(@NonNull ComponentName assistComponent, boolean isService) {
+        maybeSwapSearchIcon(assistComponent, isService);
         mView.show(true /* show */, true /* animate */);
     }
 
-    private void startAssistInternal(Bundle args) {
-        if (mAssistComponent != null) {
-            if (isAssistantService()) {
-                startVoiceInteractor(args);
-            } else {
-                startAssistActivity(args);
-            }
+    private void startAssistInternal(Bundle args, @NonNull ComponentName assistComponent,
+            boolean isService) {
+        if (isService) {
+            startVoiceInteractor(args);
+        } else {
+            startAssistActivity(args, assistComponent);
         }
     }
 
-    private void startAssistActivity(Bundle args) {
+    private void startAssistActivity(Bundle args, @NonNull ComponentName assistComponent) {
         if (!mBar.isDeviceProvisioned()) {
             return;
         }
@@ -193,9 +173,7 @@
         if (intent == null) {
             return;
         }
-        if (mAssistComponent != null) {
-            intent.setComponent(mAssistComponent);
-        }
+        intent.setComponent(assistComponent);
         intent.putExtras(args);
 
         if (structureEnabled) {
@@ -243,13 +221,9 @@
         mWindowManager.removeViewImmediate(mView);
     }
 
-    private void maybeSwapSearchIcon() {
-        if (mAssistComponent != null) {
-            replaceDrawable(mView.getOrb().getLogo(), mAssistComponent, ASSIST_ICON_METADATA_NAME,
-                    isAssistantService());
-        } else {
-            mView.getOrb().getLogo().setImageDrawable(null);
-        }
+    private void maybeSwapSearchIcon(@NonNull ComponentName assistComponent, boolean isService) {
+        replaceDrawable(mView.getOrb().getLogo(), assistComponent, ASSIST_ICON_METADATA_NAME,
+                isService);
     }
 
     public void replaceDrawable(ImageView v, ComponentName component, String name,
@@ -283,28 +257,15 @@
         v.setImageDrawable(null);
     }
 
-    private boolean isAssistantService() {
-        return mAssistComponent == null ?
-                false : mAssistComponent.equals(getVoiceInteractorComponentName());
-    }
-
-    private void updateAssistInfo() {
-        mAssistComponent = mAssistUtils.getAssistComponentForUser(UserHandle.USER_CURRENT);
-    }
-
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("AssistManager state:");
-        pw.print("  mAssistComponent="); pw.println(mAssistComponent);
+    @Nullable
+    private ComponentName getAssistInfo() {
+        return mAssistUtils.getAssistComponentForUser(UserHandle.USER_CURRENT);
     }
 
     public void showDisclosure() {
         mAssistDisclosure.postShow();
     }
 
-    public void onUserSwitched(int newUserId) {
-        updateAssistInfo();
-    }
-
     public void onLockscreenShown() {
         mAssistUtils.onLockscreenShown();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0be3069..3514c5d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -75,6 +75,8 @@
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.StatusBarWindowManager;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -1641,6 +1643,30 @@
         return mViewMediatorCallback;
     }
 
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.print("  mSystemReady: "); pw.println(mSystemReady);
+        pw.print("  mBootCompleted: "); pw.println(mBootCompleted);
+        pw.print("  mBootSendUserPresent: "); pw.println(mBootSendUserPresent);
+        pw.print("  mExternallyEnabled: "); pw.println(mExternallyEnabled);
+        pw.print("  mNeedToReshowWhenReenabled: "); pw.println(mNeedToReshowWhenReenabled);
+        pw.print("  mShowing: "); pw.println(mShowing);
+        pw.print("  mInputRestricted: "); pw.println(mInputRestricted);
+        pw.print("  mOccluded: "); pw.println(mOccluded);
+        pw.print("  mDelayedShowingSequence: "); pw.println(mDelayedShowingSequence);
+        pw.print("  mExitSecureCallback: "); pw.println(mExitSecureCallback);
+        pw.print("  mDeviceInteractive: "); pw.println(mDeviceInteractive);
+        pw.print("  mGoingToSleep: "); pw.println(mGoingToSleep);
+        pw.print("  mHiding: "); pw.println(mHiding);
+        pw.print("  mWaitingUntilKeyguardVisible: "); pw.println(mWaitingUntilKeyguardVisible);
+        pw.print("  mKeyguardDonePending: "); pw.println(mKeyguardDonePending);
+        pw.print("  mHideAnimationRun: "); pw.println(mHideAnimationRun);
+        pw.print("  mPendingReset: "); pw.println(mPendingReset);
+        pw.print("  mPendingLock: "); pw.println(mPendingLock);
+        pw.print("  mWakeAndUnlocking: "); pw.println(mWakeAndUnlocking);
+        pw.print("  mDrawnCallback: "); pw.println(mDrawnCallback);
+    }
+
     private static class StartKeyguardExitAnimParams {
 
         long startTime;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
index fe75220..8866e55 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
@@ -19,26 +19,21 @@
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
-import android.view.View.OnTouchListener;
 
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTileView;
 import com.android.systemui.statusbar.phone.QSTileHost;
 
 /**
  * A version of QSPanel that allows tiles to be dragged around rather than
- * clicked on.  Dragging is started here, receiving is handled in the NonPagedTileLayout,
+ * clicked on.  Dragging starting and receiving is handled in the NonPagedTileLayout,
  * and the saving/ordering is handled by the CustomQSTileHost.
  */
-public class CustomQSPanel extends QSPanel implements OnTouchListener {
+public class CustomQSPanel extends QSPanel {
 
     private CustomQSTileHost mCustomHost;
-    private ClipData mCurrentClip;
-    private View mCurrentView;
 
     public CustomQSPanel(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -62,52 +57,26 @@
         }
     }
 
-    @Override
-    protected void addTile(QSTile<?> tile) {
-        super.addTile(tile);
-        if (tile.getTileType() != QSTileView.QS_TYPE_QUICK) {
-            TileRecord record = mRecords.get(mRecords.size() - 1);
-            if (record.tileView.getTag() == record.tile) {
-                return;
-            }
-            record.tileView.setTag(record.tile);
-            record.tileView.setVisibility(View.VISIBLE);
-            record.tileView.init(null, null, null);
-            record.tileView.setOnTouchListener(this);
-            if (mCurrentClip != null
-                    && mCurrentClip.getItemAt(0).getText().toString().equals(tile.getTileSpec())) {
-                record.tileView.setAlpha(.3f);
-                mCurrentView = record.tileView;
-            }
-        }
+    public CustomQSTileHost getCustomHost() {
+        return mCustomHost;
     }
 
-    public void tileSelected(View v) {
-        String sourceSpec = mCurrentClip.getItemAt(0).getText().toString();
-        String destSpec = ((QSTile<?>) v.getTag()).getTileSpec();
+    public void tileSelected(QSTile<?> tile, ClipData currentClip) {
+        String sourceSpec = getSpec(currentClip);
+        String destSpec = tile.getTileSpec();
         if (!sourceSpec.equals(destSpec)) {
             mCustomHost.moveTo(sourceSpec, destSpec);
         }
     }
 
-    @Override
-    public boolean onTouch(View v, MotionEvent event) {
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                String tileSpec = (String) ((QSTile<?>) v.getTag()).getTileSpec();
-                mCurrentView = v;
-                mCurrentClip = ClipData.newPlainText(tileSpec, tileSpec);
-                View.DragShadowBuilder shadow = new View.DragShadowBuilder(v);
-                ((View) getParent().getParent()).startDrag(mCurrentClip, shadow, null, 0);
-                v.setAlpha(.3f);
-                return true;
-        }
-        return false;
+    public ClipData getClip(QSTile<?> tile) {
+        String tileSpec = tile.getTileSpec();
+        // TODO: Something better than plain text.
+        // TODO: Once using something better than plain text, stop listening to non-QS drag events.
+        return ClipData.newPlainText(tileSpec, tileSpec);
     }
 
-    public void onDragEnded() {
-        mCurrentView.setAlpha(1f);
-        mCurrentView = null;
-        mCurrentClip = null;
+    public String getSpec(ClipData data) {
+        return data.getItemAt(0).getText().toString();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java
index 0951129..84b05d0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java
@@ -37,6 +37,7 @@
     private static final String TAG = "CustomHost";
     private List<String> mTiles;
     private List<String> mSavedTiles;
+    private ArrayList<String> mStash;
 
     public CustomQSTileHost(Context context, QSTileHost host) {
         super(context, null, host.getBluetoothController(), host.getLocationController(),
@@ -70,6 +71,14 @@
                 TextUtils.join(",", mTiles), ActivityManager.getCurrentUser());
     }
 
+    public void stashCurrentTiles() {
+        mStash = new ArrayList<>(mTiles);
+    }
+
+    public void unstashTiles() {
+        setTiles(mStash);
+    }
+
     public void moveTo(String from, String to) {
         int fromIndex = mTiles.indexOf(from);
         if (fromIndex < 0) {
@@ -86,6 +95,13 @@
         super.onTuningChanged(TILES_SETTING, null);
     }
 
+    public void remove(String spec) {
+        if (!mTiles.remove(spec)) {
+            Log.e(TAG, "Unknown remove spec " + spec);
+        }
+        super.onTuningChanged(TILES_SETTING, null);
+    }
+
     public void setTiles(List<String> tiles) {
         mTiles = new ArrayList<>(tiles);
         super.onTuningChanged(TILES_SETTING, null);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/DropButton.java b/packages/SystemUI/src/com/android/systemui/qs/customize/DropButton.java
new file mode 100644
index 0000000..0e15f2b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/DropButton.java
@@ -0,0 +1,70 @@
+/*
+ * 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.systemui.qs.customize;
+
+import android.content.ClipData;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.DragEvent;
+import android.view.View;
+import android.view.View.OnDragListener;
+import android.widget.TextView;
+
+public class DropButton extends TextView implements OnDragListener {
+
+    private OnDropListener mListener;
+
+    public DropButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        // TODO: Don't do this, instead make this view the right size...
+        ((View) getParent()).setOnDragListener(this);
+    }
+
+    public void setOnDropListener(OnDropListener listener) {
+        mListener = listener;
+    }
+
+    private void setHovering(boolean hovering) {
+        setAlpha(hovering ? .5f : 1);
+    }
+
+    @Override
+    public boolean onDrag(View v, DragEvent event) {
+        switch (event.getAction()) {
+            case DragEvent.ACTION_DRAG_ENTERED:
+                setHovering(true);
+                break;
+            case DragEvent.ACTION_DROP:
+                if (mListener != null) {
+                    mListener.onDrop(this, event.getClipData());
+                }
+            case DragEvent.ACTION_DRAG_EXITED:
+            case DragEvent.ACTION_DRAG_ENDED:
+                setHovering(false);
+                break;
+        }
+        return true;
+    }
+
+    public interface OnDropListener {
+        void onDrop(View v, ClipData data);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/FloatingActionButton.java b/packages/SystemUI/src/com/android/systemui/qs/customize/FloatingActionButton.java
new file mode 100644
index 0000000..8791a10
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/FloatingActionButton.java
@@ -0,0 +1,49 @@
+/*
+ * 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.systemui.qs.customize;
+
+import android.animation.AnimatorInflater;
+import android.content.Context;
+import android.graphics.Outline;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+public class FloatingActionButton extends ImageView {
+
+    public FloatingActionButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setScaleType(ScaleType.CENTER);
+        setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, R.anim.fab_elevation));
+        setOutlineProvider(new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                outline.setOval(0, 0, getWidth(), getHeight());
+            }
+        });
+        setClipToOutline(true);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        invalidateOutline();
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
index 47c9384..012633c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/NonPagedTileLayout.java
@@ -15,12 +15,15 @@
  */
 package com.android.systemui.qs.customize;
 
+import android.content.ClipData;
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.DragEvent;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.View.OnTouchListener;
 import android.widget.LinearLayout;
 
 import com.android.systemui.R;
@@ -28,6 +31,7 @@
 import com.android.systemui.qs.PagedTileLayout.TilePage;
 import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.QSPanel.TileRecord;
+import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTileView;
 import com.android.systemui.qs.QuickTileLayout;
 
@@ -38,7 +42,7 @@
  * vertically and expects to be inside a ScrollView.
  * @see CustomQSPanel
  */
-public class NonPagedTileLayout extends LinearLayout implements QSTileLayout {
+public class NonPagedTileLayout extends LinearLayout implements QSTileLayout, OnTouchListener {
 
     private QuickTileLayout mQuickTiles;
     private final ArrayList<TilePage> mPages = new ArrayList<>();
@@ -46,6 +50,9 @@
     private CustomQSPanel mPanel;
     private final Rect mHitRect = new Rect();
 
+    private ClipData mCurrentClip;
+    private View mCurrentView;
+
     public NonPagedTileLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -63,17 +70,23 @@
         mPanel = qsPanel;
     }
 
-    private void clear() {
-        mQuickTiles.removeAllViews();
-        for (int i = 0; i < mPages.size(); i++) {
-            mPages.get(i).removeAllViews();
-        }
-    }
-
     @Override
-    public void addTile(TileRecord tile) {
-        mTiles.add(tile);
+    public void addTile(TileRecord record) {
+        mTiles.add(record);
         distributeTiles();
+        if (record.tile.getTileType() == QSTileView.QS_TYPE_QUICK
+                || record.tileView.getTag() == record.tile) {
+            return;
+        }
+        record.tileView.setTag(record.tile);
+        record.tileView.setVisibility(View.VISIBLE);
+        record.tileView.init(null, null, null);
+        record.tileView.setOnTouchListener(this);
+        if (mCurrentClip != null
+                && mCurrentClip.getItemAt(0).getText().toString().equals(record.tile.getTileSpec())) {
+            record.tileView.setAlpha(.3f);
+            mCurrentView = record.tileView;
+        }
     }
 
     @Override
@@ -118,8 +131,8 @@
 
     @Override
     public int getOffsetTop(TileRecord tile) {
-        // TODO: Fix this.
-        return getTop();
+        // No touch feedback, so this isn't required.
+        return 0;
     }
 
     @Override
@@ -145,7 +158,7 @@
                             for (int j = 0; j < NC; j++) {
                                 View child = page.getChildAt(j);
                                 if (contains(child, x, y)) {
-                                    mPanel.tileSelected(child);
+                                    mPanel.tileSelected((QSTile<?>) child.getTag(), mCurrentClip);
                                 }
                             }
                             break;
@@ -154,12 +167,35 @@
                 }
                 break;
             case DragEvent.ACTION_DRAG_ENDED:
-                mPanel.onDragEnded();
+                onDragEnded();
                 break;
         }
         return true;
     }
 
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                // Stash the current tiles, in case the drop is on info, that we can restore
+                // the previous state.
+                mPanel.getCustomHost().stashCurrentTiles();
+                mCurrentView = v;
+                mCurrentClip = mPanel.getClip((QSTile<?>) v.getTag());
+                View.DragShadowBuilder shadow = new View.DragShadowBuilder(v);
+                ((View) getParent().getParent()).startDrag(mCurrentClip, shadow, null, 0);
+                v.setAlpha(.3f);
+                return true;
+        }
+        return false;
+    }
+
+    public void onDragEnded() {
+        mCurrentView.setAlpha(1f);
+        mCurrentView = null;
+        mCurrentClip = null;
+    }
+
     private boolean contains(View v, float x, float y) {
         v.getHitRect(mHitRect);
         return mHitRect.contains((int) x, (int) y);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 7724a87..7e74785 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -15,13 +15,17 @@
  */
 package com.android.systemui.qs.customize;
 
+import android.content.ClipData;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
+import android.view.DragEvent;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.Toolbar;
 import android.widget.Toolbar.OnMenuItemClickListener;
@@ -29,8 +33,10 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.qs.QSTile.Host.Callback;
+import com.android.systemui.qs.customize.DropButton.OnDropListener;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.tuner.QSPagingSwitch;
 
 import java.util.ArrayList;
@@ -41,7 +47,8 @@
  * This adds itself to the status bar window, so it can appear on top of quick settings and
  * *someday* do fancy animations to get into/out of it.
  */
-public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener, Callback {
+public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener, Callback,
+        OnDropListener, OnClickListener {
 
     private static final int MENU_SAVE = Menu.FIRST;
     private static final int MENU_RESET = Menu.FIRST + 1;
@@ -49,10 +56,14 @@
     private PhoneStatusBar mPhoneStatusBar;
 
     private Toolbar mToolbar;
+    private ViewGroup mDragButtons;
     private CustomQSPanel mQsPanel;
 
     private boolean isShown;
     private CustomQSTileHost mHost;
+    private DropButton mInfoButton;
+    private DropButton mRemoveButton;
+    private FloatingActionButton mFab;
 
     public QSCustomizer(Context context, AttributeSet attrs) {
         super(new ContextThemeWrapper(context, android.R.style.Theme_Material), attrs);
@@ -90,6 +101,18 @@
                 mContext.getString(com.android.internal.R.string.reset));
 
         mQsPanel = (CustomQSPanel) findViewById(R.id.quick_settings_panel);
+
+        mDragButtons = (ViewGroup) findViewById(R.id.drag_buttons);
+        setDragging(false);
+
+        mInfoButton = (DropButton) findViewById(R.id.info_button);
+        mInfoButton.setOnDropListener(this);
+        mRemoveButton = (DropButton) findViewById(R.id.remove_button);
+        mRemoveButton.setOnDropListener(this);
+
+        mFab = (FloatingActionButton) findViewById(R.id.fab);
+        mFab.setImageResource(R.drawable.ic_add);
+        mFab.setOnClickListener(this);
     }
 
     public void show() {
@@ -117,6 +140,10 @@
         mHost.setTiles(tiles);
     }
 
+    private void setDragging(boolean dragging) {
+        mToolbar.setVisibility(!dragging ? View.VISIBLE : View.INVISIBLE);
+    }
+
     private void save() {
         mHost.saveCurrentTiles();
         hide();
@@ -139,4 +166,35 @@
     public void onTilesChanged() {
         mQsPanel.setTiles(mHost.getTiles());
     }
+
+    public boolean onDragEvent(DragEvent event) {
+        switch (event.getAction()) {
+            case DragEvent.ACTION_DRAG_STARTED:
+                setDragging(true);
+                break;
+            case DragEvent.ACTION_DRAG_ENDED:
+                setDragging(false);
+                break;
+        }
+        return true;
+    }
+
+    public void onDrop(View v, ClipData data) {
+        if (v == mRemoveButton) {
+            mHost.remove(mQsPanel.getSpec(data));
+        } else if (v == mInfoButton) {
+            mHost.unstashTiles();
+            SystemUIDialog dialog = new SystemUIDialog(mContext);
+            dialog.setTitle(mQsPanel.getSpec(data));
+            dialog.setPositiveButton(R.string.ok, null);
+            dialog.show();
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (mFab == v) {
+            // TODO: Show list of tiles.
+        }
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppButtonData.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppButtonData.java
index 2c6987c..f6c1062 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppButtonData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppButtonData.java
@@ -34,11 +34,15 @@
         this.pinned = pinned;
     }
 
+    public int getTaskCount() {
+        return tasks == null ? 0 : tasks.size();
+    }
+
     /**
      * Returns true if the button contains no useful information and should be removed.
      */
     public boolean isEmpty() {
-        return !pinned && (tasks == null || tasks.isEmpty());
+        return !pinned && getTaskCount() == 0;
     }
 
     public void addTask(RecentTaskInfo task) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 030501b..8e58d14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -166,13 +166,10 @@
         if (mAccessibilityController == null) {
             return;
         }
-        boolean trustManagedOrFingerprintAllowed = mUnlockMethodCache.isTrustManaged()
-                || KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed();
-
         boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
-        boolean clickToForceLock = trustManagedOrFingerprintAllowed
+        boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
                 && !mAccessibilityController.isAccessibilityEnabled();
-        boolean longClickToForceLock = trustManagedOrFingerprintAllowed
+        boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
                 && !clickToForceLock;
         setClickable(clickToForceLock || clickToUnlock);
         setLongClickable(longClickToForceLock);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
index 1c9b04f..9f5bd4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
@@ -34,6 +34,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -43,10 +44,15 @@
 import android.util.Slog;
 import android.view.DragEvent;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowManager;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
+import android.widget.PopupMenu;
 import android.widget.Toast;
 
 import com.android.internal.content.PackageMonitor;
@@ -78,6 +84,7 @@
     private final UserManager mUserManager;
     private final LayoutInflater mLayoutInflater;
     private final AppPackageMonitor mAppPackageMonitor;
+    private final WindowManager mWindowManager;
 
 
     // This view has two roles:
@@ -103,11 +110,22 @@
         }
     };
 
+    // Layout params for the window that contains the anchor for the popup menus.
+    // We need to create a window for a popup menu because the NavBar window is too narrow and can't
+    // contain the menu.
+    private final WindowManager.LayoutParams mPopupAnchorLayoutParams;
+    // View that contains the anchor for popup menus. The view occupies the whole screen, and
+    // has a child that will be moved to make the menu to appear where we need it.
+    private final ViewGroup mPopupAnchor;
+    private final PopupMenu mPopupMenu;
+    private final int [] mClickedIconLocation = new int[2];
+
     public NavigationBarApps(Context context, AttributeSet attrs) {
         super(context, attrs);
         sAppsModel = new NavigationBarAppsModel(context);
         mPackageManager = context.getPackageManager();
-        mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         mLayoutInflater = LayoutInflater.from(context);
         mAppPackageMonitor = new AppPackageMonitor();
 
@@ -131,6 +149,23 @@
         } catch (RemoteException e) {
             Slog.e(TAG, "registerTaskStackListener failed", e);
         }
+
+        mPopupAnchorLayoutParams =
+                new WindowManager.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
+                        WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
+                        WindowManager.LayoutParams.FLAG_FULLSCREEN
+                                | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+                                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
+                        PixelFormat.TRANSLUCENT);
+        mPopupAnchorLayoutParams.setTitle("ShelfMenuAnchor");
+
+        mPopupAnchor = (ViewGroup) mLayoutInflater.inflate(R.layout.shelf_menu_anchor, null);
+
+        ImageView anchorButton =
+                (ImageView) mPopupAnchor.findViewById(R.id.shelf_menu_anchor_anchor);
+        mPopupMenu = new PopupMenu(context, anchorButton);
     }
 
     // Monitor that catches events like "app uninstalled".
@@ -300,7 +335,9 @@
     private ImageView createAppButton(AppButtonData appButtonData) {
         ImageView button = (ImageView) mLayoutInflater.inflate(
                 R.layout.navigation_bar_app_item, this, false /* attachToRoot */);
+        button.setOnHoverListener(new AppHoverListener());
         button.setOnClickListener(new AppClickListener());
+        button.setOnContextClickListener(new AppContextClickListener());
         // TODO: Ripple effect. Use either KeyButtonRipple or the default ripple background.
         button.setOnLongClickListener(new AppLongClickListener());
         button.setOnDragListener(new AppIconDragListener());
@@ -580,6 +617,133 @@
     }
 
     /**
+     * Returns true if popup menu code is busy with a popup operation.
+     * Attempting  to show a popup menu or to add menu items while it's returning true will
+     * corrupt/crash the app.
+     */
+    boolean isPopupInUse() {
+        // mPopupAnchor's parent will be set to non-null/null by mWindowManager.add/RemoveView
+        // correspondingly.
+        return mPopupAnchor.getParent() != null;
+    }
+
+    /**
+     * Shows already prepopulated popup menu using appIcon for anchor location.
+     */
+    private void showPopupMenu(ImageView appIcon) {
+        // Movable view inside the popup anchor view. It serves as the actual anchor for the
+        // menu.
+        final ImageView anchorButton =
+                (ImageView) mPopupAnchor.findViewById(R.id.shelf_menu_anchor_anchor);
+        // Set same drawable as for the clicked button to have same size.
+        anchorButton.setImageDrawable(appIcon.getDrawable());
+
+        // Move the anchor button to the position of the app button.
+        appIcon.getLocationOnScreen(mClickedIconLocation);
+        anchorButton.setTranslationX(mClickedIconLocation[0]);
+        anchorButton.setTranslationY(mClickedIconLocation[1]);
+
+        final OnAttachStateChangeListener onAttachStateChangeListener =
+                new OnAttachStateChangeListener() {
+                    @Override
+                    public void onViewAttachedToWindow(View v) {
+                        mPopupMenu.show();
+                    }
+
+                    @Override
+                    public void onViewDetachedFromWindow(View v) {}
+                };
+        anchorButton.addOnAttachStateChangeListener(onAttachStateChangeListener);
+
+        mPopupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() {
+            @Override
+            public void onDismiss(PopupMenu menu) {
+                mWindowManager.removeView(mPopupAnchor);
+                anchorButton.removeOnAttachStateChangeListener(onAttachStateChangeListener);
+                mPopupMenu.setOnDismissListener(null);
+                mPopupMenu.getMenu().clear();
+            }
+        });
+
+        mWindowManager.addView(mPopupAnchor, mPopupAnchorLayoutParams);
+    }
+
+    private void activateTask(int taskPersistentId) {
+        // Launch or bring the activity to front.
+        IActivityManager manager = ActivityManagerNative.getDefault();
+        try {
+            manager.startActivityFromRecents(taskPersistentId, null /* options */);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Exception when activating a recent task", e);
+        } catch (IllegalArgumentException e) {
+            Slog.e(TAG, "Exception when activating a recent task", e);
+        }
+    }
+
+    /**
+     * Adds to the popup menu items for activating each of tasks in the specified list.
+     */
+    private void populateLaunchMenu(AppButtonData appButtonData) {
+        Menu menu = mPopupMenu.getMenu();
+        int taskCount = appButtonData.getTaskCount();
+        if (taskCount == 0) {
+            menu.add("- TBD MENU ITEM -"); // adding something so that the menu is not empty.
+            return;
+        }
+        for (int i = 0; i < taskCount; ++i) {
+            final RecentTaskInfo taskInfo = appButtonData.tasks.get(i);
+            MenuItem item = menu.add(getActivityForTask(taskInfo).flattenToShortString());
+            item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+                @Override
+                public boolean onMenuItemClick(MenuItem item) {
+                    activateTask(taskInfo.persistentId);
+                    return true;
+                }
+            });
+        }
+    }
+
+    /**
+     * Shows a task selection menu for an apps icon.
+     */
+    private void showLaunchMenu(ImageView appIcon) {
+        AppButtonData appButtonData = (AppButtonData) appIcon.getTag();
+        populateLaunchMenu(appButtonData);
+        showPopupMenu(appIcon);
+    }
+
+    /**
+     * A listener for hovering over an app icon.
+     */
+    private class AppHoverListener implements View.OnHoverListener {
+        private final long DELAY_MILLIS = 1000;
+        private Runnable mShowMenuCallback;
+
+        @Override
+        public boolean onHover(final View v, MotionEvent event) {
+            if (mShowMenuCallback == null) {
+                mShowMenuCallback = new Runnable() {
+                    @Override
+                    public void run() {
+                        if (isPopupInUse()) return;
+                        showLaunchMenu((ImageView) v);
+                    }
+                };
+            }
+
+            switch (event.getAction()) {
+                case MotionEvent.ACTION_HOVER_ENTER:
+                    postDelayed(mShowMenuCallback, DELAY_MILLIS);
+                    break;
+                case MotionEvent.ACTION_HOVER_EXIT:
+                    removeCallbacks(mShowMenuCallback);
+                    break;
+            }
+            return true;
+        }
+    }
+
+    /**
      * A click listener that launches an activity.
      */
     private class AppClickListener implements View.OnClickListener {
@@ -606,32 +770,85 @@
             mContext.startActivityAsUser(launchIntent, optsBundle, appInfo.getUser());
         }
 
-        private void activateLatestTask(List<RecentTaskInfo> tasks) {
-            // 'tasks' is guaranteed to be non-empty.
-            int latestTaskPersistentId = tasks.get(0).persistentId;
-            // Launch or bring the activity to front.
-            IActivityManager manager = ActivityManagerNative.getDefault();
-            try {
-                manager.startActivityFromRecents(latestTaskPersistentId, null /* options */);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Exception when activating a recent task", e);
-            } catch (IllegalArgumentException e) {
-                Slog.e(TAG, "Exception when activating a recent task", e);
-            }
+        /**
+         * Shows a task selection menu for clicked apps that have more than 1 running tasks.
+         */
+        void maybeShowLaunchMenu(ImageView appIcon) {
+            if (isPopupInUse()) return;
+            AppButtonData appButtonData = (AppButtonData) appIcon.getTag();
+            if (appButtonData.getTaskCount() <= 1) return;
+
+            showLaunchMenu(appIcon);
         }
 
         @Override
         public void onClick(View v) {
-            AppButtonData appButtonData = (AppButtonData)v.getTag();
+            AppButtonData appButtonData = (AppButtonData) v.getTag();
 
-            if (appButtonData.tasks == null || appButtonData.tasks.size() == 0) {
+            if (appButtonData.getTaskCount() == 0) {
                 launchApp(appButtonData.appInfo, v);
             } else {
-                activateLatestTask(appButtonData.tasks);
+                // Activate latest task.
+                activateTask(appButtonData.tasks.get(0).persistentId);
+
+                maybeShowLaunchMenu((ImageView) v);
             }
         }
     }
 
+    /**
+     * Context click listener that shows app's context menu.
+     */
+    private class AppContextClickListener implements View.OnContextClickListener {
+        void updateState(ImageView appIcon) {
+            savePinnedApps();
+            if (DEBUG) {
+                AppButtonData appButtonData = (AppButtonData) appIcon.getTag();
+                new GetActivityIconTask(mPackageManager, appIcon).execute(appButtonData);
+            }
+        }
+
+        /**
+         * Adds to the popup menu items for pinning and unpinning the app in the shelf.
+         */
+        void populateContextMenu(final ImageView appIcon) {
+            final AppButtonData appButtonData = (AppButtonData) appIcon.getTag();
+            Menu menu = mPopupMenu.getMenu();
+            if (appButtonData.pinned) {
+                menu.add("Unpin").
+                        setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+                            @Override
+                            public boolean onMenuItemClick(MenuItem item) {
+                                appButtonData.pinned = false;
+                                if (appButtonData.isEmpty()) {
+                                    removeView(appIcon);
+                                }
+                                updateState(appIcon);
+                                return true;
+                            }
+                        });
+            } else {
+                menu.add("Pin").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+                    @Override
+                    public boolean onMenuItemClick(MenuItem item) {
+                        appButtonData.pinned = true;
+                        updateState(appIcon);
+                        return true;
+                    }
+                });
+            }
+        }
+
+        @Override
+        public boolean onContextClick(View v) {
+            if (isPopupInUse()) return true;
+            ImageView appIcon = (ImageView) v;
+            populateContextMenu(appIcon);
+            showPopupMenu(appIcon);
+            return true;
+        }
+    }
+
     private void onUserSwitched(int currentUserId) {
         sAppsModel.setCurrentUser(currentUserId);
         recreatePinnedAppButtons();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index f37383a..011889a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -261,11 +261,11 @@
 
     private void getIcons(Resources res) {
         mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back);
-        mBackLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_land);
+        mBackLandIcon = mBackIcon;
         mBackAltIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime);
-        mBackAltLandIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime_land);
+        mBackAltLandIcon = mBackAltIcon;
         mRecentIcon = res.getDrawable(R.drawable.ic_sysbar_recent);
-        mRecentLandIcon = res.getDrawable(R.drawable.ic_sysbar_recent_land);
+        mRecentLandIcon = mRecentIcon;
     }
 
     @Override
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 ab8b350..d3af8f03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -292,6 +292,7 @@
     private DozeServiceHost mDozeServiceHost;
     private boolean mWakeUpComingFromTouch;
     private PointF mWakeUpTouchLocation;
+    private boolean mScreenTurningOn;
 
     int mPixelFormat;
     Object mQueueLock = new Object();
@@ -2792,9 +2793,6 @@
         if (mNextAlarmController != null) {
             mNextAlarmController.dump(fd, pw, args);
         }
-        if (mAssistManager != null) {
-            mAssistManager.dump(fd, pw, args);
-        }
         if (mSecurityController != null) {
             mSecurityController.dump(fd, pw, args);
         }
@@ -3030,7 +3028,8 @@
         updateNotifications();
         resetUserSetupObserver();
         setControllerUsers();
-        mAssistManager.onUserSwitched(newUserId);
+        clearCurrentMediaNotification();
+        updateMediaMetaData(true);
         if (mFullscreenUserSwitcher != null) {
             mFullscreenUserSwitcher.onUserSwitched(newUserId);
         }
@@ -3980,6 +3979,7 @@
     }
 
     public void onScreenTurningOn() {
+        mScreenTurningOn = true;
         mNotificationPanel.onScreenTurningOn();
         if (mLaunchCameraOnScreenTurningOn) {
             mNotificationPanel.launchCamera(false);
@@ -3992,6 +3992,7 @@
     }
 
     public void onScreenTurnedOn() {
+        mScreenTurningOn = false;
         mDozeScrimController.onScreenTurnedOn();
     }
 
@@ -4168,7 +4169,7 @@
                 mScrimController.dontAnimateBouncerChangesUntilNextFrame();
                 mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
             }
-            if (mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
+            if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
                 mNotificationPanel.launchCamera(mDeviceInteractive /* animate */);
             } else {
                 // We need to defer the camera launch until the screen comes on, since otherwise
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index a1d73d2..51c2208 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -2156,6 +2156,7 @@
 
             case MotionEvent.ACTION_DOWN: {
                 final int y = (int) ev.getY();
+                mScrolledToTopOnFirstDown = isScrolledToTop();
                 if (getChildAtPosition(ev.getX(), y) == null) {
                     setIsBeingDragged(false);
                     recycleVelocityTracker();
@@ -2169,7 +2170,6 @@
                 mLastMotionY = y;
                 mDownX = (int) ev.getX();
                 mActivePointerId = ev.getPointerId(0);
-                mScrolledToTopOnFirstDown = isScrolledToTop();
 
                 initOrResetVelocityTracker();
                 mVelocityTracker.addMovement(ev);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index 32d6805..1cf7a70f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -284,7 +284,7 @@
         return changed;
     }
 
-    private void onVolumeChangedW(int stream, int flags) {
+    private boolean onVolumeChangedW(int stream, int flags) {
         final boolean showUI = (flags & AudioManager.FLAG_SHOW_UI) != 0;
         final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0;
         final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0;
@@ -311,6 +311,7 @@
         if (changed && fromKey) {
             Events.writeEvent(mContext, Events.EVENT_KEY, stream, lastAudibleStreamVolume);
         }
+        return changed;
     }
 
     private boolean updateActiveStreamW(int activeStream) {
@@ -797,6 +798,7 @@
                 if (D.BUG) Log.d(TAG, "onReceive STREAM_DEVICES_CHANGED_ACTION stream="
                         + stream + " devices=" + devices + " oldDevices=" + oldDevices);
                 changed = checkRoutedToBluetoothW(stream);
+                changed |= onVolumeChangedW(stream, 0);
             } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
                 final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
                 if (D.BUG) Log.d(TAG, "onReceive RINGER_MODE_CHANGED_ACTION rm="
diff --git a/packages/VpnDialogs/res/values-nl/strings.xml b/packages/VpnDialogs/res/values-nl/strings.xml
index 0f28016..ae789b2 100644
--- a/packages/VpnDialogs/res/values-nl/strings.xml
+++ b/packages/VpnDialogs/res/values-nl/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Verbindingsverzoek"</string>
-    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> wil een VPN-verbinding opzetten om netwerkverkeer te controleren. Accepteer het verzoek alleen als u de bron vertrouwt. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; wordt boven aan uw scherm weergegeven wanneer VPN actief is."</string>
+    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> wil een VPN-verbinding opzetten om netwerkverkeer te controleren. Accepteer het verzoek alleen als je de bron vertrouwt. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; wordt boven aan je scherm weergegeven wanneer VPN actief is."</string>
     <string name="legacy_title" msgid="192936250066580964">"Verbinding met VPN"</string>
     <string name="configure" msgid="4905518375574791375">"Configureren"</string>
     <string name="disconnect" msgid="971412338304200056">"Verbinding verbreken"</string>
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 9f080ca..87a0b80 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -63,6 +63,13 @@
      */
     static final int FLAG_FEATURE_FILTER_KEY_EVENTS = 0x00000004;
 
+    /**
+     * Flag for enabling "Automatically click on mouse stop" feature.
+     *
+     * @see #setEnabledFeatures(int)
+     */
+    static final int FLAG_FEATURE_AUTOCLICK = 0x00000008;
+
     private final Runnable mProcessBatchedEventsRunnable = new Runnable() {
         @Override
         public void run() {
@@ -88,8 +95,6 @@
 
     private final Choreographer mChoreographer;
 
-    private int mCurrentTouchDeviceId;
-
     private boolean mInstalled;
 
     private int mEnabledFeatures;
@@ -98,17 +103,19 @@
 
     private ScreenMagnifier mScreenMagnifier;
 
+    private AutoclickController mAutoclickController;
+
+    private KeyboardInterceptor mKeyboardInterceptor;
+
     private EventStreamTransformation mEventHandler;
 
     private MotionEventHolder mEventQueue;
 
-    private boolean mMotionEventSequenceStarted;
+    private EventStreamState mMouseStreamState;
 
-    private boolean mHoverEventSequenceStarted;
+    private EventStreamState mTouchScreenStreamState;
 
-    private boolean mKeyEventSequenceStarted;
-
-    private boolean mFilterKeyEvents;
+    private EventStreamState mKeyboardStreamState;
 
     AccessibilityInputFilter(Context context, AccessibilityManagerService service) {
         super(context.getMainLooper());
@@ -142,89 +149,95 @@
     @Override
     public void onInputEvent(InputEvent event, int policyFlags) {
         if (DEBUG) {
-            Slog.d(TAG, "Received event: " + event + ", policyFlags=0x" 
+            Slog.d(TAG, "Received event: " + event + ", policyFlags=0x"
                     + Integer.toHexString(policyFlags));
         }
-        if (event instanceof MotionEvent
-                && event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
-            MotionEvent motionEvent = (MotionEvent) event;
-            onMotionEvent(motionEvent, policyFlags);
-        } else if (event instanceof KeyEvent
-                && event.isFromSource(InputDevice.SOURCE_KEYBOARD)) {
-            KeyEvent keyEvent = (KeyEvent) event;
-            onKeyEvent(keyEvent, policyFlags);
-        } else {
-            super.onInputEvent(event, policyFlags);
-        }
-    }
 
-    private void onMotionEvent(MotionEvent event, int policyFlags) {
         if (mEventHandler == null) {
             super.onInputEvent(event, policyFlags);
             return;
         }
+
+        EventStreamState state = getEventStreamState(event);
+        if (state == null) {
+            super.onInputEvent(event, policyFlags);
+            return;
+        }
+
+        int eventSource = event.getSource();
         if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) {
-            mMotionEventSequenceStarted = false;
-            mHoverEventSequenceStarted = false;
-            mEventHandler.clear();
+            state.reset();
+            mEventHandler.clearEvents(eventSource);
             super.onInputEvent(event, policyFlags);
             return;
         }
-        final int deviceId = event.getDeviceId();
-        if (mCurrentTouchDeviceId != deviceId) {
-            mCurrentTouchDeviceId = deviceId;
-            mMotionEventSequenceStarted = false;
-            mHoverEventSequenceStarted = false;
-            mEventHandler.clear();
+
+        if (state.updateDeviceId(event.getDeviceId())) {
+            mEventHandler.clearEvents(eventSource);
         }
-        if (mCurrentTouchDeviceId < 0) {
+
+        if (!state.deviceIdValid()) {
             super.onInputEvent(event, policyFlags);
             return;
         }
-        // We do not handle scroll events.
-        if (event.getActionMasked() == MotionEvent.ACTION_SCROLL) {
-            super.onInputEvent(event, policyFlags);
-            return;
+
+        if (event instanceof MotionEvent) {
+            MotionEvent motionEvent = (MotionEvent) event;
+            processMotionEvent(state, motionEvent, policyFlags);
+        } else if (event instanceof KeyEvent) {
+            KeyEvent keyEvent = (KeyEvent) event;
+            processKeyEvent(state, keyEvent, policyFlags);
         }
-        // Wait for a down touch event to start processing.
-        if (event.isTouchEvent()) {
-            if (!mMotionEventSequenceStarted) {
-                if (event.getActionMasked() != MotionEvent.ACTION_DOWN) {
-                    return;
-                }
-                mMotionEventSequenceStarted = true;
-            }
-        } else {
-            // Wait for an enter hover event to start processing.
-            if (!mHoverEventSequenceStarted) {
-                if (event.getActionMasked() != MotionEvent.ACTION_HOVER_ENTER) {
-                    return;
-                }
-                mHoverEventSequenceStarted = true;
-            }
-        }
-        batchMotionEvent((MotionEvent) event, policyFlags);
     }
 
-    private void onKeyEvent(KeyEvent event, int policyFlags) {
-        if (!mFilterKeyEvents) {
+    /**
+     * Gets current event stream state associated with an input event.
+     * @return The event stream state that should be used for the event. Null if the event should
+     *     not be handled by #AccessibilityInputFilter.
+     */
+    private EventStreamState getEventStreamState(InputEvent event) {
+        if (event instanceof MotionEvent) {
+          if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
+              if (mTouchScreenStreamState == null) {
+                  mTouchScreenStreamState = new TouchScreenEventStreamState();
+              }
+              return mTouchScreenStreamState;
+          }
+          if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+              if (mMouseStreamState == null) {
+                  mMouseStreamState = new MouseEventStreamState();
+              }
+              return mMouseStreamState;
+          }
+        } else if (event instanceof KeyEvent) {
+          if (event.isFromSource(InputDevice.SOURCE_KEYBOARD)) {
+              if (mKeyboardStreamState == null) {
+                  mKeyboardStreamState = new KeyboardEventStreamState();
+              }
+              return mKeyboardStreamState;
+          }
+        }
+        return null;
+    }
+
+    private void processMotionEvent(EventStreamState state, MotionEvent event, int policyFlags) {
+        if (!state.shouldProcessScroll() && event.getActionMasked() == MotionEvent.ACTION_SCROLL) {
             super.onInputEvent(event, policyFlags);
             return;
         }
-        if ((policyFlags & WindowManagerPolicy.FLAG_PASS_TO_USER) == 0) {
-            mKeyEventSequenceStarted = false;
-            super.onInputEvent(event, policyFlags);
+
+        if (!state.shouldProcessMotionEvent(event)) {
             return;
         }
-        // Wait for a down key event to start processing.
-        if (!mKeyEventSequenceStarted) {
-            if (event.getAction() != KeyEvent.ACTION_DOWN) {
-                super.onInputEvent(event, policyFlags);
-                return;
-            }
-            mKeyEventSequenceStarted = true;
+
+        batchMotionEvent(event, policyFlags);
+    }
+
+    private void processKeyEvent(EventStreamState state, KeyEvent event, int policyFlags) {
+        if (!state.shouldProcessKeyEvent(event)) {
+            return;
         }
-        mAms.notifyKeyEvent(event, policyFlags);
+        mEventHandler.onKeyEvent(event, policyFlags);
     }
 
     private void scheduleProcessBatchedEvents() {
@@ -293,6 +306,11 @@
     }
 
     @Override
+    public void onKeyEvent(KeyEvent event, int policyFlags) {
+        sendInputEvent(event, policyFlags);
+    }
+
+    @Override
     public void onAccessibilityEvent(AccessibilityEvent event) {
         // TODO Implement this to inject the accessibility event
         //      into the accessibility manager service similarly
@@ -305,7 +323,7 @@
     }
 
     @Override
-    public void clear() {
+    public void clearEvents(int inputSource) {
         /* do nothing */
     }
 
@@ -329,43 +347,77 @@
     }
 
     private void enableFeatures() {
-        mMotionEventSequenceStarted = false;
-        mHoverEventSequenceStarted = false;
-        if ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) {
-            mEventHandler = mScreenMagnifier = new ScreenMagnifier(mContext,
-                    Display.DEFAULT_DISPLAY, mAms);
-            mEventHandler.setNext(this);
+        resetStreamState();
+
+        if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) {
+            mAutoclickController = new AutoclickController(mContext);
+            addFirstEventHandler(mAutoclickController);
         }
+
         if ((mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
             mTouchExplorer = new TouchExplorer(mContext, mAms);
-            mTouchExplorer.setNext(this);
-            if (mEventHandler != null) {
-                mEventHandler.setNext(mTouchExplorer);
-            } else {
-                mEventHandler = mTouchExplorer;
-            }
+            addFirstEventHandler(mTouchExplorer);
         }
+
+        if ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) {
+            mScreenMagnifier = new ScreenMagnifier(mContext,
+                    Display.DEFAULT_DISPLAY, mAms);
+            addFirstEventHandler(mScreenMagnifier);
+        }
+
         if ((mEnabledFeatures & FLAG_FEATURE_FILTER_KEY_EVENTS) != 0) {
-            mFilterKeyEvents = true;
+           mKeyboardInterceptor = new KeyboardInterceptor(mAms);
+           addFirstEventHandler(mKeyboardInterceptor);
         }
     }
 
+    /**
+     * Adds an event handler to the event handler chain. The handler is added at the beginning of
+     * the chain.
+     *
+     * @param handler The handler to be added to the event handlers list.
+     */
+    private void addFirstEventHandler(EventStreamTransformation handler) {
+        if (mEventHandler != null) {
+           handler.setNext(mEventHandler);
+        } else {
+            handler.setNext(this);
+        }
+        mEventHandler = handler;
+    }
+
     void disableFeatures() {
+        if (mAutoclickController != null) {
+            mAutoclickController.onDestroy();
+            mAutoclickController = null;
+        }
         if (mTouchExplorer != null) {
-            mTouchExplorer.clear();
             mTouchExplorer.onDestroy();
             mTouchExplorer = null;
         }
         if (mScreenMagnifier != null) {
-            mScreenMagnifier.clear();
             mScreenMagnifier.onDestroy();
             mScreenMagnifier = null;
         }
+        if (mKeyboardInterceptor != null) {
+            mKeyboardInterceptor.onDestroy();
+            mKeyboardInterceptor = null;
+        }
+
         mEventHandler = null;
-        mKeyEventSequenceStarted = false;
-        mMotionEventSequenceStarted = false;
-        mHoverEventSequenceStarted = false;
-        mFilterKeyEvents = false;
+        resetStreamState();
+    }
+
+    void resetStreamState() {
+        if (mTouchScreenStreamState != null) {
+            mTouchScreenStreamState.reset();
+        }
+        if (mMouseStreamState != null) {
+            mMouseStreamState.reset();
+        }
+        if (mKeyboardStreamState != null) {
+            mKeyboardStreamState.reset();
+        }
     }
 
     @Override
@@ -402,4 +454,171 @@
             sPool.release(this);
         }
     }
+
+    /**
+     * Keeps state of event streams observed for an input device with a certain source.
+     * Provides information about whether motion and key events should be processed by accessibility
+     * #EventStreamTransformations. Base implementation describes behaviour for event sources that
+     * whose events should not be handled by a11y event stream transformations.
+     */
+    private static class EventStreamState {
+        private int mDeviceId;
+
+        EventStreamState() {
+            mDeviceId = -1;
+        }
+
+        /**
+         * Updates the ID of the device associated with the state. If the ID changes, resets
+         * internal state.
+         *
+         * @param deviceId Updated input device ID.
+         * @return Whether the device ID has changed.
+         */
+        public boolean updateDeviceId(int deviceId) {
+            if (mDeviceId == deviceId) {
+                return false;
+            }
+            // Reset clears internal state, so make sure it's called before |mDeviceId| is updated.
+            reset();
+            mDeviceId = deviceId;
+            return true;
+        }
+
+        /**
+         * @return Whether device ID is valid.
+         */
+        public boolean deviceIdValid() {
+            return mDeviceId >= 0;
+        }
+
+        /**
+         * Resets the event stream state.
+         */
+        public void reset() {
+            mDeviceId = -1;
+        }
+
+        /**
+         * @return Whether scroll events for device should be handled by event transformations.
+         */
+        public boolean shouldProcessScroll() {
+            return false;
+        }
+
+        /**
+         * @param event An observed motion event.
+         * @return Whether the event should be handled by event transformations.
+         */
+        public boolean shouldProcessMotionEvent(MotionEvent event) {
+            return false;
+        }
+
+        /**
+         * @param event An observed key event.
+         * @return Whether the event should be handled by event transformations.
+         */
+        public boolean shouldProcessKeyEvent(KeyEvent event) {
+            return false;
+        }
+    }
+
+    /**
+     * Keeps state of stream of events from a mouse device.
+     */
+    private static class MouseEventStreamState extends EventStreamState {
+        private boolean mMotionSequenceStarted;
+
+        public MouseEventStreamState() {
+            reset();
+        }
+
+        @Override
+        final public void reset() {
+            super.reset();
+            mMotionSequenceStarted = false;
+        }
+
+        @Override
+        final public boolean shouldProcessScroll() {
+            return true;
+        }
+
+        @Override
+        final public boolean shouldProcessMotionEvent(MotionEvent event) {
+            if (mMotionSequenceStarted) {
+                return true;
+            }
+            // Wait for down or move event to start processing mouse events.
+            int action = event.getActionMasked();
+            mMotionSequenceStarted =
+                    action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_HOVER_MOVE;
+            return mMotionSequenceStarted;
+        }
+    }
+
+    /**
+     * Keeps state of stream of events from a touch screen device.
+     */
+    private static class TouchScreenEventStreamState extends EventStreamState {
+        private boolean mTouchSequenceStarted;
+        private boolean mHoverSequenceStarted;
+
+        public TouchScreenEventStreamState() {
+            reset();
+        }
+
+        @Override
+        final public void reset() {
+            super.reset();
+            mTouchSequenceStarted = false;
+            mHoverSequenceStarted = false;
+        }
+
+        @Override
+        final public boolean shouldProcessMotionEvent(MotionEvent event) {
+            // Wait for a down touch event to start processing.
+            if (event.isTouchEvent()) {
+                if (mTouchSequenceStarted) {
+                    return true;
+                }
+                mTouchSequenceStarted = event.getActionMasked() == MotionEvent.ACTION_DOWN;
+                return mTouchSequenceStarted;
+            }
+
+            // Wait for an enter hover event to start processing.
+            if (mHoverSequenceStarted) {
+                return true;
+            }
+            mHoverSequenceStarted = event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER;
+            return mHoverSequenceStarted;
+        }
+    }
+
+    /**
+     * Keeps state of stream of events from a keyboard device.
+     */
+    private static class KeyboardEventStreamState extends EventStreamState {
+        private boolean mEventSequenceStarted;
+
+        public KeyboardEventStreamState() {
+            reset();
+        }
+
+        @Override
+        final public void reset() {
+            super.reset();
+            mEventSequenceStarted = false;
+        }
+
+        @Override
+        final public boolean shouldProcessKeyEvent(KeyEvent event) {
+            // Wait for a down key event to start processing.
+            if (mEventSequenceStarted) {
+                return true;
+            }
+            mEventSequenceStarted = event.getAction() == KeyEvent.ACTION_DOWN;
+            return mEventSequenceStarted;
+        }
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
new file mode 100644
index 0000000..2e6136f
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
@@ -0,0 +1,370 @@
+/*
+ * 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.accessibility;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.MotionEvent.PointerCoords;
+import android.view.MotionEvent.PointerProperties;
+import android.view.accessibility.AccessibilityEvent;
+
+/**
+ * Implements "Automatically click on mouse stop" feature.
+ *
+ * If enabled, it will observe motion events from mouse source, and send click event sequence
+ * shortly after mouse stops moving. The click will only be performed if mouse movement had been
+ * actually detected.
+ *
+ * Movement detection has tolerance to jitter that may be caused by poor motor control to prevent:
+ * <ul>
+ *   <li>Initiating unwanted clicks with no mouse movement.</li>
+ *   <li>Autoclick never occurring after mouse arriving at target.</li>
+ * </ul>
+ *
+ * Non-mouse motion events, key events (excluding modifiers) and non-movement mouse events cancel
+ * the automatic click.
+ *
+ * It is expected that each instance will receive mouse events from a single mouse device. User of
+ * the class should handle cases where multiple mouse devices are present.
+ */
+public class AutoclickController implements EventStreamTransformation {
+    private static final String LOG_TAG = AutoclickController.class.getSimpleName();
+
+    // TODO: Control click delay via settings.
+    private static final int CLICK_DELAY_MS = 600;
+
+    private EventStreamTransformation mNext;
+    private Context mContext;
+
+    // Lazily created on the first mouse motion event.
+    private ClickScheduler mClickScheduler;
+
+    public AutoclickController(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+            if (mClickScheduler == null) {
+                Handler handler = new Handler(mContext.getMainLooper());
+                mClickScheduler = new ClickScheduler(handler, CLICK_DELAY_MS);
+            }
+
+            handleMouseMotion(event, policyFlags);
+        } else if (mClickScheduler != null) {
+            mClickScheduler.cancel();
+        }
+
+        if (mNext != null) {
+            mNext.onMotionEvent(event, rawEvent, policyFlags);
+        }
+    }
+
+    @Override
+    public void onKeyEvent(KeyEvent event, int policyFlags) {
+        if (mClickScheduler != null) {
+            if (KeyEvent.isModifierKey(event.getKeyCode())) {
+                mClickScheduler.updateMetaState(event.getMetaState());
+            } else {
+                mClickScheduler.cancel();
+            }
+        }
+
+        if (mNext != null) {
+          mNext.onKeyEvent(event, policyFlags);
+        }
+    }
+
+    @Override
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+        if (mNext != null) {
+            mNext.onAccessibilityEvent(event);
+        }
+    }
+
+    @Override
+    public void setNext(EventStreamTransformation next) {
+        mNext = next;
+    }
+
+    @Override
+    public void clearEvents(int inputSource) {
+        if (inputSource == InputDevice.SOURCE_MOUSE && mClickScheduler != null) {
+            mClickScheduler.cancel();
+        }
+
+        if (mNext != null) {
+            mNext.clearEvents(inputSource);
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mClickScheduler != null) {
+            mClickScheduler.cancel();
+        }
+    }
+
+    private void handleMouseMotion(MotionEvent event, int policyFlags) {
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_HOVER_MOVE: {
+                if (event.getPointerCount() == 1) {
+                    mClickScheduler.update(event, policyFlags);
+                } else {
+                    mClickScheduler.cancel();
+                }
+            } break;
+            // Ignore hover enter and exit.
+            case MotionEvent.ACTION_HOVER_ENTER:
+            case MotionEvent.ACTION_HOVER_EXIT:
+                break;
+            default:
+                mClickScheduler.cancel();
+        }
+    }
+
+    /**
+     * Schedules and performs click event sequence that should be initiated when mouse pointer stops
+     * moving. The click is first scheduled when a mouse movement is detected, and then further
+     * delayed on every sufficient mouse movement.
+     */
+    final private class ClickScheduler implements Runnable {
+        /**
+         * Minimal distance pointer has to move relative to anchor in order for movement not to be
+         * discarded as noise. Anchor is the position of the last MOVE event that was not considered
+         * noise.
+         */
+        private static final double MOVEMENT_SLOPE = 20f;
+
+        /** Whether there is pending click. */
+        private boolean mActive;
+        /** If active, time at which pending click is scheduled. */
+        private long mScheduledClickTime;
+
+        /** Last observed motion event. null if no events have been observed yet. */
+        private MotionEvent mLastMotionEvent;
+        /** Last observed motion event's policy flags. */
+        private int mEventPolicyFlags;
+        /** Current meta state. This value will be used as meta state for click event sequence. */
+        private int mMetaState;
+
+        /**
+         * The current anchor's coordinates. Should be ignored if #mLastMotionEvent is null.
+         * Note that these are not necessary coords of #mLastMotionEvent (because last observed
+         * motion event may have been labeled as noise).
+         */
+        private PointerCoords mAnchorCoords;
+
+        /** Delay that should be used to schedule click. */
+        private int mDelay;
+
+        /** Handler for scheduling delayed operations. */
+        private Handler mHandler;
+
+        private PointerProperties mTempPointerProperties[];
+        private PointerCoords mTempPointerCoords[];
+
+        public ClickScheduler(Handler handler, int delay) {
+            mHandler = handler;
+
+            mLastMotionEvent = null;
+            resetInternalState();
+            mDelay = delay;
+            mAnchorCoords = new PointerCoords();
+        }
+
+        @Override
+        public void run() {
+            long now = SystemClock.uptimeMillis();
+            // Click was rescheduled after task was posted. Post new run task at updated time.
+            if (now < mScheduledClickTime) {
+                mHandler.postDelayed(this, mScheduledClickTime - now);
+                return;
+            }
+
+            sendClick();
+            resetInternalState();
+        }
+
+        /**
+         * Updates properties that should be used for click event sequence initiated by this object,
+         * as well as the time at which click will be scheduled.
+         * Should be called whenever new motion event is observed.
+         *
+         * @param event Motion event whose properties should be used as a base for click event
+         *     sequence.
+         * @param policyFlags Policy flags that should be send with click event sequence.
+         */
+        public void update(MotionEvent event, int policyFlags) {
+            mMetaState = event.getMetaState();
+
+            boolean moved = detectMovement(event);
+            cacheLastEvent(event, policyFlags, mLastMotionEvent == null || moved /* useAsAnchor */);
+
+            if (moved) {
+              rescheduleClick(mDelay);
+            }
+        }
+
+        /** Cancels any pending clicks and resets the object state. */
+        public void cancel() {
+            if (!mActive) {
+                return;
+            }
+            resetInternalState();
+            mHandler.removeCallbacks(this);
+        }
+
+        /**
+         * Updates the meta state that should be used for click sequence.
+         */
+        public void updateMetaState(int state) {
+            mMetaState = state;
+        }
+
+        /**
+         * Updates the time at which click sequence should occur.
+         *
+         * @param delay Delay (from now) after which click should occur.
+         */
+        private void rescheduleClick(int delay) {
+            long clickTime = SystemClock.uptimeMillis() + delay;
+            // If there already is a scheduled click at time before the updated time, just update
+            // scheduled time. The click will actually be rescheduled when pending callback is
+            // run.
+            if (mActive && clickTime > mScheduledClickTime) {
+                mScheduledClickTime = clickTime;
+                return;
+            }
+
+            if (mActive) {
+                mHandler.removeCallbacks(this);
+            }
+
+            mActive = true;
+            mScheduledClickTime = clickTime;
+
+            mHandler.postDelayed(this, delay);
+        }
+
+        /**
+         * Updates last observed motion event.
+         *
+         * @param event The last observed event.
+         * @param policyFlags The policy flags used with the last observed event.
+         * @param useAsAnchor Whether the event coords should be used as a new anchor.
+         */
+        private void cacheLastEvent(MotionEvent event, int policyFlags, boolean useAsAnchor) {
+            if (mLastMotionEvent != null) {
+                mLastMotionEvent.recycle();
+            }
+            mLastMotionEvent = MotionEvent.obtain(event);
+            mEventPolicyFlags = policyFlags;
+
+            if (useAsAnchor) {
+                final int pointerIndex = mLastMotionEvent.getActionIndex();
+                mLastMotionEvent.getPointerCoords(pointerIndex, mAnchorCoords);
+            }
+        }
+
+        private void resetInternalState() {
+            mActive = false;
+            if (mLastMotionEvent != null) {
+                mLastMotionEvent.recycle();
+                mLastMotionEvent = null;
+            }
+            mScheduledClickTime = -1;
+        }
+
+        /**
+         * @param event Observed motion event.
+         * @return Whether the event coords are far enough from the anchor for the event not to be
+         *     considered noise.
+         */
+        private boolean detectMovement(MotionEvent event) {
+            if (mLastMotionEvent == null) {
+                return false;
+            }
+            final int pointerIndex = event.getActionIndex();
+            float deltaX = mAnchorCoords.x - event.getX(pointerIndex);
+            float deltaY = mAnchorCoords.y - event.getY(pointerIndex);
+            double delta = Math.hypot(deltaX, deltaY);
+            return delta > MOVEMENT_SLOPE;
+        }
+
+        /**
+         * Creates and forwards click event sequence.
+         */
+        private void sendClick() {
+            if (mLastMotionEvent == null || mNext == null) {
+                return;
+            }
+
+            final int pointerIndex = mLastMotionEvent.getActionIndex();
+
+            if (mTempPointerProperties == null) {
+                mTempPointerProperties = new PointerProperties[1];
+                mTempPointerProperties[0] = new PointerProperties();
+            }
+
+            mLastMotionEvent.getPointerProperties(pointerIndex, mTempPointerProperties[0]);
+
+            if (mTempPointerCoords == null) {
+                mTempPointerCoords = new PointerCoords[1];
+                mTempPointerCoords[0] = new PointerCoords();
+            }
+            mLastMotionEvent.getPointerCoords(pointerIndex, mTempPointerCoords[0]);
+
+            final long now = SystemClock.uptimeMillis();
+
+            MotionEvent downEvent = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, 1,
+                    mTempPointerProperties, mTempPointerCoords, mMetaState,
+                    MotionEvent.BUTTON_PRIMARY, 1.0f, 1.0f, mLastMotionEvent.getDeviceId(), 0,
+                    mLastMotionEvent.getSource(), mLastMotionEvent.getFlags());
+
+            // The only real difference between these two events is the action flag.
+            MotionEvent upEvent = MotionEvent.obtain(downEvent);
+            upEvent.setAction(MotionEvent.ACTION_UP);
+
+            mNext.onMotionEvent(downEvent, downEvent, mEventPolicyFlags);
+            downEvent.recycle();
+
+            mNext.onMotionEvent(upEvent, upEvent, mEventPolicyFlags);
+            upEvent.recycle();
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("ClickScheduler: { active=").append(mActive);
+            builder.append(", delay=").append(mDelay);
+            builder.append(", scheduledClickTime=").append(mScheduledClickTime);
+            builder.append(", anchor={x:").append(mAnchorCoords.x);
+            builder.append(", y:").append(mAnchorCoords.y).append("}");
+            builder.append(", metastate=").append(mMetaState);
+            builder.append(", policyFlags=").append(mEventPolicyFlags);
+            builder.append(", lastMotionEvent=").append(mLastMotionEvent);
+            builder.append(" }");
+            return builder.toString();
+        }
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java b/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java
index 8c93e7b..fdc4098 100644
--- a/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java
+++ b/services/accessibility/java/com/android/server/accessibility/EventStreamTransformation.java
@@ -68,6 +68,14 @@
     public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags);
 
     /**
+     * Receives a key event.
+     *
+     * @param event The key event.
+     * @param policyFlags Policy flags for the event.
+     */
+    public void onKeyEvent(KeyEvent event, int policyFlags);
+
+    /**
      * Receives an accessibility event.
      *
      * @param event The accessibility event.
@@ -82,9 +90,11 @@
     public void setNext(EventStreamTransformation next);
 
     /**
-     * Clears the internal state of this transformation.
+     * Clears internal state associated with events from specific input source.
+     *
+     * @param inputSource The input source class for which transformation state should be cleared.
      */
-    public void clear();
+    public void clearEvents(int inputSource);
 
     /**
      * Destroys this transformation.
diff --git a/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java b/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java
new file mode 100644
index 0000000..bbb25af
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/KeyboardInterceptor.java
@@ -0,0 +1,68 @@
+/*
+ * 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.accessibility;
+
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.accessibility.AccessibilityEvent;
+
+/**
+ * Intercepts key events and forwards them to accessibility manager service.
+ */
+public class KeyboardInterceptor implements EventStreamTransformation {
+    private EventStreamTransformation mNext;
+    private AccessibilityManagerService mAms;
+
+    public KeyboardInterceptor(AccessibilityManagerService service) {
+        mAms = service;
+    }
+
+    @Override
+    public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (mNext != null) {
+            mNext.onMotionEvent(event, rawEvent, policyFlags);
+        }
+    }
+
+    @Override
+    public void onKeyEvent(KeyEvent event, int policyFlags) {
+        mAms.notifyKeyEvent(event, policyFlags);
+    }
+
+    @Override
+    public void onAccessibilityEvent(AccessibilityEvent event) {
+        if (mNext != null) {
+            mNext.onAccessibilityEvent(event);
+        }
+    }
+
+    @Override
+    public void setNext(EventStreamTransformation next) {
+        mNext = next;
+    }
+
+    @Override
+    public void clearEvents(int inputSource) {
+        if (mNext != null) {
+            mNext.clearEvents(inputSource);
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
index b4613d6..37276bd 100644
--- a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -37,6 +37,8 @@
 import android.util.TypedValue;
 import android.view.GestureDetector;
 import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.InputDevice;
+import android.view.KeyEvent;
 import android.view.MagnificationSpec;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
@@ -325,6 +327,12 @@
     @Override
     public void onMotionEvent(MotionEvent event, MotionEvent rawEvent,
             int policyFlags) {
+        if (!event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
+            if (mNext != null) {
+                mNext.onMotionEvent(event, rawEvent, policyFlags);
+            }
+            return;
+        }
         mMagnifiedContentInteractonStateHandler.onMotionEvent(event);
         switch (mCurrentState) {
             case STATE_DELEGATING: {
@@ -348,6 +356,13 @@
     }
 
     @Override
+    public void onKeyEvent(KeyEvent event, int policyFlags) {
+        if (mNext != null) {
+          mNext.onKeyEvent(event, policyFlags);
+        }
+    }
+
+    @Override
     public void onAccessibilityEvent(AccessibilityEvent event) {
         if (mNext != null) {
             mNext.onAccessibilityEvent(event);
@@ -360,22 +375,30 @@
     }
 
     @Override
-    public void clear() {
-        mCurrentState = STATE_DETECTING;
-        mDetectingStateHandler.clear();
-        mStateViewportDraggingHandler.clear();
-        mMagnifiedContentInteractonStateHandler.clear();
+    public void clearEvents(int inputSource) {
+        if (inputSource == InputDevice.SOURCE_TOUCHSCREEN) {
+            clear();
+        }
+
         if (mNext != null) {
-            mNext.clear();
+            mNext.clearEvents(inputSource);
         }
     }
 
     @Override
     public void onDestroy() {
+        clear();
         mScreenStateObserver.destroy();
         mWindowManager.setMagnificationCallbacks(null);
     }
 
+    private void clear() {
+        mCurrentState = STATE_DETECTING;
+        mDetectingStateHandler.clear();
+        mStateViewportDraggingHandler.clear();
+        mMagnifiedContentInteractonStateHandler.clear();
+    }
+
     private void handleMotionEventStateDelegating(MotionEvent event,
             MotionEvent rawEvent, int policyFlags) {
         switch (event.getActionMasked()) {
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index f18b5ef..85730cd 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -29,6 +29,8 @@
 import android.os.Handler;
 import android.os.SystemClock;
 import android.util.Slog;
+import android.view.InputDevice;
+import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
@@ -253,7 +255,22 @@
         mScaledGestureDetectionVelocity = (int) (GESTURE_DETECTION_VELOCITY_DIP * density);
     }
 
-    public void clear() {
+    @Override
+    public void clearEvents(int inputSource) {
+        if (inputSource == InputDevice.SOURCE_TOUCHSCREEN) {
+            clear();
+        }
+        if (mNext != null) {
+            mNext.clearEvents(inputSource);
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        clear();
+    }
+
+    private void clear() {
         // If we have not received an event then we are in initial
         // state. Therefore, there is not need to clean anything.
         MotionEvent event = mReceivedPointerTracker.getLastReceivedEvent();
@@ -262,10 +279,6 @@
         }
     }
 
-    public void onDestroy() {
-        // TODO: Implement
-    }
-
     private void clear(MotionEvent event, int policyFlags) {
         switch (mCurrentState) {
             case STATE_TOUCH_EXPLORING: {
@@ -304,9 +317,6 @@
         mLongPressingPointerDeltaX = 0;
         mLongPressingPointerDeltaY = 0;
         mCurrentState = STATE_TOUCH_EXPLORING;
-        if (mNext != null) {
-            mNext.clear();
-        }
         mTouchExplorationInProgress = false;
         mAms.onTouchInteractionEnd();
     }
@@ -318,6 +328,13 @@
 
     @Override
     public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (!event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
+            if (mNext != null) {
+                mNext.onMotionEvent(event, rawEvent, policyFlags);
+            }
+            return;
+        }
+
         if (DEBUG) {
             Slog.d(LOG_TAG, "Received event: " + event + ", policyFlags=0x"
                     + Integer.toHexString(policyFlags));
@@ -344,6 +361,14 @@
         }
     }
 
+    @Override
+    public void onKeyEvent(KeyEvent event, int policyFlags) {
+        if (mNext != null) {
+            mNext.onKeyEvent(event, policyFlags);
+        }
+    }
+
+    @Override
     public void onAccessibilityEvent(AccessibilityEvent event) {
         final int eventType = event.getEventType();
 
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index ff02b94..2264c69 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -338,7 +338,7 @@
         @Override
         public void onBootPhase(int phase) {
             if (phase == PHASE_SYSTEM_SERVICES_READY) {
-                sInstance.initialize(UserHandle.USER_OWNER);
+                sInstance.initialize(UserHandle.USER_SYSTEM);
             } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
                 ContentResolver r = sInstance.mContext.getContentResolver();
                 boolean areEnabled = Settings.Secure.getInt(r,
@@ -934,7 +934,7 @@
             case MSG_WIDGET_BROADCAST:
             {
                 final Intent intent = (Intent) msg.obj;
-                mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
+                mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
                 break;
             }
             }
@@ -1092,8 +1092,9 @@
         if (DEBUG) Slog.v(TAG, "Starting with transport " + mCurrentTransport);
 
         // Find all transport hosts and bind to their services
+        // TODO: http://b/22388012
         List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
-                mTransportServiceIntent, 0, UserHandle.USER_OWNER);
+                mTransportServiceIntent, 0, UserHandle.USER_SYSTEM);
         if (DEBUG) {
             Slog.v(TAG, "Found transports: " + ((hosts == null) ? "null" : hosts.size()));
         }
@@ -1953,8 +1954,9 @@
     void checkForTransportAndBind(PackageInfo pkgInfo) {
         Intent intent = new Intent(mTransportServiceIntent)
                 .setPackage(pkgInfo.packageName);
+        // TODO: http://b/22388012
         List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
-                intent, 0, UserHandle.USER_OWNER);
+                intent, 0, UserHandle.USER_SYSTEM);
         if (hosts != null) {
             final int N = hosts.size();
             for (int i = 0; i < N; i++) {
@@ -2002,9 +2004,10 @@
                 mContext.unbindService(connection);
             }
         }
+        // TODO: http://b/22388012
         return mContext.bindServiceAsUser(intent,
                 connection, Context.BIND_AUTO_CREATE,
-                UserHandle.OWNER);
+                UserHandle.SYSTEM);
     }
 
     // Add the backup agents in the given packages to our set of known backup participants.
@@ -2853,8 +2856,9 @@
 
         private void writeWidgetPayloadIfAppropriate(FileDescriptor fd, String pkgName)
                 throws IOException {
+            // TODO: http://b/22388012
             byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName,
-                    UserHandle.USER_OWNER);
+                    UserHandle.USER_SYSTEM);
             // has the widget state changed since last time?
             final File widgetFile = new File(mStateDir, pkgName + "_widget");
             final boolean priorStateExists = widgetFile.exists();
@@ -3398,8 +3402,9 @@
                                 && ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
                                 (app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
 
+                        // TODO: http://b/22388012
                         byte[] widgetBlob = AppWidgetBackupBridge.getWidgetState(pkg.packageName,
-                                UserHandle.USER_OWNER);
+                                UserHandle.USER_SYSTEM);
 
                         final int token = generateToken();
                         FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1],
@@ -3463,7 +3468,8 @@
 
             // Save associated .obb content if it exists and we did save the apk
             // check for .obb and save those too
-            final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_OWNER);
+            // TODO: http://b/22388012
+            final UserEnvironment userEnv = new UserEnvironment(UserHandle.USER_SYSTEM);
             final File obbDir = userEnv.buildExternalStorageAppObbDirs(pkg.packageName)[0];
             if (obbDir != null) {
                 if (MORE_DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
@@ -3803,8 +3809,9 @@
             // If we're doing widget state as well, ensure that we have all the involved
             // host & provider packages in the set
             if (mDoWidgets) {
+                // TODO: http://b/22388012
                 List<String> pkgs =
-                        AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_OWNER);
+                        AppWidgetBackupBridge.getWidgetParticipants(UserHandle.USER_SYSTEM);
                 if (pkgs != null) {
                     if (MORE_DEBUG) {
                         Slog.i(TAG, "Adding widget participants to backup set:");
@@ -7232,7 +7239,8 @@
     // Used by both incremental and full restore
     void restoreWidgetData(String packageName, byte[] widgetData) {
         // Apply the restored widget state and generate the ID update for the app
-        AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, UserHandle.USER_OWNER);
+        // TODO: http://b/22388012
+        AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, UserHandle.USER_SYSTEM);
     }
 
     // *****************************
@@ -7489,7 +7497,8 @@
 
             // If we're starting a full-system restore, set up to begin widget ID remapping
             if (mIsSystemRestore) {
-                AppWidgetBackupBridge.restoreStarting(UserHandle.USER_OWNER);
+                // TODO: http://b/22388012
+                AppWidgetBackupBridge.restoreStarting(UserHandle.USER_SYSTEM);
             }
 
             try {
@@ -8095,7 +8104,8 @@
             }
 
             // Kick off any work that may be needed regarding app widget restores
-            AppWidgetBackupBridge.restoreFinished(UserHandle.USER_OWNER);
+            // TODO: http://b/22388012
+            AppWidgetBackupBridge.restoreFinished(UserHandle.USER_SYSTEM);
 
             // If this was a full-system restore, record the ancestral
             // dataset information
@@ -8482,7 +8492,8 @@
 
     public void dataChanged(final String packageName) {
         final int callingUserHandle = UserHandle.getCallingUserId();
-        if (callingUserHandle != UserHandle.USER_OWNER) {
+        if (callingUserHandle != UserHandle.USER_SYSTEM) {
+            // TODO: http://b/22388012
             // App is running under a non-owner user profile.  For now, we do not back
             // up data from secondary user profiles.
             // TODO: backups for all user profiles although don't add backup for profiles
@@ -8605,7 +8616,8 @@
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup");
 
         final int callingUserHandle = UserHandle.getCallingUserId();
-        if (callingUserHandle != UserHandle.USER_OWNER) {
+        // TODO: http://b/22388012
+        if (callingUserHandle != UserHandle.USER_SYSTEM) {
             throw new IllegalStateException("Backup supported only for the device owner");
         }
 
@@ -8677,7 +8689,8 @@
                 "fullTransportBackup");
 
         final int callingUserHandle = UserHandle.getCallingUserId();
-        if (callingUserHandle != UserHandle.USER_OWNER) {
+        // TODO: http://b/22388012
+        if (callingUserHandle != UserHandle.USER_SYSTEM) {
             throw new IllegalStateException("Restore supported only for the device owner");
         }
 
@@ -8717,7 +8730,8 @@
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullRestore");
 
         final int callingUserHandle = UserHandle.getCallingUserId();
-        if (callingUserHandle != UserHandle.USER_OWNER) {
+        // TODO: http://b/22388012
+        if (callingUserHandle != UserHandle.USER_SYSTEM) {
             throw new IllegalStateException("Restore supported only for the device owner");
         }
 
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 5859c6a..a51ab55 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -62,7 +62,8 @@
     // internal control API
     public void initialize(final int whichUser) {
         // Note that only the owner user is currently involved in backup/restore
-        if (whichUser == UserHandle.USER_OWNER) {
+        // TODO: http://b/22388012
+        if (whichUser == UserHandle.USER_SYSTEM) {
             // Does this product support backup/restore at all?
             if (mGlobalDisable) {
                 Slog.i(TAG, "Backup/restore not supported");
@@ -91,8 +92,8 @@
             Slog.i(TAG, "Backup/restore not supported");
             return;
         }
-
-        if (userHandle == UserHandle.USER_OWNER) {
+        // TODO: http://b/22388012
+        if (userHandle == UserHandle.USER_SYSTEM) {
             synchronized (this) {
                 if (makeActive != isBackupServiceActive(userHandle)) {
                     Slog.i(TAG, "Making backup "
@@ -120,7 +121,8 @@
      * @return true if the service is active.
      */
     public boolean isBackupServiceActive(final int userHandle) {
-        if (userHandle == UserHandle.USER_OWNER) {
+        // TODO: http://b/22388012
+        if (userHandle == UserHandle.USER_SYSTEM) {
             synchronized (this) {
                 return mService != null;
             }
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 342a3ef..69f0cef 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -17,7 +17,6 @@
 package com.android.server;
 
 import android.app.ActivityManager;
-import android.app.KeyguardManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -33,10 +32,11 @@
 import android.os.PowerManager.WakeLock;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.os.Vibrator;
 import android.provider.Settings;
 import android.util.Slog;
+import android.view.KeyEvent;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 /**
@@ -46,10 +46,16 @@
  * added.</p>
  * @hide
  */
-class GestureLauncherService extends SystemService {
+public class GestureLauncherService extends SystemService {
     private static final boolean DBG = false;
     private static final String TAG = "GestureLauncherService";
 
+    /**
+     * Time in milliseconds in which the power button must be pressed twice so it will be considered
+     * as a camera launch.
+     */
+    private static final long CAMERA_POWER_DOUBLE_TAP_TIME_MS = 300;
+
     /** The listener that receives the gesture event. */
     private final GestureEventListener mGestureListener = new GestureEventListener();
 
@@ -91,13 +97,20 @@
      */
     private int mCameraLaunchLastEventExtra = 0;
 
+    /**
+     * Whether camera double tap power button gesture is currently enabled;
+     */
+    private boolean mCameraDoubleTapPowerEnabled;
+    private long mLastPowerDownWhileNonInteractive = 0;
+
+
     public GestureLauncherService(Context context) {
         super(context);
         mContext = context;
     }
 
     public void onStart() {
-        // Nothing to publish.
+        LocalServices.addService(GestureLauncherService.class, this);
     }
 
     public void onBootPhase(int phase) {
@@ -113,17 +126,21 @@
             mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                     "GestureLauncherService");
             updateCameraRegistered();
+            updateCameraDoubleTapPowerEnabled();
 
             mUserId = ActivityManager.getCurrentUser();
             mContext.registerReceiver(mUserReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
-            registerContentObserver();
+            registerContentObservers();
         }
     }
 
-    private void registerContentObserver() {
+    private void registerContentObservers() {
         mContext.getContentResolver().registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.CAMERA_GESTURE_DISABLED),
                 false, mSettingObserver, mUserId);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED),
+                false, mSettingObserver, mUserId);
     }
 
     private void updateCameraRegistered() {
@@ -135,6 +152,13 @@
         }
     }
 
+    private void updateCameraDoubleTapPowerEnabled() {
+        boolean enabled = isCameraDoubleTapPowerSettingEnabled(mContext, mUserId);
+        synchronized (this) {
+            mCameraDoubleTapPowerEnabled = enabled;
+        }
+    }
+
     private void unregisterCameraLaunchGesture() {
         if (mRegistered) {
             mRegistered = false;
@@ -197,6 +221,12 @@
                         Settings.Secure.CAMERA_GESTURE_DISABLED, 0, userId) == 0);
     }
 
+    public static boolean isCameraDoubleTapPowerSettingEnabled(Context context, int userId) {
+        return isCameraDoubleTapPowerEnabled(context.getResources())
+                && (Settings.Secure.getIntForUser(context.getContentResolver(),
+                        Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0, userId) == 0);
+    }
+
     /**
      * Whether to enable the camera launch gesture.
      */
@@ -207,13 +237,64 @@
                 !SystemProperties.getBoolean("gesture.disable_camera_launch", false);
     }
 
+    public static boolean isCameraDoubleTapPowerEnabled(Resources resources) {
+        return resources.getBoolean(
+                com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled);
+    }
+
     /**
      * Whether GestureLauncherService should be enabled according to system properties.
      */
     public static boolean isGestureLauncherEnabled(Resources resources) {
-        // For now, the only supported gesture is camera launch gesture, so whether to enable this
-        // service equals to isCameraLaunchEnabled();
-        return isCameraLaunchEnabled(resources);
+        return isCameraLaunchEnabled(resources) || isCameraDoubleTapPowerEnabled(resources);
+    }
+
+    public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive) {
+        boolean launched = false;
+        synchronized (this) {
+            if (!mCameraDoubleTapPowerEnabled) {
+                mLastPowerDownWhileNonInteractive = 0;
+                return false;
+            }
+            if (event.getEventTime() - mLastPowerDownWhileNonInteractive
+                    < CAMERA_POWER_DOUBLE_TAP_TIME_MS) {
+                launched = true;
+            }
+            mLastPowerDownWhileNonInteractive = interactive ? 0 : event.getEventTime();
+        }
+        if (launched) {
+            Slog.i(TAG, "Power button double tap gesture detected, launching camera.");
+            launched = handleCameraLaunchGesture(false /* useWakelock */,
+                    MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE);
+        }
+        return launched;
+    }
+
+    /**
+     * @return true if camera was launched, false otherwise.
+     */
+    private boolean handleCameraLaunchGesture(boolean useWakelock, int logCategory) {
+        boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
+        if (!userSetupComplete) {
+            if (DBG) Slog.d(TAG, String.format(
+                    "userSetupComplete = %s, ignoring camera launch gesture.",
+                    userSetupComplete));
+            return false;
+        }
+        if (DBG) Slog.d(TAG, String.format(
+                "userSetupComplete = %s, performing camera launch gesture.",
+                userSetupComplete));
+
+        if (useWakelock) {
+            // Make sure we don't sleep too early
+            mWakeLock.acquire(500L);
+        }
+        StatusBarManagerInternal service = LocalServices.getService(
+                StatusBarManagerInternal.class);
+        service.onCameraLaunchGestureDetected();
+        MetricsLogger.action(mContext, logCategory);
+        return true;
     }
 
     private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
@@ -222,8 +303,9 @@
             if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
                 mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
-                registerContentObserver();
+                registerContentObservers();
                 updateCameraRegistered();
+                updateCameraDoubleTapPowerEnabled();
             }
         }
     };
@@ -232,6 +314,7 @@
         public void onChange(boolean selfChange, android.net.Uri uri, int userId) {
             if (userId == mUserId) {
                 updateCameraRegistered();
+                updateCameraDoubleTapPowerEnabled();
             }
         }
     };
@@ -244,38 +327,19 @@
               return;
             }
             if (event.sensor == mCameraLaunchSensor) {
-                handleCameraLaunchGesture(event);
+                if (DBG) {
+                    float[] values = event.values;
+                    Slog.d(TAG, String.format("Received a camera launch event: " +
+                            "values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2]));
+                }
+                if (handleCameraLaunchGesture(true /* useWakelock */,
+                        MetricsLogger.ACTION_WIGGLE_CAMERA_GESTURE)) {
+                    trackCameraLaunchEvent(event);
+                }
                 return;
             }
         }
 
-        private void handleCameraLaunchGesture(SensorEvent event) {
-            if (DBG) {
-                float[] values = event.values;
-                Slog.d(TAG, String.format("Received a camera launch event: " +
-                      "values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2]));
-            }
-            boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(),
-                    Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
-            if (!userSetupComplete) {
-                if (DBG) Slog.d(TAG, String.format(
-                        "userSetupComplete = %s, ignoring camera launch gesture.",
-                        userSetupComplete));
-                return;
-            }
-            if (DBG) Slog.d(TAG, String.format(
-                    "userSetupComplete = %s, performing camera launch gesture.",
-                    userSetupComplete));
-
-            // Make sure we don't sleep too early
-            mWakeLock.acquire(500L);
-            StatusBarManagerInternal service = LocalServices.getService(
-                    StatusBarManagerInternal.class);
-            service.onCameraLaunchGestureDetected();
-            trackCameraLaunchEvent(event);
-            mWakeLock.release();
-        }
-
         @Override
         public void onAccuracyChanged(Sensor sensor, int accuracy) {
             // Ignored.
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 72cece3..540f8cb 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -370,11 +370,17 @@
     private boolean shouldBenchmark() {
         final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
                 Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
+        if (benchInterval == -1) {
+            return false;
+        } else if (benchInterval == 0) {
+            return true;
+        }
+
         synchronized (mLock) {
             for (int i = 0; i < mVolumes.size(); i++) {
                 final VolumeInfo vol = mVolumes.valueAt(i);
                 final VolumeRecord rec = mRecords.get(vol.fsUuid);
-                if (vol.isMountedReadable() && rec != null) {
+                if (vol.isMountedWritable() && rec != null) {
                     final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
                     if (benchAge >= benchInterval) {
                         return true;
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 7aef38d..dbf1288 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -32,6 +32,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
+import android.app.AppOpsManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -122,6 +123,7 @@
     private final Context mContext;
 
     private final PackageManager mPackageManager;
+    private final AppOpsManager mAppOpsManager;
     private UserManager mUserManager;
 
     private final MessageHandler mMessageHandler;
@@ -266,6 +268,7 @@
             IAccountAuthenticatorCache authenticatorCache) {
         mContext = context;
         mPackageManager = packageManager;
+        mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
 
         mMessageHandler = new MessageHandler(FgThread.get().getLooper());
 
@@ -510,7 +513,7 @@
         // Check if there's a shared account that needs to be created as an account
         Account[] sharedAccounts = getSharedAccountsAsUser(userId);
         if (sharedAccounts == null || sharedAccounts.length == 0) return;
-        Account[] accounts = getAccountsAsUser(null, userId);
+        Account[] accounts = getAccountsAsUser(null, userId, mContext.getOpPackageName());
         int parentUserId = UserManager.isSplitSystemUser()
                 ? mUserManager.getUserInfo(userId).restrictedProfileParentId
                 : UserHandle.USER_SYSTEM;
@@ -876,7 +879,8 @@
                     // Confirm that the owner's account still exists before this step.
                     UserAccounts owner = getUserAccounts(parentUserId);
                     synchronized (owner.cacheLock) {
-                        for (Account acc : getAccounts(parentUserId)) {
+                        for (Account acc : getAccounts(parentUserId,
+                                mContext.getOpPackageName())) {
                             if (acc.equals(account)) {
                                 mAuthenticator.addAccountFromCredentials(
                                         this, account, accountCredentials);
@@ -996,7 +1000,7 @@
 
     @Override
     public void hasFeatures(IAccountManagerResponse response,
-            Account account, String[] features) {
+            Account account, String[] features, String opPackageName) {
         int callingUid = Binder.getCallingUid();
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "hasFeatures: " + account
@@ -1009,7 +1013,8 @@
         if (account == null) throw new IllegalArgumentException("account is null");
         if (features == null) throw new IllegalArgumentException("features is null");
         int userId = UserHandle.getCallingUserId();
-        checkReadAccountsPermitted(callingUid, account.type, userId);
+        checkReadAccountsPermitted(callingUid, account.type, userId,
+                opPackageName);
 
         long identityToken = clearCallingIdentity();
         try {
@@ -2521,9 +2526,10 @@
      * Returns the accounts visible to the client within the context of a specific user
      * @hide
      */
-    public Account[] getAccounts(int userId) {
+    public Account[] getAccounts(int userId, String opPackageName) {
         int callingUid = Binder.getCallingUid();
-        List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
+        List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
+                opPackageName);
         if (visibleAccountTypes.isEmpty()) {
             return new Account[0];
         }
@@ -2585,15 +2591,16 @@
     }
 
     @Override
-    public Account[] getAccountsAsUser(String type, int userId) {
-        return getAccountsAsUser(type, userId, null, -1);
+    public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
+        return getAccountsAsUser(type, userId, null, -1, opPackageName);
     }
 
     private Account[] getAccountsAsUser(
             String type,
             int userId,
             String callingPackage,
-            int packageUid) {
+            int packageUid,
+            String opPackageName) {
         int callingUid = Binder.getCallingUid();
         // Only allow the system process to read accounts of other users
         if (userId != UserHandle.getCallingUserId()
@@ -2614,9 +2621,11 @@
         // be passed in the original caller's uid here, which is what should be used for filtering.
         if (packageUid != -1 && UserHandle.isSameApp(callingUid, Process.myUid())) {
             callingUid = packageUid;
+            opPackageName = callingPackage;
         }
 
-        List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
+        List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
+                opPackageName);
         if (visibleAccountTypes.isEmpty()
                 || (type != null && !visibleAccountTypes.contains(type))) {
             return new Account[0];
@@ -2755,22 +2764,24 @@
     }
 
     @Override
-    public Account[] getAccounts(String type) {
-        return getAccountsAsUser(type, UserHandle.getCallingUserId());
+    public Account[] getAccounts(String type, String opPackageName) {
+        return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
     }
 
     @Override
-    public Account[] getAccountsForPackage(String packageName, int uid) {
+    public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
         int callingUid = Binder.getCallingUid();
         if (!UserHandle.isSameApp(callingUid, Process.myUid())) {
             throw new SecurityException("getAccountsForPackage() called from unauthorized uid "
                     + callingUid + " with uid=" + uid);
         }
-        return getAccountsAsUser(null, UserHandle.getCallingUserId(), packageName, uid);
+        return getAccountsAsUser(null, UserHandle.getCallingUserId(), packageName, uid,
+                opPackageName);
     }
 
     @Override
-    public Account[] getAccountsByTypeForPackage(String type, String packageName) {
+    public Account[] getAccountsByTypeForPackage(String type, String packageName,
+            String opPackageName) {
         int packageUid = -1;
         try {
             packageUid = AppGlobals.getPackageManager().getPackageUid(
@@ -2779,14 +2790,16 @@
             Slog.e(TAG, "Couldn't determine the packageUid for " + packageName + re);
             return new Account[0];
         }
-        return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName, packageUid);
+        return getAccountsAsUser(type, UserHandle.getCallingUserId(), packageName,
+                packageUid, opPackageName);
     }
 
     @Override
     public void getAccountsByFeatures(
             IAccountManagerResponse response,
             String type,
-            String[] features) {
+            String[] features,
+            String opPackageName) {
         int callingUid = Binder.getCallingUid();
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Log.v(TAG, "getAccounts: accountType " + type
@@ -2799,7 +2812,8 @@
         if (type == null) throw new IllegalArgumentException("accountType is null");
         int userId = UserHandle.getCallingUserId();
 
-        List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId);
+        List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
+                opPackageName);
         if (!visibleAccountTypes.contains(type)) {
             Bundle result = new Bundle();
             // Need to return just the accounts that are from matching signatures.
@@ -3699,31 +3713,22 @@
         }
     }
 
-    private boolean isPermitted(int callingUid, String... permissions) {
+    private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
         for (String perm : permissions) {
             if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
                 if (Log.isLoggable(TAG, Log.VERBOSE)) {
                     Log.v(TAG, "  caller uid " + callingUid + " has " + perm);
                 }
-                return true;
+                final int opCode = AppOpsManager.permissionToOpCode(perm);
+                if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
+                        opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
+                    return true;
+                }
             }
         }
         return false;
     }
 
-    /** Succeeds if any of the specified permissions are granted. */
-    private void checkBinderPermission(String... permissions) {
-        final int callingUid = Binder.getCallingUid();
-        if (isPermitted(callingUid, permissions)) {
-            String msg = String.format(
-                    "caller uid %s  lacks any of %s",
-                    callingUid,
-                    TextUtils.join(",", permissions));
-            Log.w(TAG, "  " + msg);
-            throw new SecurityException(msg);
-        }
-    }
-
     private int handleIncomingUser(int userId) {
         try {
             return ActivityManagerNative.getDefault().handleIncomingUser(
@@ -3777,11 +3782,13 @@
         return fromAuthenticator || hasExplicitGrants || isPrivileged;
     }
 
-    private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId) {
+    private boolean isAccountVisibleToCaller(String accountType, int callingUid, int userId,
+            String opPackageName) {
         if (accountType == null) {
             return false;
         } else {
-            return getTypesVisibleToCaller(callingUid, userId).contains(accountType);
+            return getTypesVisibleToCaller(callingUid, userId,
+                    opPackageName).contains(accountType);
         }
     }
 
@@ -3793,9 +3800,10 @@
         }
     }
 
-    private List<String> getTypesVisibleToCaller(int callingUid, int userId) {
+    private List<String> getTypesVisibleToCaller(int callingUid, int userId,
+            String opPackageName) {
         boolean isPermitted =
-                isPermitted(callingUid, Manifest.permission.GET_ACCOUNTS,
+                isPermitted(opPackageName, callingUid, Manifest.permission.GET_ACCOUNTS,
                         Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
         Log.i(TAG, String.format("getTypesVisibleToCaller: isPermitted? %s", isPermitted));
         return getTypesForCaller(callingUid, userId, isPermitted);
@@ -3891,8 +3899,9 @@
     private void checkReadAccountsPermitted(
             int callingUid,
             String accountType,
-            int userId) {
-        if (!isAccountVisibleToCaller(accountType, callingUid, userId)) {
+            int userId,
+            String opPackageName) {
+        if (!isAccountVisibleToCaller(accountType, callingUid, userId, opPackageName)) {
             String msg = String.format(
                     "caller uid %s cannot access %s accounts",
                     callingUid,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 81936ee..14376d1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2730,31 +2730,17 @@
         }
     }
 
-    /**
-     * Activate an activity by bringing it to the top and set the focus on it.
-     * Note: This is only allowed for activities which are on the freeform stack.
-     * @param token The token of the activity calling which will get activated.
-     */
     @Override
-    public void activateActivity(IBinder token) {
-        if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "ActivateActivity token=" + token);
+    public void setFocusedTask(int taskId) {
+        if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedTask: taskId=" + taskId);
         long callingId = Binder.clearCallingIdentity();
         try {
             synchronized (ActivityManagerService.this) {
-                final ActivityRecord anyTaskRecord = ActivityRecord.isInStackLocked(token);
-                if (anyTaskRecord == null) {
-                    Slog.w(TAG, "ActivateActivity: token=" + token + " not found");
-                    return;
-                }
-                TaskRecord task = anyTaskRecord.task;
-                final boolean runsOnFreeformStack =
-                        task.stack.getStackId() == FREEFORM_WORKSPACE_STACK_ID;
-                if (!runsOnFreeformStack) {
-                    Slog.w(TAG, "Tried to use activateActivity on a non freeform workspace!");
-                } else if (task != null) {
-                    ActivityRecord topTaskRecord = task.topRunningActivityLocked(null);
-                    if (topTaskRecord != null) {
-                        setFocusedActivityLocked(topTaskRecord, "activateActivity");
+                TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+                if (task != null) {
+                    ActivityRecord r = task.topRunningActivityLocked(null);
+                    if (r != null) {
+                        setFocusedActivityLocked(r, "setFocusedTask");
                         mStackSupervisor.resumeTopActivitiesLocked(task.stack, null, null);
                     }
                 }
@@ -2764,21 +2750,6 @@
         }
     }
 
-    @Override
-    public void setFocusedTask(int taskId) {
-        if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedTask: taskId=" + taskId);
-        synchronized (ActivityManagerService.this) {
-            TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
-            if (task != null) {
-                ActivityRecord r = task.topRunningActivityLocked(null);
-                if (r != null) {
-                    setFocusedActivityLocked(r, "setFocusedTask");
-                    mStackSupervisor.resumeTopActivitiesLocked(task.stack, null, null);
-                }
-            }
-        }
-    }
-
     /** Sets the task stack listener that gets callbacks when a task stack changes. */
     @Override
     public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException {
@@ -8721,58 +8692,6 @@
     }
 
     @Override
-    public void setActivityBounds(IBinder token, Rect bounds) {
-        long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (this) {
-                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-                if (r == null) {
-                    Slog.w(TAG, "setActivityBounds: token=" + token + " not found");
-                    return;
-                }
-                final TaskRecord task = r.task;
-                if (task == null) {
-                    Slog.e(TAG, "setActivityBounds: No TaskRecord for the ActivityRecord r=" + r);
-                    return;
-                }
-                if (task.stack != null && task.stack.mStackId == DOCKED_STACK_ID) {
-                    mStackSupervisor.resizeStackLocked(task.stack.mStackId, bounds);
-                } else {
-                    mStackSupervisor.resizeTaskLocked(task, bounds);
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-    }
-
-    @Override
-    public Rect getActivityBounds(IBinder token) {
-        long ident = Binder.clearCallingIdentity();
-        Rect rect = null;
-        try {
-            synchronized (this) {
-                final ActivityRecord r = ActivityRecord.isInStackLocked(token);
-                if (r == null) {
-                    Slog.w(TAG, "getActivityBounds: token=" + token + " not found");
-                    return rect;
-                }
-                final TaskRecord task = r.task;
-                if (task == null) {
-                    Slog.e(TAG, "getActivityBounds: No TaskRecord for the ActivityRecord r=" + r);
-                    return rect;
-                }
-                if (task.mBounds != null) {
-                    rect = new Rect(task.mBounds);
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-        return rect;
-    }
-
-    @Override
     public Bitmap getTaskDescriptionIcon(String filename) {
         if (!FileUtils.isValidExtFilename(filename)
                 || !filename.contains(ActivityRecord.ACTIVITY_ICON_SUFFIX)) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 751acb6..a8a0073 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1400,16 +1400,14 @@
         // If the top activity is not fullscreen, then we need to
         // make sure any activities under it are now visible.
         boolean aboveTop = true;
-        boolean behindFullscreen = !isStackVisibleLocked();
+        final boolean stackInvisible = !isStackVisibleLocked();
+        boolean behindFullscreenActivity = stackInvisible;
         boolean noStackActivityResumed = (isInStackLocked(starting) == null);
 
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
             final ArrayList<ActivityRecord> activities = task.mActivities;
-            // Set to true if an activity in this task is fullscreen thereby hiding other
-            // activities in the same task. Initialized to the same value as behindFullscreen
-            // which represent if the entire task/stack is behind another fullscreen task/stack.
-            boolean behindFullscreenActivity = behindFullscreen;
+
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
                 if (r.finishing) {
@@ -1507,18 +1505,18 @@
                         // At this point, nothing else needs to be shown in this task.
                         behindFullscreenActivity = true;
                         if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r
-                                + " behindFullscreen=" + behindFullscreen
+                                + " stackInvisible=" + stackInvisible
                                 + " behindFullscreenActivity=" + behindFullscreenActivity);
                     } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
                         behindFullscreenActivity = true;
                         if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Showing home: at " + r
-                                + " behindFullscreen=" + behindFullscreen
+                                + " stackInvisible=" + stackInvisible
                                 + " behindFullscreenActivity=" + behindFullscreenActivity);
                     }
                 } else {
                     if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
                             "Make invisible? " + r + " finishing=" + r.finishing
-                            + " state=" + r.state + " behindFullscreen=" + behindFullscreen
+                            + " state=" + r.state + " stackInvisible=" + stackInvisible
                             + " behindFullscreenActivity=" + behindFullscreenActivity);
                     // Now for any activities that aren't visible to the user, make
                     // sure they no longer are keeping the screen frozen.
@@ -1566,9 +1564,12 @@
                     }
                 }
             }
-            // Factoring if the previous task is fullscreen there by affecting the visibility of
-            // task behind it.
-            behindFullscreen |= task.mFullscreen;
+            if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+                // The visibility of tasks and the activities they contain in freeform stack are
+                // determined individually unlike other stacks where the visibility or fullscreen
+                // status of an activity in a previous task affects other.
+                behindFullscreenActivity = stackInvisible;
+            }
         }
 
         if (mTranslucentActivityWaiting != null &&
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index dd9b6f1..8ab4ae5 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -205,6 +205,13 @@
     /** Action restriction: launching the activity is restricted by an app op. */
     private static final int ACTIVITY_RESTRICTION_APPOP = 2;
 
+    // The height/width divide used when fitting a task within a bounds with method
+    // {@link #fitWithinBounds}.
+    // We always want the task to to be visible in the bounds without affecting its size when
+    // fitting. To make sure this is the case, we don't adjust the task left or top side pass
+    // the input bounds right or bottom side minus the width or height divided by this value.
+    private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
+
     /** Status Bar Service **/
     private IBinder mToken = new Binder();
     private IStatusBarService mStatusBarService;
@@ -330,8 +337,9 @@
     /** Used to keep resumeTopActivityLocked() from being entered recursively */
     boolean inResumeTopActivity;
 
-    // temp. rect used during resize calculation so we don't need to create a new object each time.
+    // temp. rects used during resize calculation so we don't need to create a new object each time.
     private final Rect tempRect = new Rect();
+    private final Rect tempRect2 = new Rect();
 
     private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
     private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
@@ -2970,7 +2978,17 @@
             ArrayList<TaskRecord> tasks = stack.getAllTasks();
             for (int i = tasks.size() - 1; i >= 0; i--) {
                 TaskRecord task = tasks.get(i);
-                task.updateOverrideConfiguration(bounds);
+                if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+                    // For freeform stack we don't adjust the size of the tasks to match that of
+                    // the stack, but we do try to make sure the tasks are still contained with the
+                    // bounds of the stack.
+                    tempRect2.set(task.mBounds);
+                    fitWithinBounds(tempRect2, bounds);
+                    task.updateOverrideConfiguration(tempRect2);
+                } else {
+                    task.updateOverrideConfiguration(bounds);
+                }
+
                 mTmpConfigs.put(task.taskId, task.mOverrideConfig);
                 mTmpBounds.put(task.taskId, task.mBounds);
             }
@@ -4839,4 +4857,44 @@
 
         return onLeanbackOnly;
     }
+
+    /**
+     * Adjust bounds to stay within stack bounds.
+     *
+     * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
+     * that keep them unchanged, but be contained within the stack bounds.
+     *
+     * @param bounds Bounds to be adjusted.
+     * @param stackBounds Bounds within which the other bounds should remain.
+     */
+    private static void fitWithinBounds(Rect bounds, Rect stackBounds) {
+        if (stackBounds == null || stackBounds.contains(bounds)) {
+            return;
+        }
+
+        if (bounds.left < stackBounds.left || bounds.right > stackBounds.right) {
+            final int maxRight = stackBounds.right
+                    - (stackBounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
+            int horizontalDiff = stackBounds.left - bounds.left;
+            if ((horizontalDiff < 0 && bounds.left >= maxRight)
+                    || (bounds.left + horizontalDiff >= maxRight)) {
+                horizontalDiff = maxRight - bounds.left;
+            }
+            bounds.left += horizontalDiff;
+            bounds.right += horizontalDiff;
+        }
+
+        if (bounds.top < stackBounds.top || bounds.bottom > stackBounds.bottom) {
+            final int maxBottom = stackBounds.bottom
+                    - (stackBounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
+            int verticalDiff = stackBounds.top - bounds.top;
+            if ((verticalDiff < 0 && bounds.top >= maxBottom)
+                    || (bounds.top + verticalDiff >= maxBottom)) {
+                verticalDiff = maxBottom - bounds.top;
+            }
+            bounds.top += verticalDiff;
+            bounds.bottom += verticalDiff;
+        }
+    }
+
 }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 5694e704..8f10f08 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -108,13 +108,6 @@
 
     static final int INVALID_TASK_ID = -1;
 
-    // The height/width divide used when fitting a task within a bounds with method
-    // {@link #fitWithinBounds}.
-    // We always want the task to to be visible in the bounds without affecting its size when
-    // fitting. To make sure this is the case, we don't adjust the task left or top side pass
-    // the input bounds right or bottom side minus the width or height divided by this value.
-    private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
-
     final int taskId;       // Unique identifier for this task.
     String affinity;        // The affinity name for this task, or null; may change identity.
     String rootAffinity;    // Initial base affinity, or null; does not change from initial root.
@@ -1186,12 +1179,6 @@
      * @return Update configuration or null if there is no change.
      */
     Configuration updateOverrideConfiguration(Rect bounds) {
-        if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
-            // For freeform stack we don't adjust the size of the tasks to match that of the
-            // stack, but we do try to make sure the tasks are still contained with the
-            // bounds of the stack.
-            fitWithinBounds(bounds, stack.mBounds);
-        }
         if (Objects.equals(mBounds, bounds)) {
             return null;
         }
@@ -1255,45 +1242,6 @@
         return mLastNonFullscreenBounds;
     }
 
-    /**
-     * Adjust bounds to stay within stack bounds.
-     *
-     * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
-     * that keep them unchanged, but be contained within the stack bounds.
-     *
-     * @param bounds Bounds to be adjusted.
-     * @param stackBounds Bounds within which the other bounds should remain.
-     */
-    private static void fitWithinBounds(Rect bounds, Rect stackBounds) {
-        if (stackBounds == null || stackBounds.contains(bounds)) {
-            return;
-        }
-
-        if (bounds.left < stackBounds.left || bounds.right > stackBounds.right) {
-            final int maxRight = stackBounds.right
-                    - (stackBounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
-            int horizontalDiff = stackBounds.left - bounds.left;
-            if ((horizontalDiff < 0 && bounds.left >= maxRight)
-                    || (bounds.left + horizontalDiff >= maxRight)) {
-                horizontalDiff = maxRight - bounds.left;
-            }
-            bounds.left += horizontalDiff;
-            bounds.right += horizontalDiff;
-        }
-
-        if (bounds.top < stackBounds.top || bounds.bottom > stackBounds.bottom) {
-            final int maxBottom = stackBounds.bottom
-                    - (stackBounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
-            int verticalDiff = stackBounds.top - bounds.top;
-            if ((verticalDiff < 0 && bounds.top >= maxBottom)
-                    || (bounds.top + verticalDiff >= maxBottom)) {
-                verticalDiff = maxBottom - bounds.top;
-            }
-            bounds.top += verticalDiff;
-            bounds.bottom += verticalDiff;
-        }
-    }
-
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("userId="); pw.print(userId);
                 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 292aff9..e6dc895 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -340,7 +340,8 @@
         for (UserInfo user : mUserManager.getUsers(true)) {
             // Skip any partially created/removed users
             if (user.partial) continue;
-            Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(user.id);
+            Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(
+                    user.id, mContext.getOpPackageName());
             mSyncStorageEngine.doDatabaseCleanup(accountsForUser, user.id);
         }
     }
@@ -1232,7 +1233,8 @@
         }
 
         // Schedule sync for any accounts under started user
-        final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId);
+        final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId,
+                mContext.getOpPackageName());
         for (Account account : accounts) {
             scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
                     0 /* no delay */, 0 /* No flex */,
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index f53ccc9..2eabd32 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -341,7 +341,8 @@
         private int mPendingBacklight = INITIAL_BACKLIGHT;
         private int mActualState = INITIAL_SCREEN_STATE;
         private int mActualBacklight = INITIAL_BACKLIGHT;
-        private boolean mChangeInProgress;
+        private boolean mStateChangeInProgress;
+        private boolean mBacklightChangeInProgress;
 
         public PhotonicModulator() {
             super("PhotonicModulator");
@@ -349,7 +350,9 @@
 
         public boolean setState(int state, int backlight) {
             synchronized (mLock) {
-                if (state != mPendingState || backlight != mPendingBacklight) {
+                boolean stateChanged = state != mPendingState;
+                boolean backlightChanged = backlight != mPendingBacklight;
+                if (stateChanged || backlightChanged) {
                     if (DEBUG) {
                         Slog.d(TAG, "Requesting new screen state: state="
                                 + Display.stateToString(state) + ", backlight=" + backlight);
@@ -358,12 +361,15 @@
                     mPendingState = state;
                     mPendingBacklight = backlight;
 
-                    if (!mChangeInProgress) {
-                        mChangeInProgress = true;
+                    boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress;
+                    mStateChangeInProgress = stateChanged;
+                    mBacklightChangeInProgress = backlightChanged;
+
+                    if (!changeInProgress) {
                         mLock.notifyAll();
                     }
                 }
-                return !mChangeInProgress;
+                return !mStateChangeInProgress;
             }
         }
 
@@ -375,7 +381,8 @@
                 pw.println("  mPendingBacklight=" + mPendingBacklight);
                 pw.println("  mActualState=" + Display.stateToString(mActualState));
                 pw.println("  mActualBacklight=" + mActualBacklight);
-                pw.println("  mChangeInProgress=" + mChangeInProgress);
+                pw.println("  mStateChangeInProgress=" + mStateChangeInProgress);
+                pw.println("  mBacklightChangeInProgress=" + mBacklightChangeInProgress);
             }
         }
 
@@ -392,10 +399,15 @@
                     stateChanged = (state != mActualState);
                     backlight = mPendingBacklight;
                     backlightChanged = (backlight != mActualBacklight);
-                    if (!stateChanged && !backlightChanged) {
-                        // All changed applied, notify outer class and wait for more.
-                        mChangeInProgress = false;
+                    if (!stateChanged) {
+                        // State changed applied, notify outer class.
                         postScreenUpdateThreadSafe();
+                        mStateChangeInProgress = false;
+                    }
+                    if (!backlightChanged) {
+                        mBacklightChangeInProgress = false;
+                    }
+                    if (!stateChanged && !backlightChanged) {
                         try {
                             mLock.wait();
                         } catch (InterruptedException ex) { }
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 0023258..ea7d85e 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -21,10 +21,15 @@
 import android.app.ActivityManager.RunningAppProcessInfo;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManagerNative;
+import android.app.AlarmManager;
 import android.app.AppOpsManager;
 import android.app.IUserSwitchObserver;
+import android.app.PendingIntent;
 import android.content.ComponentName;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
@@ -85,6 +90,8 @@
     private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon";
     private static final int MSG_USER_SWITCHING = 10;
     private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
+    private static final String ACTION_LOCKOUT_RESET =
+            "com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
 
     private ClientMonitor mAuthClient = null;
     private ClientMonitor mEnrollClient = null;
@@ -118,9 +125,19 @@
     private long mHalDeviceId;
     private int mFailedAttempts;
     private IFingerprintDaemon mDaemon;
-    private PowerManager mPowerManager;
+    private final PowerManager mPowerManager;
+    private final AlarmManager mAlarmManager;
 
-    private final Runnable mLockoutReset = new Runnable() {
+    private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
+                resetFailedAttempts();
+            }
+        }
+    };
+
+    private final Runnable mResetFailedAttemptsRunnable = new Runnable() {
         @Override
         public void run() {
             resetFailedAttempts();
@@ -133,7 +150,10 @@
         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);
+        mPowerManager = mContext.getSystemService(PowerManager.class);
+        mAlarmManager = mContext.getSystemService(AlarmManager.class);
+        mContext.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
+                RESET_FINGERPRINT_LOCKOUT, null /* handler */);
     }
 
     @Override
@@ -262,14 +282,28 @@
         return mFailedAttempts >= MAX_FAILED_ATTEMPTS;
     }
 
+    private void scheduleLockoutReset() {
+        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS, getLockoutResetIntent());
+    }
+
+    private void cancelLockoutReset() {
+        mAlarmManager.cancel(getLockoutResetIntent());
+    }
+
+    private PendingIntent getLockoutResetIntent() {
+        return PendingIntent.getBroadcast(mContext, 0,
+                new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT);
+    }
+
     private void resetFailedAttempts() {
         if (DEBUG && inLockoutMode()) {
             Slog.v(TAG, "Reset fingerprint lockout");
         }
         mFailedAttempts = 0;
-        // If we're asked to reset failed attempts externally (i.e. from Keyguard), the runnable
-        // may still be in the queue; remove it.
-        mHandler.removeCallbacks(mLockoutReset);
+        // If we're asked to reset failed attempts externally (i.e. from Keyguard), the alarm might
+        // still be pending; remove it.
+        cancelLockoutReset();
         notifyLockoutResetMonitors();
     }
 
@@ -277,8 +311,7 @@
         mFailedAttempts++;
         if (inLockoutMode()) {
             // Failing multiple times will continue to push out the lockout time.
-            mHandler.removeCallbacks(mLockoutReset);
-            mHandler.postDelayed(mLockoutReset, FAIL_LOCKOUT_TIMEOUT_MS);
+            scheduleLockoutReset();
             if (clientMonitor != null
                     && !clientMonitor.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
                 Slog.w(TAG, "Cannot send lockout message to client");
@@ -683,7 +716,7 @@
                     FingerprintUtils.vibrateFingerprintSuccess(getContext());
                 }
                 result |= true; // we have a valid fingerprint
-                mHandler.post(mLockoutReset);
+                resetFailedAttempts();
             }
             return result;
         }
@@ -1016,7 +1049,7 @@
         public void resetTimeout(byte [] token) {
             checkPermission(RESET_FINGERPRINT_LOCKOUT);
             // TODO: confirm security token when we move timeout management into the HAL layer.
-            mHandler.post(mLockoutReset);
+            mHandler.post(mResetFailedAttemptsRunnable);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 82afdd7..d4093258 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4575,7 +4575,7 @@
                 // Check for results that need to skip the current profile.
                 ResolveInfo xpResolveInfo  = querySkipCurrentProfileIntents(matchingFilters, intent,
                         resolvedType, flags, userId);
-                if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {
+                if (xpResolveInfo != null) {
                     List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
                     result.add(xpResolveInfo);
                     return filterIfNotSystemUser(result, userId);
@@ -4667,8 +4667,8 @@
             int status = (int)(verificationState >> 32);
             if (result == null) {
                 result = new CrossProfileDomainInfo();
-                result.resolveInfo =
-                        createForwardingResolveInfo(new IntentFilter(), sourceUserId, parentUserId);
+                result.resolveInfo = createForwardingResolveInfoUnchecked(new IntentFilter(),
+                        sourceUserId, parentUserId);
                 result.bestDomainVerificationStatus = status;
             } else {
                 result.bestDomainVerificationStatus = bestDomainVerificationStatus(status,
@@ -4922,8 +4922,8 @@
                 if ((filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0) {
                     // Checking if there are activities in the target user that can handle the
                     // intent.
-                    ResolveInfo resolveInfo = checkTargetCanHandle(filter, intent, resolvedType,
-                            flags, sourceUserId);
+                    ResolveInfo resolveInfo = createForwardingResolveInfo(filter, intent,
+                            resolvedType, flags, sourceUserId);
                     if (resolveInfo != null) {
                         return resolveInfo;
                     }
@@ -4950,8 +4950,8 @@
                         && !alreadyTriedUserIds.get(targetUserId)) {
                     // Checking if there are activities in the target user that can handle the
                     // intent.
-                    ResolveInfo resolveInfo = checkTargetCanHandle(filter, intent, resolvedType,
-                            flags, sourceUserId);
+                    ResolveInfo resolveInfo = createForwardingResolveInfo(filter, intent,
+                            resolvedType, flags, sourceUserId);
                     if (resolveInfo != null) return resolveInfo;
                     alreadyTriedUserIds.put(targetUserId, true);
                 }
@@ -4960,17 +4960,24 @@
         return null;
     }
 
-    private ResolveInfo checkTargetCanHandle(CrossProfileIntentFilter filter, Intent intent,
+    /**
+     * If the filter's target user can handle the intent and is enabled: returns a ResolveInfo that
+     * will forward the intent to the filter's target user.
+     * Otherwise, returns null.
+     */
+    private ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter filter, Intent intent,
             String resolvedType, int flags, int sourceUserId) {
+        int targetUserId = filter.getTargetUserId();
         List<ResolveInfo> resultTargetUser = mActivities.queryIntent(intent,
-                resolvedType, flags, filter.getTargetUserId());
-        if (resultTargetUser != null && !resultTargetUser.isEmpty()) {
-            return createForwardingResolveInfo(filter, sourceUserId, filter.getTargetUserId());
+                resolvedType, flags, targetUserId);
+        if (resultTargetUser != null && !resultTargetUser.isEmpty()
+                && isUserEnabled(targetUserId)) {
+            return createForwardingResolveInfoUnchecked(filter, sourceUserId, targetUserId);
         }
         return null;
     }
 
-    private ResolveInfo createForwardingResolveInfo(IntentFilter filter,
+    private ResolveInfo createForwardingResolveInfoUnchecked(IntentFilter filter,
             int sourceUserId, int targetUserId) {
         ResolveInfo forwardingResolveInfo = new ResolveInfo();
         long ident = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 80cb4e6..3053904 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -118,6 +118,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.ScreenShapeHelper;
 import com.android.internal.widget.PointerLocationView;
+import com.android.server.GestureLauncherService;
 import com.android.server.LocalServices;
 import com.android.server.policy.keyguard.KeyguardServiceDelegate;
 import com.android.server.policy.keyguard.KeyguardServiceDelegate.DrawnListener;
@@ -126,7 +127,6 @@
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 
@@ -944,10 +944,17 @@
             }
         }
 
+        GestureLauncherService gestureService = LocalServices.getService(
+                GestureLauncherService.class);
+        boolean gesturedServiceIntercepted = false;
+        if (gestureService != null) {
+            gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive);
+        }
+
         // If the power key has still not yet been handled, then detect short
         // press, long press, or multi press and decide what to do.
         mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
-                || mScreenshotChordVolumeUpKeyTriggered;
+                || mScreenshotChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
         if (!mPowerKeyHandled) {
             if (interactive) {
                 // When interactive, we're already awake.
@@ -7054,5 +7061,8 @@
         if (mBurnInProtectionHelper != null) {
             mBurnInProtectionHelper.dump(prefix, pw);
         }
+        if (mKeyguardDelegate != null) {
+            mKeyguardDelegate.dump(prefix, pw);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 6b45941..7ae3c79 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -23,6 +23,8 @@
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardService;
 
+import java.io.PrintWriter;
+
 /**
  * A local class that keeps a cache of keyguard state that can be restored in the event
  * keyguard crashes. It currently also allows runtime-selectable
@@ -393,4 +395,26 @@
             mKeyguardService.onActivityDrawn();
         }
     }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + TAG);
+        prefix += "  ";
+        pw.println(prefix + "showing=" + mKeyguardState.showing);
+        pw.println(prefix + "showingAndNotOccluded=" + mKeyguardState.showingAndNotOccluded);
+        pw.println(prefix + "inputRestricted=" + mKeyguardState.inputRestricted);
+        pw.println(prefix + "occluded=" + mKeyguardState.occluded);
+        pw.println(prefix + "secure=" + mKeyguardState.secure);
+        pw.println(prefix + "dreaming=" + mKeyguardState.dreaming);
+        pw.println(prefix + "systemIsReady=" + mKeyguardState.systemIsReady);
+        pw.println(prefix + "deviceHasKeyguard=" + mKeyguardState.deviceHasKeyguard);
+        pw.println(prefix + "enabled=" + mKeyguardState.enabled);
+        pw.println(prefix + "offReason=" + mKeyguardState.offReason);
+        pw.println(prefix + "currentUser=" + mKeyguardState.currentUser);
+        pw.println(prefix + "bootCompleted=" + mKeyguardState.bootCompleted);
+        pw.println(prefix + "screenState=" + mKeyguardState.screenState);
+        pw.println(prefix + "interactiveState=" + mKeyguardState.interactiveState);
+        if (mKeyguardService != null) {
+            mKeyguardService.dump(prefix, pw);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index cd88b66..429b188 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -27,6 +27,8 @@
 import com.android.internal.policy.IKeyguardService;
 import com.android.internal.policy.IKeyguardStateCallback;
 
+import java.io.PrintWriter;
+
 /**
  * A wrapper class for KeyguardService.  It implements IKeyguardService to ensure the interface
  * remains consistent.
@@ -239,4 +241,8 @@
     public boolean isInputRestricted() {
         return mKeyguardStateMonitor.isInputRestricted();
     }
+
+    public void dump(String prefix, PrintWriter pw) {
+        mKeyguardStateMonitor.dump(prefix, pw);
+    }
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index f1f9c50..30cff03 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -25,6 +25,8 @@
 import com.android.internal.policy.IKeyguardStateCallback;
 import com.android.internal.widget.LockPatternUtils;
 
+import java.io.PrintWriter;
+
 /**
  * Maintains a cached copy of Keyguard's state.
  * @hide
@@ -90,4 +92,13 @@
     public void onInputRestrictedStateChanged(boolean inputRestricted) {
         mInputRestricted = inputRestricted;
     }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + TAG);
+        prefix += "  ";
+        pw.println(prefix + "mIsShowing=" + mIsShowing);
+        pw.println(prefix + "mSimSecure=" + mSimSecure);
+        pw.println(prefix + "mInputRestricted=" + mInputRestricted);
+        pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
+    }
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index ee2353f..d814ebf 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -445,14 +445,16 @@
 
         // Unregister all callbacks and unbind all services.
         for (ServiceState serviceState : userState.serviceStateMap.values()) {
-            if (serviceState.callback != null) {
-                try {
-                    serviceState.service.unregisterCallback(serviceState.callback);
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "error in unregisterCallback", e);
+            if (serviceState.service != null) {
+                if (serviceState.callback != null) {
+                    try {
+                        serviceState.service.unregisterCallback(serviceState.callback);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "error in unregisterCallback", e);
+                    }
                 }
+                mContext.unbindService(serviceState.connection);
             }
-            mContext.unbindService(serviceState.connection);
         }
         userState.serviceStateMap.clear();
     }
@@ -1974,7 +1976,12 @@
                 Slog.d(TAG, "onServiceConnected(component=" + component + ")");
             }
             synchronized (mLock) {
-                UserState userState = getOrCreateUserStateLocked(mUserId);
+                UserState userState = mUserStates.get(mUserId);
+                if (userState == null) {
+                    // The user was removed while connecting.
+                    mContext.unbindService(this);
+                    return;
+                }
                 ServiceState serviceState = userState.serviceStateMap.get(mComponent);
                 serviceState.service = ITvInputService.Stub.asInterface(service);
 
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c76e64c..192b168 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -133,6 +133,7 @@
     private static final int DEFAULT_APP_TRANSITION_DURATION = 336;
     private static final int THUMBNAIL_APP_TRANSITION_DURATION = 336;
     private static final int THUMBNAIL_APP_TRANSITION_ALPHA_DURATION = 336;
+    private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
 
     private final Context mContext;
     private final Handler mH;
@@ -242,10 +243,6 @@
         return mNextAppTransition != TRANSIT_UNSET;
     }
 
-    boolean isTransitionNone() {
-        return mNextAppTransition == TRANSIT_NONE;
-    }
-
     boolean isTransitionEqual(int transit) {
         return mNextAppTransition == transit;
     }
@@ -254,7 +251,7 @@
         return mNextAppTransition;
      }
 
-    void setAppTransition(int transit) {
+    private void setAppTransition(int transit) {
         mNextAppTransition = transit;
     }
 
@@ -299,7 +296,7 @@
         return mNextAppTransitionScaleUp;
     }
 
-    boolean prepare() {
+    private boolean prepare() {
         if (!isRunning()) {
             mAppTransitionState = APP_STATE_IDLE;
             notifyAppTransitionPendingLocked();
@@ -1458,4 +1455,34 @@
     public void setCurrentUser(int newUserId) {
         mCurrentUserId = newUserId;
     }
+
+    /**
+     * @return true if transition is not running and should not be skipped, false if transition is
+     *         already running
+     */
+    boolean prepareAppTransitionLocked(int transit, boolean alwaysKeepCurrent) {
+        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:"
+                + " transit=" + appTransitionToString(transit)
+                + " " + this
+                + " alwaysKeepCurrent=" + alwaysKeepCurrent
+                + " Callers=" + Debug.getCallers(3));
+        if (!isTransitionSet() || mNextAppTransition == TRANSIT_NONE) {
+            setAppTransition(transit);
+        } else if (!alwaysKeepCurrent) {
+            if (transit == TRANSIT_TASK_OPEN && isTransitionEqual(TRANSIT_TASK_CLOSE)) {
+                // Opening a new task always supersedes a close for the anim.
+                setAppTransition(transit);
+            } else if (transit == TRANSIT_ACTIVITY_OPEN
+                    && isTransitionEqual(TRANSIT_ACTIVITY_CLOSE)) {
+                // Opening a new activity always supersedes a close for the anim.
+                setAppTransition(transit);
+            }
+        }
+        boolean prepared = prepare();
+        if (isTransitionSet()) {
+            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
+            mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, APP_TRANSITION_TIMEOUT_MS);
+        }
+        return prepared;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 99e9fe6..325196d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -21,8 +21,10 @@
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerService.TAG;
 
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.util.DisplayMetrics;
 import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayInfo;
@@ -240,17 +242,85 @@
         return -1;
     }
 
+    /**
+     * Find the id of the task whose outside touch area (for resizing) (x, y)
+     * falls within. Returns -1 if the touch doesn't fall into a resizing area.
+     */
+    int taskIdForControlPoint(int x, int y) {
+        final int delta = calculatePixelFromDp(WindowState.RESIZE_HANDLE_WIDTH_IN_DP);
+        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            TaskStack stack = mStacks.get(stackNdx);
+            if (!stack.allowTaskResize()) {
+                break;
+            }
+            final ArrayList<Task> tasks = stack.getTasks();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                final Task task = tasks.get(taskNdx);
+                if (task.isFullscreen()) {
+                    return -1;
+                }
+                task.getBounds(mTmpRect);
+                mTmpRect.inset(-delta, -delta);
+                if (mTmpRect.contains(x, y)) {
+                    mTmpRect.inset(delta, delta);
+                    if (!mTmpRect.contains(x, y)) {
+                        return task.mTaskId;
+                    }
+                    // User touched inside the task. No need to look further,
+                    // focus transfer will be handled in ACTION_UP.
+                    return -1;
+                }
+            }
+        }
+        return -1;
+    }
+
+    private int calculatePixelFromDp(int dp) {
+        final Configuration serviceConfig = mService.mCurConfiguration;
+        // TODO(multidisplay): Update Dp to that of display stack is on.
+        final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+        return (int)(dp * density);
+    }
+
     void setTouchExcludeRegion(Task focusedTask) {
         mTouchExcludeRegion.set(mBaseDisplayRect);
         WindowList windows = getWindowList();
+        final int delta = calculatePixelFromDp(WindowState.RESIZE_HANDLE_WIDTH_IN_DP);
         for (int i = windows.size() - 1; i >= 0; --i) {
             final WindowState win = windows.get(i);
-            final Task task = win.getTask();
-            if (win.isVisibleLw() && task != null && task != focusedTask) {
-                mTmpRect.set(win.mVisibleFrame);
-                // If no intersection, we need mTmpRect to be unmodified.
-                mTmpRect.intersect(win.mVisibleInsets);
-                mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
+            final Task task = win.mAppToken != null ? win.getTask() : null;
+            if (win.isVisibleLw() && task != null) {
+                /**
+                 * Exclusion region is the region that TapDetector doesn't care about.
+                 * Here we want to remove all non-focused tasks from the exclusion region.
+                 * We also remove the outside touch area for resizing for all freeform
+                 * tasks (including the focused).
+                 *
+                 * (For freeform focused task, the below logic will first remove the enlarged
+                 * area, then add back the inner area.)
+                 */
+                final boolean isFreeformed = win.inFreeformWorkspace();
+                if (task != focusedTask || isFreeformed) {
+                    mTmpRect.set(win.mVisibleFrame);
+                    mTmpRect.intersect(win.mVisibleInsets);
+                    /**
+                     * If the task is freeformed, enlarge the area to account for outside
+                     * touch area for resize.
+                     */
+                    if (isFreeformed) {
+                        mTmpRect.inset(-delta, -delta);
+                    }
+                    mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
+                }
+                /**
+                 * If we removed the focused task above, add it back and only leave its
+                 * outside touch area in the exclusion. TapDectector is not interested in
+                 * any touch inside the focused task itself.
+                 */
+                if (task == focusedTask && isFreeformed) {
+                    mTmpRect.inset(delta, delta);
+                    mTouchExcludeRegion.op(mTmpRect, Region.Op.UNION);
+                }
             }
         }
         if (mTapDetector != null) {
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index e87dcde..8f77176 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -283,11 +283,12 @@
 
         // stop intercepting input
         mService.mDragState.unregister();
-        mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
 
         // free our resources and drop all the object references
         mService.mDragState.reset();
         mService.mDragState = null;
+
+        mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
     }
 
     void notifyMoveLw(float x, float y) {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index b3244ff..9adcafc 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -64,9 +64,9 @@
     public InputMonitor(WindowManagerService service) {
         mService = service;
     }
-    
+
     /* Notifies the window manager about a broken input channel.
-     * 
+     *
      * Called by the InputManager.
      */
     @Override
@@ -83,10 +83,10 @@
             }
         }
     }
-    
+
     /* Notifies the window manager about an application that is not responding.
      * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
-     * 
+     *
      * Called by the InputManager.
      */
     @Override
@@ -257,6 +257,20 @@
             }
         }
 
+        final boolean inPositioning = (mService.mTaskPositioner != null);
+        if (inPositioning) {
+            if (WindowManagerService.DEBUG_TASK_POSITIONING) {
+                Log.d(WindowManagerService.TAG, "Inserting window handle for repositioning");
+            }
+            final InputWindowHandle dragWindowHandle = mService.mTaskPositioner.mDragWindowHandle;
+            if (dragWindowHandle != null) {
+                addInputWindowHandleLw(dragWindowHandle);
+            } else {
+                Slog.e(WindowManagerService.TAG,
+                        "Repositioning is in progress but there is no drag window handle.");
+            }
+        }
+
         boolean addInputConsumerHandle = mService.mInputConsumer != null;
 
         // Add all windows on the default display.
@@ -437,56 +451,56 @@
             if (WindowManagerService.DEBUG_INPUT) {
                 Slog.v(WindowManagerService.TAG, "Pausing WindowToken " + window);
             }
-            
+
             window.paused = true;
             updateInputWindowsLw(true /*force*/);
         }
     }
-    
+
     public void resumeDispatchingLw(WindowToken window) {
         if (window.paused) {
             if (WindowManagerService.DEBUG_INPUT) {
                 Slog.v(WindowManagerService.TAG, "Resuming WindowToken " + window);
             }
-            
+
             window.paused = false;
             updateInputWindowsLw(true /*force*/);
         }
     }
-    
+
     public void freezeInputDispatchingLw() {
         if (! mInputDispatchFrozen) {
             if (WindowManagerService.DEBUG_INPUT) {
                 Slog.v(WindowManagerService.TAG, "Freezing input dispatching");
             }
-            
+
             mInputDispatchFrozen = true;
             updateInputDispatchModeLw();
         }
     }
-    
+
     public void thawInputDispatchingLw() {
         if (mInputDispatchFrozen) {
             if (WindowManagerService.DEBUG_INPUT) {
                 Slog.v(WindowManagerService.TAG, "Thawing input dispatching");
             }
-            
+
             mInputDispatchFrozen = false;
             updateInputDispatchModeLw();
         }
     }
-    
+
     public void setEventDispatchingLw(boolean enabled) {
         if (mInputDispatchEnabled != enabled) {
             if (WindowManagerService.DEBUG_INPUT) {
                 Slog.v(WindowManagerService.TAG, "Setting event dispatching to " + enabled);
             }
-            
+
             mInputDispatchEnabled = enabled;
             updateInputDispatchModeLw();
         }
     }
-    
+
     private void updateInputDispatchModeLw() {
         mService.mInputManager.setInputDispatchMode(mInputDispatchEnabled, mInputDispatchFrozen);
     }
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 12f61f9..1f62bc1 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -347,6 +347,13 @@
         return true;    // success!
     }
 
+    public boolean startMovingTask(IWindow window, float startX, float startY) {
+        if (WindowManagerService.DEBUG_TASK_POSITIONING) Slog.d(
+                WindowManagerService.TAG, "startMovingTask: {" + startX + "," + startY + "}");
+
+        return mService.startMovingTask(window, startX, startY);
+    }
+
     public void reportDropResult(IWindow window, boolean consumed) {
         IBinder token = window.asBinder();
         if (WindowManagerService.DEBUG_DRAG) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 666d902..07a850b 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -40,6 +40,13 @@
      * when no window animation is driving it. */
     private static final int DEFAULT_DIM_DURATION = 200;
 
+    // Return value from {@link setBounds} indicating no change was made to the Task bounds.
+    static final int BOUNDS_CHANGE_NONE = 0;
+    // Return value from {@link setBounds} indicating the position of the Task bounds changed.
+    static final int BOUNDS_CHANGE_POSITION = 1;
+    // Return value from {@link setBounds} indicating the size of the Task bounds changed.
+    static final int BOUNDS_CHANGE_SIZE = 1 << 1;
+
     TaskStack mStack;
     final AppTokenList mAppTokens = new AppTokenList();
     final int mTaskId;
@@ -165,7 +172,7 @@
     }
 
     /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
-    boolean setBounds(Rect bounds, Configuration config) {
+    int setBounds(Rect bounds, Configuration config) {
         if (config == null) {
             config = Configuration.EMPTY;
         }
@@ -190,7 +197,7 @@
                     // ensure bounds are entirely within the display rect
                     if (!bounds.intersect(mTmpRect)) {
                         // Can't set bounds outside the containing display...Sorry!
-                        return false;
+                        return BOUNDS_CHANGE_NONE;
                     }
                 }
                 mFullscreen = mTmpRect.equals(bounds);
@@ -199,17 +206,25 @@
 
         if (bounds == null) {
             // Can't set to fullscreen if we don't have a display to get bounds from...
-            return false;
+            return BOUNDS_CHANGE_NONE;
         }
         if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
-            return false;
+            return BOUNDS_CHANGE_NONE;
+        }
+
+        int boundsChange = BOUNDS_CHANGE_NONE;
+        if (mBounds.left != bounds.left || mBounds.right != bounds.right) {
+            boundsChange |= BOUNDS_CHANGE_POSITION;
+        }
+        if (mBounds.width() != bounds.width() || mBounds.height() != bounds.height()) {
+            boundsChange |= BOUNDS_CHANGE_SIZE;
         }
 
         mBounds.set(bounds);
         mRotation = rotation;
         updateDimLayer();
         mOverrideConfig = mFullscreen ? Configuration.EMPTY : config;
-        return true;
+        return boundsChange;
     }
 
     void getBounds(Rect out) {
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
new file mode 100644
index 0000000..71b83a5
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -0,0 +1,325 @@
+/*
+ * 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.wm;
+
+import com.android.server.input.InputApplicationHandle;
+import com.android.server.input.InputWindowHandle;
+import com.android.server.wm.WindowManagerService.H;
+import static com.android.server.wm.WindowManagerService.DEBUG_TASK_POSITIONING;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import android.annotation.IntDef;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Looper;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+
+class TaskPositioner {
+    private static final String TAG = "TaskPositioner";
+
+    @IntDef(flag = true,
+            value = {
+                    CTRL_NONE,
+                    CTRL_LEFT,
+                    CTRL_RIGHT,
+                    CTRL_TOP,
+                    CTRL_BOTTOM
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface CtrlType {}
+
+    private static final int CTRL_NONE   = 0x0;
+    private static final int CTRL_LEFT   = 0x1;
+    private static final int CTRL_RIGHT  = 0x2;
+    private static final int CTRL_TOP    = 0x4;
+    private static final int CTRL_BOTTOM = 0x8;
+
+    private final WindowManagerService mService;
+    private WindowPositionerEventReceiver mInputEventReceiver;
+    private Display mDisplay;
+    private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+
+    private int mTaskId;
+    private final Rect mWindowOriginalBounds = new Rect();
+    private final Rect mWindowDragBounds = new Rect();
+    private float mStartDragX;
+    private float mStartDragY;
+    @CtrlType
+    private int mCtrlType = CTRL_NONE;
+
+    InputChannel mServerChannel;
+    InputChannel mClientChannel;
+    InputApplicationHandle mDragApplicationHandle;
+    InputWindowHandle mDragWindowHandle;
+
+    private final class WindowPositionerEventReceiver extends InputEventReceiver {
+        public WindowPositionerEventReceiver(InputChannel inputChannel, Looper looper) {
+            super(inputChannel, looper);
+        }
+
+        @Override
+        public void onInputEvent(InputEvent event) {
+            if (!(event instanceof MotionEvent)
+                    || (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
+                return;
+            }
+            final MotionEvent motionEvent = (MotionEvent) event;
+            boolean handled = false;
+
+            try {
+                boolean endDrag = false;
+                final float newX = motionEvent.getRawX();
+                final float newY = motionEvent.getRawY();
+
+                switch (motionEvent.getAction()) {
+                    case MotionEvent.ACTION_DOWN: {
+                        if (DEBUG_TASK_POSITIONING) {
+                            Slog.w(TAG, "ACTION_DOWN @ {" + newX + ", " + newY + "}");
+                        }
+                    } break;
+
+                    case MotionEvent.ACTION_MOVE: {
+                        if (DEBUG_TASK_POSITIONING){
+                            Slog.w(TAG, "ACTION_MOVE @ {" + newX + ", " + newY + "}");
+                        }
+                        synchronized (mService.mWindowMap) {
+                            notifyMoveLocked(newX, newY);
+                        }
+                        try {
+                            mService.mActivityManager.resizeTask(mTaskId, mWindowDragBounds);
+                        } catch(RemoteException e) {}
+                    } break;
+
+                    case MotionEvent.ACTION_UP: {
+                        if (DEBUG_TASK_POSITIONING) {
+                            Slog.w(TAG, "ACTION_UP @ {" + newX + ", " + newY + "}");
+                        }
+                        endDrag = true;
+                    } break;
+
+                    case MotionEvent.ACTION_CANCEL: {
+                        if (DEBUG_TASK_POSITIONING) {
+                            Slog.w(TAG, "ACTION_CANCEL @ {" + newX + ", " + newY + "}");
+                        }
+                        endDrag = true;
+                    } break;
+                }
+
+                if (endDrag) {
+                    // Post back to WM to handle clean-ups. We still need the input
+                    // event handler for the last finishInputEvent()!
+                    mService.mH.sendEmptyMessage(H.FINISH_TASK_POSITIONING);
+                }
+                handled = true;
+            } catch (Exception e) {
+                Slog.e(TAG, "Exception caught by drag handleMotion", e);
+            } finally {
+                finishInputEvent(event, handled);
+            }
+        }
+    }
+
+    TaskPositioner(WindowManagerService service) {
+        mService = service;
+    }
+
+    /**
+     * @param display The Display that the window being dragged is on.
+     */
+    void register(Display display) {
+        if (DEBUG_TASK_POSITIONING) {
+            Slog.d(TAG, "Registering task positioner");
+        }
+
+        if (mClientChannel != null) {
+            Slog.e(TAG, "Task positioner already registered");
+            return;
+        }
+
+        mDisplay = display;
+        mDisplay.getMetrics(mDisplayMetrics);
+        final InputChannel[] channels = InputChannel.openInputChannelPair(TAG);
+        mServerChannel = channels[0];
+        mClientChannel = channels[1];
+        mService.mInputManager.registerInputChannel(mServerChannel, null);
+
+        mInputEventReceiver = new WindowPositionerEventReceiver(mClientChannel,
+                mService.mH.getLooper());
+
+        mDragApplicationHandle = new InputApplicationHandle(null);
+        mDragApplicationHandle.name = TAG;
+        mDragApplicationHandle.dispatchingTimeoutNanos =
+                WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+
+        mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null,
+                mDisplay.getDisplayId());
+        mDragWindowHandle.name = TAG;
+        mDragWindowHandle.inputChannel = mServerChannel;
+        mDragWindowHandle.layer = getDragLayerLocked();
+        mDragWindowHandle.layoutParamsFlags = 0;
+        mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
+        mDragWindowHandle.dispatchingTimeoutNanos =
+                WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+        mDragWindowHandle.visible = true;
+        mDragWindowHandle.canReceiveKeys = false;
+        mDragWindowHandle.hasFocus = true;
+        mDragWindowHandle.hasWallpaper = false;
+        mDragWindowHandle.paused = false;
+        mDragWindowHandle.ownerPid = Process.myPid();
+        mDragWindowHandle.ownerUid = Process.myUid();
+        mDragWindowHandle.inputFeatures = 0;
+        mDragWindowHandle.scaleFactor = 1.0f;
+
+        // The drag window cannot receive new touches.
+        mDragWindowHandle.touchableRegion.setEmpty();
+
+        // The drag window covers the entire display
+        mDragWindowHandle.frameLeft = 0;
+        mDragWindowHandle.frameTop = 0;
+        final Point p = new Point();
+        mDisplay.getRealSize(p);
+        mDragWindowHandle.frameRight = p.x;
+        mDragWindowHandle.frameBottom = p.y;
+
+        // Pause rotations before a drag.
+        if (WindowManagerService.DEBUG_ORIENTATION) {
+            Slog.d(TAG, "Pausing rotation during re-position");
+        }
+        mService.pauseRotationLocked();
+    }
+
+    void unregister() {
+        if (DEBUG_TASK_POSITIONING) {
+            Slog.d(TAG, "Unregistering task positioner");
+        }
+
+        if (mClientChannel == null) {
+            Slog.e(TAG, "Task positioner not registered");
+            return;
+        }
+
+        mService.mInputManager.unregisterInputChannel(mServerChannel);
+
+        mInputEventReceiver.dispose();
+        mInputEventReceiver = null;
+        mClientChannel.dispose();
+        mServerChannel.dispose();
+        mClientChannel = null;
+        mServerChannel = null;
+
+        mDragWindowHandle = null;
+        mDragApplicationHandle = null;
+        mDisplay = null;
+
+        // Resume rotations after a drag.
+        if (WindowManagerService.DEBUG_ORIENTATION) {
+            Slog.d(TAG, "Resuming rotation after re-position");
+        }
+        mService.resumeRotationLocked();
+    }
+
+    void startDragLocked(WindowState win, boolean resize, float startX, float startY) {
+        if (DEBUG_TASK_POSITIONING) {Slog.d(TAG,
+                "startDragLocked: win=" + win + ", resize=" + resize
+                + ", {" + startX + ", " + startY + "}");
+        }
+        mCtrlType = CTRL_NONE;
+        if (resize) {
+            final Rect visibleFrame = win.mVisibleFrame;
+            if (startX < visibleFrame.left) {
+                mCtrlType |= CTRL_LEFT;
+            }
+            if (startX > visibleFrame.right) {
+                mCtrlType |= CTRL_RIGHT;
+            }
+            if (startY < visibleFrame.top) {
+                mCtrlType |= CTRL_TOP;
+            }
+            if (startY > visibleFrame.bottom) {
+                mCtrlType |= CTRL_BOTTOM;
+            }
+        }
+
+        final Task task = win.getTask();
+        mTaskId = task.mTaskId;
+        mStartDragX = startX;
+        mStartDragY = startY;
+
+        mService.getTaskBounds(mTaskId, mWindowOriginalBounds);
+    }
+
+    private void notifyMoveLocked(float x, float y) {
+        if (DEBUG_TASK_POSITIONING) {
+            Slog.d(TAG, "notifyMoveLw: {" + x + "," + y + "}");
+        }
+
+        if (mCtrlType != CTRL_NONE) {
+            // This is a resizing operation.
+            final int deltaX = Math.round(x - mStartDragX);
+            final int deltaY = Math.round(y - mStartDragY);
+            // TODO: fix the min sizes when we have mininum width/height support,
+            //       use hard-coded min sizes for now.
+            final int minSizeX = (int)(dipToPx(96));
+            final int minSizeY = (int)(dipToPx(64));
+            int left = mWindowOriginalBounds.left;
+            int top = mWindowOriginalBounds.top;
+            int right = mWindowOriginalBounds.right;
+            int bottom = mWindowOriginalBounds.bottom;
+            if ((mCtrlType & CTRL_LEFT) != 0) {
+                left = Math.min(left + deltaX, right - minSizeX);
+            }
+            if ((mCtrlType & CTRL_TOP) != 0) {
+                top = Math.min(top + deltaY, bottom - minSizeY);
+            }
+            if ((mCtrlType & CTRL_RIGHT) != 0) {
+                right = Math.max(left + minSizeX, right + deltaX);
+            }
+            if ((mCtrlType & CTRL_BOTTOM) != 0) {
+                bottom = Math.max(top + minSizeY, bottom + deltaY);
+            }
+            mWindowDragBounds.set(left, top, right, bottom);
+        } else {
+            // This is a moving operation.
+            mWindowDragBounds.set(mWindowOriginalBounds);
+            mWindowDragBounds.offset(Math.round(x - mStartDragX),
+                    Math.round(y - mStartDragY));
+        }
+    }
+
+    private int getDragLayerLocked() {
+        return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_DRAG)
+                * WindowManagerService.TYPE_LAYER_MULTIPLIER
+                + WindowManagerService.TYPE_LAYER_OFFSET;
+    }
+
+    private float dipToPx(float dip) {
+        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, mDisplayMetrics);
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index f21f00a..ae3bb9b 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -25,7 +25,6 @@
 import android.os.Debug;
 import android.os.RemoteException;
 import android.util.EventLog;
-import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.DisplayInfo;
@@ -34,7 +33,6 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.List;
 
 public class TaskStack implements DimLayer.DimLayerUser {
 
@@ -95,6 +93,11 @@
         }
     }
 
+    boolean allowTaskResize() {
+        return mStackId == FREEFORM_WORKSPACE_STACK_ID
+                || mStackId == DOCKED_STACK_ID;
+    }
+
     /**
      * Set the bounds of the stack and its containing tasks.
      * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
@@ -414,7 +417,7 @@
             }
         }
         if (doAnotherLayoutPass) {
-            mService.requestTraversalLocked();
+            mService.mWindowPlacerLocked.requestTraversal();
         }
 
         if (mStackId == DOCKED_STACK_ID) {
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index c97d12f..ce1b785 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -47,12 +47,23 @@
     public void onPointerEvent(MotionEvent motionEvent) {
         final int action = motionEvent.getAction();
         switch (action & MotionEvent.ACTION_MASK) {
-            case MotionEvent.ACTION_DOWN:
+            case MotionEvent.ACTION_DOWN: {
                 mPointerId = motionEvent.getPointerId(0);
                 mDownX = motionEvent.getX();
                 mDownY = motionEvent.getY();
+
+                final int x = (int) mDownX;
+                final int y = (int) mDownY;
+                synchronized (this) {
+                    if (!mTouchExcludeRegion.contains(x, y)) {
+                        mService.mH.obtainMessage(H.TAP_DOWN_OUTSIDE_TASK, x, y,
+                                mDisplayContent).sendToTarget();
+                    }
+                }
                 break;
-            case MotionEvent.ACTION_MOVE:
+            }
+
+            case MotionEvent.ACTION_MOVE: {
                 if (mPointerId >= 0) {
                     int index = motionEvent.findPointerIndex(mPointerId);
                     if ((motionEvent.getEventTime() - motionEvent.getDownTime()) > TAP_TIMEOUT_MSEC
@@ -63,6 +74,8 @@
                     }
                 }
                 break;
+            }
+
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_POINTER_UP: {
                 int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK)
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index b334a05..ab1bf20 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -57,6 +57,7 @@
     final WindowManagerService mService;
     final Context mContext;
     final WindowManagerPolicy mPolicy;
+    private final WindowSurfacePlacer mWindowPlacerLocked;
 
     /** Is any window animating? */
     boolean mAnimating;
@@ -112,6 +113,7 @@
         mService = service;
         mContext = service.mContext;
         mPolicy = service.mPolicy;
+        mWindowPlacerLocked = service.mWindowPlacerLocked;
 
         mAnimationFrameCallback = new Choreographer.FrameCallback() {
             public void doFrame(long frameTimeNs) {
@@ -300,7 +302,7 @@
                     setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
                             WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                     if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                        mService.mWindowPlacerLocked.debugLayoutRepeats(
+                        mWindowPlacerLocked.debugLayoutRepeats(
                                 "updateWindowsAndWallpaperLocked 2",
                                 getPendingLayoutChanges(Display.DEFAULT_DISPLAY));
                     }
@@ -315,7 +317,7 @@
                         setPendingLayoutChanges(displayId,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                            mService.mWindowPlacerLocked.debugLayoutRepeats(
+                            mWindowPlacerLocked.debugLayoutRepeats(
                                     "updateWindowsAndWallpaperLocked 3",
                                     getPendingLayoutChanges(displayId));
                         }
@@ -410,7 +412,7 @@
                         setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                            mService.mWindowPlacerLocked.debugLayoutRepeats(
+                            mWindowPlacerLocked.debugLayoutRepeats(
                                     "updateWindowsAndWallpaperLocked 4",
                                     getPendingLayoutChanges(Display.DEFAULT_DISPLAY));
                         }
@@ -435,7 +437,7 @@
                         setPendingLayoutChanges(displayId,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                            mService.mWindowPlacerLocked.debugLayoutRepeats(
+                            mWindowPlacerLocked.debugLayoutRepeats(
                                     "updateWindowsAndWallpaperLocked 5",
                                     getPendingLayoutChanges(displayId));
                         }
@@ -741,15 +743,15 @@
 
         boolean doRequest = false;
         if (mBulkUpdateParams != 0) {
-            doRequest = mService.mWindowPlacerLocked.copyAnimToLayoutParamsLocked();
+            doRequest = mWindowPlacerLocked.copyAnimToLayoutParamsLocked();
         }
 
         if (hasPendingLayoutChanges || doRequest) {
-            mService.requestTraversalLocked();
+            mWindowPlacerLocked.requestTraversal();
         }
 
         if (!mAnimating && wasAnimating) {
-            mService.requestTraversalLocked();
+            mWindowPlacerLocked.requestTraversal();
         }
         if (WindowManagerService.DEBUG_WINDOW_TRACE) {
             Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
@@ -850,7 +852,7 @@
             if (displayId == windows.get(i).getDisplayId()) {
                 setPendingLayoutChanges(displayId, changes);
                 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                    mService.mWindowPlacerLocked.debugLayoutRepeats(reason,
+                    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 1ccb592..69440b8 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -207,6 +207,7 @@
     static final boolean DEBUG_SURFACE_TRACE = false;
     static final boolean DEBUG_WINDOW_TRACE = false;
     static final boolean DEBUG_TASK_MOVEMENT = false;
+    static final boolean DEBUG_TASK_POSITIONING = false;
     static final boolean DEBUG_STACK = false;
     static final boolean DEBUG_DISPLAY = false;
     static final boolean DEBUG_POWER = false;
@@ -471,7 +472,6 @@
     int mSystemDecorLayer = 0;
     final Rect mScreenRect = new Rect();
 
-    boolean mTraversalScheduled = false;
     boolean mDisplayFrozen = false;
     long mDisplayFreezeTime = 0;
     int mLastDisplayFreezeDuration = 0;
@@ -599,6 +599,7 @@
     // Whether or not a layout can cause a wake up when theater mode is enabled.
     boolean mAllowTheaterModeWakeFromLayout;
 
+    TaskPositioner mTaskPositioner;
     DragState mDragState = null;
 
     // For frozen screen animations.
@@ -1790,7 +1791,7 @@
                 }
                 if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
                     // No need for this guy!
-                    if (localLOGV) Slog.v(
+                    if (DEBUG_STARTING_WINDOW || localLOGV) Slog.v(
                             TAG, "**** NO NEED TO START: " + attrs.getTitle());
                     return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
                 }
@@ -2773,7 +2774,7 @@
                     if (displayContent != null) {
                         displayContent.layoutNeeded = true;
                     }
-                    requestTraversalLocked();
+                    mWindowPlacerLocked.requestTraversal();
                 }
             }
         } finally {
@@ -3472,35 +3473,12 @@
                 "prepareAppTransition()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
         }
-
         synchronized(mWindowMap) {
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:"
-                    + " transit=" + AppTransition.appTransitionToString(transit)
-                    + " " + mAppTransition
-                    + " alwaysKeepCurrent=" + alwaysKeepCurrent
-                    + " Callers=" + Debug.getCallers(3));
-            if (!mAppTransition.isTransitionSet() || mAppTransition.isTransitionNone()) {
-                mAppTransition.setAppTransition(transit);
-            } else if (!alwaysKeepCurrent) {
-                if (transit == AppTransition.TRANSIT_TASK_OPEN
-                        && mAppTransition.isTransitionEqual(
-                                AppTransition.TRANSIT_TASK_CLOSE)) {
-                    // Opening a new task always supersedes a close for the anim.
-                    mAppTransition.setAppTransition(transit);
-                } else if (transit == AppTransition.TRANSIT_ACTIVITY_OPEN
-                        && mAppTransition.isTransitionEqual(
-                            AppTransition.TRANSIT_ACTIVITY_CLOSE)) {
-                    // Opening a new activity always supersedes a close for the anim.
-                    mAppTransition.setAppTransition(transit);
-                }
-            }
-            if (okToDisplay() && mAppTransition.prepare()) {
+            boolean prepared = mAppTransition.prepareAppTransitionLocked(
+                    transit, alwaysKeepCurrent);
+            if (prepared && okToDisplay()) {
                 mSkipAppTransitionAnimation = false;
             }
-            if (mAppTransition.isTransitionSet()) {
-                mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
-                mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, 5000);
-            }
         }
     }
 
@@ -3836,7 +3814,7 @@
             if (atoken != null) {
                 atoken.appFullscreen = toOpaque;
                 setWindowOpaqueLocked(token, toOpaque);
-                requestTraversalLocked();
+                mWindowPlacerLocked.requestTraversal();
             }
         }
     }
@@ -4660,8 +4638,12 @@
                 throw new IllegalArgumentException("resizeTask: taskId " + taskId
                         + " not found.");
             }
-            if (task.setBounds(bounds, configuration)) {
-                task.resizeWindows();
+            final int boundsChanged = task.setBounds(bounds, configuration);
+            if (boundsChanged != Task.BOUNDS_CHANGE_NONE) {
+                if ((boundsChanged & Task.BOUNDS_CHANGE_SIZE) == Task.BOUNDS_CHANGE_SIZE) {
+                    task.resizeWindows();
+                }
+
                 if (relayout) {
                     task.getDisplayContent().layoutNeeded = true;
                     mWindowPlacerLocked.performSurfacePlacement();
@@ -4841,7 +4823,7 @@
             mAnimator.mKeyguardGoingAway = true;
             mAnimator.mKeyguardGoingAwayToNotificationShade = keyguardGoingToNotificationShade;
             mAnimator.mKeyguardGoingAwayDisableWindowAnimations = disableWindowAnimations;
-            requestTraversalLocked();
+            mWindowPlacerLocked.requestTraversal();
         }
     }
 
@@ -6841,6 +6823,88 @@
         }
     }
 
+    boolean startMovingTask(IWindow window, float startX, float startY) {
+        WindowState callingWin = null;
+        synchronized (mWindowMap) {
+            callingWin = windowForClientLocked(null, window, false);
+            if (!startPositioningLocked(callingWin, false /*resize*/, startX, startY)) {
+                return false;
+            }
+        }
+        try {
+            mActivityManager.setFocusedTask(callingWin.getTask().mTaskId);
+        } catch(RemoteException e) {}
+        return true;
+    }
+
+    private void startResizingTask(DisplayContent displayContent, int startX, int startY) {
+        int taskId = -1;
+        AppWindowToken atoken = null;
+        synchronized (mWindowMap) {
+            taskId = displayContent.taskIdForControlPoint(startX, startY);
+            Task task = mTaskIdToTask.get(taskId);
+            if (task == null || task.mAppTokens == null) {
+                return;
+            }
+            AppTokenList tokens = task.mAppTokens;
+            atoken = tokens.get(tokens.size() - 1);
+            WindowState win = atoken.findMainWindow();
+            if (!startPositioningLocked(win, true /*resize*/, startX, startY)) {
+                return;
+            }
+        }
+        try {
+            mActivityManager.setFocusedTask(taskId);
+        } catch(RemoteException e) {}
+    }
+
+    private boolean startPositioningLocked(
+            WindowState win, boolean resize, float startX, float startY) {
+        if (WindowManagerService.DEBUG_TASK_POSITIONING) {
+            Slog.d(TAG, "startPositioningLocked: win=" + win +
+                    ", resize=" + resize + ", {" + startX + ", " + startY + "}");
+        }
+        if (win == null || win.getAppToken() == null || !win.inFreeformWorkspace()) {
+            Slog.w(TAG, "startPositioningLocked: Bad window " + win);
+            return false;
+        }
+
+        final DisplayContent displayContent = win.getDisplayContent();
+        if (displayContent == null) {
+            Slog.w(TAG, "startPositioningLocked: Invalid display content " + win);
+            return false;
+        }
+
+        Display display = displayContent.getDisplay();
+        mTaskPositioner = new TaskPositioner(this);
+        mTaskPositioner.register(display);
+        mInputMonitor.updateInputWindowsLw(true /*force*/);
+        if (!mInputManager.transferTouchFocus(
+                win.mInputChannel, mTaskPositioner.mServerChannel)) {
+            Slog.e(TAG, "startPositioningLocked: Unable to transfer touch focus");
+            mTaskPositioner.unregister();
+            mTaskPositioner = null;
+            mInputMonitor.updateInputWindowsLw(true /*force*/);
+            return false;
+        }
+
+        mTaskPositioner.startDragLocked(win, resize, startX, startY);
+        return true;
+    }
+
+    private void finishPositioning() {
+        if (WindowManagerService.DEBUG_TASK_POSITIONING) {
+            Slog.d(TAG, "finishPositioning");
+        }
+        synchronized (mWindowMap) {
+            if (mTaskPositioner != null) {
+                mTaskPositioner.unregister();
+                mTaskPositioner = null;
+                mInputMonitor.updateInputWindowsLw(true /*force*/);
+            }
+        }
+    }
+
     // -------------------------------------------------------------
     // Drag and drop
     // -------------------------------------------------------------
@@ -7106,6 +7170,9 @@
         public static final int RESET_ANR_MESSAGE = 38;
         public static final int WALLPAPER_DRAW_PENDING_TIMEOUT = 39;
 
+        public static final int TAP_DOWN_OUTSIDE_TASK = 40;
+        public static final int FINISH_TASK_POSITIONING = 41;
+
         @Override
         public void handleMessage(Message msg) {
             if (DEBUG_WINDOW_TRACE) {
@@ -7180,7 +7247,6 @@
 
                 case DO_TRAVERSAL: {
                     synchronized(mWindowMap) {
-                        mTraversalScheduled = false;
                         mWindowPlacerLocked.performSurfacePlacement();
                     }
                 } break;
@@ -7567,6 +7633,17 @@
                     }
                 }
                 break;
+
+                case TAP_DOWN_OUTSIDE_TASK: {
+                    startResizingTask((DisplayContent)msg.obj, msg.arg1, msg.arg2);
+                }
+                break;
+
+                case FINISH_TASK_POSITIONING: {
+                    finishPositioning();
+                }
+                break;
+
                 case NOTIFY_ACTIVITY_DRAWN:
                     try {
                         mActivityManager.notifyActivityDrawn((IBinder) msg.obj);
@@ -8463,14 +8540,7 @@
 
     void requestTraversal() {
         synchronized (mWindowMap) {
-            requestTraversalLocked();
-        }
-    }
-
-    void requestTraversalLocked() {
-        if (!mTraversalScheduled) {
-            mTraversalScheduled = true;
-            mH.sendEmptyMessage(H.DO_TRAVERSAL);
+            mWindowPlacerLocked.requestTraversal();
         }
     }
 
@@ -9334,6 +9404,7 @@
             if (mInputMethodWindow != null) {
                 pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
             }
+            mWindowPlacerLocked.dump(pw, "  ");
             mWallpaperControllerLocked.dump(pw, "  ");
             if (mInputMethodAnimLayerAdjustment != 0 ||
                     mWallpaperControllerLocked.getAnimLayerAdjustment() != 0) {
@@ -9369,8 +9440,7 @@
                     pw.print(" window="); pw.print(mWindowAnimationScaleSetting);
                     pw.print(" transition="); pw.print(mTransitionAnimationScaleSetting);
                     pw.print(" animator="); pw.println(mAnimatorDurationScaleSetting);
-            pw.print("  mTraversalScheduled="); pw.println(mTraversalScheduled);
-            pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
+            pw.print(" mSkipAppTransitionAnimation=");pw.println(mSkipAppTransitionAnimation);
             pw.println("  mLayoutToAnim:");
             mAppTransition.dump(pw, "    ");
         }
@@ -9728,7 +9798,7 @@
                 createDisplayContentLocked(display);
                 displayReady(displayId);
             }
-            requestTraversalLocked();
+            mWindowPlacerLocked.requestTraversal();
         }
     }
 
@@ -9751,7 +9821,7 @@
             }
         }
         mAnimator.removeDisplayLocked(displayId);
-        requestTraversalLocked();
+        mWindowPlacerLocked.requestTraversal();
     }
 
     public void onDisplayChanged(int displayId) {
@@ -9763,7 +9833,7 @@
         if (displayContent != null) {
             displayContent.updateDisplayInfo();
         }
-        requestTraversalLocked();
+        mWindowPlacerLocked.requestTraversal();
     }
 
     @Override
@@ -9910,7 +9980,7 @@
                         }
                     }
                 }
-                requestTraversalLocked();
+                mWindowPlacerLocked.requestTraversal();
             }
             mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
             if (mWaitingForDrawn.isEmpty()) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d756d39..789354d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -86,7 +86,7 @@
 
     // The thickness of a window resize handle outside the window bounds on the free form workspace
     // to capture touch events in that area.
-    private static final int RESIZE_HANDLE_WIDTH_IN_DP = 10;
+    static final int RESIZE_HANDLE_WIDTH_IN_DP = 10;
 
     static final boolean BOUNDS_FOR_TOUCH = true;
 
@@ -1640,7 +1640,7 @@
             Slog.w(TAG, "Failed to report 'resized' to the client of " + this
                     + ", removing this window.");
             mService.mPendingRemove.add(this);
-            mService.requestTraversalLocked();
+            mService.mWindowPlacerLocked.requestTraversal();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 066dc95..bf1ab8f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1446,7 +1446,7 @@
         updateSurfaceWindowCrop(recoveringMemory);
     }
 
-    public void prepareSurfaceLocked(final boolean recoveringMemory) {
+    void prepareSurfaceLocked(final boolean recoveringMemory) {
         final WindowState w = mWin;
         if (mSurfaceControl == null) {
             if (w.mOrientationChanging) {
@@ -1782,17 +1782,14 @@
      *
      * @return Returns true if the surface was successfully shown.
      */
-    boolean showSurfaceRobustlyLocked() {
+    private boolean showSurfaceRobustlyLocked() {
         try {
-            if (mSurfaceControl != null) {
-                mSurfaceShown = true;
-                mSurfaceControl.show();
-                if (mWin.mTurnOnScreen) {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG,
-                            "Show surface turning screen on: " + mWin);
-                    mWin.mTurnOnScreen = false;
-                    mAnimator.mBulkUpdateParams |= SET_TURN_ON_SCREEN;
-                }
+            mSurfaceShown = true;
+            mSurfaceControl.show();
+            if (mWin.mTurnOnScreen) {
+                if (DEBUG_VISIBILITY) Slog.v(TAG, "Show surface turning screen on: " + mWin);
+                mWin.mTurnOnScreen = false;
+                mAnimator.mBulkUpdateParams |= SET_TURN_ON_SCREEN;
             }
             return true;
         } catch (RuntimeException e) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 8582ca2..52efa68 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -57,6 +57,7 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 
 /**
@@ -108,6 +109,8 @@
 
     private int mPreferredModeId = 0;
 
+    private boolean mTraversalScheduled;
+
     public WindowSurfacePlacer(WindowManagerService service) {
         mService = service;
         mWallpaperControllerLocked = mService.mWallpaperControllerLocked;
@@ -116,11 +119,11 @@
     final void performSurfacePlacement() {
         int loopCount = 6;
         do {
-            mService.mTraversalScheduled = false;
+            mTraversalScheduled = false;
             performSurfacePlacementLoop();
             mService.mH.removeMessages(DO_TRAVERSAL);
             loopCount--;
-        } while (mService.mTraversalScheduled && loopCount > 0);
+        } while (mTraversalScheduled && loopCount > 0);
         mWallpaperActionPending = false;
     }
 
@@ -177,7 +180,7 @@
 
             if (mService.needsLayout()) {
                 if (++mLayoutRepeatCount < 6) {
-                    mService.requestTraversalLocked();
+                    requestTraversal();
                 } else {
                     Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
                     mLayoutRepeatCount = 0;
@@ -257,290 +260,7 @@
                 ">>> 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();
+            applySurfaceChangesTransaction(recoveringMemory, numDisplays, defaultDw, defaultDh);
         } catch (RuntimeException e) {
             Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
         } finally {
@@ -801,6 +521,279 @@
         }
     }
 
+    private void applySurfaceChangesTransaction(boolean recoveringMemory, int numDisplays,
+            int defaultDw, int defaultDh) {
+        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 (int 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();
+
+            for (int i = windows.size() - 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();
+    }
+
     boolean isInLayout() {
         return mInLayout;
     }
@@ -1514,4 +1507,15 @@
 
         return doRequest;
     }
+
+    void requestTraversal() {
+        if (!mTraversalScheduled) {
+            mTraversalScheduled = true;
+            mService.mH.sendEmptyMessage(DO_TRAVERSAL);
+        }
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("mTraversalScheduled="); pw.println(mTraversalScheduled);
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6d7343d..67e5703 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1132,7 +1132,7 @@
         updateScreenCaptureDisabledInWindowManager(userHandle, false /* default value */);
     }
 
-    void loadDeviceOwner() {
+    void loadOwners() {
         synchronized (this) {
             mOwners.load();
             updateDeviceOwnerLocked();
@@ -1790,7 +1790,7 @@
 
     private void onLockSettingsReady() {
         getUserData(UserHandle.USER_OWNER);
-        loadDeviceOwner();
+        loadOwners();
         cleanUpOldUsers();
         // Register an observer for watching for user setup complete.
         new SetupContentObserver(mHandler).register(mContext.getContentResolver());
@@ -4685,7 +4685,10 @@
             throw new IllegalStateException("Trying to set the device owner, but device owner "
                     + "is already set.");
         }
-        // STOPSHIP Make sure the DO user is running
+        if (!mUserManager.isUserRunning(new UserHandle(userId))) {
+            throw new IllegalStateException("User not running: " + userId);
+        }
+
         int callingUid = Binder.getCallingUid();
         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
             if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
@@ -4705,12 +4708,8 @@
                 }
             }
             return;
-        } else {
-            // STOPSHIP check the caller UID with userId
         }
-        if (mUserManager.isUserRunning(new UserHandle(userId))) {
-            throw new IllegalStateException("User not running: " + userId);
-        }
+        // STOPSHIP check the caller UID with userId
 
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 0f20dde..f9aa124 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -82,7 +82,7 @@
         mAms.addAccountExplicitly(a31, "p31", null);
         mAms.addAccountExplicitly(a32, "p32", null);
 
-        Account[] accounts = mAms.getAccounts(null);
+        Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
         Arrays.sort(accounts, new AccountSorter());
         assertEquals(6, accounts.length);
         assertEquals(a11, accounts[0]);
@@ -92,7 +92,7 @@
         assertEquals(a22, accounts[4]);
         assertEquals(a32, accounts[5]);
 
-        accounts = mAms.getAccounts("type1" );
+        accounts = mAms.getAccounts("type1", mContext.getOpPackageName());
         Arrays.sort(accounts, new AccountSorter());
         assertEquals(3, accounts.length);
         assertEquals(a11, accounts[0]);
@@ -101,7 +101,7 @@
 
         mAms.removeAccountInternal(a21);
 
-        accounts = mAms.getAccounts("type1" );
+        accounts = mAms.getAccounts("type1", mContext.getOpPackageName());
         Arrays.sort(accounts, new AccountSorter());
         assertEquals(2, accounts.length);
         assertEquals(a11, accounts[0]);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index b021e80..0c3f9da 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -235,7 +235,8 @@
         final StorageManager storageManager = StorageManager.from(mContext);
         final StorageVolume primary = storageManager.getPrimaryVolume();
         massStorageSupported = primary != null && primary.allowMassStorage();
-        mUseUsbNotification = !massStorageSupported;
+        mUseUsbNotification = !massStorageSupported && mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_usbChargingMessage);
 
         // make sure the ADB_ENABLED setting value matches the current state
         try {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index aa750ef..b868832 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -78,6 +78,15 @@
     public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
 
     /**
+     * Flag to require or skip entitlement checks.
+     * If true, entitlement checks will be executed if device has been configured for it,
+     * If false, entitlement checks will be skipped.
+     * @hide
+     */
+    public static final String
+            KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
+
+    /**
      * If true, enable vibration (haptic feedback) for key presses in the EmergencyDialer activity.
      * The pattern is set on a per-platform basis using config_virtualKeyVibePattern. To be
      * consistent with the regular Dialer, this value should agree with the corresponding values
@@ -274,6 +283,27 @@
             = "carrier_use_ims_first_for_emergency_bool";
 
     /**
+     * When IMS instant lettering is available for a carrier (see
+     * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines the list of characters
+     * which may not be contained in messages.  Should be specified as a regular expression suitable
+     * for use with {@link String#matches(String)}.
+     * @hide
+     */
+    public static final String KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING =
+            "carrier_instant_lettering_invalid_chars_string";
+
+    /**
+     * When IMS instant lettering is available for a carrier (see
+     * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines a list of characters which
+     * must be escaped with a backslash '\' character.  Should be specified as a string containing
+     * the characters to be escaped.  For example to escape quote and backslash the string would be
+     * a quote and a backslash.
+     * @hide
+     */
+    public static final String KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING =
+            "carrier_instant_lettering_escaped_chars_string";
+
+    /**
      * If Voice Radio Technology is RIL_RADIO_TECHNOLOGY_LTE:14 or RIL_RADIO_TECHNOLOGY_UNKNOWN:0
      * this is the value that should be used instead. A configuration value of
      * RIL_RADIO_TECHNOLOGY_UNKNOWN:0 means there is no replacement value and that the default
@@ -354,6 +384,14 @@
      * sends out successive DTMF tones on the network.
      * @hide
      */
+    public static final String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
+
+    /**
+     * Specifies the amount of gap to be added in millis between DTMF tones. When a non-zero value
+     * is specified, the UE shall wait for the specified amount of time before it sends out
+     * successive DTMF tones on the network.
+     * @hide
+     */
     public static final String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
 
     /**
@@ -378,6 +416,18 @@
     public static final String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
 
     /**
+     * Determine whether IMS apn can be shown.
+     * @hide
+     */
+    public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
+
+    /**
+     * Determine whether preferred network type can be shown.
+     * @hide
+     */
+    public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
+
+    /**
      * If this is true, the SIM card (through Customer Service Profile EF file) will be able to
      * prevent manual operator selection. If false, this SIM setting will be ignored and manual
      * operator selection will always be available. See CPHS4_2.WW6, CPHS B.4.7.1 for more
@@ -448,6 +498,8 @@
         sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL, true);
+        sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING, "");
+        sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING, "");
         sDefaults.putBoolean(KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL, false);
         sDefaults.putBoolean(KEY_DTMF_TYPE_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL, true);
@@ -468,6 +520,7 @@
         sDefaults.putBoolean(KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL, false);
         sDefaults.putBoolean(KEY_VOICE_PRIVACY_DISABLE_UI_BOOL, false);
         sDefaults.putBoolean(KEY_WORLD_PHONE_BOOL, false);
+        sDefaults.putBoolean(KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
         sDefaults.putInt(KEY_VOLTE_REPLACEMENT_RAT_INT, 0);
         sDefaults.putString(KEY_DEFAULT_SIM_CALL_MANAGER_STRING, "");
         sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, "");
@@ -485,10 +538,13 @@
         sDefaults.putStringArray(KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putBoolean(KEY_FORCE_HOME_NETWORK_BOOL, false);
+        sDefaults.putInt(KEY_GSM_DTMF_TONE_DELAY_INT, 0);
         sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
         sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
         sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
+        sDefaults.putBoolean(KEY_HIDE_IMS_APN_BOOL, false);
+        sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false);
 
         // MMS defaults
         sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index cbe7c5d..c29bb48 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -66,6 +66,7 @@
           mErrorOnMissingConfigEntry(false), mOutputTextSymbols(NULL),
           mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL),
           mBuildSharedLibrary(false),
+          mBuildAppAsSharedLibrary(false),
           mArgc(0), mArgv(NULL)
         {}
     ~Bundle(void) {}
@@ -206,6 +207,8 @@
     void setSingleCrunchOutputFile(const char* val) { mSingleCrunchOutputFile = val; }
     bool getBuildSharedLibrary() const { return mBuildSharedLibrary; }
     void setBuildSharedLibrary(bool val) { mBuildSharedLibrary = val; }
+    bool getBuildAppAsSharedLibrary() const { return mBuildAppAsSharedLibrary; }
+    void setBuildAppAsSharedLibrary(bool val) { mBuildAppAsSharedLibrary = val; }
     void setNoVersionVectors(bool val) { mNoVersionVectors = val; }
     bool getNoVersionVectors() const { return mNoVersionVectors; }
 
@@ -327,6 +330,7 @@
     const char* mSingleCrunchInputFile;
     const char* mSingleCrunchOutputFile;
     bool        mBuildSharedLibrary;
+    bool        mBuildAppAsSharedLibrary;
     android::String8 mPlatformVersionCode;
     android::String8 mPlatformVersionName;
 
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index d12ab3b..21f47bc2 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -2395,11 +2395,11 @@
             // Write the R.java file into the appropriate class directory
             // e.g. gen/com/foo/app/R.java
             err = writeResourceSymbols(bundle, assets, assets->getPackage(), true,
-                    bundle->getBuildSharedLibrary());
+                    bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
         } else {
             const String8 customPkg(bundle->getCustomPackage());
             err = writeResourceSymbols(bundle, assets, customPkg, true,
-                    bundle->getBuildSharedLibrary());
+                    bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
         }
         if (err < 0) {
             goto bail;
@@ -2414,7 +2414,7 @@
             while (packageString != NULL) {
                 // Write the R.java file out with the correct package name
                 err = writeResourceSymbols(bundle, assets, String8(packageString), true,
-                        bundle->getBuildSharedLibrary());
+                        bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary());
                 if (err < 0) {
                     goto bail;
                 }
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index bcf0d5e5..6411286 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -200,6 +200,9 @@
         "   --shared-lib\n"
         "       Make a shared library resource package that can be loaded by an application\n"
         "       at runtime to access the libraries resources. Implies --non-constant-id.\n"
+        "   --app-as-shared-lib\n"
+        "       Make an app resource package that also can be loaded as shared library at runtime.\n"
+        "       Implies --non-constant-id.\n"
         "   --error-on-failed-insert\n"
         "       Forces aapt to return an error if it fails to insert values into the manifest\n"
         "       with --debug-mode, --min-sdk-version, --target-sdk-version --version-code\n"
@@ -668,6 +671,9 @@
                 } else if (strcmp(cp, "-shared-lib") == 0) {
                     bundle.setNonConstantId(true);
                     bundle.setBuildSharedLibrary(true);
+                } else if (strcmp(cp, "-app-as-shared-lib") == 0) {
+                    bundle.setNonConstantId(true);
+                    bundle.setBuildAppAsSharedLibrary(true);
                 } else if (strcmp(cp, "-no-crunch") == 0) {
                     bundle.setUseCrunchCache(true);
                 } else if (strcmp(cp, "-ignore-assets") == 0) {
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index a4e5d3d..e22e76d 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -2120,7 +2120,7 @@
     size_t N = symbols->getSymbols().size();
     for (i=0; i<N; i++) {
         const AaptSymbolEntry& sym = symbols->getSymbols().valueAt(i);
-        if (sym.typeCode == AaptSymbolEntry::TYPE_UNKNOWN) {
+        if (sym.typeCode != AaptSymbolEntry::TYPE_INT32) {
             continue;
         }
         if (!assets->isJavaSymbol(sym, includePrivate)) {
diff --git a/tools/aidl b/tools/aidl
new file mode 100644
index 0000000..8a42fa0
--- /dev/null
+++ b/tools/aidl
@@ -0,0 +1,4 @@
+Where has aidl gone?
+
+  aidl has moved to //system/tools/aidl as part of adding support for
+  generating bindings in C++.
diff --git a/tools/aidl/AST.cpp b/tools/aidl/AST.cpp
deleted file mode 100644
index bfa6765..0000000
--- a/tools/aidl/AST.cpp
+++ /dev/null
@@ -1,912 +0,0 @@
-#include "AST.h"
-#include "Type.h"
-
-void
-WriteModifiers(FILE* to, int mod, int mask)
-{
-    int m = mod & mask;
-
-    if (m & OVERRIDE) {
-        fprintf(to, "@Override ");
-    }
-
-    if ((m & SCOPE_MASK) == PUBLIC) {
-        fprintf(to, "public ");
-    }
-    else if ((m & SCOPE_MASK) == PRIVATE) {
-        fprintf(to, "private ");
-    }
-    else if ((m & SCOPE_MASK) == PROTECTED) {
-        fprintf(to, "protected ");
-    }
-
-    if (m & STATIC) {
-        fprintf(to, "static ");
-    }
-    
-    if (m & FINAL) {
-        fprintf(to, "final ");
-    }
-
-    if (m & ABSTRACT) {
-        fprintf(to, "abstract ");
-    }
-}
-
-void
-WriteArgumentList(FILE* to, const vector<Expression*>& arguments)
-{
-    size_t N = arguments.size();
-    for (size_t i=0; i<N; i++) {
-        arguments[i]->Write(to);
-        if (i != N-1) {
-            fprintf(to, ", ");
-        }
-    }
-}
-
-ClassElement::ClassElement()
-{
-}
-
-ClassElement::~ClassElement()
-{
-}
-
-Field::Field()
-    :ClassElement(),
-     modifiers(0),
-     variable(NULL)
-{
-}
-
-Field::Field(int m, Variable* v)
-    :ClassElement(),
-     modifiers(m),
-     variable(v)
-{
-}
-
-Field::~Field()
-{
-}
-
-void
-Field::GatherTypes(set<Type*>* types) const
-{
-    types->insert(this->variable->type);
-}
-
-void
-Field::Write(FILE* to)
-{
-    if (this->comment.length() != 0) {
-        fprintf(to, "%s\n", this->comment.c_str());
-    }
-    WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | FINAL | OVERRIDE);
-    fprintf(to, "%s %s", this->variable->type->QualifiedName().c_str(),
-            this->variable->name.c_str());
-    if (this->value.length() != 0) {
-        fprintf(to, " = %s", this->value.c_str());
-    }
-    fprintf(to, ";\n");
-}
-
-Expression::~Expression()
-{
-}
-
-LiteralExpression::LiteralExpression(const string& v)
-    :value(v)
-{
-}
-
-LiteralExpression::~LiteralExpression()
-{
-}
-
-void
-LiteralExpression::Write(FILE* to)
-{
-    fprintf(to, "%s", this->value.c_str());
-}
-
-StringLiteralExpression::StringLiteralExpression(const string& v)
-    :value(v)
-{
-}
-
-StringLiteralExpression::~StringLiteralExpression()
-{
-}
-
-void
-StringLiteralExpression::Write(FILE* to)
-{
-    fprintf(to, "\"%s\"", this->value.c_str());
-}
-
-Variable::Variable()
-    :type(NULL),
-     name(),
-     dimension(0)
-{
-}
-
-Variable::Variable(Type* t, const string& n)
-    :type(t),
-     name(n),
-     dimension(0)
-{
-}
-
-Variable::Variable(Type* t, const string& n, int d)
-    :type(t),
-     name(n),
-     dimension(d)
-{
-}
-
-Variable::~Variable()
-{
-}
-
-void
-Variable::GatherTypes(set<Type*>* types) const
-{
-    types->insert(this->type);
-}
-
-void
-Variable::WriteDeclaration(FILE* to)
-{
-    string dim;
-    for (int i=0; i<this->dimension; i++) {
-        dim += "[]";
-    }
-    fprintf(to, "%s%s %s", this->type->QualifiedName().c_str(), dim.c_str(),
-            this->name.c_str());
-}
-
-void
-Variable::Write(FILE* to)
-{
-    fprintf(to, "%s", name.c_str());
-}
-
-FieldVariable::FieldVariable(Expression* o, const string& n)
-    :object(o),
-     clazz(NULL),
-     name(n)
-{
-}
-
-FieldVariable::FieldVariable(Type* c, const string& n)
-    :object(NULL),
-     clazz(c),
-     name(n)
-{
-}
-
-FieldVariable::~FieldVariable()
-{
-}
-
-void
-FieldVariable::Write(FILE* to)
-{
-    if (this->object != NULL) {
-        this->object->Write(to);
-    }
-    else if (this->clazz != NULL) {
-        fprintf(to, "%s", this->clazz->QualifiedName().c_str());
-    }
-    fprintf(to, ".%s", name.c_str());
-}
-
-
-Statement::~Statement()
-{
-}
-
-StatementBlock::StatementBlock()
-{
-}
-
-StatementBlock::~StatementBlock()
-{
-}
-
-void
-StatementBlock::Write(FILE* to)
-{
-    fprintf(to, "{\n");
-    int N = this->statements.size();
-    for (int i=0; i<N; i++) {
-        this->statements[i]->Write(to);
-    }
-    fprintf(to, "}\n");
-}
-
-void
-StatementBlock::Add(Statement* statement)
-{
-    this->statements.push_back(statement);
-}
-
-void
-StatementBlock::Add(Expression* expression)
-{
-    this->statements.push_back(new ExpressionStatement(expression));
-}
-
-ExpressionStatement::ExpressionStatement(Expression* e)
-    :expression(e)
-{
-}
-
-ExpressionStatement::~ExpressionStatement()
-{
-}
-
-void
-ExpressionStatement::Write(FILE* to)
-{
-    this->expression->Write(to);
-    fprintf(to, ";\n");
-}
-
-Assignment::Assignment(Variable* l, Expression* r)
-    :lvalue(l),
-     rvalue(r),
-     cast(NULL)
-{
-}
-
-Assignment::Assignment(Variable* l, Expression* r, Type* c)
-    :lvalue(l),
-     rvalue(r),
-     cast(c)
-{
-}
-
-Assignment::~Assignment()
-{
-}
-
-void
-Assignment::Write(FILE* to)
-{
-    this->lvalue->Write(to);
-    fprintf(to, " = ");
-    if (this->cast != NULL) {
-        fprintf(to, "(%s)", this->cast->QualifiedName().c_str());
-    }
-    this->rvalue->Write(to);
-}
-
-MethodCall::MethodCall(const string& n)
-    :obj(NULL),
-     clazz(NULL),
-     name(n)
-{
-}
-
-MethodCall::MethodCall(const string& n, int argc = 0, ...)
-    :obj(NULL),
-     clazz(NULL),
-     name(n)
-{
-  va_list args;
-  va_start(args, argc);
-  init(argc, args);
-  va_end(args);
-}
-
-MethodCall::MethodCall(Expression* o, const string& n)
-    :obj(o),
-     clazz(NULL),
-     name(n)
-{
-}
-
-MethodCall::MethodCall(Type* t, const string& n)
-    :obj(NULL),
-     clazz(t),
-     name(n)
-{
-}
-
-MethodCall::MethodCall(Expression* o, const string& n, int argc = 0, ...)
-    :obj(o),
-     clazz(NULL),
-     name(n)
-{
-  va_list args;
-  va_start(args, argc);
-  init(argc, args);
-  va_end(args);
-}
-
-MethodCall::MethodCall(Type* t, const string& n, int argc = 0, ...)
-    :obj(NULL),
-     clazz(t),
-     name(n)
-{
-  va_list args;
-  va_start(args, argc);
-  init(argc, args);
-  va_end(args);
-}
-
-MethodCall::~MethodCall()
-{
-}
-
-void
-MethodCall::init(int n, va_list args)
-{
-    for (int i=0; i<n; i++) {
-        Expression* expression = (Expression*)va_arg(args, void*);
-        this->arguments.push_back(expression);
-    }
-}
-
-void
-MethodCall::Write(FILE* to)
-{
-    if (this->obj != NULL) {
-        this->obj->Write(to);
-        fprintf(to, ".");
-    }
-    else if (this->clazz != NULL) {
-        fprintf(to, "%s.", this->clazz->QualifiedName().c_str());
-    }
-    fprintf(to, "%s(", this->name.c_str());
-    WriteArgumentList(to, this->arguments);
-    fprintf(to, ")");
-}
-
-Comparison::Comparison(Expression* l, const string& o, Expression* r)
-    :lvalue(l),
-     op(o),
-     rvalue(r)
-{
-}
-
-Comparison::~Comparison()
-{
-}
-
-void
-Comparison::Write(FILE* to)
-{
-    fprintf(to, "(");
-    this->lvalue->Write(to);
-    fprintf(to, "%s", this->op.c_str());
-    this->rvalue->Write(to);
-    fprintf(to, ")");
-}
-
-NewExpression::NewExpression(Type* t)
-    :type(t)
-{
-}
-
-NewExpression::NewExpression(Type* t, int argc = 0, ...)
-    :type(t)
-{
-  va_list args;
-  va_start(args, argc);
-  init(argc, args);
-  va_end(args);
-}
-
-NewExpression::~NewExpression()
-{
-}
-
-void
-NewExpression::init(int n, va_list args)
-{
-    for (int i=0; i<n; i++) {
-        Expression* expression = (Expression*)va_arg(args, void*);
-        this->arguments.push_back(expression);
-    }
-}
-
-void
-NewExpression::Write(FILE* to)
-{
-    fprintf(to, "new %s(", this->type->InstantiableName().c_str());
-    WriteArgumentList(to, this->arguments);
-    fprintf(to, ")");
-}
-
-NewArrayExpression::NewArrayExpression(Type* t, Expression* s)
-    :type(t),
-     size(s)
-{
-}
-
-NewArrayExpression::~NewArrayExpression()
-{
-}
-
-void
-NewArrayExpression::Write(FILE* to)
-{
-    fprintf(to, "new %s[", this->type->QualifiedName().c_str());
-    size->Write(to);
-    fprintf(to, "]");
-}
-
-Ternary::Ternary()
-    :condition(NULL),
-     ifpart(NULL),
-     elsepart(NULL)
-{
-}
-
-Ternary::Ternary(Expression* a, Expression* b, Expression* c)
-    :condition(a),
-     ifpart(b),
-     elsepart(c)
-{
-}
-
-Ternary::~Ternary()
-{
-}
-
-void
-Ternary::Write(FILE* to)
-{
-    fprintf(to, "((");
-    this->condition->Write(to);
-    fprintf(to, ")?(");
-    this->ifpart->Write(to);
-    fprintf(to, "):(");
-    this->elsepart->Write(to);
-    fprintf(to, "))");
-}
-
-Cast::Cast()
-    :type(NULL),
-     expression(NULL)
-{
-}
-
-Cast::Cast(Type* t, Expression* e)
-    :type(t),
-     expression(e)
-{
-}
-
-Cast::~Cast()
-{
-}
-
-void
-Cast::Write(FILE* to)
-{
-    fprintf(to, "((%s)", this->type->QualifiedName().c_str());
-    expression->Write(to);
-    fprintf(to, ")");
-}
-
-VariableDeclaration::VariableDeclaration(Variable* l, Expression* r, Type* c)
-    :lvalue(l),
-     cast(c),
-     rvalue(r)
-{
-}
-
-VariableDeclaration::VariableDeclaration(Variable* l)
-    :lvalue(l),
-     cast(NULL),
-     rvalue(NULL)
-{
-}
-
-VariableDeclaration::~VariableDeclaration()
-{
-}
-
-void
-VariableDeclaration::Write(FILE* to)
-{
-    this->lvalue->WriteDeclaration(to);
-    if (this->rvalue != NULL) {
-        fprintf(to, " = ");
-        if (this->cast != NULL) {
-            fprintf(to, "(%s)", this->cast->QualifiedName().c_str());
-        }
-        this->rvalue->Write(to);
-    }
-    fprintf(to, ";\n");
-}
-
-IfStatement::IfStatement()
-    :expression(NULL),
-     statements(new StatementBlock),
-     elseif(NULL)
-{
-}
-
-IfStatement::~IfStatement()
-{
-}
-
-void
-IfStatement::Write(FILE* to)
-{
-    if (this->expression != NULL) {
-        fprintf(to, "if (");
-        this->expression->Write(to);
-        fprintf(to, ") ");
-    }
-    this->statements->Write(to);
-    if (this->elseif != NULL) {
-        fprintf(to, "else ");
-        this->elseif->Write(to);
-    }
-}
-
-ReturnStatement::ReturnStatement(Expression* e)
-    :expression(e)
-{
-}
-
-ReturnStatement::~ReturnStatement()
-{
-}
-
-void
-ReturnStatement::Write(FILE* to)
-{
-    fprintf(to, "return ");
-    this->expression->Write(to);
-    fprintf(to, ";\n");
-}
-
-TryStatement::TryStatement()
-    :statements(new StatementBlock)
-{
-}
-
-TryStatement::~TryStatement()
-{
-}
-
-void
-TryStatement::Write(FILE* to)
-{
-    fprintf(to, "try ");
-    this->statements->Write(to);
-}
-
-CatchStatement::CatchStatement(Variable* e)
-    :statements(new StatementBlock),
-     exception(e)
-{
-}
-
-CatchStatement::~CatchStatement()
-{
-}
-
-void
-CatchStatement::Write(FILE* to)
-{
-    fprintf(to, "catch ");
-    if (this->exception != NULL) {
-        fprintf(to, "(");
-        this->exception->WriteDeclaration(to);
-        fprintf(to, ") ");
-    }
-    this->statements->Write(to);
-}
-
-FinallyStatement::FinallyStatement()
-    :statements(new StatementBlock)
-{
-}
-
-FinallyStatement::~FinallyStatement()
-{
-}
-
-void
-FinallyStatement::Write(FILE* to)
-{
-    fprintf(to, "finally ");
-    this->statements->Write(to);
-}
-
-Case::Case()
-    :statements(new StatementBlock)
-{
-}
-
-Case::Case(const string& c)
-    :statements(new StatementBlock)
-{
-    cases.push_back(c);
-}
-
-Case::~Case()
-{
-}
-
-void
-Case::Write(FILE* to)
-{
-    int N = this->cases.size();
-    if (N > 0) {
-        for (int i=0; i<N; i++) {
-            string s = this->cases[i];
-            if (s.length() != 0) {
-                fprintf(to, "case %s:\n", s.c_str());
-            } else {
-                fprintf(to, "default:\n");
-            }
-        }
-    } else {
-        fprintf(to, "default:\n");
-    }
-    statements->Write(to);
-}
-
-SwitchStatement::SwitchStatement(Expression* e)
-    :expression(e)
-{
-}
-
-SwitchStatement::~SwitchStatement()
-{
-}
-
-void
-SwitchStatement::Write(FILE* to)
-{
-    fprintf(to, "switch (");
-    this->expression->Write(to);
-    fprintf(to, ")\n{\n");
-    int N = this->cases.size();
-    for (int i=0; i<N; i++) {
-        this->cases[i]->Write(to);
-    }
-    fprintf(to, "}\n");
-}
-
-Break::Break()
-{
-}
-
-Break::~Break()
-{
-}
-
-void
-Break::Write(FILE* to)
-{
-    fprintf(to, "break;\n");
-}
-
-Method::Method()
-    :ClassElement(),
-     modifiers(0),
-     returnType(NULL), // (NULL means constructor)
-     returnTypeDimension(0),
-     statements(NULL)
-{
-}
-
-Method::~Method()
-{
-}
-
-void
-Method::GatherTypes(set<Type*>* types) const
-{
-    size_t N, i;
-
-    if (this->returnType) {
-        types->insert(this->returnType);
-    }
-
-    N = this->parameters.size();
-    for (i=0; i<N; i++) {
-        this->parameters[i]->GatherTypes(types);
-    }
-
-    N = this->exceptions.size();
-    for (i=0; i<N; i++) {
-        types->insert(this->exceptions[i]);
-    }
-}
-
-void
-Method::Write(FILE* to)
-{
-    size_t N, i;
-
-    if (this->comment.length() != 0) {
-        fprintf(to, "%s\n", this->comment.c_str());
-    }
-
-    WriteModifiers(to, this->modifiers, SCOPE_MASK | STATIC | ABSTRACT | FINAL | OVERRIDE);
-
-    if (this->returnType != NULL) {
-        string dim;
-        for (i=0; i<this->returnTypeDimension; i++) {
-            dim += "[]";
-        }
-        fprintf(to, "%s%s ", this->returnType->QualifiedName().c_str(),
-                dim.c_str());
-    }
-   
-    fprintf(to, "%s(", this->name.c_str());
-
-    N = this->parameters.size();
-    for (i=0; i<N; i++) {
-        this->parameters[i]->WriteDeclaration(to);
-        if (i != N-1) {
-            fprintf(to, ", ");
-        }
-    }
-
-    fprintf(to, ")");
-
-    N = this->exceptions.size();
-    for (i=0; i<N; i++) {
-        if (i == 0) {
-            fprintf(to, " throws ");
-        } else {
-            fprintf(to, ", ");
-        }
-        fprintf(to, "%s", this->exceptions[i]->QualifiedName().c_str());
-    }
-
-    if (this->statements == NULL) {
-        fprintf(to, ";\n");
-    } else {
-        fprintf(to, "\n");
-        this->statements->Write(to);
-    }
-}
-
-Class::Class()
-    :modifiers(0),
-     what(CLASS),
-     type(NULL),
-     extends(NULL)
-{
-}
-
-Class::~Class()
-{
-}
-
-void
-Class::GatherTypes(set<Type*>* types) const
-{
-    int N, i;
-
-    types->insert(this->type);
-    if (this->extends != NULL) {
-        types->insert(this->extends);
-    }
-
-    N = this->interfaces.size();
-    for (i=0; i<N; i++) {
-        types->insert(this->interfaces[i]);
-    }
-
-    N = this->elements.size();
-    for (i=0; i<N; i++) {
-        this->elements[i]->GatherTypes(types);
-    }
-}
-
-void
-Class::Write(FILE* to)
-{
-    size_t N, i;
-
-    if (this->comment.length() != 0) {
-        fprintf(to, "%s\n", this->comment.c_str());
-    }
-
-    WriteModifiers(to, this->modifiers, ALL_MODIFIERS);
-
-    if (this->what == Class::CLASS) {
-        fprintf(to, "class ");
-    } else {
-        fprintf(to, "interface ");
-    }
-
-    string name = this->type->Name();
-    size_t pos = name.rfind('.');
-    if (pos != string::npos) {
-        name = name.c_str() + pos + 1;
-    }
-
-    fprintf(to, "%s", name.c_str());
-
-    if (this->extends != NULL) {
-        fprintf(to, " extends %s", this->extends->QualifiedName().c_str());
-    }
-
-    N = this->interfaces.size();
-    if (N != 0) {
-        if (this->what == Class::CLASS) {
-            fprintf(to, " implements");
-        } else {
-            fprintf(to, " extends");
-        }
-        for (i=0; i<N; i++) {
-            fprintf(to, " %s", this->interfaces[i]->QualifiedName().c_str());
-        }
-    }
-
-    fprintf(to, "\n");
-    fprintf(to, "{\n");
-
-    N = this->elements.size();
-    for (i=0; i<N; i++) {
-        this->elements[i]->Write(to);
-    }
-
-    fprintf(to, "}\n");
-
-}
-
-Document::Document()
-{
-}
-
-Document::~Document()
-{
-}
-
-static string
-escape_backslashes(const string& str)
-{
-    string result;
-    const size_t I=str.length();
-    for (size_t i=0; i<I; i++) {
-        char c = str[i];
-        if (c == '\\') {
-            result += "\\\\";
-        } else {
-            result += c;
-        }
-    }
-    return result;
-}
-
-void
-Document::Write(FILE* to)
-{
-    size_t N, i;
-
-    if (this->comment.length() != 0) {
-        fprintf(to, "%s\n", this->comment.c_str());
-    }
-    fprintf(to, "/*\n"
-                " * This file is auto-generated.  DO NOT MODIFY.\n"
-                " * Original file: %s\n"
-                " */\n", escape_backslashes(this->originalSrc).c_str());
-    if (this->package.length() != 0) {
-        fprintf(to, "package %s;\n", this->package.c_str());
-    }
-
-    N = this->classes.size();
-    for (i=0; i<N; i++) {
-        Class* c = this->classes[i];
-        c->Write(to);
-    }
-}
-
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
deleted file mode 100644
index d7bfccb..0000000
--- a/tools/aidl/AST.h
+++ /dev/null
@@ -1,371 +0,0 @@
-#ifndef AIDL_AST_H_
-#define AIDL_AST_H_
-
-#include <string>
-#include <vector>
-#include <set>
-#include <stdarg.h>
-#include <stdio.h>
-
-using namespace std;
-
-class Type;
-
-enum {
-    PACKAGE_PRIVATE = 0x00000000,
-    PUBLIC          = 0x00000001,
-    PRIVATE         = 0x00000002,
-    PROTECTED       = 0x00000003,
-    SCOPE_MASK      = 0x00000003,
-
-    STATIC          = 0x00000010,
-    FINAL           = 0x00000020,
-    ABSTRACT        = 0x00000040,
-
-    OVERRIDE        = 0x00000100,
-
-    ALL_MODIFIERS   = 0xffffffff
-};
-
-// Write the modifiers that are set in both mod and mask
-void WriteModifiers(FILE* to, int mod, int mask);
-
-struct ClassElement
-{
-    ClassElement();
-    virtual ~ClassElement();
-
-    virtual void GatherTypes(set<Type*>* types) const = 0;
-    virtual void Write(FILE* to) = 0;
-};
-
-struct Expression
-{
-    virtual ~Expression();
-    virtual void Write(FILE* to) = 0;
-};
-
-struct LiteralExpression : public Expression
-{
-    string value;
-
-    LiteralExpression(const string& value);
-    virtual ~LiteralExpression();
-    virtual void Write(FILE* to);
-};
-
-// TODO: also escape the contents.  not needed for now
-struct StringLiteralExpression : public Expression
-{
-    string value;
-
-    StringLiteralExpression(const string& value);
-    virtual ~StringLiteralExpression();
-    virtual void Write(FILE* to);
-};
-
-struct Variable : public Expression
-{
-    Type* type;
-    string name;
-    int dimension;
-
-    Variable();
-    Variable(Type* type, const string& name);
-    Variable(Type* type, const string& name, int dimension);
-    virtual ~Variable();
-
-    virtual void GatherTypes(set<Type*>* types) const;
-    void WriteDeclaration(FILE* to);
-    void Write(FILE* to);
-};
-
-struct FieldVariable : public Expression
-{
-    Expression* object;
-    Type* clazz;
-    string name;
-
-    FieldVariable(Expression* object, const string& name);
-    FieldVariable(Type* clazz, const string& name);
-    virtual ~FieldVariable();
-
-    void Write(FILE* to);
-};
-
-struct Field : public ClassElement
-{
-    string comment;
-    int modifiers;
-    Variable *variable;
-    string value;
-
-    Field();
-    Field(int modifiers, Variable* variable);
-    virtual ~Field();
-
-    virtual void GatherTypes(set<Type*>* types) const;
-    virtual void Write(FILE* to);
-};
-
-struct Statement
-{
-    virtual ~Statement();
-    virtual void Write(FILE* to) = 0;
-};
-
-struct StatementBlock : public Statement
-{
-    vector<Statement*> statements;
-
-    StatementBlock();
-    virtual ~StatementBlock();
-    virtual void Write(FILE* to);
-
-    void Add(Statement* statement);
-    void Add(Expression* expression);
-};
-
-struct ExpressionStatement : public Statement
-{
-    Expression* expression;
-
-    ExpressionStatement(Expression* expression);
-    virtual ~ExpressionStatement();
-    virtual void Write(FILE* to);
-};
-
-struct Assignment : public Expression
-{
-    Variable* lvalue;
-    Expression* rvalue;
-    Type* cast;
-
-    Assignment(Variable* lvalue, Expression* rvalue);
-    Assignment(Variable* lvalue, Expression* rvalue, Type* cast);
-    virtual ~Assignment();
-    virtual void Write(FILE* to);
-};
-
-struct MethodCall : public Expression
-{
-    Expression* obj;
-    Type* clazz;
-    string name;
-    vector<Expression*> arguments;
-    vector<string> exceptions;
-
-    MethodCall(const string& name);
-    MethodCall(const string& name, int argc, ...);
-    MethodCall(Expression* obj, const string& name);
-    MethodCall(Type* clazz, const string& name);
-    MethodCall(Expression* obj, const string& name, int argc, ...);
-    MethodCall(Type* clazz, const string& name, int argc, ...);
-    virtual ~MethodCall();
-    virtual void Write(FILE* to);
-
-private:
-    void init(int n, va_list args);
-};
-
-struct Comparison : public Expression
-{
-    Expression* lvalue;
-    string op;
-    Expression* rvalue;
-
-    Comparison(Expression* lvalue, const string& op, Expression* rvalue);
-    virtual ~Comparison();
-    virtual void Write(FILE* to);
-};
-
-struct NewExpression : public Expression
-{
-    Type* type;
-    vector<Expression*> arguments;
-
-    NewExpression(Type* type);
-    NewExpression(Type* type, int argc, ...);
-    virtual ~NewExpression();
-    virtual void Write(FILE* to);
-
-private:
-    void init(int n, va_list args);
-};
-
-struct NewArrayExpression : public Expression
-{
-    Type* type;
-    Expression* size;
-
-    NewArrayExpression(Type* type, Expression* size);
-    virtual ~NewArrayExpression();
-    virtual void Write(FILE* to);
-};
-
-struct Ternary : public Expression
-{
-    Expression* condition;
-    Expression* ifpart;
-    Expression* elsepart;
-
-    Ternary();
-    Ternary(Expression* condition, Expression* ifpart, Expression* elsepart);
-    virtual ~Ternary();
-    virtual void Write(FILE* to);
-};
-
-struct Cast : public Expression
-{
-    Type* type;
-    Expression* expression;
-
-    Cast();
-    Cast(Type* type, Expression* expression);
-    virtual ~Cast();
-    virtual void Write(FILE* to);
-};
-
-struct VariableDeclaration : public Statement
-{
-    Variable* lvalue;
-    Type* cast;
-    Expression* rvalue;
-
-    VariableDeclaration(Variable* lvalue);
-    VariableDeclaration(Variable* lvalue, Expression* rvalue, Type* cast = NULL);
-    virtual ~VariableDeclaration();
-    virtual void Write(FILE* to);
-};
-
-struct IfStatement : public Statement
-{
-    Expression* expression;
-    StatementBlock* statements;
-    IfStatement* elseif;
-
-    IfStatement();
-    virtual ~IfStatement();
-    virtual void Write(FILE* to);
-};
-
-struct ReturnStatement : public Statement
-{
-    Expression* expression;
-
-    ReturnStatement(Expression* expression);
-    virtual ~ReturnStatement();
-    virtual void Write(FILE* to);
-};
-
-struct TryStatement : public Statement
-{
-    StatementBlock* statements;
-
-    TryStatement();
-    virtual ~TryStatement();
-    virtual void Write(FILE* to);
-};
-
-struct CatchStatement : public Statement
-{
-    StatementBlock* statements;
-    Variable* exception;
-
-    CatchStatement(Variable* exception);
-    virtual ~CatchStatement();
-    virtual void Write(FILE* to);
-};
-
-struct FinallyStatement : public Statement
-{
-    StatementBlock* statements;
-
-    FinallyStatement();
-    virtual ~FinallyStatement();
-    virtual void Write(FILE* to);
-};
-
-struct Case
-{
-    vector<string> cases;
-    StatementBlock* statements;
-
-    Case();
-    Case(const string& c);
-    virtual ~Case();
-    virtual void Write(FILE* to);
-};
-
-struct SwitchStatement : public Statement
-{
-    Expression* expression;
-    vector<Case*> cases;
-
-    SwitchStatement(Expression* expression);
-    virtual ~SwitchStatement();
-    virtual void Write(FILE* to);
-};
-
-struct Break : public Statement
-{
-    Break();
-    virtual ~Break();
-    virtual void Write(FILE* to);
-};
-
-struct Method : public ClassElement
-{
-    string comment;
-    int modifiers;
-    Type* returnType;
-    size_t returnTypeDimension;
-    string name;
-    vector<Variable*> parameters;
-    vector<Type*> exceptions;
-    StatementBlock* statements;
-
-    Method();
-    virtual ~Method();
-
-    virtual void GatherTypes(set<Type*>* types) const;
-    virtual void Write(FILE* to);
-};
-
-struct Class : public ClassElement
-{
-    enum {
-        CLASS,
-        INTERFACE
-    };
-
-    string comment;
-    int modifiers;
-    int what;               // CLASS or INTERFACE
-    Type* type;
-    Type* extends;
-    vector<Type*> interfaces;
-    vector<ClassElement*> elements;
-
-    Class();
-    virtual ~Class();
-
-    virtual void GatherTypes(set<Type*>* types) const;
-    virtual void Write(FILE* to);
-};
-
-struct Document
-{
-    string comment;
-    string package;
-    string originalSrc;
-    set<Type*> imports;
-    vector<Class*> classes;
-
-    Document();
-    virtual ~Document();
-
-    virtual void Write(FILE* to);
-};
-
-#endif // AIDL_AST_H_
diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk
deleted file mode 100644
index d11264e..0000000
--- a/tools/aidl/Android.mk
+++ /dev/null
@@ -1,80 +0,0 @@
-# Copyright 2007 The Android Open Source Project
-#
-# Copies files into the directory structure described by a manifest
-
-# This tool is prebuilt if we're doing an app-only build.
-ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
-
-LOCAL_PATH:= $(call my-dir)
-
-# Logic shared between aidl and its unittests
-include $(CLEAR_VARS)
-LOCAL_MODULE := libaidl-common
-LOCAL_MODULE_HOST_OS := darwin linux windows
-
-LOCAL_CLANG_CFLAGS := -Wall -Werror
-# Tragically, the code is riddled with unused parameters.
-LOCAL_CLANG_CFLAGS += -Wno-unused-parameter
-# yacc dumps a lot of code *just in case*.
-LOCAL_CLANG_CFLAGS += -Wno-unused-function
-LOCAL_CLANG_CFLAGS += -Wno-unneeded-internal-declaration
-# yacc is a tool from a more civilized age.
-LOCAL_CLANG_CFLAGS += -Wno-deprecated-register
-# yacc also has a habit of using char* over const char*.
-LOCAL_CLANG_CFLAGS += -Wno-writable-strings
-
-LOCAL_SRC_FILES := \
-    AST.cpp \
-    Type.cpp \
-    aidl.cpp \
-    aidl_language.cpp \
-    aidl_language_l.l \
-    aidl_language_y.y \
-    generate_java.cpp \
-    generate_java_binder.cpp \
-    options.cpp \
-    search_path.cpp \
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
-# aidl executable
-include $(CLEAR_VARS)
-LOCAL_MODULE := aidl
-
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_SRC_FILES := main.cpp
-LOCAL_STATIC_LIBRARIES := libaidl-common
-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/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_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/NOTICE b/tools/aidl/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/tools/aidl/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   Copyright (c) 2005-2008, 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.
-
-   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.
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
deleted file mode 100644
index d9b8b88..0000000
--- a/tools/aidl/Type.cpp
+++ /dev/null
@@ -1,1245 +0,0 @@
-#include "Type.h"
-
-#include <sys/types.h>
-
-Namespace NAMES;
-
-Type* VOID_TYPE;
-Type* BOOLEAN_TYPE;
-Type* BYTE_TYPE;
-Type* CHAR_TYPE;
-Type* INT_TYPE;
-Type* LONG_TYPE;
-Type* FLOAT_TYPE;
-Type* DOUBLE_TYPE;
-Type* STRING_TYPE;
-Type* OBJECT_TYPE;
-Type* CHAR_SEQUENCE_TYPE;
-Type* TEXT_UTILS_TYPE;
-Type* REMOTE_EXCEPTION_TYPE;
-Type* RUNTIME_EXCEPTION_TYPE;
-Type* IBINDER_TYPE;
-Type* IINTERFACE_TYPE;
-Type* BINDER_NATIVE_TYPE;
-Type* BINDER_PROXY_TYPE;
-Type* PARCEL_TYPE;
-Type* PARCELABLE_INTERFACE_TYPE;
-Type* CONTEXT_TYPE;
-Type* MAP_TYPE;
-Type* LIST_TYPE;
-Type* CLASSLOADER_TYPE;
-
-Expression* NULL_VALUE;
-Expression* THIS_VALUE;
-Expression* SUPER_VALUE;
-Expression* TRUE_VALUE;
-Expression* FALSE_VALUE;
-
-void
-register_base_types()
-{
-    VOID_TYPE = new BasicType("void",
-            "XXX", "XXX", "XXX", "XXX", "XXX");
-    NAMES.Add(VOID_TYPE);
-
-    BOOLEAN_TYPE = new BooleanType();
-    NAMES.Add(BOOLEAN_TYPE);
-
-    BYTE_TYPE = new BasicType("byte",
-            "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");
-    NAMES.Add(INT_TYPE);
-
-    LONG_TYPE = new BasicType("long",
-            "writeLong", "readLong", "writeLongArray", "createLongArray",
-            "readLongArray");
-    NAMES.Add(LONG_TYPE);
-
-    FLOAT_TYPE = new BasicType("float",
-            "writeFloat", "readFloat", "writeFloatArray", "createFloatArray",
-            "readFloatArray");
-    NAMES.Add(FLOAT_TYPE);
-
-    DOUBLE_TYPE = new BasicType("double",
-            "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);
-    NAMES.Add(OBJECT_TYPE);
-
-    CHAR_SEQUENCE_TYPE = new CharSequenceType();
-    NAMES.Add(CHAR_SEQUENCE_TYPE);
-
-    MAP_TYPE = new MapType();
-    NAMES.Add(MAP_TYPE);
-
-    LIST_TYPE = new ListType();
-    NAMES.Add(LIST_TYPE);
-
-    TEXT_UTILS_TYPE = new Type("android.text", "TextUtils", Type::BUILT_IN, false, false);
-    NAMES.Add(TEXT_UTILS_TYPE);
-
-    REMOTE_EXCEPTION_TYPE = new RemoteExceptionType();
-    NAMES.Add(REMOTE_EXCEPTION_TYPE);
-
-    RUNTIME_EXCEPTION_TYPE = new RuntimeExceptionType();
-    NAMES.Add(RUNTIME_EXCEPTION_TYPE);
-
-    IBINDER_TYPE = new IBinderType();
-    NAMES.Add(IBINDER_TYPE);
-
-    IINTERFACE_TYPE = new IInterfaceType();
-    NAMES.Add(IINTERFACE_TYPE);
-
-    BINDER_NATIVE_TYPE = new BinderType();
-    NAMES.Add(BINDER_NATIVE_TYPE);
-
-    BINDER_PROXY_TYPE = new BinderProxyType();
-    NAMES.Add(BINDER_PROXY_TYPE);
-
-    PARCEL_TYPE = new ParcelType();
-    NAMES.Add(PARCEL_TYPE);
-
-    PARCELABLE_INTERFACE_TYPE = new ParcelableInterfaceType();
-    NAMES.Add(PARCELABLE_INTERFACE_TYPE);
-
-    CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false);
-    NAMES.Add(CONTEXT_TYPE);
-
-    CLASSLOADER_TYPE = new ClassLoaderType();
-    NAMES.Add(CLASSLOADER_TYPE);
-
-    NULL_VALUE = new LiteralExpression("null");
-    THIS_VALUE = new LiteralExpression("this");
-    SUPER_VALUE = new LiteralExpression("super");
-    TRUE_VALUE = new LiteralExpression("true");
-    FALSE_VALUE = new LiteralExpression("false");
-
-    NAMES.AddGenericType("java.util", "List", 1);
-    NAMES.AddGenericType("java.util", "Map", 2);
-}
-
-static Type*
-make_generic_type(const string& package, const string& name,
-                    const vector<Type*>& args)
-{
-    if (package == "java.util" && name == "List") {
-        return new GenericListType("java.util", "List", args);
-    }
-    return NULL;
-    //return new GenericType(package, name, args);
-}
-
-// ================================================================
-
-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_canBeOut(canBeOut)
-{
-    m_qualifiedName = name;
-}
-
-Type::Type(const string& package, const string& name,
-            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_canBeOut(canBeOut)
-{
-    if (package.length() > 0) {
-        m_qualifiedName = package;
-        m_qualifiedName += '.';
-    }
-    m_qualifiedName += name;
-}
-
-Type::~Type()
-{
-}
-
-bool
-Type::CanBeArray() const
-{
-    return false;
-}
-
-string
-Type::ImportType() const
-{
-    return m_qualifiedName;
-}
-
-string
-Type::CreatorName() const
-{
-    return "";
-}
-
-string
-Type::InstantiableName() const
-{
-    return QualifiedName();
-}
-
-
-void
-Type::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%sn",
-            __FILE__, __LINE__, m_qualifiedName.c_str());
-    addTo->Add(new LiteralExpression("/* WriteToParcel error "
-                + m_qualifiedName + " */"));
-}
-
-void
-Type::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
-            __FILE__, __LINE__, m_qualifiedName.c_str());
-    addTo->Add(new LiteralExpression("/* CreateFromParcel error "
-                + m_qualifiedName + " */"));
-}
-
-void
-Type::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
-            __FILE__, __LINE__, m_qualifiedName.c_str());
-    addTo->Add(new LiteralExpression("/* ReadFromParcel error "
-                + m_qualifiedName + " */"));
-}
-
-void
-Type::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
-            __FILE__, __LINE__, m_qualifiedName.c_str());
-    addTo->Add(new LiteralExpression("/* WriteArrayToParcel error "
-                + m_qualifiedName + " */"));
-}
-
-void
-Type::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                            Variable* parcel, Variable**)
-{
-    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
-            __FILE__, __LINE__, m_qualifiedName.c_str());
-    addTo->Add(new LiteralExpression("/* CreateArrayFromParcel error "
-                + m_qualifiedName + " */"));
-}
-
-void
-Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
-            __FILE__, __LINE__, m_qualifiedName.c_str());
-    addTo->Add(new LiteralExpression("/* ReadArrayFromParcel error "
-                + m_qualifiedName + " */"));
-}
-
-void
-Type::SetQualifiedName(const string& qualified)
-{
-    m_qualifiedName = qualified;
-}
-
-Expression*
-Type::BuildWriteToParcelFlags(int flags)
-{
-    if (flags == 0) {
-        return new LiteralExpression("0");
-    }
-    if ((flags&PARCELABLE_WRITE_RETURN_VALUE) != 0) {
-        return new FieldVariable(PARCELABLE_INTERFACE_TYPE,
-                "PARCELABLE_WRITE_RETURN_VALUE");
-    }
-    return new LiteralExpression("0");
-}
-
-// ================================================================
-
-BasicType::BasicType(const string& name, const string& marshallParcel,
-          const string& unmarshallParcel, const string& writeArrayParcel,
-          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)
-{
-}
-
-void
-BasicType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    addTo->Add(new MethodCall(parcel, m_marshallParcel, 1, v));
-}
-
-void
-BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallParcel)));
-}
-
-bool
-BasicType::CanBeArray() const
-{
-    return true;
-}
-
-void
-BasicType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    addTo->Add(new MethodCall(parcel, m_writeArrayParcel, 1, v));
-}
-
-void
-BasicType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                            Variable* parcel, Variable**)
-{
-    addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayParcel)));
-}
-
-void
-BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    addTo->Add(new MethodCall(parcel, m_readArrayParcel, 1, v));
-}
-
-// ================================================================
-
-BooleanType::BooleanType()
-    :Type("boolean", BUILT_IN, true, false)
-{
-}
-
-void
-BooleanType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    addTo->Add(new MethodCall(parcel, "writeInt", 1, 
-                new Ternary(v, new LiteralExpression("1"),
-                    new LiteralExpression("0"))));
-}
-
-void
-BooleanType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    addTo->Add(new Assignment(v, new Comparison(new LiteralExpression("0"),
-                    "!=", new MethodCall(parcel, "readInt"))));
-}
-
-bool
-BooleanType::CanBeArray() const
-{
-    return true;
-}
-
-void
-BooleanType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    addTo->Add(new MethodCall(parcel, "writeBooleanArray", 1, v));
-}
-
-void
-BooleanType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                            Variable* parcel, Variable**)
-{
-    addTo->Add(new Assignment(v, new MethodCall(parcel, "createBooleanArray")));
-}
-
-void
-BooleanType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
-}
-
-// ================================================================
-
-CharType::CharType()
-    :Type("char", BUILT_IN, true, false)
-{
-}
-
-void
-CharType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    addTo->Add(new MethodCall(parcel, "writeInt", 1, 
-                    new Cast(INT_TYPE, v)));
-}
-
-void
-CharType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    addTo->Add(new Assignment(v, new MethodCall(parcel, "readInt"), this));
-}
-
-bool
-CharType::CanBeArray() const
-{
-    return true;
-}
-
-void
-CharType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    addTo->Add(new MethodCall(parcel, "writeCharArray", 1, v));
-}
-
-void
-CharType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                            Variable* parcel, Variable**)
-{
-    addTo->Add(new Assignment(v, new MethodCall(parcel, "createCharArray")));
-}
-
-void
-CharType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
-}
-
-// ================================================================
-
-StringType::StringType()
-    :Type("java.lang", "String", BUILT_IN, true, false)
-{
-}
-
-string
-StringType::CreatorName() const
-{
-    return "android.os.Parcel.STRING_CREATOR";
-}
-
-void
-StringType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    addTo->Add(new MethodCall(parcel, "writeString", 1, v));
-}
-
-void
-StringType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    addTo->Add(new Assignment(v, new MethodCall(parcel, "readString")));
-}
-
-bool
-StringType::CanBeArray() const
-{
-    return true;
-}
-
-void
-StringType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    addTo->Add(new MethodCall(parcel, "writeStringArray", 1, v));
-}
-
-void
-StringType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                            Variable* parcel, Variable**)
-{
-    addTo->Add(new Assignment(v, new MethodCall(parcel, "createStringArray")));
-}
-
-void
-StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
-}
-
-// ================================================================
-
-CharSequenceType::CharSequenceType()
-    :Type("java.lang", "CharSequence", BUILT_IN, true, false)
-{
-}
-
-string
-CharSequenceType::CreatorName() const
-{
-    return "android.os.Parcel.STRING_CREATOR";
-}
-
-void
-CharSequenceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    // if (v != null) {
-    //     parcel.writeInt(1);
-    //     v.writeToParcel(parcel);
-    // } else {
-    //     parcel.writeInt(0);
-    // }
-    IfStatement* elsepart = new IfStatement();
-    elsepart->statements->Add(new MethodCall(parcel, "writeInt", 1,
-                                new LiteralExpression("0")));
-    IfStatement* ifpart = new IfStatement;
-    ifpart->expression = new Comparison(v, "!=", NULL_VALUE);
-    ifpart->elseif = elsepart;
-    ifpart->statements->Add(new MethodCall(parcel, "writeInt", 1,
-                                new LiteralExpression("1")));
-    ifpart->statements->Add(new MethodCall(TEXT_UTILS_TYPE, "writeToParcel",
-                                3, v, parcel, BuildWriteToParcelFlags(flags)));
-
-    addTo->Add(ifpart);
-}
-
-void
-CharSequenceType::CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                Variable* parcel, Variable**)
-{
-    // if (0 != parcel.readInt()) {
-    //     v = TextUtils.createFromParcel(parcel)
-    // } else {
-    //     v = null;
-    // }
-    IfStatement* elsepart = new IfStatement();
-    elsepart->statements->Add(new Assignment(v, NULL_VALUE));
-
-    IfStatement* ifpart = new IfStatement();
-    ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
-                new MethodCall(parcel, "readInt"));
-    ifpart->elseif = elsepart;
-    ifpart->statements->Add(new Assignment(v,
-                new MethodCall(TEXT_UTILS_TYPE,
-                                    "CHAR_SEQUENCE_CREATOR.createFromParcel", 1, parcel)));
-
-    addTo->Add(ifpart);
-}
-
-
-// ================================================================
-
-RemoteExceptionType::RemoteExceptionType()
-    :Type("android.os", "RemoteException", BUILT_IN, false, false)
-{
-}
-
-void
-RemoteExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-RemoteExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-// ================================================================
-
-RuntimeExceptionType::RuntimeExceptionType()
-    :Type("java.lang", "RuntimeException", BUILT_IN, false, false)
-{
-}
-
-void
-RuntimeExceptionType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-RuntimeExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-
-// ================================================================
-
-IBinderType::IBinderType()
-    :Type("android.os", "IBinder", BUILT_IN, true, false)
-{
-}
-
-void
-IBinderType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    addTo->Add(new MethodCall(parcel, "writeStrongBinder", 1, v));
-}
-
-void
-IBinderType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    addTo->Add(new Assignment(v, new MethodCall(parcel, "readStrongBinder")));
-}
-
-void
-IBinderType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    addTo->Add(new MethodCall(parcel, "writeBinderArray", 1, v));
-}
-
-void
-IBinderType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                            Variable* parcel, Variable**)
-{
-    addTo->Add(new Assignment(v, new MethodCall(parcel, "createBinderArray")));
-}
-
-void
-IBinderType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    addTo->Add(new MethodCall(parcel, "readBinderArray", 1, v));
-}
-
-
-// ================================================================
-
-IInterfaceType::IInterfaceType()
-    :Type("android.os", "IInterface", BUILT_IN, false, false)
-{
-}
-
-void
-IInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-IInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-
-// ================================================================
-
-BinderType::BinderType()
-    :Type("android.os", "Binder", BUILT_IN, false, false)
-{
-}
-
-void
-BinderType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-BinderType::CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable**)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-
-// ================================================================
-
-BinderProxyType::BinderProxyType()
-    :Type("android.os", "BinderProxy", BUILT_IN, false, false)
-{
-}
-
-void
-BinderProxyType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-BinderProxyType::CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable**)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-
-// ================================================================
-
-ParcelType::ParcelType()
-    :Type("android.os", "Parcel", BUILT_IN, false, false)
-{
-}
-
-void
-ParcelType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-ParcelType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-// ================================================================
-
-ParcelableInterfaceType::ParcelableInterfaceType()
-    :Type("android.os", "Parcelable", BUILT_IN, false, false)
-{
-}
-
-void
-ParcelableInterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-void
-ParcelableInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
-}
-
-// ================================================================
-
-MapType::MapType()
-    :Type("java.util", "Map", BUILT_IN, true, true)
-{
-}
-
-void
-MapType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    addTo->Add(new MethodCall(parcel, "writeMap", 1, v));
-}
-
-static void EnsureClassLoader(StatementBlock* addTo, Variable** cl)
-{
-    // We don't want to look up the class loader once for every
-    // collection argument, so ensure we do it at most once per method.
-    if (*cl == NULL) {
-        *cl = new Variable(CLASSLOADER_TYPE, "cl");
-        addTo->Add(new VariableDeclaration(*cl,
-                new LiteralExpression("this.getClass().getClassLoader()"),
-                CLASSLOADER_TYPE));
-    }
-}
-
-void
-MapType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
-{
-    EnsureClassLoader(addTo, cl);
-    addTo->Add(new Assignment(v, new MethodCall(parcel, "readHashMap", 1, *cl)));
-}
-
-void
-MapType::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
-{
-    EnsureClassLoader(addTo, cl);
-    addTo->Add(new MethodCall(parcel, "readMap", 2, v, *cl));
-}
-
-
-// ================================================================
-
-ListType::ListType()
-    :Type("java.util", "List", BUILT_IN, true, true)
-{
-}
-
-string
-ListType::InstantiableName() const
-{
-    return "java.util.ArrayList";
-}
-
-void
-ListType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    addTo->Add(new MethodCall(parcel, "writeList", 1, v));
-}
-
-void
-ListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
-{
-    EnsureClassLoader(addTo, cl);
-    addTo->Add(new Assignment(v, new MethodCall(parcel, "readArrayList", 1, *cl)));
-}
-
-void
-ListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
-                    Variable* parcel, Variable** cl)
-{
-    EnsureClassLoader(addTo, cl);
-    addTo->Add(new MethodCall(parcel, "readList", 2, v, *cl));
-}
-
-// ================================================================
-
-UserDataType::UserDataType(const string& package, const string& name,
-                        bool builtIn, bool canWriteToParcel,
-                        const string& declFile, int declLine)
-    :Type(package, name, builtIn ? BUILT_IN : USERDATA, canWriteToParcel,
-            true, declFile, declLine)
-{
-}
-
-string
-UserDataType::CreatorName() const
-{
-    return QualifiedName() + ".CREATOR";
-}
-
-void
-UserDataType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    // if (v != null) {
-    //     parcel.writeInt(1);
-    //     v.writeToParcel(parcel);
-    // } else {
-    //     parcel.writeInt(0);
-    // }
-    IfStatement* elsepart = new IfStatement();
-    elsepart->statements->Add(new MethodCall(parcel, "writeInt", 1,
-                                new LiteralExpression("0")));
-    IfStatement* ifpart = new IfStatement;
-    ifpart->expression = new Comparison(v, "!=", NULL_VALUE);
-    ifpart->elseif = elsepart;
-    ifpart->statements->Add(new MethodCall(parcel, "writeInt", 1,
-                                new LiteralExpression("1")));
-    ifpart->statements->Add(new MethodCall(v, "writeToParcel", 2,
-                                parcel, BuildWriteToParcelFlags(flags)));
-
-    addTo->Add(ifpart);
-}
-
-void
-UserDataType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    // if (0 != parcel.readInt()) {
-    //     v = CLASS.CREATOR.createFromParcel(parcel)
-    // } else {
-    //     v = null;
-    // }
-    IfStatement* elsepart = new IfStatement();
-    elsepart->statements->Add(new Assignment(v, NULL_VALUE));
-
-    IfStatement* ifpart = new IfStatement();
-    ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
-                new MethodCall(parcel, "readInt"));
-    ifpart->elseif = elsepart;
-    ifpart->statements->Add(new Assignment(v,
-                new MethodCall(v->type, "CREATOR.createFromParcel", 1, parcel)));
-
-    addTo->Add(ifpart);
-}
-
-void
-UserDataType::ReadFromParcel(StatementBlock* addTo, Variable* v,
-                    Variable* parcel, Variable**)
-{
-    // TODO: really, we don't need to have this extra check, but we
-    // don't have two separate marshalling code paths
-    // if (0 != parcel.readInt()) {
-    //     v.readFromParcel(parcel)
-    // }
-    IfStatement* ifpart = new IfStatement();
-    ifpart->expression = new Comparison(new LiteralExpression("0"), "!=",
-                new MethodCall(parcel, "readInt"));
-    ifpart->statements->Add(new MethodCall(v, "readFromParcel", 1, parcel));
-    addTo->Add(ifpart);
-}
-
-bool
-UserDataType::CanBeArray() const
-{
-    return true;
-}
-
-void
-UserDataType::WriteArrayToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    addTo->Add(new MethodCall(parcel, "writeTypedArray", 2, v,
-                BuildWriteToParcelFlags(flags)));
-}
-
-void
-UserDataType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                            Variable* parcel, Variable**)
-{
-    string creator = v->type->QualifiedName() + ".CREATOR";
-    addTo->Add(new Assignment(v, new MethodCall(parcel,
-                "createTypedArray", 1, new LiteralExpression(creator))));
-}
-
-void
-UserDataType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    string creator = v->type->QualifiedName() + ".CREATOR";
-    addTo->Add(new MethodCall(parcel, "readTypedArray", 2,
-                    v, new LiteralExpression(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,
-                        declFile, declLine)
-    ,m_oneway(oneway)
-{
-}
-
-bool
-InterfaceType::OneWay() const
-{
-    return m_oneway;
-}
-
-void
-InterfaceType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    // parcel.writeStrongBinder(v != null ? v.asBinder() : null);
-    addTo->Add(new MethodCall(parcel, "writeStrongBinder", 1, 
-                new Ternary(
-                    new Comparison(v, "!=", NULL_VALUE),
-                    new MethodCall(v, "asBinder"),
-                    NULL_VALUE)));
-}
-
-void
-InterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    // v = Interface.asInterface(parcel.readStrongBinder());
-    string type = v->type->QualifiedName();
-    type += ".Stub";
-    addTo->Add(new Assignment(v,
-                new MethodCall( NAMES.Find(type), "asInterface", 1,
-                    new MethodCall(parcel, "readStrongBinder"))));
-}
-
-
-// ================================================================
-
-GenericType::GenericType(const string& package, const string& name,
-                         const vector<Type*>& args)
-    :Type(package, name, BUILT_IN, true, true)
-{
-    m_args = args;
-
-    m_importName = package + '.' + name;
-
-    string gen = "<";
-    int N = args.size();
-    for (int i=0; i<N; i++) {
-        Type* t = args[i];
-        gen += t->QualifiedName();
-        if (i != N-1) {
-            gen += ',';
-        }
-    }
-    gen += '>';
-    m_genericArguments = gen;
-    SetQualifiedName(m_importName + gen);
-}
-
-const vector<Type*>&
-GenericType::GenericArgumentTypes() const
-{
-    return m_args;
-}
-
-string
-GenericType::GenericArguments() const
-{
-    return m_genericArguments;
-}
-
-string
-GenericType::ImportType() const
-{
-    return m_importName;
-}
-
-void
-GenericType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    fprintf(stderr, "implement GenericType::WriteToParcel\n");
-}
-
-void
-GenericType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    fprintf(stderr, "implement GenericType::CreateFromParcel\n");
-}
-
-void
-GenericType::ReadFromParcel(StatementBlock* addTo, Variable* v,
-                            Variable* parcel, Variable**)
-{
-    fprintf(stderr, "implement GenericType::ReadFromParcel\n");
-}
-
-
-// ================================================================
-
-GenericListType::GenericListType(const string& package, const string& name,
-                         const vector<Type*>& args)
-    :GenericType(package, name, args),
-     m_creator(args[0]->CreatorName())
-{
-}
-
-string
-GenericListType::CreatorName() const
-{
-    return "android.os.Parcel.arrayListCreator";
-}
-
-string
-GenericListType::InstantiableName() const
-{
-    return "java.util.ArrayList" + GenericArguments();
-}
-
-void
-GenericListType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
-{
-    if (m_creator == STRING_TYPE->CreatorName()) {
-        addTo->Add(new MethodCall(parcel, "writeStringList", 1, v));
-    } else if (m_creator == IBINDER_TYPE->CreatorName()) {
-        addTo->Add(new MethodCall(parcel, "writeBinderList", 1, v));
-    } else {
-        // parcel.writeTypedListXX(arg);
-        addTo->Add(new MethodCall(parcel, "writeTypedList", 1, v));
-    }
-}
-
-void
-GenericListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
-{
-    if (m_creator == STRING_TYPE->CreatorName()) {
-        addTo->Add(new Assignment(v,
-                   new MethodCall(parcel, "createStringArrayList", 0)));
-    } else if (m_creator == IBINDER_TYPE->CreatorName()) {
-        addTo->Add(new Assignment(v,
-                   new MethodCall(parcel, "createBinderArrayList", 0)));
-    } else {
-        // v = _data.readTypedArrayList(XXX.creator);
-        addTo->Add(new Assignment(v,
-                   new MethodCall(parcel, "createTypedArrayList", 1,
-                   new LiteralExpression(m_creator))));
-    }
-}
-
-void
-GenericListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
-                            Variable* parcel, Variable**)
-{
-    if (m_creator == STRING_TYPE->CreatorName()) {
-        addTo->Add(new MethodCall(parcel, "readStringList", 1, v));
-    } else if (m_creator == IBINDER_TYPE->CreatorName()) {
-        addTo->Add(new MethodCall(parcel, "readBinderList", 1, v));
-    } else {
-        // v = _data.readTypedList(v, XXX.creator);
-        addTo->Add(new MethodCall(parcel, "readTypedList", 2,
-                       v,
-                       new LiteralExpression(m_creator)));
-    }
-}
-
-
-// ================================================================
-
-ClassLoaderType::ClassLoaderType()
-    :Type("java.lang", "ClassLoader", BUILT_IN, false, false)
-{
-}
-
-
-// ================================================================
-
-Namespace::Namespace()
-{
-}
-
-Namespace::~Namespace()
-{
-    int N = m_types.size();
-    for (int i=0; i<N; i++) {
-        delete m_types[i];
-    }
-}
-
-void
-Namespace::Add(Type* type)
-{
-    Type* t = Find(type->QualifiedName());
-    if (t == NULL) {
-        m_types.push_back(type);
-    }
-}
-
-void
-Namespace::AddGenericType(const string& package, const string& name, int args)
-{
-    Generic g;
-        g.package = package;
-        g.name = name;
-        g.qualified = package + '.' + name;
-        g.args = args;
-    m_generics.push_back(g);
-}
-
-Type*
-Namespace::Find(const string& name) const
-{
-    int N = m_types.size();
-    for (int i=0; i<N; i++) {
-        if (m_types[i]->QualifiedName() == name) {
-            return m_types[i];
-        }
-    }
-    return NULL;
-}
-
-Type*
-Namespace::Find(const char* package, const char* name) const
-{
-    string s;
-    if (package != NULL) {
-        s += package;
-        s += '.';
-    }
-    s += name;
-    return Find(s);
-}
-
-static string
-normalize_generic(const string& s)
-{
-    string r;
-    int N = s.size();
-    for (int i=0; i<N; i++) {
-        char c = s[i];
-        if (!isspace(c)) {
-            r += c;
-        }
-    }
-    return r;
-}
-
-Type*
-Namespace::Search(const string& name)
-{
-    // an exact match wins
-    Type* result = Find(name);
-    if (result != NULL) {
-        return result;
-    }
-
-    // try the class names
-    // our language doesn't allow you to not specify outer classes
-    // when referencing an inner class.  that could be changed, and this
-    // would be the place to do it, but I don't think the complexity in
-    // scoping rules is worth it.
-    int N = m_types.size();
-    for (int i=0; i<N; i++) {
-        if (m_types[i]->Name() == name) {
-            return m_types[i];
-        }
-    }
-
-    // we got to here and it's not a generic, give up
-    if (name.find('<') == name.npos) {
-        return NULL;
-    }
-
-    // remove any whitespace
-    string normalized = normalize_generic(name);
-
-    // find the part before the '<', find a generic for it
-    ssize_t baseIndex = normalized.find('<');
-    string base(normalized.c_str(), baseIndex);
-    const Generic* g = search_generic(base);
-    if (g == NULL) {
-        return NULL;
-    }
-
-    // For each of the args, do a recursive search on it.  We don't allow
-    // generics within generics like Java does, because we're really limiting
-    // them to just built-in container classes, at least for now.  Our syntax
-    // ensures this right now as well.
-    vector<Type*> args;
-    size_t start = baseIndex + 1;
-    size_t end = start;
-    while (normalized[start] != '\0') {
-        end = normalized.find(',', start);
-        if (end == normalized.npos) {
-            end = normalized.find('>', start);
-        }
-        string s(normalized.c_str()+start, end-start);
-        Type* t = this->Search(s);
-        if (t == NULL) {
-            // maybe we should print a warning here?
-            return NULL;
-        }
-        args.push_back(t);
-        start = end+1;
-    }
-
-    // construct a GenericType, add it to our name set so they always get
-    // the same object, and return it.
-    result = make_generic_type(g->package, g->name, args);
-    if (result == NULL) {
-        return NULL;
-    }
-
-    this->Add(result);
-    return this->Find(result->QualifiedName());
-}
-
-const Namespace::Generic*
-Namespace::search_generic(const string& name) const
-{
-    int N = m_generics.size();
-
-    // first exact match
-    for (int i=0; i<N; i++) {
-        const Generic& g = m_generics[i];
-        if (g.qualified == name) {
-            return &g;
-        }
-    }
-
-    // then name match
-    for (int i=0; i<N; i++) {
-        const Generic& g = m_generics[i];
-        if (g.name == name) {
-            return &g;
-        }
-    }
-
-    return NULL;
-}
-
-void
-Namespace::Dump() const
-{
-    int n = m_types.size();
-    for (int i=0; i<n; i++) {
-        Type* t = m_types[i];
-        printf("type: package=%s name=%s qualifiedName=%s\n",
-                t->Package().c_str(), t->Name().c_str(),
-                t->QualifiedName().c_str());
-    }
-}
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
deleted file mode 100644
index 6ede79a..0000000
--- a/tools/aidl/Type.h
+++ /dev/null
@@ -1,472 +0,0 @@
-#ifndef AIDL_TYPE_H_
-#define AIDL_TYPE_H_
-
-#include "AST.h"
-#include <string>
-#include <vector>
-
-using namespace std;
-
-class Type
-{
-public:
-    // kinds
-    enum {
-        BUILT_IN,
-        USERDATA,
-        INTERFACE,
-        GENERATED
-    };
-    
-    // WriteToParcel flags
-    enum {
-        PARCELABLE_WRITE_RETURN_VALUE = 0x0001
-    };
-
-                    Type(const string& name, int kind, bool canWriteToParcel,
-                         bool canBeOut);
-                    Type(const string& package, const string& name,
-                            int kind, bool canWriteToParcel, bool canBeOut,
-                            const string& declFile = "", int declLine = -1);
-    virtual         ~Type();
-
-    inline string   Package() const             { return m_package; }
-    inline string   Name() const                { return m_name; }
-    inline string   QualifiedName() const       { return m_qualifiedName; }
-    inline int      Kind() const                { return m_kind; }
-    inline string   DeclFile() const            { return m_declFile; }
-    inline int      DeclLine() const            { return m_declLine; }
-    inline bool     CanWriteToParcel() const    { return m_canWriteToParcel; }
-    inline bool     CanBeOutParameter() const   { return m_canBeOut; }
-    
-    virtual string  ImportType() const;
-    virtual string  CreatorName() const;
-    virtual string  InstantiableName() const;
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-
-    virtual bool    CanBeArray() const;
-
-    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-
-protected:
-    void SetQualifiedName(const string& qualified);
-    Expression* BuildWriteToParcelFlags(int flags);
-
-private:
-    Type();
-    Type(const Type&);
-
-    string m_package;
-    string m_name;
-    string m_qualifiedName;
-    string m_declFile;
-    int m_declLine;
-    int m_kind;
-    bool m_canWriteToParcel;
-    bool m_canBeOut;
-};
-
-class BasicType : public Type
-{
-public:
-                    BasicType(const string& name,
-                              const string& marshallParcel,
-                              const string& unmarshallParcel,
-                              const string& writeArrayParcel,
-                              const string& createArrayParcel,
-                              const string& readArrayParcel);
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-
-    virtual bool    CanBeArray() const;
-
-    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-
-private:
-    string m_marshallParcel;
-    string m_unmarshallParcel;
-    string m_writeArrayParcel;
-    string m_createArrayParcel;
-    string m_readArrayParcel;
-};
-
-class BooleanType : public Type
-{
-public:
-                    BooleanType();
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-
-    virtual bool    CanBeArray() const;
-
-    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class CharType : public Type
-{
-public:
-                    CharType();
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-
-    virtual bool    CanBeArray() const;
-
-    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-
-class StringType : public Type
-{
-public:
-                    StringType();
-
-    virtual string  CreatorName() const;
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-
-    virtual bool    CanBeArray() const;
-
-    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class CharSequenceType : public Type
-{
-public:
-                    CharSequenceType();
-
-    virtual string  CreatorName() const;
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class RemoteExceptionType : public Type
-{
-public:
-                    RemoteExceptionType();
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class RuntimeExceptionType : public Type
-{
-public:
-                    RuntimeExceptionType();
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class IBinderType : public Type
-{
-public:
-                    IBinderType();
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-
-    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class IInterfaceType : public Type
-{
-public:
-                    IInterfaceType();
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class BinderType : public Type
-{
-public:
-                    BinderType();
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class BinderProxyType : public Type
-{
-public:
-                    BinderProxyType();
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class ParcelType : public Type
-{
-public:
-                    ParcelType();
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class ParcelableInterfaceType : public Type
-{
-public:
-                    ParcelableInterfaceType();
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class MapType : public Type
-{
-public:
-                    MapType();
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class ListType : public Type
-{
-public:
-                    ListType();
-
-    virtual string  InstantiableName() const;
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class UserDataType : public Type
-{
-public:
-                    UserDataType(const string& package, const string& name,
-                            bool builtIn, bool canWriteToParcel,
-                            const string& declFile = "", int declLine = -1);
-
-    virtual string  CreatorName() const;
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-
-    virtual bool    CanBeArray() const;
-
-    virtual void    WriteArrayToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-    virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-};
-
-class InterfaceType : public Type
-{
-public:
-                    InterfaceType(const string& package, const string& name,
-                            bool builtIn, bool oneway,
-                            const string& declFile, int declLine);
-
-    bool            OneWay() const;
-    
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-                                    
-private:
-    bool m_oneway;
-};
-
-
-class GenericType : public Type
-{
-public:
-                    GenericType(const string& package, const string& name,
-                                 const vector<Type*>& args);
-
-    const vector<Type*>& GenericArgumentTypes() const;
-    string          GenericArguments() const;
-
-    virtual string  ImportType() const;
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-
-private:
-    string m_genericArguments;
-    string m_importName;
-    vector<Type*> m_args;
-};
-
-class ClassLoaderType : public Type
-{
-public:
-                    ClassLoaderType();
-};
-
-class GenericListType : public GenericType
-{
-public:
-                    GenericListType(const string& package, const string& name,
-                                 const vector<Type*>& args);
-
-    virtual string  CreatorName() const;
-    virtual string  InstantiableName() const;
-
-    virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, int flags);
-    virtual void    CreateFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-    virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
-                                    Variable* parcel, Variable** cl);
-
-private:
-    string m_creator;
-};
-
-class Namespace
-{
-public:
-            Namespace();
-            ~Namespace();
-    void    Add(Type* type);
-
-    // args is the number of template types (what is this called?)
-    void    AddGenericType(const string& package, const string& name, int args);
-
-    // lookup a specific class name
-    Type*   Find(const string& name) const;
-    Type*   Find(const char* package, const char* name) const;
-    
-    // try to search by either a full name or a partial name
-    Type*   Search(const string& name);
-
-    void    Dump() const;
-
-private:
-    struct Generic {
-        string package;
-        string name;
-        string qualified;
-        int args;
-    };
-
-    const Generic* search_generic(const string& name) const;
-
-    vector<Type*> m_types;
-    vector<Generic> m_generics;
-};
-
-extern Namespace NAMES;
-
-extern Type* VOID_TYPE;
-extern Type* BOOLEAN_TYPE;
-extern Type* BYTE_TYPE;
-extern Type* CHAR_TYPE;
-extern Type* INT_TYPE;
-extern Type* LONG_TYPE;
-extern Type* FLOAT_TYPE;
-extern Type* DOUBLE_TYPE;
-extern Type* OBJECT_TYPE;
-extern Type* STRING_TYPE;
-extern Type* CHAR_SEQUENCE_TYPE;
-extern Type* TEXT_UTILS_TYPE;
-extern Type* REMOTE_EXCEPTION_TYPE;
-extern Type* RUNTIME_EXCEPTION_TYPE;
-extern Type* IBINDER_TYPE;
-extern Type* IINTERFACE_TYPE;
-extern Type* BINDER_NATIVE_TYPE;
-extern Type* BINDER_PROXY_TYPE;
-extern Type* PARCEL_TYPE;
-extern Type* PARCELABLE_INTERFACE_TYPE;
-
-extern Type* CONTEXT_TYPE;
-
-extern Expression* NULL_VALUE;
-extern Expression* THIS_VALUE;
-extern Expression* SUPER_VALUE;
-extern Expression* TRUE_VALUE;
-extern Expression* FALSE_VALUE;
-
-void register_base_types();
-
-#endif // AIDL_TYPE_H_
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
deleted file mode 100644
index 832c51c..0000000
--- a/tools/aidl/aidl.cpp
+++ /dev/null
@@ -1,1070 +0,0 @@
-
-#include "aidl_language.h"
-#include "options.h"
-#include "os.h"
-#include "search_path.h"
-#include "Type.h"
-#include "generate_java.h"
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <map>
-
-#ifdef _WIN32
-#include <io.h>
-#include <direct.h>
-#include <sys/stat.h>
-#endif
-
-#ifndef O_BINARY
-#  define O_BINARY  0
-#endif
-
-// The following are gotten as the offset from the allowable id's between
-// android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
-// android.os.IBinder.LAST_CALL_TRANSACTION=16777215
-#define MIN_USER_SET_METHOD_ID                0
-#define MAX_USER_SET_METHOD_ID                16777214
-
-using namespace std;
-
-static void
-test_document(document_item_type* d)
-{
-    while (d) {
-        if (d->item_type == INTERFACE_TYPE_BINDER) {
-            interface_type* c = (interface_type*)d;
-            printf("interface %s %s {\n", c->package, c->name.data);
-            interface_item_type *q = (interface_item_type*)c->interface_items;
-            while (q) {
-                if (q->item_type == METHOD_TYPE) {
-                    method_type *m = (method_type*)q;
-                    printf("  %s %s(", m->type.type.data, m->name.data);
-                    arg_type *p = m->args;
-                    while (p) {
-                        printf("%s %s",p->type.type.data,p->name.data);
-                        if (p->next) printf(", ");
-                        p=p->next;
-                    }
-                    printf(")");
-                    printf(";\n");
-                }
-                q=q->next;
-            }
-            printf("}\n");
-        }
-        else if (d->item_type == USER_DATA_TYPE) {
-            user_data_type* b = (user_data_type*)d;
-            if (b->parcelable) {
-                printf("parcelable %s %s;\n", b->package, b->name.data);
-            }
-        }
-        else {
-            printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
-        }
-        d = d->next;
-    }
-}
-
-// ==========================================================
-int
-convert_direction(const char* direction)
-{
-    if (direction == NULL) {
-        return IN_PARAMETER;
-    }
-    if (0 == strcmp(direction, "in")) {
-        return IN_PARAMETER;
-    }
-    if (0 == strcmp(direction, "out")) {
-        return OUT_PARAMETER;
-    }
-    return INOUT_PARAMETER;
-}
-
-// ==========================================================
-struct import_info {
-    const char* from;
-    const char* filename;
-    buffer_type statement;
-    const char* neededClass;
-    document_item_type* doc;
-    struct import_info* next;
-};
-
-document_item_type* g_document = NULL;
-import_info* g_imports = NULL;
-
-static void
-main_document_parsed(document_item_type* d)
-{
-    g_document = d;
-}
-
-static void
-main_import_parsed(buffer_type* statement)
-{
-    import_info* import = (import_info*)malloc(sizeof(import_info));
-    memset(import, 0, sizeof(import_info));
-    import->from = strdup(g_currentFilename);
-    import->statement.lineno = statement->lineno;
-    import->statement.data = strdup(statement->data);
-    import->statement.extra = NULL;
-    import->next = g_imports;
-    import->neededClass = parse_import_statement(statement->data);
-    g_imports = import;
-}
-
-static ParserCallbacks g_mainCallbacks = {
-    &main_document_parsed,
-    &main_import_parsed
-};
-
-char*
-parse_import_statement(const char* text)
-{
-    const char* end;
-    int len;
-
-    while (isspace(*text)) {
-        text++;
-    }
-    while (!isspace(*text)) {
-        text++;
-    }
-    while (isspace(*text)) {
-        text++;
-    }
-    end = text;
-    while (!isspace(*end) && *end != ';') {
-        end++;
-    }
-    len = end-text;
-
-    char* rv = (char*)malloc(len+1);
-    memcpy(rv, text, len);
-    rv[len] = '\0';
-
-    return rv;
-}
-
-// ==========================================================
-static void
-import_import_parsed(buffer_type* statement)
-{
-}
-
-// ==========================================================
-static int
-check_filename(const char* filename, const char* package, buffer_type* name)
-{
-    const char* p;
-    string expected;
-    string fn;
-    size_t len;
-    char cwd[MAXPATHLEN];
-    bool valid = false;
-
-#ifdef _WIN32
-    if (isalpha(filename[0]) && filename[1] == ':'
-        && filename[2] == OS_PATH_SEPARATOR) {
-#else
-    if (filename[0] == OS_PATH_SEPARATOR) {
-#endif
-        fn = filename;
-    } else {
-        fn = getcwd(cwd, sizeof(cwd));
-        len = fn.length();
-        if (fn[len-1] != OS_PATH_SEPARATOR) {
-            fn += OS_PATH_SEPARATOR;
-        }
-        fn += filename;
-    }
-
-    if (package) {
-        expected = package;
-        expected += '.';
-    }
-
-    len = expected.length();
-    for (size_t i=0; i<len; i++) {
-        if (expected[i] == '.') {
-            expected[i] = OS_PATH_SEPARATOR;
-        }
-    }
-
-    p = strchr(name->data, '.');
-    len = p ? p-name->data : strlen(name->data);
-    expected.append(name->data, len);
-    
-    expected += ".aidl";
-
-    len = fn.length();
-    valid = (len >= expected.length());
-
-    if (valid) {
-        p = fn.c_str() + (len - expected.length());
-
-#ifdef _WIN32
-        if (OS_PATH_SEPARATOR != '/') {
-            // Input filename under cygwin most likely has / separators
-            // whereas the expected string uses \\ separators. Adjust
-            // them accordingly.
-          for (char *c = const_cast<char *>(p); *c; ++c) {
-                if (*c == '/') *c = OS_PATH_SEPARATOR;
-            }
-        }
-#endif
-
-        // aidl assumes case-insensitivity on Mac Os and Windows.
-#if defined(__linux__)
-        valid = (expected == p);
-#else
-        valid = !strcasecmp(expected.c_str(), p);
-#endif
-    }
-
-    if (!valid) {
-        fprintf(stderr, "%s:%d interface %s should be declared in a file"
-                " called %s.\n",
-                filename, name->lineno, name->data, expected.c_str());
-        return 1;
-    }
-
-    return 0;
-}
-
-static int
-check_filenames(const char* filename, document_item_type* items)
-{
-    int err = 0;
-    while (items) {
-        if (items->item_type == USER_DATA_TYPE) {
-            user_data_type* p = (user_data_type*)items;
-            err |= check_filename(filename, p->package, &p->name);
-        }
-        else if (items->item_type == INTERFACE_TYPE_BINDER) {
-            interface_type* c = (interface_type*)items;
-            err |= check_filename(filename, c->package, &c->name);
-        }
-        else {
-            fprintf(stderr, "aidl: internal error unkown document type %d.\n",
-                        items->item_type);
-            return 1;
-        }
-        items = items->next;
-    }
-    return err;
-}
-
-// ==========================================================
-static const char*
-kind_to_string(int kind)
-{
-    switch (kind)
-    {
-        case Type::INTERFACE:
-            return "an interface";
-        case Type::USERDATA:
-            return "a user data";
-        default:
-            return "ERROR";
-    }
-}
-
-static char*
-rfind(char* str, char c)
-{
-    char* p = str + strlen(str) - 1;
-    while (p >= str) {
-        if (*p == c) {
-            return p;
-        }
-        p--;
-    }
-    return NULL;
-}
-
-static int
-gather_types(const char* filename, document_item_type* items)
-{
-    int err = 0;
-    while (items) {
-        Type* type;
-        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->parcelable, filename, p->name.lineno);
-        }
-        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,
-                            filename, c->name.lineno);
-        }
-        else {
-            fprintf(stderr, "aidl: internal error %s:%d\n", __FILE__, __LINE__);
-            return 1;
-        }
-
-        Type* old = NAMES.Find(type->QualifiedName());
-        if (old == NULL) {
-            NAMES.Add(type);
-
-            if (items->item_type == INTERFACE_TYPE_BINDER) {
-                // for interfaces, also add the stub and proxy types, 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 += ".Stub";
-                Type* stub = new Type(c->package ? c->package : "",
-                                        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,
-                                        filename, c->name.lineno);
-                NAMES.Add(proxy);
-            }
-        } else {
-            if (old->Kind() == Type::BUILT_IN) {
-                fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
-                            filename, type->DeclLine(),
-                            type->QualifiedName().c_str());
-                err = 1;
-            }
-            else if (type->Kind() != old->Kind()) {
-                const char* oldKind = kind_to_string(old->Kind());
-                const char* newKind = kind_to_string(type->Kind());
-
-                fprintf(stderr, "%s:%d attempt to redefine %s as %s,\n",
-                            filename, type->DeclLine(),
-                            type->QualifiedName().c_str(), newKind);
-                fprintf(stderr, "%s:%d    previously defined here as %s.\n",
-                            old->DeclFile().c_str(), old->DeclLine(), oldKind);
-                err = 1;
-            }
-        }
-
-        items = items->next;
-    }
-    return err;
-}
-
-// ==========================================================
-static bool
-matches_keyword(const char* str)
-{
-    static const char* KEYWORDS[] = { "abstract", "assert", "boolean", "break",
-        "byte", "case", "catch", "char", "class", "const", "continue",
-        "default", "do", "double", "else", "enum", "extends", "final",
-        "finally", "float", "for", "goto", "if", "implements", "import",
-        "instanceof", "int", "interface", "long", "native", "new", "package",
-        "private", "protected", "public", "return", "short", "static",
-        "strictfp", "super", "switch", "synchronized", "this", "throw",
-        "throws", "transient", "try", "void", "volatile", "while",
-        "true", "false", "null",
-        NULL
-    };
-    const char** k = KEYWORDS;
-    while (*k) {
-        if (0 == strcmp(str, *k)) {
-            return true;
-        }
-        k++;
-    }
-    return false;
-}
-
-static int
-check_method(const char* filename, method_type* m)
-{
-    int err = 0;
-
-    // return type
-    Type* returnType = NAMES.Search(m->type.type.data);
-    if (returnType == NULL) {
-        fprintf(stderr, "%s:%d unknown return type %s\n", filename,
-                    m->type.type.lineno, m->type.type.data);
-        err = 1;
-        return err;
-    }
-
-    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;
-    }
-
-    if (m->type.dimension > 0 && !returnType->CanBeArray()) {
-        fprintf(stderr, "%s:%d return type %s%s can't be an array.\n", filename,
-                m->type.array_token.lineno, m->type.type.data,
-                m->type.array_token.data);
-        err = 1;
-    }
-
-    if (m->type.dimension > 1) {
-        fprintf(stderr, "%s:%d return type %s%s only one"
-                " dimensional arrays are supported\n", filename,
-                m->type.array_token.lineno, m->type.type.data,
-                m->type.array_token.data);
-        err = 1;
-    }
-
-    int index = 1;
-
-    arg_type* arg = m->args;
-    while (arg) {
-        Type* t = NAMES.Search(arg->type.type.data);
-
-        // check the arg type
-        if (t == NULL) {
-            fprintf(stderr, "%s:%d parameter %s (%d) unknown type %s\n",
-                    filename, m->type.type.lineno, arg->name.data, index,
-                    arg->type.type.data);
-            err = 1;
-            goto next;
-        }
-
-        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 (arg->direction.data == NULL
-                && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
-            fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
-                                " parameter, so you must declare it as in,"
-                                " out or inout.\n",
-                        filename, m->type.type.lineno, index,
-                        arg->type.type.data, arg->name.data);
-            err = 1;
-        }
-
-        if (convert_direction(arg->direction.data) != IN_PARAMETER
-                && !t->CanBeOutParameter()
-                && arg->type.dimension == 0) {
-            fprintf(stderr, "%s:%d parameter %d: '%s %s %s' can only be an in"
-                            " parameter.\n",
-                        filename, m->type.type.lineno, index,
-                        arg->direction.data, arg->type.type.data,
-                        arg->name.data);
-            err = 1;
-        }
-
-        if (arg->type.dimension > 0 && !t->CanBeArray()) {
-            fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' can't be an"
-                    " array.\n", filename,
-                    m->type.array_token.lineno, index, arg->direction.data,
-                    arg->type.type.data, arg->type.array_token.data,
-                    arg->name.data);
-            err = 1;
-        }
-
-        if (arg->type.dimension > 1) {
-            fprintf(stderr, "%s:%d parameter %d: '%s %s%s %s' only one"
-                    " dimensional arrays are supported\n", filename,
-                    m->type.array_token.lineno, index, arg->direction.data,
-                    arg->type.type.data, arg->type.array_token.data,
-                    arg->name.data);
-            err = 1;
-        }
-
-        // check that the name doesn't match a keyword
-        if (matches_keyword(arg->name.data)) {
-            fprintf(stderr, "%s:%d parameter %d %s is named the same as a"
-                    " Java or aidl keyword\n",
-                    filename, m->name.lineno, index, arg->name.data);
-            err = 1;
-        }
-        
-next:
-        index++;
-        arg = arg->next;
-    }
-
-    return err;
-}
-
-static int
-check_types(const char* filename, document_item_type* items)
-{
-    int err = 0;
-    while (items) {
-        // (nothing to check for USER_DATA_TYPE)
-        if (items->item_type == INTERFACE_TYPE_BINDER) {
-            map<string,method_type*> methodNames;
-            interface_type* c = (interface_type*)items;
-
-            interface_item_type* member = c->interface_items;
-            while (member) {
-                if (member->item_type == METHOD_TYPE) {
-                    method_type* m = (method_type*)member;
-
-                    err |= check_method(filename, m);
-
-                    // prevent duplicate methods
-                    if (methodNames.find(m->name.data) == methodNames.end()) {
-                        methodNames[m->name.data] = m;
-                    } else {
-                        fprintf(stderr,"%s:%d attempt to redefine method %s,\n",
-                                filename, m->name.lineno, m->name.data);
-                        method_type* old = methodNames[m->name.data];
-                        fprintf(stderr, "%s:%d    previously defined here.\n",
-                                filename, old->name.lineno);
-                        err = 1;
-                    }
-                }
-                member = member->next;
-            }
-        }
-
-        items = items->next;
-    }
-    return err;
-}
-
-// ==========================================================
-static int
-exactly_one_interface(const char* filename, const document_item_type* items, const Options& options,
-                      bool* onlyParcelable)
-{
-    if (items == NULL) {
-        fprintf(stderr, "%s: file does not contain any interfaces\n",
-                            filename);
-        return 1;
-    }
-
-    const document_item_type* next = items->next;
-    // Allow parcelables to skip the "one-only" rule.
-    if (items->next != NULL && next->item_type != USER_DATA_TYPE) {
-        int lineno = -1;
-        if (next->item_type == INTERFACE_TYPE_BINDER) {
-            lineno = ((interface_type*)next)->interface_token.lineno;
-        }
-        fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
-                            filename, lineno);
-        return 1;
-    }
-
-    if (items->item_type == USER_DATA_TYPE) {
-        *onlyParcelable = true;
-        if (options.failOnParcelable) {
-            fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
-                            " parcelables,\n", filename,
-                            ((user_data_type*)items)->keyword_token.lineno);
-            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;
-        }
-    } else {
-        *onlyParcelable = false;
-    }
-
-    return 0;
-}
-
-// ==========================================================
-void
-generate_dep_file(const Options& options, const document_item_type* items)
-{
-    /* we open the file in binary mode to ensure that the same output is
-     * generated on all platforms !!
-     */
-    FILE* to = NULL;
-    if (options.autoDepFile) {
-        string fileName = options.outputFileName + ".d";
-        to = fopen(fileName.c_str(), "wb");
-    } else {
-        to = fopen(options.depFileName.c_str(), "wb");
-    }
-
-    if (to == NULL) {
-        return;
-    }
-
-    const char* slash = "\\";
-    import_info* import = g_imports;
-    if (import == NULL) {
-        slash = "";
-    }
-
-    if (items->item_type == INTERFACE_TYPE_BINDER) {
-        fprintf(to, "%s: \\\n", options.outputFileName.c_str());
-    } else {
-        // parcelable: there's no output file.
-        fprintf(to, " : \\\n");
-    }
-    fprintf(to, "  %s %s\n", options.inputFileName.c_str(), slash);
-
-    while (import) {
-        if (import->next == NULL) {
-            slash = "";
-        }
-        if (import->filename) {
-            fprintf(to, "  %s %s\n", import->filename, slash);
-        }
-        import = import->next;
-    }
-
-    fprintf(to, "\n");
-
-    // Output "<input_aidl_file>: " so make won't fail if the input .aidl file
-    // has been deleted, moved or renamed in incremental build.
-    fprintf(to, "%s :\n", options.inputFileName.c_str());
-
-    // Output "<imported_file>: " so make won't fail if the imported file has
-    // been deleted, moved or renamed in incremental build.
-    import = g_imports;
-    while (import) {
-        if (import->filename) {
-            fprintf(to, "%s :\n", import->filename);
-        }
-        import = import->next;
-    }
-
-    fclose(to);
-}
-
-// ==========================================================
-static string
-generate_outputFileName2(const Options& options, const buffer_type& name, const char* package)
-{
-    string result;
-
-    // create the path to the destination folder based on the
-    // interface package name
-    result = options.outputBaseFolder;
-    result += OS_PATH_SEPARATOR;
-
-    string packageStr = package;
-    size_t len = packageStr.length();
-    for (size_t i=0; i<len; i++) {
-        if (packageStr[i] == '.') {
-            packageStr[i] = OS_PATH_SEPARATOR;
-        }
-    }
-
-    result += packageStr;
-
-    // add the filename by replacing the .aidl extension to .java
-    const char* p = strchr(name.data, '.');
-    len = p ? p-name.data : strlen(name.data);
-
-    result += OS_PATH_SEPARATOR;
-    result.append(name.data, len);
-    result += ".java";
-
-    return result;
-}
-
-// ==========================================================
-static string
-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) {
-        interface_type* type = (interface_type*)items;
-
-        return generate_outputFileName2(options, type->name, type->package);
-    } else if (items->item_type == USER_DATA_TYPE) {
-        user_data_type* type = (user_data_type*)items;
-        return generate_outputFileName2(options, type->name, type->package);
-    }
-
-    // I don't think we can come here, but safer than returning NULL.
-    string result;
-    return result;
-}
-
-
-
-// ==========================================================
-static void
-check_outputFilePath(const string& path) {
-    size_t len = path.length();
-    for (size_t i=0; i<len ; i++) {
-        if (path[i] == OS_PATH_SEPARATOR) {
-            string p = path.substr(0, i);
-            if (access(path.data(), F_OK) != 0) {
-#ifdef _WIN32
-                _mkdir(p.data());
-#else
-                mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
-#endif
-            }
-        }
-    }
-}
-
-
-// ==========================================================
-static int
-parse_preprocessed_file(const string& filename)
-{
-    int err;
-
-    FILE* f = fopen(filename.c_str(), "rb");
-    if (f == NULL) {
-        fprintf(stderr, "aidl: can't open preprocessed file: %s\n",
-                filename.c_str());
-        return 1;
-    }
-
-    int lineno = 1;
-    char line[1024];
-    char type[1024];
-    char fullname[1024];
-    while (fgets(line, sizeof(line), f)) {
-        // skip comments and empty lines
-        if (!line[0] || strncmp(line, "//", 2) == 0) {
-          continue;
-        }
-
-        sscanf(line, "%s %[^; \r\n\t];", type, fullname);
-
-        char* packagename;
-        char* classname = rfind(fullname, '.');
-        if (classname != NULL) {
-            *classname = '\0';
-            classname++;
-            packagename = fullname;
-        } else {
-            classname = fullname;
-            packagename = NULL;
-        }
-
-        //printf("%s:%d:...%s...%s...%s...\n", filename.c_str(), lineno,
-        //        type, packagename, classname);
-        document_item_type* doc;
-        
-        if (0 == strcmp("parcelable", 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->parcelable = true;
-            doc = (document_item_type*)parcl;
-        }
-        else if (0 == strcmp("interface", type)) {
-            interface_type* iface = (interface_type*)malloc(
-                    sizeof(interface_type));
-            memset(iface, 0, sizeof(interface_type));
-            iface->document_item.item_type = INTERFACE_TYPE_BINDER;
-            iface->interface_token.lineno = lineno;
-            iface->interface_token.data = strdup(type);
-            iface->package = packagename ? strdup(packagename) : NULL;
-            iface->name.lineno = lineno;
-            iface->name.data = strdup(classname);
-            iface->open_brace_token.lineno = lineno;
-            iface->open_brace_token.data = strdup("{");
-            iface->close_brace_token.lineno = lineno;
-            iface->close_brace_token.data = strdup("}");
-            doc = (document_item_type*)iface;
-        }
-        else {
-            fprintf(stderr, "%s:%d: bad type in line: %s\n",
-                    filename.c_str(), lineno, line);
-            fclose(f);
-            return 1;
-        }
-        err = gather_types(filename.c_str(), doc);
-        lineno++;
-    }
-
-    if (!feof(f)) {
-        fprintf(stderr, "%s:%d: error reading file, line to long.\n",
-                filename.c_str(), lineno);
-        return 1;
-    }
-
-    fclose(f);
-    return 0;
-}
-
-static int
-check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
-{
-    // Check whether there are any methods with manually assigned id's and any that are not.
-    // Either all method id's must be manually assigned or all of them must not.
-    // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
-    set<int> usedIds;
-    interface_item_type* item = first_item;
-    bool hasUnassignedIds = false;
-    bool hasAssignedIds = false;
-    while (item != NULL) {
-        if (item->item_type == METHOD_TYPE) {
-            method_type* method_item = (method_type*)item;
-            if (method_item->hasId) {
-                hasAssignedIds = true;
-                method_item->assigned_id = atoi(method_item->id.data);
-                // Ensure that the user set id is not duplicated.
-                if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
-                    // We found a duplicate id, so throw an error.
-                    fprintf(stderr,
-                            "%s:%d Found duplicate method id (%d) for method: %s\n",
-                            filename, method_item->id.lineno,
-                            method_item->assigned_id, method_item->name.data);
-                    return 1;
-                }
-                // Ensure that the user set id is within the appropriate limits
-                if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
-                        method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
-                    fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
-                            filename, method_item->id.lineno,
-                            method_item->assigned_id, method_item->name.data);
-                    fprintf(stderr, "    Value for id must be between %d and %d inclusive.\n",
-                            MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
-                    return 1;
-                }
-                usedIds.insert(method_item->assigned_id);
-            } else {
-                hasUnassignedIds = true;
-            }
-            if (hasAssignedIds && hasUnassignedIds) {
-                fprintf(stderr,
-                        "%s: You must either assign id's to all methods or to none of them.\n",
-                        filename);
-                return 1;
-            }
-        }
-        item = item->next;
-    }
-
-    // In the case that all methods have unassigned id's, set a unique id for them.
-    if (hasUnassignedIds) {
-        int newId = 0;
-        item = first_item;
-        while (item != NULL) {
-            if (item->item_type == METHOD_TYPE) {
-                method_type* method_item = (method_type*)item;
-                method_item->assigned_id = newId++;
-            }
-            item = item->next;
-        }
-    }
-
-    // success
-    return 0;
-}
-
-// ==========================================================
-int
-compile_aidl(Options& options)
-{
-    int err = 0, N;
-
-    set_import_paths(options.importPaths);
-
-    register_base_types();
-
-    // import the preprocessed file
-    N = options.preprocessedFiles.size();
-    for (int i=0; i<N; i++) {
-        const string& s = options.preprocessedFiles[i];
-        err |= parse_preprocessed_file(s);
-    }
-    if (err != 0) {
-        return err;
-    }
-
-    // parse the main file
-    g_callbacks = &g_mainCallbacks;
-    err = parse_aidl(options.inputFileName.c_str());
-    document_item_type* mainDoc = g_document;
-    g_document = NULL;
-
-    // parse the imports
-    g_callbacks = &g_mainCallbacks;
-    import_info* import = g_imports;
-    while (import) {
-        if (NAMES.Find(import->neededClass) == NULL) {
-            import->filename = find_import_file(import->neededClass);
-            if (!import->filename) {
-                fprintf(stderr, "%s:%d: couldn't find import for class %s\n",
-                        import->from, import->statement.lineno,
-                        import->neededClass);
-                err |= 1;
-            } else {
-                err |= parse_aidl(import->filename);
-                import->doc = g_document;
-                if (import->doc == NULL) {
-                    err |= 1;
-                }
-            }
-        }
-        import = import->next;
-    }
-    // bail out now if parsing wasn't successful
-    if (err != 0 || mainDoc == NULL) {
-        //fprintf(stderr, "aidl: parsing failed, stopping.\n");
-        return 1;
-    }
-
-    // complain about ones that aren't in the right files
-    err |= check_filenames(options.inputFileName.c_str(), mainDoc);
-    import = g_imports;
-    while (import) {
-        err |= check_filenames(import->filename, import->doc);
-        import = import->next;
-    }
-
-    // gather the types that have been declared
-    err |= gather_types(options.inputFileName.c_str(), mainDoc);
-    import = g_imports;
-    while (import) {
-        err |= gather_types(import->filename, import->doc);
-        import = import->next;
-    }
-
-#if 0
-    printf("---- main doc ----\n");
-    test_document(mainDoc);
-
-    import = g_imports;
-    while (import) {
-        printf("---- import doc ----\n");
-        test_document(import->doc);
-        import = import->next;
-    }
-    NAMES.Dump();
-#endif
-
-    // check the referenced types in mainDoc to make sure we've imported them
-    err |= check_types(options.inputFileName.c_str(), mainDoc);
-
-    // finally, there really only needs to be one thing in mainDoc, and it
-    // needs to be an interface.
-    bool onlyParcelable = false;
-    err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
-
-    // If this includes an interface definition, then assign method ids and validate.
-    if (!onlyParcelable) {
-        err |= check_and_assign_method_ids(options.inputFileName.c_str(),
-                ((interface_type*)mainDoc)->interface_items);
-    }
-
-    // after this, there shouldn't be any more errors because of the
-    // input.
-    if (err != 0 || mainDoc == NULL) {
-        return 1;
-    }
-
-    // if needed, generate the outputFileName from the outputBaseFolder
-    if (options.outputFileName.length() == 0 &&
-            options.outputBaseFolder.length() > 0) {
-        options.outputFileName = generate_outputFileName(options, mainDoc);
-    }
-
-    // if we were asked to, generate a make dependency file
-    // unless it's a parcelable *and* it's supposed to fail on parcelable
-    if ((options.autoDepFile || options.depFileName != "") &&
-            !(onlyParcelable && options.failOnParcelable)) {
-        // make sure the folders of the output file all exists
-        check_outputFilePath(options.outputFileName);
-        generate_dep_file(options, mainDoc);
-    }
-
-    // they didn't ask to fail on parcelables, so just exit quietly.
-    if (onlyParcelable && !options.failOnParcelable) {
-        return 0;
-    }
-
-    // make sure the folders of the output file all exists
-    check_outputFilePath(options.outputFileName);
-
-    err = generate_java(options.outputFileName, options.inputFileName.c_str(),
-                        (interface_type*)mainDoc);
-
-    return err;
-}
-
-int
-preprocess_aidl(const Options& options)
-{
-    vector<string> lines;
-    int err;
-
-    // read files
-    int N = options.filesToPreprocess.size();
-    for (int i=0; i<N; i++) {
-        g_callbacks = &g_mainCallbacks;
-        err = parse_aidl(options.filesToPreprocess[i].c_str());
-        if (err != 0) {
-            return err;
-        }
-        document_item_type* doc = g_document;
-        string line;
-        if (doc->item_type == USER_DATA_TYPE) {
-            user_data_type* parcelable = (user_data_type*)doc;
-            if (parcelable->parcelable) {
-                line = "parcelable ";
-            }
-            if (parcelable->package) {
-                line += parcelable->package;
-                line += '.';
-            }
-            line += parcelable->name.data;
-        } else {
-            line = "interface ";
-            interface_type* iface = (interface_type*)doc;
-            if (iface->package) {
-                line += iface->package;
-                line += '.';
-            }
-            line += iface->name.data;
-        }
-        line += ";\n";
-        lines.push_back(line);
-    }
-
-    // write preprocessed file
-    int fd = open( options.outputFileName.c_str(), 
-                   O_RDWR|O_CREAT|O_TRUNC|O_BINARY,
-#ifdef _WIN32
-                   _S_IREAD|_S_IWRITE);
-#else    
-                   S_IRUSR|S_IWUSR|S_IRGRP);
-#endif            
-    if (fd == -1) {
-        fprintf(stderr, "aidl: could not open file for write: %s\n",
-                options.outputFileName.c_str());
-        return 1;
-    }
-
-    N = lines.size();
-    for (int i=0; i<N; i++) {
-        const string& s = lines[i];
-        int len = s.length();
-        if (len != write(fd, s.c_str(), len)) {
-            fprintf(stderr, "aidl: error writing to file %s\n",
-                options.outputFileName.c_str());
-            close(fd);
-            unlink(options.outputFileName.c_str());
-            return 1;
-        }
-    }
-
-    close(fd);
-    return 0;
-}
diff --git a/tools/aidl/aidl.h b/tools/aidl/aidl.h
deleted file mode 100644
index 98b15f3..0000000
--- a/tools/aidl/aidl.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef AIDL_AIDL_H_
-#define AIDL_AIDL_H_
-
-#include "options.h"
-
-int compile_aidl(Options& options);
-int preprocess_aidl(const Options& options);
-
-#endif  // AIDL_AIDL_H_
diff --git a/tools/aidl/aidl_language.cpp b/tools/aidl/aidl_language.cpp
deleted file mode 100644
index 5fab6c2..0000000
--- a/tools/aidl/aidl_language.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "aidl_language.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#ifdef _WIN32
-int isatty(int  fd)
-{
-    return (fd == 0);
-}
-#endif
-
-#if 0
-ParserCallbacks k_parserCallbacks = {
-    NULL
-};
-#endif
-
-ParserCallbacks* g_callbacks = NULL; // &k_parserCallbacks;
-
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
deleted file mode 100644
index a3b1efc..0000000
--- a/tools/aidl/aidl_language.h
+++ /dev/null
@@ -1,165 +0,0 @@
-#ifndef AIDL_AIDL_LANGUAGE_H_
-#define AIDL_AIDL_LANGUAGE_H_
-
-
-typedef enum {
-    NO_EXTRA_TEXT = 0,
-    SHORT_COMMENT,
-    LONG_COMMENT,
-    COPY_TEXT,
-    WHITESPACE
-} which_extra_text;
-
-typedef struct extra_text_type {
-    unsigned lineno;
-    which_extra_text which;
-    char* data; 
-    unsigned len;
-    struct extra_text_type* next;
-} extra_text_type;
-
-typedef struct buffer_type {
-    unsigned lineno;
-    unsigned token;
-    char *data;
-    extra_text_type* extra;
-} buffer_type;
-
-typedef struct type_type {
-    buffer_type type;
-    buffer_type array_token;
-    int dimension;
-} type_type;
-
-typedef struct arg_type {
-    buffer_type comma_token; // empty in the first one in the list
-    buffer_type direction;
-    type_type type;
-    buffer_type name;
-    struct arg_type *next;
-} arg_type;
-
-enum {
-    METHOD_TYPE
-};
-
-typedef struct interface_item_type {
-    unsigned item_type;
-    struct interface_item_type* next;
-} interface_item_type;
-
-typedef struct method_type {
-    interface_item_type interface_item;
-    type_type type;
-    bool oneway;
-    buffer_type oneway_token;
-    buffer_type name;
-    buffer_type open_paren_token;
-    arg_type* args;
-    buffer_type close_paren_token;
-    bool hasId;
-    buffer_type equals_token;
-    buffer_type id;
-    // XXX missing comments/copy text here
-    buffer_type semicolon_token;
-    buffer_type* comments_token; // points into this structure, DO NOT DELETE
-    int assigned_id;
-} method_type;
-
-enum {
-    USER_DATA_TYPE = 12,
-    INTERFACE_TYPE_BINDER
-};
-
-typedef struct document_item_type {
-    unsigned item_type;
-    struct document_item_type* next;
-} document_item_type;
-
-
-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;
-    bool parcelable;
-} user_data_type;
-
-typedef struct interface_type {
-    document_item_type document_item;
-    buffer_type interface_token;
-    bool oneway;
-    buffer_type oneway_token;
-    char* package;
-    buffer_type name;
-    buffer_type open_brace_token;
-    interface_item_type* interface_items;
-    buffer_type close_brace_token;
-    buffer_type* comments_token; // points into this structure, DO NOT DELETE
-} interface_type;
-
-typedef union lexer_type {
-    buffer_type buffer;
-    type_type type;
-    arg_type *arg;
-    method_type* method;
-    interface_item_type* interface_item;
-    interface_type* interface_obj;
-    user_data_type* user_data;
-    document_item_type* document_item;
-} lexer_type;
-
-
-#define YYSTYPE lexer_type
-
-#if __cplusplus
-extern "C" {
-#endif
-
-int parse_aidl(char const *);
-
-// strips off the leading whitespace, the "import" text
-// also returns whether it's a local or system import
-// we rely on the input matching the import regex from below
-char* parse_import_statement(const char* text);
-
-// in, out or inout
-enum {
-    IN_PARAMETER = 1,
-    OUT_PARAMETER = 2,
-    INOUT_PARAMETER = 3
-};
-int convert_direction(const char* direction);
-
-// callbacks from within the parser
-// these functions all take ownership of the strings
-typedef struct ParserCallbacks {
-    void (*document)(document_item_type* items);
-    void (*import)(buffer_type* statement);
-} ParserCallbacks;
-
-extern ParserCallbacks* g_callbacks;
-
-// true if there was an error parsing, false otherwise
-extern int g_error;
-
-// the name of the file we're currently parsing
-extern char const* g_currentFilename;
-
-// the package name for our current file
-extern char const* g_currentPackage;
-
-typedef enum {
-    STATEMENT_INSIDE_INTERFACE
-} error_type;
-
-void init_buffer_type(buffer_type* buf, int lineno);
-
-
-#if __cplusplus
-}
-#endif
-
-
-#endif // AIDL_AIDL_LANGUAGE_H_
diff --git a/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l
deleted file mode 100644
index aa42f2e..0000000
--- a/tools/aidl/aidl_language_l.l
+++ /dev/null
@@ -1,212 +0,0 @@
-%{
-#include "aidl_language.h"
-#include "aidl_language_y.h"
-#include "search_path.h"
-#include <string.h>
-#include <stdlib.h>
-
-extern YYSTYPE yylval;
-
-// comment and whitespace handling
-// these functions save a copy of the buffer
-static void begin_extra_text(unsigned lineno, which_extra_text which);
-static void append_extra_text(char* text);
-static extra_text_type* get_extra_text(void);   // you now own the object
-                                                // this returns
-static void drop_extra_text(void);
-
-// package handling
-static void do_package_statement(const char* importText);
-
-#define SET_BUFFER(t) \
-    do { \
-        yylval.buffer.lineno = yylineno; \
-        yylval.buffer.token = (t); \
-        yylval.buffer.data = strdup(yytext); \
-        yylval.buffer.extra = get_extra_text(); \
-    } while(0)
-
-%}
-
-%option yylineno
-%option noyywrap
-
-%x COPYING LONG_COMMENT
-
-identifier  [_a-zA-Z][_a-zA-Z0-9\.]*
-whitespace  ([ \t\n\r]+)
-brackets    \[{whitespace}?\]
-idvalue     (0|[1-9][0-9]*)
-
-%%
-
-
-\%\%\{              { begin_extra_text(yylineno, COPY_TEXT); BEGIN(COPYING); }
-<COPYING>\}\%\%     { BEGIN(INITIAL); }
-<COPYING>.*\n       { append_extra_text(yytext); }
-<COPYING>.*         { append_extra_text(yytext); }
-<COPYING>\n+        { append_extra_text(yytext); }
-
-
-\/\*                            { begin_extra_text(yylineno, (which_extra_text)LONG_COMMENT);
-                                  BEGIN(LONG_COMMENT); }
-<LONG_COMMENT>[^*]*             { append_extra_text(yytext); }
-<LONG_COMMENT>\*+[^/]           { append_extra_text(yytext); }
-<LONG_COMMENT>\n                { append_extra_text(yytext); }
-<LONG_COMMENT>\**\/             { BEGIN(INITIAL); }
-
-^{whitespace}?import{whitespace}[^ \t\r\n]+{whitespace}?;  {
-                                                SET_BUFFER(IMPORT);
-                                                return IMPORT;
-                                            }
-^{whitespace}?package{whitespace}[^ \t\r\n]+{whitespace}?;  {
-                                                do_package_statement(yytext);
-                                                SET_BUFFER(PACKAGE);
-                                                return PACKAGE;
-                                            }
-<<EOF>>             { yyterminate(); }
-
-\/\/.*\n            { begin_extra_text(yylineno, SHORT_COMMENT);
-                        append_extra_text(yytext); }
-
-{whitespace}    { /* begin_extra_text(yylineno, WHITESPACE);
-                    append_extra_text(yytext); */ }
-
-;               { SET_BUFFER(';'); return ';'; }
-\{              { SET_BUFFER('{'); return '{'; }
-\}              { SET_BUFFER('}'); return '}'; }
-\(              { SET_BUFFER('('); return '('; }
-\)              { SET_BUFFER(')'); return ')'; }
-,               { SET_BUFFER(','); return ','; }
-=               { SET_BUFFER('='); return '='; }
-
-    /* keywords */
-parcelable      { SET_BUFFER(PARCELABLE); return PARCELABLE; }
-interface       { SET_BUFFER(INTERFACE); return INTERFACE; }
-in              { SET_BUFFER(IN); return IN; }
-out             { SET_BUFFER(OUT); return OUT; }
-inout           { SET_BUFFER(INOUT); return INOUT; }
-oneway          { SET_BUFFER(ONEWAY); return ONEWAY; }
-
-{brackets}+     { SET_BUFFER(ARRAY); return ARRAY; }
-{idvalue}       { SET_BUFFER(IDVALUE); return IDVALUE; }
-{identifier}                                        { SET_BUFFER(IDENTIFIER); return IDENTIFIER; }
-{identifier}\<{whitespace}*{identifier}({whitespace}*,{whitespace}*{identifier})*{whitespace}*\>    {
-                                                      SET_BUFFER(GENERIC); return GENERIC; }
-
-    /* syntax error! */
-.               { printf("UNKNOWN(%s)", yytext);
-                  yylval.buffer.lineno = yylineno;
-                  yylval.buffer.token = IDENTIFIER;
-                  yylval.buffer.data = strdup(yytext);
-                  return IDENTIFIER;
-                }
-
-%%
-
-// comment and whitespace handling
-// ================================================
-extra_text_type* g_extraText = NULL;
-extra_text_type* g_nextExtraText = NULL;
-
-void begin_extra_text(unsigned lineno, which_extra_text which)
-{
-    extra_text_type* text = (extra_text_type*)malloc(sizeof(extra_text_type));
-    text->lineno = lineno;
-    text->which = which;
-    text->data = NULL;
-    text->len = 0;
-    text->next = NULL;
-    if (g_nextExtraText == NULL) {
-        g_extraText = text;
-    } else {
-        g_nextExtraText->next = text;
-    }
-    g_nextExtraText = text;
-}
-
-void append_extra_text(char* text)
-{
-    if (g_nextExtraText->data == NULL) {
-        g_nextExtraText->data = strdup(text);
-        g_nextExtraText->len = strlen(text);
-    } else {
-        char* orig = g_nextExtraText->data;
-        unsigned oldLen = g_nextExtraText->len;
-        unsigned len = strlen(text);
-        g_nextExtraText->len += len;
-        g_nextExtraText->data = (char*)malloc(g_nextExtraText->len+1);
-        memcpy(g_nextExtraText->data, orig, oldLen);
-        memcpy(g_nextExtraText->data+oldLen, text, len);
-        g_nextExtraText->data[g_nextExtraText->len] = '\0';
-        free(orig);
-    }
-}
-
-extra_text_type*
-get_extra_text(void)
-{
-    extra_text_type* result = g_extraText;
-    g_extraText = NULL;
-    g_nextExtraText = NULL;
-    return result;
-}
-
-void drop_extra_text(void)
-{
-    extra_text_type* p = g_extraText;
-    while (p) {
-        extra_text_type* next = p->next;
-        free(p->data);
-        free(p);
-        free(next);
-    }
-    g_extraText = NULL;
-    g_nextExtraText = NULL;
-}
-
-
-// package handling
-// ================================================
-void do_package_statement(const char* importText)
-{
-    if (g_currentPackage) free((void*)g_currentPackage);
-    g_currentPackage = parse_import_statement(importText);
-}
-
-
-// main parse function
-// ================================================
-char const* g_currentFilename = NULL;
-char const* g_currentPackage = NULL;
-
-int yyparse(void);
-
-int parse_aidl(char const *filename)
-{
-    yyin = fopen(filename, "r");
-    if (yyin) {
-        char const* oldFilename = g_currentFilename;
-        char const* oldPackage = g_currentPackage;
-        g_currentFilename = strdup(filename);
-
-        g_error = 0;
-        yylineno = 1;
-        int rv = yyparse();
-        if (g_error != 0) {
-            rv = g_error;
-        }
-
-        free((void*)g_currentFilename);
-        g_currentFilename = oldFilename;
-        
-        if (g_currentPackage) free((void*)g_currentPackage);
-        g_currentPackage = oldPackage;
-
-        return rv;
-    } else {
-        fprintf(stderr, "aidl: unable to open file for read: %s\n", filename);
-        return 1;
-    }
-}
-
diff --git a/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y
deleted file mode 100644
index 9c5d10e..0000000
--- a/tools/aidl/aidl_language_y.y
+++ /dev/null
@@ -1,334 +0,0 @@
-%{
-#include "aidl_language.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-int yyerror(char* errstr);
-int yylex(void);
-extern int yylineno;
-
-static int count_brackets(const char*);
-
-%}
-
-%token IMPORT
-%token PACKAGE
-%token IDENTIFIER
-%token IDVALUE
-%token GENERIC
-%token ARRAY
-%token PARCELABLE
-%token INTERFACE
-%token IN
-%token OUT
-%token INOUT
-%token ONEWAY
-
-%%
-document:
-        document_items                          { g_callbacks->document($1.document_item); }
-    |   headers document_items                  { g_callbacks->document($2.document_item); }
-    ;
-
-headers:
-        package                                 { }
-    |   imports                                 { }
-    |   package imports                         { }
-    ;
-
-package:
-        PACKAGE                                 { }
-    ;
-
-imports:
-        IMPORT                                  { g_callbacks->import(&($1.buffer)); }
-    |   IMPORT imports                          { g_callbacks->import(&($1.buffer)); }
-    ;
-
-document_items:
-                                                { $$.document_item = NULL; }
-    |   document_items declaration              {
-                                                    if ($2.document_item == NULL) {
-                                                        // error cases only
-                                                        $$ = $1;
-                                                    } else {
-                                                        document_item_type* p = $1.document_item;
-                                                        while (p && p->next) {
-                                                            p=p->next;
-                                                        }
-                                                        if (p) {
-                                                            p->next = (document_item_type*)$2.document_item;
-                                                            $$ = $1;
-                                                        } else {
-                                                            $$.document_item = (document_item_type*)$2.document_item;
-                                                        }
-                                                    }
-                                                }
-    | document_items error                      {
-                                                    fprintf(stderr, "%s:%d: syntax error don't know what to do with \"%s\"\n", g_currentFilename,
-                                                            $2.buffer.lineno, $2.buffer.data);
-                                                    $$ = $1;
-                                                }
-    ;
-
-declaration:
-        parcelable_decl                            { $$.document_item = (document_item_type*)$1.user_data; }
-    |   interface_decl                             { $$.document_item = (document_item_type*)$1.interface_item; }
-    ;
-
-parcelable_decl:
-        PARCELABLE 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->parcelable = true;
-                                                        $$.user_data = b;
-                                                    }
-    |   PARCELABLE ';'                              {
-                                                        fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name.\n",
-                                                                     g_currentFilename, $1.buffer.lineno);
-                                                        $$.user_data = NULL;
-                                                    }
-    |   PARCELABLE error ';'                        {
-                                                        fprintf(stderr, "%s:%d syntax error in parcelable declaration. Expected type name, saw \"%s\".\n",
-                                                                     g_currentFilename, $2.buffer.lineno, $2.buffer.data);
-                                                        $$.user_data = NULL;
-                                                    }
-    ;
-
-interface_header:
-        INTERFACE                                  {
-                                                        interface_type* c = (interface_type*)malloc(sizeof(interface_type));
-                                                        c->document_item.item_type = INTERFACE_TYPE_BINDER;
-                                                        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;
-                                                   }
-    |   ONEWAY INTERFACE                           {
-                                                        interface_type* c = (interface_type*)malloc(sizeof(interface_type));
-                                                        c->document_item.item_type = INTERFACE_TYPE_BINDER;
-                                                        c->document_item.next = NULL;
-                                                        c->interface_token = $2.buffer;
-                                                        c->oneway = true;
-                                                        c->oneway_token = $1.buffer;
-                                                        c->comments_token = &c->oneway_token;
-                                                        $$.interface_obj = c;
-                                                   }
-    ;
-
-interface_decl:
-        interface_header IDENTIFIER '{' interface_items '}' { 
-                                                        interface_type* c = $1.interface_obj;
-                                                        c->name = $2.buffer;
-                                                        c->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
-                                                        c->open_brace_token = $3.buffer;
-                                                        c->interface_items = $4.interface_item;
-                                                        c->close_brace_token = $5.buffer;
-                                                        $$.interface_obj = c;
-                                                    }
-    |   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 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;
-                                                    }
-
-    ;
-
-interface_items:
-                                                    { $$.interface_item = NULL; }
-    |   interface_items method_decl                 {
-                                                        interface_item_type* p=$1.interface_item;
-                                                        while (p && p->next) {
-                                                            p=p->next;
-                                                        }
-                                                        if (p) {
-                                                            p->next = (interface_item_type*)$2.method;
-                                                            $$ = $1;
-                                                        } else {
-                                                            $$.interface_item = (interface_item_type*)$2.method;
-                                                        }
-                                                    }
-    |   interface_items error ';'                   {
-                                                        fprintf(stderr, "%s:%d: syntax error before ';' (expected method declaration)\n",
-                                                                    g_currentFilename, $3.buffer.lineno);
-                                                        $$ = $1;
-                                                    }
-    ;
-
-method_decl:
-        type IDENTIFIER '(' arg_list ')' ';'  {
-                                                        method_type *method = (method_type*)malloc(sizeof(method_type));
-                                                        method->interface_item.item_type = METHOD_TYPE;
-                                                        method->interface_item.next = NULL;
-                                                        method->oneway = false;
-                                                        method->type = $1.type;
-                                                        memset(&method->oneway_token, 0, sizeof(buffer_type));
-                                                        method->name = $2.buffer;
-                                                        method->open_paren_token = $3.buffer;
-                                                        method->args = $4.arg;
-                                                        method->close_paren_token = $5.buffer;
-                                                        method->hasId = false;
-                                                        memset(&method->equals_token, 0, sizeof(buffer_type));
-                                                        memset(&method->id, 0, sizeof(buffer_type));
-                                                        method->semicolon_token = $6.buffer;
-                                                        method->comments_token = &method->type.type;
-                                                        $$.method = method;
-                                                    }
-    |   ONEWAY type IDENTIFIER '(' arg_list ')' ';'  {
-                                                        method_type *method = (method_type*)malloc(sizeof(method_type));
-                                                        method->interface_item.item_type = METHOD_TYPE;
-                                                        method->interface_item.next = NULL;
-                                                        method->oneway = true;
-                                                        method->oneway_token = $1.buffer;
-                                                        method->type = $2.type;
-                                                        method->name = $3.buffer;
-                                                        method->open_paren_token = $4.buffer;
-                                                        method->args = $5.arg;
-                                                        method->close_paren_token = $6.buffer;
-                                                        method->hasId = false;
-                                                        memset(&method->equals_token, 0, sizeof(buffer_type));
-                                                        memset(&method->id, 0, sizeof(buffer_type));
-                                                        method->semicolon_token = $7.buffer;
-                                                        method->comments_token = &method->oneway_token;
-                                                        $$.method = method;
-                                                    }
-    |    type IDENTIFIER '(' arg_list ')' '=' IDVALUE ';'  {
-                                                        method_type *method = (method_type*)malloc(sizeof(method_type));
-                                                        method->interface_item.item_type = METHOD_TYPE;
-                                                        method->interface_item.next = NULL;
-                                                        method->oneway = false;
-                                                        memset(&method->oneway_token, 0, sizeof(buffer_type));
-                                                        method->type = $1.type;
-                                                        method->name = $2.buffer;
-                                                        method->open_paren_token = $3.buffer;
-                                                        method->args = $4.arg;
-                                                        method->close_paren_token = $5.buffer;
-                                                        method->hasId = true;
-                                                        method->equals_token = $6.buffer;
-                                                        method->id = $7.buffer;
-                                                        method->semicolon_token = $8.buffer;
-                                                        method->comments_token = &method->type.type;
-                                                        $$.method = method;
-                                                    }
-    |   ONEWAY type IDENTIFIER '(' arg_list ')' '=' IDVALUE ';'  {
-                                                        method_type *method = (method_type*)malloc(sizeof(method_type));
-                                                        method->interface_item.item_type = METHOD_TYPE;
-                                                        method->interface_item.next = NULL;
-                                                        method->oneway = true;
-                                                        method->oneway_token = $1.buffer;
-                                                        method->type = $2.type;
-                                                        method->name = $3.buffer;
-                                                        method->open_paren_token = $4.buffer;
-                                                        method->args = $5.arg;
-                                                        method->close_paren_token = $6.buffer;
-                                                        method->hasId = true;
-                                                        method->equals_token = $7.buffer;
-                                                        method->id = $8.buffer;
-                                                        method->semicolon_token = $9.buffer;
-                                                        method->comments_token = &method->oneway_token;
-                                                        $$.method = method;
-                                                    }
-    ;
-
-arg_list:
-                                { $$.arg = NULL; }
-    |   arg                     { $$ = $1; }
-    |   arg_list ',' arg        {
-                                    if ($$.arg != NULL) {
-                                        // only NULL on error
-                                        $$ = $1;
-                                        arg_type *p = $1.arg;
-                                        while (p && p->next) {
-                                            p=p->next;
-                                        }
-                                        $3.arg->comma_token = $2.buffer;
-                                        p->next = $3.arg;
-                                    }
-                                }
-    |   error                   {
-                                    fprintf(stderr, "%s:%d: syntax error in parameter list\n", g_currentFilename, $1.buffer.lineno);
-                                    $$.arg = NULL;
-                                }
-    ;
-
-arg:
-        direction type IDENTIFIER     {
-                                                arg_type* arg = (arg_type*)malloc(sizeof(arg_type));
-                                                memset(&arg->comma_token, 0, sizeof(buffer_type));
-                                                arg->direction = $1.buffer;
-                                                arg->type = $2.type;
-                                                arg->name = $3.buffer;
-                                                arg->next = NULL;
-                                                $$.arg = arg;
-                                      }
-    ;
-
-type:
-        IDENTIFIER              {
-                                    $$.type.type = $1.buffer;
-                                    init_buffer_type(&$$.type.array_token, yylineno);
-                                    $$.type.dimension = 0;
-                                }
-    |   IDENTIFIER ARRAY        {
-                                    $$.type.type = $1.buffer;
-                                    $$.type.array_token = $2.buffer;
-                                    $$.type.dimension = count_brackets($2.buffer.data);
-                                }
-    |   GENERIC                 {
-                                    $$.type.type = $1.buffer;
-                                    init_buffer_type(&$$.type.array_token, yylineno);
-                                    $$.type.dimension = 0;
-                                }
-    ;
-
-direction:
-                    { init_buffer_type(&$$.buffer, yylineno); }
-    |   IN          { $$.buffer = $1.buffer; }
-    |   OUT         { $$.buffer = $1.buffer; }
-    |   INOUT       { $$.buffer = $1.buffer; }
-    ;
-
-%%
-
-#include <ctype.h>
-#include <stdio.h>
-
-int g_error = 0;
-
-int yyerror(char* errstr)
-{
-    fprintf(stderr, "%s:%d: %s\n", g_currentFilename, yylineno, errstr);
-    g_error = 1;
-    return 1;
-}
-
-void init_buffer_type(buffer_type* buf, int lineno)
-{
-    buf->lineno = lineno;
-    buf->token = 0;
-    buf->data = NULL;
-    buf->extra = NULL;
-}
-
-static int count_brackets(const char* s)
-{
-    int n=0;
-    while (*s) {
-        if (*s == '[') n++;
-        s++;
-    }
-    return n;
-}
diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
deleted file mode 100644
index 1509340..0000000
--- a/tools/aidl/generate_java.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-#include "generate_java.h"
-#include "Type.h"
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-// =================================================
-VariableFactory::VariableFactory(const string& base)
-    :m_base(base),
-     m_index(0)
-{
-}
-
-Variable*
-VariableFactory::Get(Type* type)
-{
-    char name[100];
-    sprintf(name, "%s%d", m_base.c_str(), m_index);
-    m_index++;
-    Variable* v = new Variable(type, name);
-    m_vars.push_back(v);
-    return v;
-}
-
-Variable*
-VariableFactory::Get(int index)
-{
-    return m_vars[index];
-}
-
-// =================================================
-string
-gather_comments(extra_text_type* extra)
-{
-    string s;
-    while (extra) {
-        if (extra->which == SHORT_COMMENT) {
-            s += extra->data;
-        }
-        else if (extra->which == LONG_COMMENT) {
-            s += "/*";
-            s += extra->data;
-            s += "*/";
-        }
-        extra = extra->next;
-    }
-    return s;
-}
-
-string
-append(const char* a, const char* b)
-{
-    string s = a;
-    s += b;
-    return s;
-}
-
-// =================================================
-int
-generate_java(const string& filename, const string& originalSrc,
-                interface_type* iface)
-{
-    Class* cl;
-
-    if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) {
-        cl = generate_binder_interface_class(iface);
-    }
-
-    Document* document = new Document;
-        document->comment = "";
-        if (iface->package) document->package = iface->package;
-        document->originalSrc = originalSrc;
-        document->classes.push_back(cl);
-
-//    printf("outputting... filename=%s\n", filename.c_str());
-    FILE* to;
-    if (filename == "-") {
-        to = stdout;
-    } else {
-       /* open file in binary mode to ensure that the tool produces the
-        * same output on all platforms !!
-        */
-        to = fopen(filename.c_str(), "wb");
-        if (to == NULL) {
-            fprintf(stderr, "unable to open %s for write\n", filename.c_str());
-            return 1;
-        }
-    }
-
-    document->Write(to);
-
-    fclose(to);
-    return 0;
-}
-
diff --git a/tools/aidl/generate_java.h b/tools/aidl/generate_java.h
deleted file mode 100644
index 4e79743..0000000
--- a/tools/aidl/generate_java.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef AIDL_GENERATE_JAVA_H_
-#define AIDL_GENERATE_JAVA_H_
-
-#include "aidl_language.h"
-#include "AST.h"
-
-#include <string>
-
-using namespace std;
-
-int generate_java(const string& filename, const string& originalSrc,
-                interface_type* iface);
-
-Class* generate_binder_interface_class(const interface_type* iface);
-
-string gather_comments(extra_text_type* extra);
-string append(const char* a, const char* b);
-
-class VariableFactory
-{
-public:
-    VariableFactory(const string& base); // base must be short
-    Variable* Get(Type* type);
-    Variable* Get(int index);
-private:
-    vector<Variable*> m_vars;
-    string m_base;
-    int m_index;
-};
-
-#endif // AIDL_GENERATE_JAVA_H_
-
diff --git a/tools/aidl/generate_java_binder.cpp b/tools/aidl/generate_java_binder.cpp
deleted file mode 100644
index f291ceb..0000000
--- a/tools/aidl/generate_java_binder.cpp
+++ /dev/null
@@ -1,560 +0,0 @@
-#include "generate_java.h"
-#include "Type.h"
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-// =================================================
-class StubClass : public Class
-{
-public:
-    StubClass(Type* type, Type* interfaceType);
-    virtual ~StubClass();
-
-    Variable* transact_code;
-    Variable* transact_data;
-    Variable* transact_reply;
-    Variable* transact_flags;
-    SwitchStatement* transact_switch;
-private:
-    void make_as_interface(Type* interfaceType);
-};
-
-StubClass::StubClass(Type* type, Type* interfaceType)
-    :Class()
-{
-    this->comment = "/** Local-side IPC implementation stub class. */";
-    this->modifiers = PUBLIC | ABSTRACT | STATIC;
-    this->what = Class::CLASS;
-    this->type = type;
-    this->extends = BINDER_NATIVE_TYPE;
-    this->interfaces.push_back(interfaceType);
-
-    // descriptor
-    Field* descriptor = new Field(STATIC | FINAL | PRIVATE,
-                            new Variable(STRING_TYPE, "DESCRIPTOR"));
-    descriptor->value = "\"" + interfaceType->QualifiedName() + "\"";
-    this->elements.push_back(descriptor);
-
-    // ctor
-    Method* ctor = new Method;
-        ctor->modifiers = PUBLIC;
-        ctor->comment = "/** Construct the stub at attach it to the "
-                        "interface. */";
-        ctor->name = "Stub";
-        ctor->statements = new StatementBlock;
-    MethodCall* attach = new MethodCall(THIS_VALUE, "attachInterface",
-                            2, THIS_VALUE, new LiteralExpression("DESCRIPTOR"));
-    ctor->statements->Add(attach);
-    this->elements.push_back(ctor);
-
-    // asInterface
-    make_as_interface(interfaceType);
-
-    // asBinder
-    Method* asBinder = new Method;
-        asBinder->modifiers = PUBLIC | OVERRIDE;
-        asBinder->returnType = IBINDER_TYPE;
-        asBinder->name = "asBinder";
-        asBinder->statements = new StatementBlock;
-    asBinder->statements->Add(new ReturnStatement(THIS_VALUE));
-    this->elements.push_back(asBinder);
-
-    // onTransact
-    this->transact_code = new Variable(INT_TYPE, "code");
-    this->transact_data = new Variable(PARCEL_TYPE, "data");
-    this->transact_reply = new Variable(PARCEL_TYPE, "reply");
-    this->transact_flags = new Variable(INT_TYPE, "flags");
-    Method* onTransact = new Method;
-        onTransact->modifiers = PUBLIC | OVERRIDE;
-        onTransact->returnType = BOOLEAN_TYPE;
-        onTransact->name = "onTransact";
-        onTransact->parameters.push_back(this->transact_code);
-        onTransact->parameters.push_back(this->transact_data);
-        onTransact->parameters.push_back(this->transact_reply);
-        onTransact->parameters.push_back(this->transact_flags);
-        onTransact->statements = new StatementBlock;
-        onTransact->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
-    this->elements.push_back(onTransact);
-    this->transact_switch = new SwitchStatement(this->transact_code);
-
-    onTransact->statements->Add(this->transact_switch);
-    MethodCall* superCall = new MethodCall(SUPER_VALUE, "onTransact", 4,
-                                    this->transact_code, this->transact_data,
-                                    this->transact_reply, this->transact_flags);
-    onTransact->statements->Add(new ReturnStatement(superCall));
-}
-
-StubClass::~StubClass()
-{
-}
-
-void
-StubClass::make_as_interface(Type *interfaceType)
-{
-    Variable* obj = new Variable(IBINDER_TYPE, "obj");
-
-    Method* m = new Method;
-        m->comment = "/**\n * Cast an IBinder object into an ";
-        m->comment += interfaceType->QualifiedName();
-        m->comment += " interface,\n";
-        m->comment += " * generating a proxy if needed.\n */";
-        m->modifiers = PUBLIC | STATIC;
-        m->returnType = interfaceType;
-        m->name = "asInterface";
-        m->parameters.push_back(obj);
-        m->statements = new StatementBlock;
-
-    IfStatement* ifstatement = new IfStatement();
-        ifstatement->expression = new Comparison(obj, "==", NULL_VALUE);
-        ifstatement->statements = new StatementBlock;
-        ifstatement->statements->Add(new ReturnStatement(NULL_VALUE));
-    m->statements->Add(ifstatement);
-
-    // IInterface iin = obj.queryLocalInterface(DESCRIPTOR)
-    MethodCall* queryLocalInterface = new MethodCall(obj, "queryLocalInterface");
-    queryLocalInterface->arguments.push_back(new LiteralExpression("DESCRIPTOR"));
-    IInterfaceType* iinType = new IInterfaceType();
-    Variable *iin = new Variable(iinType, "iin");
-    VariableDeclaration* iinVd = new VariableDeclaration(iin, queryLocalInterface, NULL);
-    m->statements->Add(iinVd);
-
-    // Ensure the instance type of the local object is as expected.
-    // One scenario where this is needed is if another package (with a
-    // different class loader) runs in the same process as the service.
-
-    // if (iin != null && iin instanceof <interfaceType>) return (<interfaceType>) iin;
-    Comparison* iinNotNull = new Comparison(iin, "!=", NULL_VALUE);
-    Comparison* instOfCheck = new Comparison(iin, " instanceof ",
-            new LiteralExpression(interfaceType->QualifiedName()));
-    IfStatement* instOfStatement = new IfStatement();
-        instOfStatement->expression = new Comparison(iinNotNull, "&&", instOfCheck);
-        instOfStatement->statements = new StatementBlock;
-        instOfStatement->statements->Add(new ReturnStatement(new Cast(interfaceType, iin)));
-    m->statements->Add(instOfStatement);
-
-    string proxyType = interfaceType->QualifiedName();
-    proxyType += ".Stub.Proxy";
-    NewExpression* ne = new NewExpression(NAMES.Find(proxyType));
-    ne->arguments.push_back(obj);
-    m->statements->Add(new ReturnStatement(ne));
-
-    this->elements.push_back(m);
-}
-
-
-
-// =================================================
-class ProxyClass : public Class
-{
-public:
-    ProxyClass(Type* type, InterfaceType* interfaceType);
-    virtual ~ProxyClass();
-
-    Variable* mRemote;
-    bool mOneWay;
-};
-
-ProxyClass::ProxyClass(Type* type, InterfaceType* interfaceType)
-    :Class()
-{
-    this->modifiers = PRIVATE | STATIC;
-    this->what = Class::CLASS;
-    this->type = type;
-    this->interfaces.push_back(interfaceType);
-
-    mOneWay = interfaceType->OneWay();
-
-    // IBinder mRemote
-    mRemote = new Variable(IBINDER_TYPE, "mRemote");
-    this->elements.push_back(new Field(PRIVATE, mRemote));
-
-    // Proxy()
-    Variable* remote = new Variable(IBINDER_TYPE, "remote");
-    Method* ctor = new Method;
-        ctor->name = "Proxy";
-        ctor->statements = new StatementBlock;
-        ctor->parameters.push_back(remote);
-    ctor->statements->Add(new Assignment(mRemote, remote));
-    this->elements.push_back(ctor);
-
-    // IBinder asBinder()
-    Method* asBinder = new Method;
-        asBinder->modifiers = PUBLIC | OVERRIDE;
-        asBinder->returnType = IBINDER_TYPE;
-        asBinder->name = "asBinder";
-        asBinder->statements = new StatementBlock;
-    asBinder->statements->Add(new ReturnStatement(mRemote));
-    this->elements.push_back(asBinder);
-}
-
-ProxyClass::~ProxyClass()
-{
-}
-
-// =================================================
-static void
-generate_new_array(Type* t, StatementBlock* addTo, Variable* v,
-                            Variable* parcel)
-{
-    Variable* len = new Variable(INT_TYPE, v->name + "_length");
-    addTo->Add(new VariableDeclaration(len, new MethodCall(parcel, "readInt")));
-    IfStatement* lencheck = new IfStatement();
-    lencheck->expression = new Comparison(len, "<", new LiteralExpression("0"));
-    lencheck->statements->Add(new Assignment(v, NULL_VALUE));
-    lencheck->elseif = new IfStatement();
-    lencheck->elseif->statements->Add(new Assignment(v,
-                new NewArrayExpression(t, len)));
-    addTo->Add(lencheck);
-}
-
-static void
-generate_write_to_parcel(Type* t, StatementBlock* addTo, Variable* v,
-                            Variable* parcel, int flags)
-{
-    if (v->dimension == 0) {
-        t->WriteToParcel(addTo, v, parcel, flags);
-    }
-    if (v->dimension == 1) {
-        t->WriteArrayToParcel(addTo, v, parcel, flags);
-    }
-}
-
-static void
-generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
-                            Variable* parcel, Variable** cl)
-{
-    if (v->dimension == 0) {
-        t->CreateFromParcel(addTo, v, parcel, cl);
-    }
-    if (v->dimension == 1) {
-        t->CreateArrayFromParcel(addTo, v, parcel, cl);
-    }
-}
-
-static void
-generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
-                            Variable* parcel, Variable** cl)
-{
-    if (v->dimension == 0) {
-        t->ReadFromParcel(addTo, v, parcel, cl);
-    }
-    if (v->dimension == 1) {
-        t->ReadArrayFromParcel(addTo, v, parcel, cl);
-    }
-}
-
-
-static void
-generate_method(const method_type* method, Class* interface,
-                    StubClass* stubClass, ProxyClass* proxyClass, int index)
-{
-    arg_type* arg;
-    int i;
-    bool hasOutParams = false;
-
-    const bool oneway = proxyClass->mOneWay || method->oneway;
-
-    // == the TRANSACT_ constant =============================================
-    string transactCodeName = "TRANSACTION_";
-    transactCodeName += method->name.data;
-
-    char transactCodeValue[60];
-    sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
-
-    Field* transactCode = new Field(STATIC | FINAL,
-                            new Variable(INT_TYPE, transactCodeName));
-    transactCode->value = transactCodeValue;
-    stubClass->elements.push_back(transactCode);
-
-    // == the declaration in the interface ===================================
-    Method* decl = new Method;
-        decl->comment = gather_comments(method->comments_token->extra);
-        decl->modifiers = PUBLIC;
-        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;
-    }
-
-    decl->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
-
-    interface->elements.push_back(decl);
-
-    // == the stub method ====================================================
-
-    Case* c = new Case(transactCodeName);
-
-    MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
-
-    // interface token validation is the very first thing we do
-    c->statements->Add(new MethodCall(stubClass->transact_data,
-            "enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
-
-    // args
-    Variable* cl = 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;
-
-        c->statements->Add(new VariableDeclaration(v));
-
-        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
-            generate_create_from_parcel(t, c->statements, v,
-                    stubClass->transact_data, &cl);
-        } else {
-            if (arg->type.dimension == 0) {
-                c->statements->Add(new Assignment(v, new NewExpression(v->type)));
-            }
-            else if (arg->type.dimension == 1) {
-                generate_new_array(v->type, c->statements, v,
-                        stubClass->transact_data);
-            }
-            else {
-                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
-                        __LINE__);
-            }
-        }
-
-        realCall->arguments.push_back(v);
-
-        arg = arg->next;
-    }
-
-    // the real call
-    Variable* _result = NULL;
-    if (0 == strcmp(method->type.type.data, "void")) {
-        c->statements->Add(realCall);
-
-        if (!oneway) {
-            // report that there were no exceptions
-            MethodCall* ex = new MethodCall(stubClass->transact_reply,
-                    "writeNoException", 0);
-            c->statements->Add(ex);
-        }
-    } else {
-        _result = new Variable(decl->returnType, "_result",
-                                decl->returnTypeDimension);
-        c->statements->Add(new VariableDeclaration(_result, realCall));
-
-        if (!oneway) {
-            // report that there were no exceptions
-            MethodCall* ex = new MethodCall(stubClass->transact_reply,
-                    "writeNoException", 0);
-            c->statements->Add(ex);
-        }
-
-        // marshall the return value
-        generate_write_to_parcel(decl->returnType, c->statements, _result,
-                                    stubClass->transact_reply,
-                                    Type::PARCELABLE_WRITE_RETURN_VALUE);
-    }
-
-    // out parameters
-    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) {
-            generate_write_to_parcel(t, c->statements, v,
-                                stubClass->transact_reply,
-                                Type::PARCELABLE_WRITE_RETURN_VALUE);
-            hasOutParams = true;
-        }
-
-        arg = arg->next;
-    }
-
-    // return true
-    c->statements->Add(new ReturnStatement(TRUE_VALUE));
-    stubClass->transact_switch->cases.push_back(c);
-
-    // == the proxy method ===================================================
-    Method* proxy = new Method;
-        proxy->comment = gather_comments(method->comments_token->extra);
-        proxy->modifiers = PUBLIC | OVERRIDE;
-        proxy->returnType = NAMES.Search(method->type.type.data);
-        proxy->returnTypeDimension = method->type.dimension;
-        proxy->name = method->name.data;
-        proxy->statements = new StatementBlock;
-        arg = method->args;
-        while (arg != NULL) {
-            proxy->parameters.push_back(new Variable(
-                            NAMES.Search(arg->type.type.data), arg->name.data,
-                            arg->type.dimension));
-            arg = arg->next;
-        }
-        proxy->exceptions.push_back(REMOTE_EXCEPTION_TYPE);
-    proxyClass->elements.push_back(proxy);
-
-    // the parcels
-    Variable* _data = new Variable(PARCEL_TYPE, "_data");
-    proxy->statements->Add(new VariableDeclaration(_data,
-                                new MethodCall(PARCEL_TYPE, "obtain")));
-    Variable* _reply = NULL;
-    if (!oneway) {
-        _reply = new Variable(PARCEL_TYPE, "_reply");
-        proxy->statements->Add(new VariableDeclaration(_reply,
-                                    new MethodCall(PARCEL_TYPE, "obtain")));
-    }
-
-    // the return value
-    _result = NULL;
-    if (0 != strcmp(method->type.type.data, "void")) {
-        _result = new Variable(proxy->returnType, "_result",
-                method->type.dimension);
-        proxy->statements->Add(new VariableDeclaration(_result));
-    }
-
-    // try and finally
-    TryStatement* tryStatement = new TryStatement();
-    proxy->statements->Add(tryStatement);
-    FinallyStatement* finallyStatement = new FinallyStatement();
-    proxy->statements->Add(finallyStatement);
-
-    // the interface identifier token: the DESCRIPTOR constant, marshalled as a string
-    tryStatement->statements->Add(new MethodCall(_data, "writeInterfaceToken",
-            1, new LiteralExpression("DESCRIPTOR")));
-
-    // the parameters
-    arg = method->args;
-    while (arg != NULL) {
-        Type* t = NAMES.Search(arg->type.type.data);
-        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
-        int dir = convert_direction(arg->direction.data);
-        if (dir == OUT_PARAMETER && arg->type.dimension != 0) {
-            IfStatement* checklen = new IfStatement();
-            checklen->expression = new Comparison(v, "==", NULL_VALUE);
-            checklen->statements->Add(new MethodCall(_data, "writeInt", 1,
-                        new LiteralExpression("-1")));
-            checklen->elseif = new IfStatement();
-            checklen->elseif->statements->Add(new MethodCall(_data, "writeInt",
-                        1, new FieldVariable(v, "length")));
-            tryStatement->statements->Add(checklen);
-        }
-        else if (dir & IN_PARAMETER) {
-            generate_write_to_parcel(t, tryStatement->statements, v, _data, 0);
-        }
-        arg = arg->next;
-    }
-
-    // the transact call
-    MethodCall* call = new MethodCall(proxyClass->mRemote, "transact", 4,
-                            new LiteralExpression("Stub." + transactCodeName),
-                            _data, _reply ? _reply : NULL_VALUE,
-                            new LiteralExpression(
-                                oneway ? "android.os.IBinder.FLAG_ONEWAY" : "0"));
-    tryStatement->statements->Add(call);
-
-    // throw back exceptions.
-    if (_reply) {
-        MethodCall* ex = new MethodCall(_reply, "readException", 0);
-        tryStatement->statements->Add(ex);
-    }
-
-    // returning and cleanup
-    if (_reply != NULL) {
-        if (_result != NULL) {
-            generate_create_from_parcel(proxy->returnType,
-                    tryStatement->statements, _result, _reply, &cl);
-        }
-
-        // the out/inout parameters
-        arg = method->args;
-        while (arg != NULL) {
-            Type* t = NAMES.Search(arg->type.type.data);
-            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
-            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
-                generate_read_from_parcel(t, tryStatement->statements,
-                                            v, _reply, &cl);
-            }
-            arg = arg->next;
-        }
-
-        finallyStatement->statements->Add(new MethodCall(_reply, "recycle"));
-    }
-    finallyStatement->statements->Add(new MethodCall(_data, "recycle"));
-
-    if (_result != NULL) {
-        proxy->statements->Add(new ReturnStatement(_result));
-    }
-}
-
-static void
-generate_interface_descriptors(StubClass* stub, ProxyClass* proxy)
-{
-    // the interface descriptor transaction handler
-    Case* c = new Case("INTERFACE_TRANSACTION");
-    c->statements->Add(new MethodCall(stub->transact_reply, "writeString",
-            1, new LiteralExpression("DESCRIPTOR")));
-    c->statements->Add(new ReturnStatement(TRUE_VALUE));
-    stub->transact_switch->cases.push_back(c);
-
-    // and the proxy-side method returning the descriptor directly
-    Method* getDesc = new Method;
-    getDesc->modifiers = PUBLIC;
-    getDesc->returnType = STRING_TYPE;
-    getDesc->returnTypeDimension = 0;
-    getDesc->name = "getInterfaceDescriptor";
-    getDesc->statements = new StatementBlock;
-    getDesc->statements->Add(new ReturnStatement(new LiteralExpression("DESCRIPTOR")));
-    proxy->elements.push_back(getDesc);
-}
-
-Class*
-generate_binder_interface_class(const interface_type* iface)
-{
-    InterfaceType* interfaceType = static_cast<InterfaceType*>(
-        NAMES.Find(iface->package, iface->name.data));
-
-    // the interface class
-    Class* interface = new Class;
-        interface->comment = gather_comments(iface->comments_token->extra);
-        interface->modifiers = PUBLIC;
-        interface->what = Class::INTERFACE;
-        interface->type = interfaceType;
-        interface->interfaces.push_back(IINTERFACE_TYPE);
-
-    // the stub inner class
-    StubClass* stub = new StubClass(
-        NAMES.Find(iface->package, append(iface->name.data, ".Stub").c_str()),
-        interfaceType);
-    interface->elements.push_back(stub);
-
-    // the proxy inner class
-    ProxyClass* proxy = new ProxyClass(
-        NAMES.Find(iface->package,
-                         append(iface->name.data, ".Stub.Proxy").c_str()),
-        interfaceType);
-    stub->elements.push_back(proxy);
-
-    // stub and proxy support for getInterfaceDescriptor()
-    generate_interface_descriptors(stub, proxy);
-
-    // all the declared methods of the interface
-    int index = 0;
-    interface_item_type* item = iface->interface_items;
-    while (item != NULL) {
-        if (item->item_type == METHOD_TYPE) {
-            method_type * method_item = (method_type*) item;
-            generate_method(method_item, interface, stub, proxy, method_item->assigned_id);
-        }
-        item = item->next;
-        index++;
-    }
-
-    return interface;
-}
-
diff --git a/tools/aidl/main.cpp b/tools/aidl/main.cpp
deleted file mode 100644
index 7cc2198..0000000
--- a/tools/aidl/main.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "aidl.h"
-#include "options.h"
-
-#include <stdio.h>
-
-int
-main(int argc, const char **argv)
-{
-    Options options;
-    int result = parse_options(argc, argv, &options);
-    if (result) {
-        return result;
-    }
-
-    switch (options.task) {
-        case COMPILE_AIDL:
-            return compile_aidl(options);
-        case PREPROCESS_AIDL:
-            return preprocess_aidl(options);
-    }
-    fprintf(stderr, "aidl: internal error\n");
-    return 1;
-}
diff --git a/tools/aidl/options.cpp b/tools/aidl/options.cpp
deleted file mode 100644
index 52b0972..0000000
--- a/tools/aidl/options.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-
-#include "options.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-static int
-usage()
-{
-    fprintf(stderr,
-            "usage: aidl OPTIONS INPUT [OUTPUT]\n"
-            "       aidl --preprocess OUTPUT INPUT...\n"
-            "\n"
-            "OPTIONS:\n"
-            "   -I<DIR>    search path for import statements.\n"
-            "   -d<FILE>   generate dependency file.\n"
-            "   -a         generate dependency file next to the output file with the name based on the input file.\n"
-            "   -p<FILE>   file created by --preprocess to import.\n"
-            "   -o<FOLDER> base output folder for generated files.\n"
-            "   -b         fail when trying to compile a parcelable.\n"
-            "\n"
-            "INPUT:\n"
-            "   An aidl interface file.\n"
-            "\n"
-            "OUTPUT:\n"
-            "   The generated interface files.\n"
-            "   If omitted and the -o option is not used, the input filename is used, with the .aidl extension changed to a .java extension.\n"
-            "   If the -o option is used, the generated files will be placed in the base output folder, under their package folder\n"
-           );
-    return 1;
-}
-
-int
-parse_options(int argc, const char* const* argv, Options *options)
-{
-    int i = 1;
-
-    if (argc >= 2 && 0 == strcmp(argv[1], "--preprocess")) {
-        if (argc < 4) {
-            return usage();
-        }
-        options->outputFileName = argv[2];
-        for (int i=3; i<argc; i++) {
-            options->filesToPreprocess.push_back(argv[i]);
-        }
-        options->task = PREPROCESS_AIDL;
-        return 0;
-    }
-
-    // OPTIONS
-    while (i < argc) {
-        const char* s = argv[i];
-        int len = strlen(s);
-        if (s[0] == '-') {
-            if (len > 1) {
-                // -I<system-import-path>
-                if (s[1] == 'I') {
-                    if (len > 2) {
-                        options->importPaths.push_back(s+2);
-                    } else {
-                        fprintf(stderr, "-I option (%d) requires a path.\n", i);
-                        return usage();
-                    }
-                }
-                else if (s[1] == 'd') {
-                    if (len > 2) {
-                        options->depFileName = s+2;
-                    } else {
-                        fprintf(stderr, "-d option (%d) requires a file.\n", i);
-                        return usage();
-                    }
-                }
-                else if (s[1] == 'a') {
-                    options->autoDepFile = true;
-                }
-                else if (s[1] == 'p') {
-                    if (len > 2) {
-                        options->preprocessedFiles.push_back(s+2);
-                    } else {
-                        fprintf(stderr, "-p option (%d) requires a file.\n", i);
-                        return usage();
-                    }
-                }
-                else if (s[1] == 'o') {
-                    if (len > 2) {
-                        options->outputBaseFolder = s+2;
-                    } else {
-                        fprintf(stderr, "-o option (%d) requires a path.\n", i);
-                        return usage();
-                    }
-                }
-                else if (len == 2 && s[1] == 'b') {
-                    options->failOnParcelable = true;
-                }
-                else {
-                    // s[1] is not known
-                    fprintf(stderr, "unknown option (%d): %s\n", i, s);
-                    return usage();
-                }
-            } else {
-                // len <= 1
-                fprintf(stderr, "unknown option (%d): %s\n", i, s);
-                return usage();
-            }
-        } else {
-            // s[0] != '-'
-            break;
-        }
-        i++;
-    }
-
-    // INPUT
-    if (i < argc) {
-        options->inputFileName = argv[i];
-        i++;
-    } else {
-        fprintf(stderr, "INPUT required\n");
-        return usage();
-    }
-
-    // OUTPUT
-    if (i < argc) {
-        options->outputFileName = argv[i];
-        i++;
-    } else if (options->outputBaseFolder.length() == 0) {
-        // copy input into output and change the extension from .aidl to .java
-        options->outputFileName = options->inputFileName;
-        string::size_type pos = options->outputFileName.size()-5;
-        if (options->outputFileName.compare(pos, 5, ".aidl") == 0) {  // 5 = strlen(".aidl")
-            options->outputFileName.replace(pos, 5, ".java"); // 5 = strlen(".aidl")
-        } else {
-            fprintf(stderr, "INPUT is not an .aidl file.\n");
-            return usage();
-        }
-     }
-
-    // anything remaining?
-    if (i != argc) {
-        fprintf(stderr, "unknown option%s:", (i==argc-1?(const char*)"":(const char*)"s"));
-        for (; i<argc-1; i++) {
-            fprintf(stderr, " %s", argv[i]);
-        }
-        fprintf(stderr, "\n");
-        return usage();
-    }
-
-    return 0;
-}
-
diff --git a/tools/aidl/options.h b/tools/aidl/options.h
deleted file mode 100644
index 4e95e11..0000000
--- a/tools/aidl/options.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef AIDL_OPTIONS_H_
-#define AIDL_OPTIONS_H_
-
-#include <string.h>
-#include <string>
-#include <vector>
-
-using namespace std;
-
-enum {
-    COMPILE_AIDL,
-    PREPROCESS_AIDL
-};
-
-// This struct is the parsed version of the command line options
-struct Options
-{
-    int task{COMPILE_AIDL};
-    bool failOnParcelable{false};
-    vector<string> importPaths;
-    vector<string> preprocessedFiles;
-    string inputFileName;
-    string outputFileName;
-    string outputBaseFolder;
-    string depFileName;
-    bool autoDepFile{false};
-
-    vector<string> filesToPreprocess;
-};
-
-// takes the inputs from the command line and fills in the Options struct
-// Returns 0 on success, and nonzero on failure.
-// It also prints the usage statement on failure.
-int parse_options(int argc, const char* const* argv, Options *options);
-
-#endif // AIDL_OPTIONS_H_
diff --git a/tools/aidl/options_unittest.cpp b/tools/aidl/options_unittest.cpp
deleted file mode 100644
index fec7f87..0000000
--- a/tools/aidl/options_unittest.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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 <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include "options.h"
-
-using std::vector;
-using std::string;
-
-const char kPreprocessCommandOutputFile[] = "output_file_name";
-const char kPreprocessCommandInput1[] = "input1";
-const char kPreprocessCommandInput2[] = "input2";
-const char kPreprocessCommandInput3[] = "input3";
-const char* kPreprocessCommand[] = {
-    "aidl", "--preprocess",
-    kPreprocessCommandOutputFile,
-    kPreprocessCommandInput1,
-    kPreprocessCommandInput2,
-    kPreprocessCommandInput3,
-};
-
-TEST(OptionsTests, ParsesPreprocess) {
-  Options options;
-  const int argc = sizeof(kPreprocessCommand) / sizeof(*kPreprocessCommand);
-  EXPECT_EQ(parse_options(argc, kPreprocessCommand, &options), 0);
-  EXPECT_EQ(options.task, PREPROCESS_AIDL);
-  EXPECT_EQ(options.failOnParcelable, false);
-  EXPECT_EQ(options.importPaths.size(), 0u);
-  EXPECT_EQ(options.preprocessedFiles.size(), 0u);
-  EXPECT_EQ(options.inputFileName, string{""});
-  EXPECT_EQ(options.outputFileName, string{kPreprocessCommandOutputFile});
-  EXPECT_EQ(options.autoDepFile, false);
-  const vector<string> expected_input{kPreprocessCommandInput1,
-                                      kPreprocessCommandInput2,
-                                      kPreprocessCommandInput3};
-  EXPECT_EQ(options.filesToPreprocess, expected_input);
-}
diff --git a/tools/aidl/os.h b/tools/aidl/os.h
deleted file mode 100644
index 752ed47..0000000
--- a/tools/aidl/os.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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 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_OS_H_
-#define AIDL_OS_H_
-
-#if defined(_WIN32)
-#define OS_PATH_SEPARATOR '\\'
-#else
-#define OS_PATH_SEPARATOR '/'
-#endif
-
-#endif  // AIDL_OS_H_
diff --git a/tools/aidl/search_path.cpp b/tools/aidl/search_path.cpp
deleted file mode 100644
index 029e216..0000000
--- a/tools/aidl/search_path.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <unistd.h>
-#include "search_path.h"
-#include "options.h"
-#include "os.h"
-#include <string.h>
-
-#ifdef _WIN32
-#include <io.h>
-#endif
-
-static vector<string> g_importPaths;
-
-void
-set_import_paths(const vector<string>& importPaths)
-{
-    g_importPaths = importPaths;
-}
-
-char*
-find_import_file(const char* given)
-{
-    string expected = given;
-
-    int N = expected.length();
-    for (int i=0; i<N; i++) {
-        char c = expected[i];
-        if (c == '.') {
-            expected[i] = OS_PATH_SEPARATOR;
-        }
-    }
-    expected += ".aidl";
-
-    vector<string>& paths = g_importPaths;
-    for (vector<string>::iterator it=paths.begin(); it!=paths.end(); it++) {
-        string f = *it;
-        if (f.size() == 0) {
-            f = ".";
-            f += OS_PATH_SEPARATOR;
-        }
-        else if (f[f.size()-1] != OS_PATH_SEPARATOR) {
-            f += OS_PATH_SEPARATOR;
-        }
-        f.append(expected);
-
-#ifdef _WIN32
-        /* check that the file exists and is not write-only */
-        if (0 == _access(f.c_str(), 0) &&  /* mode 0=exist */
-            0 == _access(f.c_str(), 4) ) { /* mode 4=readable */
-#else
-        if (0 == access(f.c_str(), R_OK)) {
-#endif        
-            return strdup(f.c_str());
-        }
-    }
-
-    return NULL;
-}
-
diff --git a/tools/aidl/search_path.h b/tools/aidl/search_path.h
deleted file mode 100644
index 4fec257..0000000
--- a/tools/aidl/search_path.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef AIDL_SEARCH_PATH_H_
-#define AIDL_SEARCH_PATH_H_
-
-#include <stdio.h>
-
-#if __cplusplus
-#include <vector>
-#include <string>
-using namespace std;
-extern "C" {
-#endif
-
-// returns a FILE* and the char* for the file that it found
-// given is the class name we're looking for
-char* find_import_file(const char* given);
-
-#if __cplusplus
-}; // extern "C"
-void set_import_paths(const vector<string>& importPaths);
-#endif
-
-#endif // AIDL_SEARCH_PATH_H_
diff --git a/tools/aidl/test_main.cpp b/tools/aidl/test_main.cpp
deleted file mode 100644
index 4d820af7..0000000
--- a/tools/aidl/test_main.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#include <gtest/gtest.h>
-
-int main(int argc, char **argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
-}
diff --git a/tools/aidl/tests/end_to_end_tests.cpp b/tools/aidl/tests/end_to_end_tests.cpp
deleted file mode 100644
index 54ca603..0000000
--- a/tools/aidl/tests/end_to_end_tests.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * 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
deleted file mode 100644
index b17a800..0000000
--- a/tools/aidl/tests/example_interface_test_data.cpp
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * 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_data.h b/tools/aidl/tests/test_data.h
deleted file mode 100644
index cd8887f..0000000
--- a/tools/aidl/tests/test_data.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index bea1f86..2997907 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -148,6 +148,13 @@
     }
 
     @Override
+    public boolean startMovingTask(IWindow window, float startX, float startY)
+            throws RemoteException {
+        // pass for now
+        return false;
+    }
+
+    @Override
     public void reportDropResult(IWindow window, boolean consumed) throws RemoteException {
         // pass for now
     }