Merge "Don't move task if it is already in the destination stack"
diff --git a/core/java/android/content/pm/AppsQueryHelper.java b/core/java/android/content/pm/AppsQueryHelper.java
index a5a8e3f..084bc18 100644
--- a/core/java/android/content/pm/AppsQueryHelper.java
+++ b/core/java/android/content/pm/AppsQueryHelper.java
@@ -18,13 +18,11 @@
 
 import android.Manifest;
 import android.app.AppGlobals;
-import android.content.Context;
 import android.content.Intent;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.ArraySet;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethod;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -44,36 +42,37 @@
     public static int GET_NON_LAUNCHABLE_APPS = 1;
 
     /**
-     * Return apps with {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission
+     * Return apps with {@link Manifest.permission#INTERACT_ACROSS_USERS} permission
      */
     public static int GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM = 1 << 1;
 
     /**
-     * Return all input methods that are marked as default.
-     * <p>When this flag is set, {@code user} specified in
-     * {@link #queryApps(int, boolean, UserHandle)} must be
-     * {@link UserHandle#myUserId user of the current process}.
+     * Return all input methods available for the current user.
      */
-    public static int GET_DEFAULT_IMES = 1 << 2;
+    public static int GET_IMES = 1 << 2;
 
-    private final Context mContext;
+    private final IPackageManager mPackageManager;
     private List<ApplicationInfo> mAllApps;
 
-    public AppsQueryHelper(Context context) {
-        mContext = context;
+    public AppsQueryHelper(IPackageManager packageManager) {
+        mPackageManager = packageManager;
+    }
+
+    public AppsQueryHelper() {
+        this(AppGlobals.getPackageManager());
     }
 
     /**
      * Return a List of all packages that satisfy a specified criteria.
      * @param flags search flags. Use any combination of {@link #GET_NON_LAUNCHABLE_APPS},
-     * {@link #GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM} or {@link #GET_DEFAULT_IMES}.
+     * {@link #GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM} or {@link #GET_IMES}.
      * @param systemAppsOnly if true, only system apps will be returned
      * @param user user, whose apps are queried
      */
     public List<String> queryApps(int flags, boolean systemAppsOnly, UserHandle user) {
         boolean nonLaunchableApps = (flags & GET_NON_LAUNCHABLE_APPS) > 0;
         boolean interactAcrossUsers = (flags & GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM) > 0;
-        boolean defaultImes = (flags & GET_DEFAULT_IMES) > 0;
+        boolean imes = (flags & GET_IMES) > 0;
         if (mAllApps == null) {
             mAllApps = getAllApps(user.getIdentifier());
         }
@@ -113,7 +112,6 @@
                 }
             }
         }
-
         if (interactAcrossUsers) {
             final List<PackageInfo> packagesHoldingPermissions = getPackagesHoldingPermission(
                     Manifest.permission.INTERACT_ACROSS_USERS, user.getIdentifier());
@@ -129,29 +127,18 @@
             }
         }
 
-        if (defaultImes) {
-            if (UserHandle.myUserId() != user.getIdentifier()) {
-                throw new IllegalArgumentException("Specified user handle " + user
-                        + " is not a user of the current process.");
-            }
-            List<InputMethodInfo> imis = getInputMethodList();
-            int imisSize = imis.size();
-            ArraySet<String> defaultImePackages = new ArraySet<>();
-            for (int i = 0; i < imisSize; i++) {
-                InputMethodInfo imi = imis.get(i);
-                if (imi.isDefault(mContext)) {
-                    defaultImePackages.add(imi.getPackageName());
-                }
-            }
-            final int allAppsSize = mAllApps.size();
-            for (int i = 0; i < allAppsSize; i++) {
-                final ApplicationInfo appInfo = mAllApps.get(i);
-                if (systemAppsOnly && !appInfo.isSystemApp()) {
+        if (imes) {
+            final List<ResolveInfo> resolveInfos = queryIntentServicesAsUser(
+                    new Intent(InputMethod.SERVICE_INTERFACE), user.getIdentifier());
+            final int resolveInfosSize = resolveInfos.size();
+
+            for (int i = 0; i < resolveInfosSize; i++) {
+                ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
+                if (systemAppsOnly && !serviceInfo.applicationInfo.isSystemApp()) {
                     continue;
                 }
-                final String packageName = appInfo.packageName;
-                if (defaultImePackages.contains(packageName)) {
-                    result.add(packageName);
+                if (!result.contains(serviceInfo.packageName)) {
+                    result.add(serviceInfo.packageName);
                 }
             }
         }
@@ -163,9 +150,8 @@
     @SuppressWarnings("unchecked")
     protected List<ApplicationInfo> getAllApps(int userId) {
         try {
-            return AppGlobals.getPackageManager().getInstalledApplications(
-                    PackageManager.GET_UNINSTALLED_PACKAGES
-                            | PackageManager.GET_DISABLED_COMPONENTS, userId).getList();
+            return mPackageManager.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES
+                    | PackageManager.GET_DISABLED_COMPONENTS, userId).getList();
         } catch (RemoteException e) {
             throw new IllegalStateException("Package manager has died", e);
         }
@@ -173,17 +159,22 @@
 
     @VisibleForTesting
     protected List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int userId) {
-        return mContext.getPackageManager()
-                .queryIntentActivitiesAsUser(intent, PackageManager.GET_DISABLED_COMPONENTS
-                        | PackageManager.GET_UNINSTALLED_PACKAGES, userId);
+        try {
+            return mPackageManager.queryIntentActivities(intent, null,
+                    PackageManager.GET_DISABLED_COMPONENTS
+                            | PackageManager.GET_UNINSTALLED_PACKAGES,
+                    userId);
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Package manager has died", e);
+        }
     }
 
     @VisibleForTesting
-    @SuppressWarnings("unchecked")
-    protected List<PackageInfo> getPackagesHoldingPermission(String perm, int userId) {
+    protected List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int userId) {
         try {
-            return AppGlobals.getPackageManager().getPackagesHoldingPermissions(new String[]{perm},
-                    0, userId).getList();
+            return mPackageManager.queryIntentServices(intent, null,
+                    PackageManager.GET_META_DATA
+                            | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId);
         } catch (RemoteException e) {
             throw new IllegalStateException("Package manager has died", e);
         }
@@ -191,9 +182,13 @@
 
     @VisibleForTesting
     @SuppressWarnings("unchecked")
-    protected List<InputMethodInfo> getInputMethodList() {
-        InputMethodManager imm = (InputMethodManager)
-                mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
-        return imm.getInputMethodList();
+    protected List<PackageInfo> getPackagesHoldingPermission(String perm, int userId) {
+        try {
+            return mPackageManager.getPackagesHoldingPermissions(new String[]{perm}, 0,
+                    userId).getList();
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Package manager has died", e);
+        }
     }
+
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 625ed38..fdea1ba 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1638,6 +1638,8 @@
                 final boolean stableInsetsChanged = !mPendingStableInsets.equals(
                         mAttachInfo.mStableInsets);
                 final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
+                final boolean surfaceSizeChanged = (relayoutResult
+                        & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
                 if (contentInsetsChanged) {
                     mAttachInfo.mContentInsets.set(mPendingContentInsets);
                     if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
@@ -1723,10 +1725,20 @@
                             mAttachInfo.mHardwareRenderer.isEnabled()) {
                         mAttachInfo.mHardwareRenderer.destroy();
                     }
-                } else if (surfaceGenerationId != mSurface.getGenerationId() &&
-                        mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
+                } else if ((surfaceGenerationId != mSurface.getGenerationId()
+                        || surfaceSizeChanged)
+                        && mSurfaceHolder == null
+                        && mAttachInfo.mHardwareRenderer != null) {
                     mFullRedrawNeeded = true;
                     try {
+                        // Need to do updateSurface (which leads to CanvasContext::setSurface and
+                        // re-create the EGLSurface) if either the Surface changed (as indicated by
+                        // generation id), or WindowManager changed the surface size. The latter is
+                        // because on some chips, changing the consumer side's BufferQueue size may
+                        // not take effect immediately unless we create a new EGLSurface.
+                        // Note that frame size change doesn't always imply surface size change (eg.
+                        // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
+                        // flag from WindowManager.
                         mAttachInfo.mHardwareRenderer.updateSurface(mSurface);
                     } catch (OutOfResourcesException e) {
                         handleOutOfResourcesException(e);
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 43d643e..c08e1b5 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -77,6 +77,11 @@
     public static final int RELAYOUT_RES_DRAG_RESIZING = 0x8;
 
     /**
+     * The window manager has changed the size of the surface from the last call.
+     */
+    public static final int RELAYOUT_RES_SURFACE_RESIZED = 0x10;
+
+    /**
      * Flag for relayout: the client will be later giving
      * internal insets; as a result, the window will not impact other window
      * layouts until the insets are given.
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
index 2d23cda..c89f293c 100644
--- a/core/jni/android_util_Log.cpp
+++ b/core/jni/android_util_Log.cpp
@@ -42,7 +42,9 @@
 static levels_t levels;
 
 static jboolean isLoggable(const char* tag, jint level) {
-    return __android_log_is_loggable(level, tag, ANDROID_LOG_INFO);
+    return __android_log_is_loggable(level, tag,
+                                     ANDROID_LOG_INFO |
+                                     ANDROID_LOGGABLE_FLAG_NOT_WITHIN_SIGNAL);
 }
 
 static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
diff --git a/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
index 4c9b00a..dcf2c89 100644
--- a/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
+++ b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
@@ -33,7 +33,7 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        mAppsQueryHelper = new AppsQueryHelperTestable(getContext());
+        mAppsQueryHelper = new AppsQueryHelperTestable();
     }
 
     public void testQueryAppsSystemAppsOnly() {
@@ -78,33 +78,20 @@
         assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "sys_app3"), apps);
     }
 
-    public void testQueryAppsDefaultIme() {
-        // Test query default system IMEs
-        List<String> apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES,
+    public void testQueryAppsImes() {
+        // Test query system IMEs
+        List<String> apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_IMES,
                 true, UserHandle.of(UserHandle.myUserId()));
         assertEqualsIgnoreOrder(Arrays.asList("sys_app1"), apps);
 
-        // Test query default IMEs
-        apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES, false,
+        // Test query IMEs
+        apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_IMES, false,
                 UserHandle.of(UserHandle.myUserId()));
         assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "app4"), apps);
-
-        // Test that GET_DEFAULT_IMES cannot be used with a user id different from current process
-        try {
-            mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES, false,
-                    UserHandle.of(UserHandle.USER_NULL));
-            fail("queryApps must fail if wrong user was passed");
-        } catch (IllegalArgumentException e) {
-            // OK
-        }
     }
 
     private class AppsQueryHelperTestable extends AppsQueryHelper {
 
-        public AppsQueryHelperTestable(Context context) {
-            super(context);
-        }
-
         @Override
         protected List<ApplicationInfo> getAllApps(int userId) {
             final ApplicationInfo ai1 = new ApplicationInfo();
@@ -145,18 +132,19 @@
         }
 
         @Override
-        protected List<InputMethodInfo> getInputMethodList() {
+        protected List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int userId) {
             final ResolveInfo sysApp1 = new ResolveInfo();
             sysApp1.serviceInfo = new ServiceInfo();
             sysApp1.serviceInfo.packageName = "sys_app1";
             sysApp1.serviceInfo.name = "name";
-            InputMethodInfo imi1 = new InputMethodInfo(sysApp1, false, null, null, 0, true);
+            sysApp1.serviceInfo.applicationInfo = new ApplicationInfo();
+            sysApp1.serviceInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
             final ResolveInfo app4 = new ResolveInfo();
             app4.serviceInfo = new ServiceInfo();
             app4.serviceInfo.packageName = "app4";
             app4.serviceInfo.name = "name";
-            InputMethodInfo imi2 = new InputMethodInfo(app4, false, null, null, 0, true);
-            return Arrays.asList(imi1, imi2);
+            app4.serviceInfo.applicationInfo = new ApplicationInfo();
+            return Arrays.asList(sysApp1, app4);
         }
     }
 
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 39d13df..64f2698 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -913,16 +913,26 @@
     protected void onBoundsChange(Rect bounds) {}
 
     /**
-     * Return the intrinsic width of the underlying drawable object.  Returns
-     * -1 if it has no intrinsic width, such as with a solid color.
+     * Returns the drawable's intrinsic width.
+     * <p>
+     * Intrinsic width is the width at which the drawable would like to be laid
+     * out, including any inherent padding. If the drawable has no intrinsic
+     * width, such as a solid color, this method returns -1.
+     *
+     * @return the intrinsic width, or -1 if no intrinsic width
      */
     public int getIntrinsicWidth() {
         return -1;
     }
 
     /**
-     * Return the intrinsic height of the underlying drawable object. Returns
-     * -1 if it has no intrinsic height, such as with a solid color.
+     * Returns the drawable's intrinsic height.
+     * <p>
+     * Intrinsic height is the height at which the drawable would like to be
+     * laid out, including any inherent padding. If the drawable has no
+     * intrinsic height, such as a solid color, this method returns -1.
+     *
+     * @return the intrinsic height, or -1 if no intrinsic height
      */
     public int getIntrinsicHeight() {
         return -1;
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 927b9c9..36d4272 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -222,12 +222,20 @@
 
     @Override
     public int getIntrinsicWidth() {
-        return getDrawable().getIntrinsicWidth() + mState.mInsetLeft + mState.mInsetRight;
+        final int childWidth = getDrawable().getIntrinsicWidth();
+        if (childWidth < 0) {
+            return -1;
+        }
+        return childWidth + mState.mInsetLeft + mState.mInsetRight;
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return getDrawable().getIntrinsicHeight() + mState.mInsetTop + mState.mInsetBottom;
+        final int childHeight = getDrawable().getIntrinsicHeight();
+        if (childHeight < 0) {
+            return -1;
+        }
+        return childHeight + mState.mInsetTop + mState.mInsetBottom;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index bf5417d..95f1eb2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -27,6 +27,7 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.Log;
 import android.view.Display;
 import android.view.View;
@@ -193,6 +194,12 @@
      */
     @Override
     public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
+        // Ensure the device has been provisioned before allowing the user to interact with
+        // recents
+        if (!isDeviceProvisioned()) {
+            return;
+        }
+
         if (proxyToOverridePackage(ACTION_SHOW_RECENTS)) {
             return;
         }
@@ -222,6 +229,12 @@
      */
     @Override
     public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
+        // Ensure the device has been provisioned before allowing the user to interact with
+        // recents
+        if (!isDeviceProvisioned()) {
+            return;
+        }
+
         if (proxyToOverridePackage(ACTION_HIDE_RECENTS)) {
             return;
         }
@@ -251,6 +264,12 @@
      */
     @Override
     public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
+        // Ensure the device has been provisioned before allowing the user to interact with
+        // recents
+        if (!isDeviceProvisioned()) {
+            return;
+        }
+
         if (proxyToOverridePackage(ACTION_TOGGLE_RECENTS)) {
             return;
         }
@@ -280,6 +299,12 @@
      */
     @Override
     public void preloadRecents() {
+        // Ensure the device has been provisioned before allowing the user to interact with
+        // recents
+        if (!isDeviceProvisioned()) {
+            return;
+        }
+
         int currentUser = sSystemServicesProxy.getCurrentUser();
         if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.preloadRecents();
@@ -302,6 +327,12 @@
 
     @Override
     public void cancelPreloadingRecents() {
+        // Ensure the device has been provisioned before allowing the user to interact with
+        // recents
+        if (!isDeviceProvisioned()) {
+            return;
+        }
+
         int currentUser = sSystemServicesProxy.getCurrentUser();
         if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.cancelPreloadingRecents();
@@ -329,11 +360,23 @@
 
     @Override
     public void showNextAffiliatedTask() {
+        // Ensure the device has been provisioned before allowing the user to interact with
+        // recents
+        if (!isDeviceProvisioned()) {
+            return;
+        }
+
         mImpl.showNextAffiliatedTask();
     }
 
     @Override
     public void showPrevAffiliatedTask() {
+        // Ensure the device has been provisioned before allowing the user to interact with
+        // recents
+        if (!isDeviceProvisioned()) {
+            return;
+        }
+
         mImpl.showPrevAffiliatedTask();
     }
 
@@ -456,6 +499,14 @@
     }
 
     /**
+     * @return whether this device is provisioned.
+     */
+    private boolean isDeviceProvisioned() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+    }
+
+    /**
      * Attempts to proxy the following action to the override recents package.
      * @return whether the proxying was successful
      */
diff --git a/rs/java/android/renderscript/ScriptGroup.java b/rs/java/android/renderscript/ScriptGroup.java
index 54180f4..9bbacbc 100644
--- a/rs/java/android/renderscript/ScriptGroup.java
+++ b/rs/java/android/renderscript/ScriptGroup.java
@@ -278,6 +278,8 @@
             public ValueAndSize(RenderScript rs, Object obj) {
                 if (obj instanceof Allocation) {
                     value = ((Allocation)obj).getID(rs);
+                    // Special value for size to tell the runtime and driver that
+                    // the value is an Allocation
                     size = -1;
                 } else if (obj instanceof Boolean) {
                     value = ((Boolean)obj).booleanValue() ? 1 : 0;
@@ -289,10 +291,10 @@
                     value = ((Long)obj).longValue();
                     size = 8;
                 } else if (obj instanceof Float) {
-                    value = ((Float)obj).longValue();
+                    value = Float.floatToRawIntBits(((Float)obj).floatValue());
                     size = 4;
                 } else if (obj instanceof Double) {
-                    value = ((Double)obj).longValue();
+                    value = Double.doubleToRawLongBits(((Double)obj).doubleValue());
                     size = 8;
                 }
             }
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index be7071e..113241d 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -393,7 +393,6 @@
 
   size_t numValues, numDependencies;
   RsScriptFieldID* fieldIDs;
-  uintptr_t* values;
   RsClosure* depClosures;
   RsScriptFieldID* depFieldIDs;
 
@@ -430,15 +429,6 @@
     fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
   }
 
-  values = (uintptr_t*)alloca(sizeof(uintptr_t) * numValues);
-  if (values == nullptr) {
-      goto exit;
-  }
-
-  for (size_t i = 0; i < numValues; i++) {
-    values[i] = (uintptr_t)jValues[i];
-  }
-
   depClosures = (RsClosure*)alloca(sizeof(RsClosure) * numDependencies);
   if (depClosures == nullptr) {
       goto exit;
@@ -459,7 +449,7 @@
 
   ret = (jlong)(uintptr_t)rsClosureCreate(
       (RsContext)con, (RsScriptKernelID)kernelID, (RsAllocation)returnValue,
-      fieldIDs, numValues, values, numValues,
+      fieldIDs, numValues, jValues, numValues,
       (int*)jSizes, numValues,
       depClosures, numDependencies,
       depFieldIDs, numDependencies);
@@ -511,7 +501,6 @@
 
   size_t numValues;
   RsScriptFieldID* fieldIDs;
-  uintptr_t* values;
 
   if (fieldIDs_length != values_length || values_length != sizes_length) {
       ALOGE("Unmatched field IDs, values, and sizes in closure creation.");
@@ -534,18 +523,9 @@
     fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
   }
 
-  values = (uintptr_t*)alloca(sizeof(uintptr_t) * numValues);
-  if (values == nullptr) {
-      goto exit;
-  }
-
-  for (size_t i = 0; i < numValues; i++) {
-    values[i] = (uintptr_t)jValues[i];
-  }
-
   ret = (jlong)(uintptr_t)rsInvokeClosureCreate(
       (RsContext)con, (RsScriptInvokeID)invokeID, jParams, jParamLength,
-      fieldIDs, numValues, values, numValues,
+      fieldIDs, numValues, jValues, numValues,
       (int*)jSizes, numValues);
 
 exit:
@@ -561,15 +541,17 @@
 static void
 nClosureSetArg(JNIEnv *_env, jobject _this, jlong con, jlong closureID,
                jint index, jlong value, jint size) {
+  // Size is signed with -1 indicating the value is an Allocation
   rsClosureSetArg((RsContext)con, (RsClosure)closureID, (uint32_t)index,
-                  (uintptr_t)value, (size_t)size);
+                  (uintptr_t)value, size);
 }
 
 static void
 nClosureSetGlobal(JNIEnv *_env, jobject _this, jlong con, jlong closureID,
                   jlong fieldID, jlong value, jint size) {
+  // Size is signed with -1 indicating the value is an Allocation
   rsClosureSetGlobal((RsContext)con, (RsClosure)closureID,
-                     (RsScriptFieldID)fieldID, (uintptr_t)value, (size_t)size);
+                     (RsScriptFieldID)fieldID, (int64_t)value, size);
 }
 
 static long
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cde126a..566065c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12102,8 +12102,6 @@
                 }
             }
 
-            enableSystemUserApps();
-
             // Start up initial activity.
             mBooting = true;
             startHomeActivityLocked(currentUserId, "systemReady");
@@ -12155,43 +12153,6 @@
         }
     }
 
-    private void enableSystemUserApps() {
-        // For system user, enable apps based on the following conditions:
-        // - app is whitelisted; or has no launcher icons; or has INTERACT_ACROSS_USERS permission
-        // - app is not in the blacklist
-        if (UserManager.isSplitSystemUser()) {
-            AppsQueryHelper queryHelper = new AppsQueryHelper(mContext);
-            Set<String> enableApps = new HashSet<>();
-            enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS
-                            | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM
-                            | AppsQueryHelper.GET_DEFAULT_IMES,
-                            /* systemAppsOnly */ true, UserHandle.SYSTEM));
-            ArraySet<String> wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps();
-            enableApps.addAll(wlApps);
-            ArraySet<String> blApps = SystemConfig.getInstance().getSystemUserBlacklistedApps();
-            enableApps.removeAll(blApps);
-
-            List<String> systemApps = queryHelper.queryApps(0, /* systemAppsOnly */ true,
-                    UserHandle.SYSTEM);
-            final int systemAppsSize = systemApps.size();
-            for (int i = 0; i < systemAppsSize; i++) {
-                String pName = systemApps.get(i);
-                boolean enable = enableApps.contains(pName);
-                try {
-                    if (enable) {
-                        AppGlobals.getPackageManager().installExistingPackageAsUser(pName,
-                                UserHandle.USER_SYSTEM);
-                    } else {
-                        AppGlobals.getPackageManager().deletePackageAsUser(pName, null,
-                                UserHandle.USER_SYSTEM, PackageManager.DELETE_SYSTEM_APP);
-                    }
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Error occured when processing package " + pName, e);
-                }
-            }
-        }
-    }
-
     private boolean makeAppCrashingLocked(ProcessRecord app,
             String shortMsg, String longMsg, String stackTrace) {
         app.crashing = true;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 853a55c..9896ec5 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1338,7 +1338,12 @@
             return topHomeActivity == null || !topHomeActivity.isHomeActivity();
         }
 
-        final int belowFocusedIndex = mStacks.indexOf(focusedStack) - 1;
+        // Find the first stack below focused stack that actually got something visible.
+        int belowFocusedIndex = mStacks.indexOf(focusedStack) - 1;
+        while (belowFocusedIndex >= 0 &&
+                mStacks.get(belowFocusedIndex).topRunningActivityLocked() == null) {
+            belowFocusedIndex--;
+        }
         if ((focusedStackId == DOCKED_STACK_ID || focusedStackId == PINNED_STACK_ID)
                 && stackIndex == belowFocusedIndex) {
             // Stacks directly behind the docked or pinned stack are always visible.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bb805c1..c152514 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -105,6 +105,7 @@
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.AppsQueryHelper;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IOnPermissionsChangeListener;
 import android.content.pm.IPackageDataObserver;
@@ -1810,10 +1811,48 @@
             boolean factoryTest, boolean onlyCore) {
         PackageManagerService m = new PackageManagerService(context, installer,
                 factoryTest, onlyCore);
+        m.enableSystemUserApps();
         ServiceManager.addService("package", m);
         return m;
     }
 
+    private void enableSystemUserApps() {
+        if (!UserManager.isSplitSystemUser()) {
+            return;
+        }
+        // For system user, enable apps based on the following conditions:
+        // - app is whitelisted or belong to one of these groups:
+        //   -- system app which has no launcher icons
+        //   -- system app which has INTERACT_ACROSS_USERS permission
+        //   -- system IME app
+        // - app is not in the blacklist
+        AppsQueryHelper queryHelper = new AppsQueryHelper(this);
+        Set<String> enableApps = new ArraySet<>();
+        enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS
+                | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM
+                | AppsQueryHelper.GET_IMES, /* systemAppsOnly */ true, UserHandle.SYSTEM));
+        ArraySet<String> wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps();
+        enableApps.addAll(wlApps);
+        ArraySet<String> blApps = SystemConfig.getInstance().getSystemUserBlacklistedApps();
+        enableApps.removeAll(blApps);
+
+        List<String> systemApps = queryHelper.queryApps(0, /* systemAppsOnly */ true,
+                UserHandle.SYSTEM);
+        final int systemAppsSize = systemApps.size();
+        synchronized (mPackages) {
+            for (int i = 0; i < systemAppsSize; i++) {
+                String pName = systemApps.get(i);
+                PackageSetting pkgSetting = mSettings.mPackages.get(pName);
+                // Should not happen, but we shouldn't be failing if it does
+                if (pkgSetting == null) {
+                    continue;
+                }
+                boolean installed = enableApps.contains(pName);
+                pkgSetting.setInstalled(installed, UserHandle.USER_SYSTEM);
+            }
+        }
+    }
+
     static String[] splitString(String str, char sep) {
         int count = 1;
         int i = 0;
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index ac79b36..97713fc 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -54,6 +54,15 @@
                 @Override
                 public void onReceive(Context context, Intent intent) {
 
+                    // When a package is replaced we will receive two intents, one representing the
+                    // removal of the old package and one representing the addition of the new
+                    // package. We here ignore the intent representing the removed package to make
+                    // sure we don't change WebView provider twice.
+                    if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)
+                            && intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
+                        return;
+                    }
+
                     for (String packageName : WebViewFactory.getWebViewPackageNames()) {
                         String webviewPackage = "package:" + packageName;
 
@@ -73,7 +82,8 @@
                 }
         };
         IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addDataScheme("package");
         getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a22f821..490f5d8 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2725,6 +2725,8 @@
                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
             }
 
+            final int oldSurfaceResizeGeneration = winAnimator.mSurfaceResizeGeneration;
+
             win.setDisplayLayoutNeeded();
             win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
             configChanged = updateOrientationFromAppTokensLocked(false);
@@ -2737,6 +2739,9 @@
             if (win.mAppToken != null) {
                 win.mAppToken.updateReportedVisibilityLocked();
             }
+            if (winAnimator.mSurfaceResizeGeneration != oldSurfaceResizeGeneration) {
+                result |= WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED;
+            }
             outFrame.set(win.mCompatFrame);
             outOverscanInsets.set(win.mOverscanInsets);
             outContentInsets.set(win.mContentInsets);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index decfb34..4b2edf6 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -99,6 +99,7 @@
      * we must tell them application to resize (and thus redraw itself).
      */
     boolean mSurfaceResized;
+    int mSurfaceResizeGeneration;
     WindowSurfaceController mSurfaceController;
     private WindowSurfaceController mPendingDestroySurface;
 
@@ -1183,6 +1184,7 @@
                 recoveringMemory);
 
         if (mSurfaceResized) {
+            mSurfaceResizeGeneration++;
             mAnimator.setPendingLayoutChanges(w.getDisplayId(),
                     WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
             w.applyDimLayerIfNeeded();
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index deafe20..73d8585 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -190,22 +190,32 @@
 
 bool ResourceTable::addResource(const ResourceNameRef& name, const ConfigDescription& config,
                                 std::unique_ptr<Value> value, IDiagnostics* diag) {
-    return addResourceImpl(name, {}, config, std::move(value), kValidNameChars, diag);
+    return addResourceImpl(name, {}, config, std::move(value), kValidNameChars,
+                           resolveValueCollision, diag);
 }
 
 bool ResourceTable::addResource(const ResourceNameRef& name, const ResourceId resId,
                                 const ConfigDescription& config, std::unique_ptr<Value> value,
                                 IDiagnostics* diag) {
-    return addResourceImpl(name, resId, config, std::move(value), kValidNameChars, diag);
+    return addResourceImpl(name, resId, config, std::move(value), kValidNameChars,
+                           resolveValueCollision, diag);
 }
 
 bool ResourceTable::addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
                                      const Source& source, const StringPiece16& path,
                                      IDiagnostics* diag) {
+    return addFileReference(name, config, source, path, resolveValueCollision, diag);
+}
+
+bool ResourceTable::addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
+                                     const Source& source, const StringPiece16& path,
+                                     std::function<int(Value*,Value*)> conflictResolver,
+                                     IDiagnostics* diag) {
     std::unique_ptr<FileReference> fileRef = util::make_unique<FileReference>(
             stringPool.makeRef(path));
     fileRef->setSource(source);
-    return addResourceImpl(name, ResourceId{}, config, std::move(fileRef), kValidNameChars, diag);
+    return addResourceImpl(name, ResourceId{}, config, std::move(fileRef), kValidNameChars,
+                           conflictResolver, diag);
 }
 
 bool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
@@ -213,7 +223,7 @@
                                             std::unique_ptr<Value> value,
                                             IDiagnostics* diag) {
     return addResourceImpl(name, ResourceId{}, config, std::move(value), kValidNameMangledChars,
-                           diag);
+                           resolveValueCollision, diag);
 }
 
 bool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
@@ -221,12 +231,17 @@
                                             const ConfigDescription& config,
                                             std::unique_ptr<Value> value,
                                             IDiagnostics* diag) {
-    return addResourceImpl(name, id, config, std::move(value), kValidNameMangledChars, diag);
+    return addResourceImpl(name, id, config, std::move(value), kValidNameMangledChars,
+                           resolveValueCollision, diag);
 }
 
-bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceId resId,
-                                    const ConfigDescription& config, std::unique_ptr<Value> value,
-                                    const char16_t* validChars, IDiagnostics* diag) {
+bool ResourceTable::addResourceImpl(const ResourceNameRef& name,
+                                    const ResourceId resId,
+                                    const ConfigDescription& config,
+                                    std::unique_ptr<Value> value,
+                                    const char16_t* validChars,
+                                    std::function<int(Value*,Value*)> conflictResolver,
+                                    IDiagnostics* diag) {
     assert(value && "value can't be nullptr");
     assert(diag && "diagnostics can't be nullptr");
 
@@ -289,7 +304,7 @@
         // This resource did not exist before, add it.
         entry->values.insert(iter, ResourceConfigValue{ config, std::move(value) });
     } else {
-        int collisionResult = resolveValueCollision(iter->value.get(), value.get());
+        int collisionResult = conflictResolver(iter->value.get(), value.get());
         if (collisionResult > 0) {
             // Take the incoming value.
             iter->value = std::move(value);
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 980504b..6b7b07e 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -163,7 +163,12 @@
                      IDiagnostics* diag);
 
     bool addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
-                          const Source& source, const StringPiece16& path, IDiagnostics* diag);
+                          const Source& source, const StringPiece16& path,
+                          IDiagnostics* diag);
+
+    bool addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
+                          const Source& source, const StringPiece16& path,
+                          std::function<int(Value*,Value*)> conflictResolver, IDiagnostics* diag);
 
     /**
      * Same as addResource, but doesn't verify the validity of the name. This is used
@@ -221,9 +226,14 @@
 private:
     ResourceTablePackage* findOrCreatePackage(const StringPiece16& name);
 
-    bool addResourceImpl(const ResourceNameRef& name, ResourceId resId,
-                         const ConfigDescription& config, std::unique_ptr<Value> value,
-                         const char16_t* validChars, IDiagnostics* diag);
+    bool addResourceImpl(const ResourceNameRef& name,
+                         ResourceId resId,
+                         const ConfigDescription& config,
+                         std::unique_ptr<Value> value,
+                         const char16_t* validChars,
+                         std::function<int(Value*,Value*)> conflictResolver,
+                         IDiagnostics* diag);
+
     bool setSymbolStateImpl(const ResourceNameRef& name, ResourceId resId,
                             const Symbol& symbol, const char16_t* validChars, IDiagnostics* diag);
 };
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 9ce3734..93f2dc6f 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -48,6 +48,7 @@
     std::string outputPath;
     std::string manifestPath;
     std::vector<std::string> includePaths;
+    std::vector<std::string> overlayFiles;
     Maybe<std::string> generateJavaClassPath;
     std::vector<std::string> extraJavaPackages;
     Maybe<std::string> generateProguardRulesPath;
@@ -88,9 +89,11 @@
     }
 };
 
-struct LinkCommand {
-    LinkOptions mOptions;
-    LinkContext mContext;
+class LinkCommand {
+public:
+    LinkCommand(const LinkOptions& options) :
+            mOptions(options), mContext(), mFinalTable() {
+    }
 
     std::string buildResourceFileName(const ResourceFile& resFile) {
         std::stringstream out;
@@ -117,8 +120,7 @@
         AssetManagerSymbolTableBuilder builder;
         for (const std::string& path : mOptions.includePaths) {
             if (mOptions.verbose) {
-                mContext.getDiagnostics()->note(
-                        DiagMessage(Source{ path }) << "loading include path");
+                mContext.getDiagnostics()->note(DiagMessage(path) << "loading include path");
             }
 
             std::unique_ptr<android::AssetManager> assetManager =
@@ -126,7 +128,7 @@
             int32_t cookie = 0;
             if (!assetManager->addAssetPath(android::String8(path.data(), path.size()), &cookie)) {
                 mContext.getDiagnostics()->error(
-                        DiagMessage(Source{ path }) << "failed to load include path");
+                        DiagMessage(path) << "failed to load include path");
                 return {};
             }
             builder.add(std::move(assetManager));
@@ -141,12 +143,12 @@
         std::string errorStr;
         Maybe<android::FileMap> map = file::mmapPath(input, &errorStr);
         if (!map) {
-            mContext.getDiagnostics()->error(DiagMessage(Source{ input }) << errorStr);
+            mContext.getDiagnostics()->error(DiagMessage(input) << errorStr);
             return {};
         }
 
         std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
-        BinaryResourceParser parser(&mContext, table.get(), Source{ input },
+        BinaryResourceParser parser(&mContext, table.get(), Source(input),
                                     map.value().getDataPtr(), map.value().getDataLength());
         if (!parser.parse()) {
             return {};
@@ -160,11 +162,11 @@
     std::unique_ptr<XmlResource> loadXml(const std::string& path) {
         std::ifstream fin(path, std::ifstream::binary);
         if (!fin) {
-            mContext.getDiagnostics()->error(DiagMessage(Source{ path }) << strerror(errno));
+            mContext.getDiagnostics()->error(DiagMessage(path) << strerror(errno));
             return {};
         }
 
-        return xml::inflate(&fin, mContext.getDiagnostics(), Source{ path });
+        return xml::inflate(&fin, mContext.getDiagnostics(), Source(path));
     }
 
     /**
@@ -255,9 +257,9 @@
         return {};
     }
 
-    bool verifyNoExternalPackages(ResourceTable* table) {
+    bool verifyNoExternalPackages() {
         bool error = false;
-        for (const auto& package : table->packages) {
+        for (const auto& package : mFinalTable.packages) {
             if (mContext.getCompilationPackage() != package->name ||
                     !package->id || package->id.value() != mContext.getPackageId()) {
                 // We have a package that is not related to the one we're building!
@@ -401,6 +403,103 @@
         return true;
     }
 
+    bool mergeStaticLibrary(const std::string& input) {
+        // TODO(adamlesinski): Load resources from a static library APK and merge the table into
+        // TableMerger.
+        mContext.getDiagnostics()->warn(DiagMessage()
+                                        << "linking static libraries not supported yet: "
+                                        << input);
+        return true;
+    }
+
+    bool mergeResourceTable(const std::string& input, bool override) {
+        if (mOptions.verbose) {
+            mContext.getDiagnostics()->note(DiagMessage() << "linking " << input);
+        }
+
+        std::unique_ptr<ResourceTable> table = loadTable(input);
+        if (!table) {
+            return false;
+        }
+
+        if (!mTableMerger->merge(Source(input), table.get(), override)) {
+            return false;
+        }
+        return true;
+    }
+
+    bool mergeCompiledFile(const std::string& input, ResourceFile&& file, bool override) {
+        if (file.name.package.empty()) {
+            file.name.package = mContext.getCompilationPackage().toString();
+        }
+
+        ResourceNameRef resName = file.name;
+
+        Maybe<ResourceName> mangledName = mContext.getNameMangler()->mangleName(file.name);
+        if (mangledName) {
+            resName = mangledName.value();
+        }
+
+        std::function<int(Value*,Value*)> resolver;
+        if (override) {
+            resolver = [](Value* a, Value* b) -> int {
+                int result = ResourceTable::resolveValueCollision(a, b);
+                if (result == 0) {
+                    // Always accept the new value if it would normally conflict (override).
+                    result = 1;
+                }
+                return result;
+            };
+        } else {
+            // Otherwise use the default resolution.
+            resolver = ResourceTable::resolveValueCollision;
+        }
+
+        // Add this file to the table.
+        if (!mFinalTable.addFileReference(resName, file.config, file.source,
+                                          util::utf8ToUtf16(buildResourceFileName(file)),
+                                          resolver, mContext.getDiagnostics())) {
+            return false;
+        }
+
+        // Add the exports of this file to the table.
+        for (SourcedResourceName& exportedSymbol : file.exportedSymbols) {
+            if (exportedSymbol.name.package.empty()) {
+                exportedSymbol.name.package = mContext.getCompilationPackage().toString();
+            }
+
+            ResourceNameRef resName = exportedSymbol.name;
+
+            Maybe<ResourceName> mangledName = mContext.getNameMangler()->mangleName(
+                    exportedSymbol.name);
+            if (mangledName) {
+                resName = mangledName.value();
+            }
+
+            std::unique_ptr<Id> id = util::make_unique<Id>();
+            id->setSource(file.source.withLine(exportedSymbol.line));
+            bool result = mFinalTable.addResourceAllowMangled(resName, {}, std::move(id),
+                    mContext.getDiagnostics());
+            if (!result) {
+                return false;
+            }
+        }
+
+        mFilesToProcess[resName.toResourceName()] = FileToProcess{ Source(input), std::move(file) };
+        return true;
+    }
+
+    bool processFile(const std::string& input, bool override) {
+        if (util::stringEndsWith<char>(input, ".apk")) {
+            return mergeStaticLibrary(input);
+        } else if (util::stringEndsWith<char>(input, ".arsc.flat")) {
+            return mergeResourceTable(input, override);
+        } else if (Maybe<ResourceFile> maybeF = loadFileExportHeader(input)) {
+            return mergeCompiledFile(input, std::move(maybeF.value()), override);
+        }
+        return false;
+    }
+
     int run(const std::vector<std::string>& inputFiles) {
         // Load the AndroidManifest.xml
         std::unique_ptr<XmlResource> manifestXml = loadXml(mOptions.manifestPath);
@@ -438,82 +537,25 @@
             return 1;
         }
 
+        mTableMerger = util::make_unique<TableMerger>(&mContext, &mFinalTable);
+
         if (mOptions.verbose) {
             mContext.getDiagnostics()->note(
                     DiagMessage() << "linking package '" << mContext.mCompilationPackage << "' "
                                   << "with package ID " << std::hex << (int) mContext.mPackageId);
         }
 
-        ResourceTable mergedTable;
-        TableMerger tableMerger(&mContext, &mergedTable);
-
-        struct FilesToProcess {
-            Source source;
-            ResourceFile file;
-        };
-
         bool error = false;
-        std::queue<FilesToProcess> filesToProcess;
+
         for (const std::string& input : inputFiles) {
-            if (util::stringEndsWith<char>(input, ".apk")) {
-                // TODO(adamlesinski): Load resources from a static library APK
-                //                     Merge the table into TableMerger.
+            if (!processFile(input, false)) {
+                error = true;
+            }
+        }
 
-            } else if (util::stringEndsWith<char>(input, ".arsc.flat")) {
-                if (mOptions.verbose) {
-                    mContext.getDiagnostics()->note(DiagMessage() << "linking " << input);
-                }
-
-                std::unique_ptr<ResourceTable> table = loadTable(input);
-                if (!table) {
-                    return 1;
-                }
-
-                if (!tableMerger.merge(Source(input), table.get())) {
-                    return 1;
-                }
-
-            } else {
-                // Extract the exported IDs here so we can build the resource table.
-                if (Maybe<ResourceFile> maybeF = loadFileExportHeader(input)) {
-                    ResourceFile& f = maybeF.value();
-
-                    if (f.name.package.empty()) {
-                        f.name.package = mContext.getCompilationPackage().toString();
-                    }
-
-                    Maybe<ResourceName> mangledName = mContext.getNameMangler()->mangleName(f.name);
-
-                    // Add this file to the table.
-                    if (!mergedTable.addFileReference(mangledName ? mangledName.value() : f.name,
-                                                      f.config, f.source,
-                                                      util::utf8ToUtf16(buildResourceFileName(f)),
-                                                      mContext.getDiagnostics())) {
-                        error = true;
-                    }
-
-                    // Add the exports of this file to the table.
-                    for (SourcedResourceName& exportedSymbol : f.exportedSymbols) {
-                        if (exportedSymbol.name.package.empty()) {
-                            exportedSymbol.name.package = mContext.getCompilationPackage()
-                                    .toString();
-                        }
-
-                        Maybe<ResourceName> mangledName = mContext.getNameMangler()->mangleName(
-                                exportedSymbol.name);
-                        std::unique_ptr<Id> id = util::make_unique<Id>();
-                        id->setSource(f.source.withLine(exportedSymbol.line));
-                        if (!mergedTable.addResourceAllowMangled(
-                                mangledName ? mangledName.value() : exportedSymbol.name,
-                                {}, std::move(id), mContext.getDiagnostics())) {
-                            error = true;
-                        }
-                    }
-
-                    filesToProcess.push(FilesToProcess{ Source(input), std::move(f) });
-                } else {
-                    return 1;
-                }
+        for (const std::string& input : mOptions.overlayFiles) {
+            if (!processFile(input, true)) {
+                error = true;
             }
         }
 
@@ -522,13 +564,13 @@
             return 1;
         }
 
-        if (!verifyNoExternalPackages(&mergedTable)) {
+        if (!verifyNoExternalPackages()) {
             return 1;
         }
 
         if (!mOptions.staticLib) {
             PrivateAttributeMover mover;
-            if (!mover.consume(&mContext, &mergedTable)) {
+            if (!mover.consume(&mContext, &mFinalTable)) {
                 mContext.getDiagnostics()->error(
                         DiagMessage() << "failed moving private attributes");
                 return 1;
@@ -537,22 +579,22 @@
 
         {
             IdAssigner idAssigner;
-            if (!idAssigner.consume(&mContext, &mergedTable)) {
+            if (!idAssigner.consume(&mContext, &mFinalTable)) {
                 mContext.getDiagnostics()->error(DiagMessage() << "failed assigning IDs");
                 return 1;
             }
         }
 
-        mContext.mNameMangler = util::make_unique<NameMangler>(
-                NameManglerPolicy{ mContext.mCompilationPackage, tableMerger.getMergedPackages() });
+        mContext.mNameMangler = util::make_unique<NameMangler>(NameManglerPolicy{
+                mContext.mCompilationPackage, mTableMerger->getMergedPackages() });
         mContext.mSymbols = JoinedSymbolTableBuilder()
-                .addSymbolTable(util::make_unique<SymbolTableWrapper>(&mergedTable))
+                .addSymbolTable(util::make_unique<SymbolTableWrapper>(&mFinalTable))
                 .addSymbolTable(std::move(mContext.mSymbols))
                 .build();
 
         {
             ReferenceLinker linker;
-            if (!linker.consume(&mContext, &mergedTable)) {
+            if (!linker.consume(&mContext, &mFinalTable)) {
                 mContext.getDiagnostics()->error(DiagMessage() << "failed linking references");
                 return 1;
             }
@@ -598,20 +640,20 @@
             }
         }
 
-        for (; !filesToProcess.empty(); filesToProcess.pop()) {
-            FilesToProcess& f = filesToProcess.front();
-            if (f.file.name.type != ResourceType::kRaw &&
-                    util::stringEndsWith<char>(f.source.path, ".xml.flat")) {
+        for (auto& pair : mFilesToProcess) {
+            FileToProcess& file = pair.second;
+            if (file.file.name.type != ResourceType::kRaw &&
+                    util::stringEndsWith<char>(file.source.path, ".xml.flat")) {
                 if (mOptions.verbose) {
-                    mContext.getDiagnostics()->note(DiagMessage() << "linking " << f.source.path);
+                    mContext.getDiagnostics()->note(DiagMessage() << "linking " << file.source.path);
                 }
 
-                std::unique_ptr<XmlResource> xmlRes = loadBinaryXmlSkipFileExport(f.source.path);
+                std::unique_ptr<XmlResource> xmlRes = loadBinaryXmlSkipFileExport(file.source.path);
                 if (!xmlRes) {
                     return 1;
                 }
 
-                xmlRes->file = std::move(f.file);
+                xmlRes->file = std::move(file.file);
 
                 XmlReferenceLinker xmlLinker;
                 if (xmlLinker.consume(&mContext, xmlRes.get())) {
@@ -631,7 +673,7 @@
                     }
 
                     if (!mOptions.noAutoVersion) {
-                        Maybe<ResourceTable::SearchResult> result = mergedTable.findResource(
+                        Maybe<ResourceTable::SearchResult> result = mFinalTable.findResource(
                                 xmlRes->file.name);
                         for (int sdkLevel : xmlLinker.getSdkLevels()) {
                             if (sdkLevel > xmlRes->file.config.sdkVersion &&
@@ -639,7 +681,7 @@
                                                                     xmlRes->file.config,
                                                                     sdkLevel)) {
                                 xmlRes->file.config.sdkVersion = sdkLevel;
-                                if (!mergedTable.addFileReference(xmlRes->file.name,
+                                if (!mFinalTable.addFileReference(xmlRes->file.name,
                                                                   xmlRes->file.config,
                                                                   xmlRes->file.source,
                                                                   util::utf8ToUtf16(
@@ -662,10 +704,11 @@
                 }
             } else {
                 if (mOptions.verbose) {
-                    mContext.getDiagnostics()->note(DiagMessage() << "copying " << f.source.path);
+                    mContext.getDiagnostics()->note(DiagMessage() << "copying "
+                                                    << file.source.path);
                 }
 
-                if (!copyFileToArchive(f.source.path, buildResourceFileName(f.file), 0,
+                if (!copyFileToArchive(file.source.path, buildResourceFileName(file.file), 0,
                                        archiveWriter.get())) {
                     error = true;
                 }
@@ -679,13 +722,13 @@
 
         if (!mOptions.noAutoVersion) {
             AutoVersioner versioner;
-            if (!versioner.consume(&mContext, &mergedTable)) {
+            if (!versioner.consume(&mContext, &mFinalTable)) {
                 mContext.getDiagnostics()->error(DiagMessage() << "failed versioning styles");
                 return 1;
             }
         }
 
-        if (!flattenTable(&mergedTable, archiveWriter.get())) {
+        if (!flattenTable(&mFinalTable, archiveWriter.get())) {
             mContext.getDiagnostics()->error(DiagMessage() << "failed to write resources.arsc");
             return 1;
         }
@@ -704,7 +747,7 @@
                 // to the original package, and private and public symbols to the private package.
 
                 options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
-                if (!writeJavaFile(&mergedTable, mContext.getCompilationPackage(),
+                if (!writeJavaFile(&mFinalTable, mContext.getCompilationPackage(),
                                    mContext.getCompilationPackage(), options)) {
                     return 1;
                 }
@@ -713,12 +756,12 @@
                 outputPackage = mOptions.privateSymbols.value();
             }
 
-            if (!writeJavaFile(&mergedTable, actualPackage, outputPackage, options)) {
+            if (!writeJavaFile(&mFinalTable, actualPackage, outputPackage, options)) {
                 return 1;
             }
 
             for (std::string& extraPackage : mOptions.extraJavaPackages) {
-                if (!writeJavaFile(&mergedTable, actualPackage, util::utf8ToUtf16(extraPackage),
+                if (!writeJavaFile(&mFinalTable, actualPackage, util::utf8ToUtf16(extraPackage),
                                    options)) {
                     return 1;
                 }
@@ -732,10 +775,10 @@
         }
 
         if (mOptions.verbose) {
-            Debug::printTable(&mergedTable);
-            for (; !tableMerger.getFileMergeQueue()->empty();
-                    tableMerger.getFileMergeQueue()->pop()) {
-                const FileToMerge& f = tableMerger.getFileMergeQueue()->front();
+            Debug::printTable(&mFinalTable);
+            for (; !mTableMerger->getFileMergeQueue()->empty();
+                    mTableMerger->getFileMergeQueue()->pop()) {
+                const FileToMerge& f = mTableMerger->getFileMergeQueue()->front();
                 mContext.getDiagnostics()->note(
                         DiagMessage() << f.srcPath << " -> " << f.dstPath << " from (0x"
                                       << std::hex << (uintptr_t) f.srcTable << std::dec);
@@ -744,6 +787,18 @@
 
         return 0;
     }
+
+private:
+    LinkOptions mOptions;
+    LinkContext mContext;
+    ResourceTable mFinalTable;
+    std::unique_ptr<TableMerger> mTableMerger;
+
+    struct FileToProcess {
+        Source source;
+        ResourceFile file;
+    };
+    std::map<ResourceName, FileToProcess> mFilesToProcess;
 };
 
 int link(const std::vector<StringPiece>& args) {
@@ -755,6 +810,9 @@
             .requiredFlag("--manifest", "Path to the Android manifest to build",
                           &options.manifestPath)
             .optionalFlagList("-I", "Adds an Android APK to link against", &options.includePaths)
+            .optionalFlagList("-R", "Compilation unit to link, using `overlay` semantics. "
+                              "The last conflicting resource given takes precedence.",
+                              &options.overlayFiles)
             .optionalFlag("--java", "Directory in which to generate R.java",
                           &options.generateJavaClassPath)
             .optionalFlag("--proguard", "Output file for generated Proguard rules",
@@ -794,7 +852,7 @@
         options.targetSdkVersionDefault = util::utf8ToUtf16(targetSdkVersion.value());
     }
 
-    LinkCommand cmd = { options };
+    LinkCommand cmd(options);
     return cmd.run(flags.getArgs());
 }
 
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 1eea410..a06a1bf 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -37,7 +37,7 @@
 /**
  * This will merge packages with the same package name (or no package name).
  */
-bool TableMerger::merge(const Source& src, ResourceTable* table) {
+bool TableMerger::merge(const Source& src, ResourceTable* table, bool overrideExisting) {
     const uint8_t desiredPackageId = mContext->getPackageId();
 
     bool error = false;
@@ -55,7 +55,7 @@
             // mangled, then looked up at resolution time.
             // Also, when linking, we convert references with no package name to use
             // the compilation package name.
-            if (!doMerge(src, table, package.get(), false)) {
+            if (!doMerge(src, table, package.get(), false, overrideExisting)) {
                 error = true;
             }
         }
@@ -79,7 +79,7 @@
 
         bool mangle = packageName != mContext->getCompilationPackage();
         mMergedPackages.insert(package->name);
-        if (!doMerge(src, table, package.get(), mangle)) {
+        if (!doMerge(src, table, package.get(), mangle, false)) {
             error = true;
         }
     }
@@ -87,7 +87,8 @@
 }
 
 bool TableMerger::doMerge(const Source& src, ResourceTable* srcTable,
-                          ResourceTablePackage* srcPackage, const bool manglePackage) {
+                          ResourceTablePackage* srcPackage, const bool manglePackage,
+                          const bool overrideExisting) {
     bool error = false;
 
     for (auto& srcType : srcPackage->types) {
@@ -149,7 +150,7 @@
                 if (iter != dstEntry->values.end() && iter->config == srcValue.config) {
                     const int collisionResult = ResourceTable::resolveValueCollision(
                             iter->value.get(), srcValue.value.get());
-                    if (collisionResult == 0) {
+                    if (collisionResult == 0 && !overrideExisting) {
                         // Error!
                         ResourceNameRef resourceName(srcPackage->name,
                                                      srcType->type,
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index c903f1b..a2c9dbf 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -63,7 +63,7 @@
     /**
      * Merges resources from the same or empty package. This is for local sources.
      */
-    bool merge(const Source& src, ResourceTable* table);
+    bool merge(const Source& src, ResourceTable* table, bool overrideExisting);
 
     /**
      * Merges resources from the given package, mangling the name. This is for static libraries.
@@ -79,7 +79,7 @@
     std::queue<FileToMerge> mFilesToMerge;
 
     bool doMerge(const Source& src, ResourceTable* srcTable, ResourceTablePackage* srcPackage,
-                 const bool manglePackage);
+                 const bool manglePackage, const bool overrideExisting);
 
     std::unique_ptr<Value> cloneAndMangle(ResourceTable* table, const std::u16string& package,
                                           Value* value);
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 0af4314..b7ffba7 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -59,7 +59,7 @@
     ResourceTable finalTable;
     TableMerger merger(mContext.get(), &finalTable);
 
-    ASSERT_TRUE(merger.merge({}, tableA.get()));
+    ASSERT_TRUE(merger.merge({}, tableA.get(), false));
     ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get()));
 
     EXPECT_TRUE(merger.getMergedPackages().count(u"com.app.b") != 0);
@@ -89,7 +89,7 @@
     ResourceTable finalTable;
     TableMerger merger(mContext.get(), &finalTable);
 
-    ASSERT_TRUE(merger.merge({}, tableA.get()));
+    ASSERT_TRUE(merger.merge({}, tableA.get(), false));
     ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get()));
 
     FileReference* f = test::getValue<FileReference>(&finalTable, u"@com.app.a:xml/file");