Merge "Add Dialog list, shadow, inflation tests"
diff --git a/Android.mk b/Android.mk
index 40da134..e84b683 100644
--- a/Android.mk
+++ b/Android.mk
@@ -160,6 +160,7 @@
 	core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintService.aidl \
+	core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \
 	core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
 	core/java/android/hardware/hdmi/IHdmiControlService.aidl \
diff --git a/api/current.txt b/api/current.txt
index e9c5727..b296672 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9663,12 +9663,14 @@
     method public int diff(android.content.res.Configuration);
     method public boolean equals(android.content.res.Configuration);
     method public int getLayoutDirection();
+    method public android.util.LocaleList getLocales();
     method public boolean isLayoutSizeAtLeast(int);
     method public boolean isScreenRound();
     method public static boolean needNewResources(int, int);
     method public void readFromParcel(android.os.Parcel);
     method public void setLayoutDirection(java.util.Locale);
     method public void setLocale(java.util.Locale);
+    method public void setLocales(android.util.LocaleList);
     method public void setTo(android.content.res.Configuration);
     method public void setToDefaults();
     method public int updateFrom(android.content.res.Configuration);
@@ -9742,7 +9744,7 @@
     field public int hardKeyboardHidden;
     field public int keyboard;
     field public int keyboardHidden;
-    field public java.util.Locale locale;
+    field public deprecated java.util.Locale locale;
     field public int mcc;
     field public int mnc;
     field public int navigation;
@@ -18164,6 +18166,7 @@
     method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
     method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
+    method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
     method public android.mtp.MtpObjectInfo.Builder setParent(int);
     method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
     method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
@@ -34200,11 +34203,15 @@
 
   public final class LocaleList {
     ctor public LocaleList();
+    ctor public LocaleList(java.util.Locale);
     ctor public LocaleList(java.util.Locale[]);
+    method public static android.util.LocaleList forLanguageTags(java.lang.String);
     method public java.util.Locale get(int);
+    method public static android.util.LocaleList getEmptyLocaleList();
     method public java.util.Locale getPrimary();
     method public boolean isEmpty();
     method public int size();
+    method public java.lang.String toLanguageTags();
   }
 
   public final class Log {
diff --git a/api/system-current.txt b/api/system-current.txt
index e234970..7cc66cf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -10000,12 +10000,14 @@
     method public int diff(android.content.res.Configuration);
     method public boolean equals(android.content.res.Configuration);
     method public int getLayoutDirection();
+    method public android.util.LocaleList getLocales();
     method public boolean isLayoutSizeAtLeast(int);
     method public boolean isScreenRound();
     method public static boolean needNewResources(int, int);
     method public void readFromParcel(android.os.Parcel);
     method public void setLayoutDirection(java.util.Locale);
     method public void setLocale(java.util.Locale);
+    method public void setLocales(android.util.LocaleList);
     method public void setTo(android.content.res.Configuration);
     method public void setToDefaults();
     method public int updateFrom(android.content.res.Configuration);
@@ -10079,7 +10081,7 @@
     field public int hardKeyboardHidden;
     field public int keyboard;
     field public int keyboardHidden;
-    field public java.util.Locale locale;
+    field public deprecated java.util.Locale locale;
     field public int mcc;
     field public int mnc;
     field public int navigation;
@@ -19676,6 +19678,7 @@
     method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
     method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
+    method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
     method public android.mtp.MtpObjectInfo.Builder setParent(int);
     method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
     method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
@@ -36494,11 +36497,15 @@
 
   public final class LocaleList {
     ctor public LocaleList();
+    ctor public LocaleList(java.util.Locale);
     ctor public LocaleList(java.util.Locale[]);
+    method public static android.util.LocaleList forLanguageTags(java.lang.String);
     method public java.util.Locale get(int);
+    method public static android.util.LocaleList getEmptyLocaleList();
     method public java.util.Locale getPrimary();
     method public boolean isEmpty();
     method public int size();
+    method public java.lang.String toLanguageTags();
   }
 
   public final class Log {
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 3b026d2..132ffef 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -2196,6 +2196,7 @@
             fragment.mTag = tag;
             fragment.mInLayout = true;
             fragment.mFragmentManager = this;
+            fragment.mHost = mHost;
             fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
             addFragment(fragment, true);
         } else if (fragment.mInLayout) {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6feb860..914945b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -531,12 +531,14 @@
 
     /**
      * String retrieved from the seinfo tag found in selinux policy. This value
-     * is useful in setting an SELinux security context on the process as well
-     * as its data directory.
+     * can be overridden with a value set through the mac_permissions.xml policy
+     * construct. This value is useful in setting an SELinux security context on
+     * the process as well as its data directory. The String default is being used
+     * here to represent a catchall label when no policy matches.
      *
      * {@hide}
      */
-    public String seinfo;
+    public String seinfo = "default";
 
     /**
      * Paths to all shared libraries this application is linked against.  This
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index fd60476..3ecbaa0 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -22,11 +22,13 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import android.annotation.Nullable;
 import android.content.pm.ActivityInfo;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.LocaleList;
 import android.view.View;
 
 import java.io.IOException;
@@ -36,7 +38,7 @@
 /**
  * This class describes all device configuration information that can
  * impact the resources the application retrieves.  This includes both
- * user-specified configuration options (locale and scaling) as well
+ * user-specified configuration options (locale list and scaling) as well
  * as device configurations (such as input modes, screen size and screen orientation).
  * <p>You can acquire this object from {@link Resources}, using {@link
  * Resources#getConfiguration}. Thus, from an activity, you can get it by chaining the request
@@ -78,8 +80,13 @@
      * Current user preference for the locale, corresponding to
      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
      * resource qualifier.
+     *
+     * @deprecated Do not set or read this directly. Use {@link #getLocales()} and
+     * {@link #setLocales(LocaleList)}.
      */
-    public Locale locale;
+    @Deprecated public Locale locale;
+
+    private LocaleList mLocaleList;
 
     /**
      * Locale should persist on setting.  This is hidden because it is really
@@ -648,6 +655,15 @@
         setTo(o);
     }
 
+    /* This brings mLocaleList in sync with locale in case a user of the older API who doesn't know
+     * about setLocales() has changed locale directly. */
+    private void fixUpLocaleList() {
+        if ((locale == null && !mLocaleList.isEmpty()) ||
+                (locale != null && !locale.equals(mLocaleList.getPrimary()))) {
+            mLocaleList = new LocaleList(locale);
+        }
+    }
+
     public void setTo(Configuration o) {
         fontScale = o.fontScale;
         mcc = o.mcc;
@@ -655,6 +671,8 @@
         if (o.locale != null) {
             locale = (Locale) o.locale.clone();
         }
+        o.fixUpLocaleList();
+        mLocaleList = o.mLocaleList;
         userSetLocale = o.userSetLocale;
         touchscreen = o.touchscreen;
         keyboard = o.keyboard;
@@ -692,11 +710,12 @@
         } else {
             sb.append("?mnc");
         }
-        if (locale != null) {
+        fixUpLocaleList();
+        if (!mLocaleList.isEmpty()) {
             sb.append(" ");
-            sb.append(locale);
+            sb.append(mLocaleList);
         } else {
-            sb.append(" ?locale");
+            sb.append(" ?localeList");
         }
         int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK);
         switch (layoutDir) {
@@ -819,6 +838,7 @@
     public void setToDefaults() {
         fontScale = 1;
         mcc = mnc = 0;
+        mLocaleList = LocaleList.getEmptyLocaleList();
         locale = null;
         userSetLocale = false;
         touchscreen = TOUCHSCREEN_UNDEFINED;
@@ -864,16 +884,20 @@
             changed |= ActivityInfo.CONFIG_MNC;
             mnc = delta.mnc;
         }
-        if (delta.locale != null
-                && (locale == null || !locale.equals(delta.locale))) {
+        fixUpLocaleList();
+        delta.fixUpLocaleList();
+        if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) {
             changed |= ActivityInfo.CONFIG_LOCALE;
-            locale = delta.locale != null
-                    ? (Locale) delta.locale.clone() : null;
-            // If locale has changed, then layout direction is also changed ...
-            changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
-            // ... and we need to update the layout direction (represented by the first
-            // 2 most significant bits in screenLayout).
-            setLayoutDirection(locale);
+            mLocaleList = delta.mLocaleList;
+            // delta.locale can't be null, since delta.mLocaleList is not empty.
+            if (!delta.locale.equals(locale)) {
+                locale = (Locale) delta.locale.clone();
+                // If locale has changed, then layout direction is also changed ...
+                changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
+                // ... and we need to update the layout direction (represented by the first
+                // 2 most significant bits in screenLayout).
+                setLayoutDirection(locale);
+            }
         }
         final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
         if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED &&
@@ -1023,8 +1047,9 @@
         if (delta.mnc != 0 && mnc != delta.mnc) {
             changed |= ActivityInfo.CONFIG_MNC;
         }
-        if (delta.locale != null
-                && (locale == null || !locale.equals(delta.locale))) {
+        fixUpLocaleList();
+        delta.fixUpLocaleList();
+        if (!mLocaleList.equals(delta.mLocaleList)) {
             changed |= ActivityInfo.CONFIG_LOCALE;
             changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
         }
@@ -1146,14 +1171,15 @@
         dest.writeFloat(fontScale);
         dest.writeInt(mcc);
         dest.writeInt(mnc);
-        if (locale == null) {
-            dest.writeInt(0);
-        } else {
-            dest.writeInt(1);
-            dest.writeString(locale.getLanguage());
-            dest.writeString(locale.getCountry());
-            dest.writeString(locale.getVariant());
+
+        fixUpLocaleList();
+        final int localeListSize = mLocaleList.size();
+        dest.writeInt(localeListSize);
+        for (int i = 0; i < localeListSize; ++i) {
+            final Locale l = mLocaleList.get(i);
+            dest.writeString(l.toLanguageTag());
         }
+
         if(userSetLocale) {
             dest.writeInt(1);
         } else {
@@ -1182,10 +1208,15 @@
         fontScale = source.readFloat();
         mcc = source.readInt();
         mnc = source.readInt();
-        if (source.readInt() != 0) {
-            locale = new Locale(source.readString(), source.readString(),
-                    source.readString());
+
+        final int localeListSize = source.readInt();
+        final Locale[] localeArray = new Locale[localeListSize];
+        for (int i = 0; i < localeListSize; ++i) {
+            localeArray[i] = Locale.forLanguageTag(source.readString());
         }
+        mLocaleList = new LocaleList(localeArray);
+        locale = mLocaleList.getPrimary();
+
         userSetLocale = (source.readInt()==1);
         touchscreen = source.readInt();
         keyboard = source.readInt();
@@ -1234,18 +1265,33 @@
         if (n != 0) return n;
         n = this.mnc - that.mnc;
         if (n != 0) return n;
-        if (this.locale == null) {
-            if (that.locale != null) return 1;
-        } else if (that.locale == null) {
+
+        fixUpLocaleList();
+        that.fixUpLocaleList();
+        // for backward compatibility, we consider an empty locale list to be greater
+        // than any non-empty locale list.
+        if (this.mLocaleList.isEmpty()) {
+            if (!that.mLocaleList.isEmpty()) return 1;
+        } else if (that.mLocaleList.isEmpty()) {
             return -1;
         } else {
-            n = this.locale.getLanguage().compareTo(that.locale.getLanguage());
-            if (n != 0) return n;
-            n = this.locale.getCountry().compareTo(that.locale.getCountry());
-            if (n != 0) return n;
-            n = this.locale.getVariant().compareTo(that.locale.getVariant());
+            final int minSize = Math.min(this.mLocaleList.size(), that.mLocaleList.size());
+            for (int i = 0; i < minSize; ++i) {
+                final Locale thisLocale = this.mLocaleList.get(i);
+                final Locale thatLocale = that.mLocaleList.get(i);
+                n = thisLocale.getLanguage().compareTo(thatLocale.getLanguage());
+                if (n != 0) return n;
+                n = thisLocale.getCountry().compareTo(thatLocale.getCountry());
+                if (n != 0) return n;
+                n = thisLocale.getVariant().compareTo(thatLocale.getVariant());
+                if (n != 0) return n;
+                n = thisLocale.toLanguageTag().compareTo(thatLocale.toLanguageTag());
+                if (n != 0) return n;
+            }
+            n = this.mLocaleList.size() - that.mLocaleList.size();
             if (n != 0) return n;
         }
+
         n = this.touchscreen - that.touchscreen;
         if (n != 0) return n;
         n = this.keyboard - that.keyboard;
@@ -1288,13 +1334,13 @@
         }
         return false;
     }
-    
+
     public int hashCode() {
         int result = 17;
         result = 31 * result + Float.floatToIntBits(fontScale);
         result = 31 * result + mcc;
         result = 31 * result + mnc;
-        result = 31 * result + (locale != null ? locale.hashCode() : 0);
+        result = 31 * result + mLocaleList.hashCode();
         result = 31 * result + touchscreen;
         result = 31 * result + keyboard;
         result = 31 * result + keyboardHidden;
@@ -1312,14 +1358,47 @@
     }
 
     /**
-     * Set the locale. This is the preferred way for setting up the locale (instead of using the
-     * direct accessor). This will also set the layout direction according to the locale.
+     * Get the locale list. This is the preferred way for getting the locales (instead of using
+     * the direct accessor to {@link #locale}, which would only provide the primary locale).
+     *
+     * @return The locale list.
+     */
+    public LocaleList getLocales() {
+        fixUpLocaleList();
+        return mLocaleList;
+    }
+
+    /**
+     * Set the locale list. This is the preferred way for setting up the locales (instead of using
+     * the direct accessor or {@link #setLocale(Locale)}). This will also set the layout direction
+     * according to the first locale in the list.
+     *
+     * Note that the layout direction will always come from the first locale in the locale list,
+     * even if the locale is not supported by the resources (the resources may only support
+     * another locale further down the list which has a different direction).
+     *
+     * @param locales The locale list. If null, an empty LocaleList will be assigned.
+     */
+    public void setLocales(@Nullable LocaleList locales) {
+        mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales;
+        locale = mLocaleList.getPrimary();
+        setLayoutDirection(locale);
+    }
+
+    /**
+     * Set the locale list to a list of just one locale. This will also set the layout direction
+     * according to the locale.
+     *
+     * Note that after this is run, calling <code>.equals()</code> on the input locale and the
+     * {@link #locale} attribute would return <code>true</code> if they are not null, but there is
+     * no guarantee that they would be the same object.
+     *
+     * See also the note about layout direction in {@link #setLocales(LocaleList)}.
      *
      * @param loc The locale. Can be null.
      */
-    public void setLocale(Locale loc) {
-        locale = loc;
-        setLayoutDirection(locale);
+    public void setLocale(@Nullable Locale loc) {
+        setLocales(new LocaleList(loc));
     }
 
     /**
@@ -1335,19 +1414,19 @@
     }
 
     /**
-     * Set the layout direction from the Locale.
+     * Set the layout direction from a Locale.
      *
-     * @param locale The Locale. If null will set the layout direction to
+     * @param loc The Locale. If null will set the layout direction to
      * {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction
      * corresponding to the Locale.
      *
      * @see View#LAYOUT_DIRECTION_LTR
      * @see View#LAYOUT_DIRECTION_RTL
      */
-    public void setLayoutDirection(Locale locale) {
+    public void setLayoutDirection(Locale loc) {
         // There is a "1" difference between the configuration values for
         // layout direction and View constants for layout direction, just add "1".
-        final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(locale);
+        final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(loc);
         screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)|
                 (layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT);
     }
@@ -1370,21 +1449,21 @@
      *
      * @hide
      */
-    public static String localeToResourceQualifier(Locale locale) {
+    public static String localeToResourceQualifier(Locale loc) {
         StringBuilder sb = new StringBuilder();
-        boolean l = (locale.getLanguage().length() != 0);
-        boolean c = (locale.getCountry().length() != 0);
-        boolean s = (locale.getScript().length() != 0);
-        boolean v = (locale.getVariant().length() != 0);
-
+        boolean l = (loc.getLanguage().length() != 0);
+        boolean c = (loc.getCountry().length() != 0);
+        boolean s = (loc.getScript().length() != 0);
+        boolean v = (loc.getVariant().length() != 0);
+        // TODO: take script and extensions into account
         if (l) {
-            sb.append(locale.getLanguage());
+            sb.append(loc.getLanguage());
             if (c) {
-                sb.append("-r").append(locale.getCountry());
+                sb.append("-r").append(loc.getCountry());
                 if (s) {
-                    sb.append("-s").append(locale.getScript());
+                    sb.append("-s").append(loc.getScript());
                     if (v) {
-                        sb.append("-v").append(locale.getVariant());
+                        sb.append("-v").append(loc.getVariant());
                     }
                 }
             }
@@ -1409,6 +1488,7 @@
             }
         }
 
+        // TODO: send the whole locale list
         if (config.locale != null && !config.locale.getLanguage().isEmpty()) {
             parts.add(localeToResourceQualifier(config.locale));
         }
@@ -1646,8 +1726,10 @@
             delta.mnc = change.mnc;
         }
 
-        if ((base.locale == null && change.locale != null) ||
-                (base.locale != null && !base.locale.equals(change.locale)))  {
+        base.fixUpLocaleList();
+        change.fixUpLocaleList();
+        if (!base.mLocaleList.equals(change.mLocaleList))  {
+            delta.mLocaleList = change.mLocaleList;
             delta.locale = change.locale;
         }
 
@@ -1724,7 +1806,7 @@
     private static final String XML_ATTR_FONT_SCALE = "fs";
     private static final String XML_ATTR_MCC = "mcc";
     private static final String XML_ATTR_MNC = "mnc";
-    private static final String XML_ATTR_LOCALE = "locale";
+    private static final String XML_ATTR_LOCALES = "locales";
     private static final String XML_ATTR_TOUCHSCREEN = "touch";
     private static final String XML_ATTR_KEYBOARD = "key";
     private static final String XML_ATTR_KEYBOARD_HIDDEN = "keyHid";
@@ -1754,10 +1836,9 @@
         configOut.mcc = XmlUtils.readIntAttribute(parser, XML_ATTR_MCC, 0);
         configOut.mnc = XmlUtils.readIntAttribute(parser, XML_ATTR_MNC, 0);
 
-        final String localeStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALE);
-        if (localeStr != null) {
-            configOut.locale = Locale.forLanguageTag(localeStr);
-        }
+        final String localesStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALES);
+        configOut.mLocaleList = LocaleList.forLanguageTags(localesStr);
+        configOut.locale = configOut.mLocaleList.getPrimary();
 
         configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN,
                 TOUCHSCREEN_UNDEFINED);
@@ -1807,8 +1888,9 @@
         if (config.mnc != 0) {
             XmlUtils.writeIntAttribute(xml, XML_ATTR_MNC, config.mnc);
         }
-        if (config.locale != null) {
-            XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALE, config.locale.toLanguageTag());
+        config.fixUpLocaleList();
+        if (!config.mLocaleList.isEmpty()) {
+           XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALES, config.mLocaleList.toLanguageTags());
         }
         if (config.touchscreen != TOUCHSCREEN_UNDEFINED) {
             XmlUtils.writeIntAttribute(xml, XML_ATTR_TOUCHSCREEN, config.touchscreen);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 7cff11b..1f23c0a 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -392,6 +392,18 @@
     };
 
     /**
+     * @hide
+     */
+    public static abstract class LockoutResetCallback {
+
+        /**
+         * Called when lockout period expired and clients are allowed to listen for fingerprint
+         * again.
+         */
+        public void onLockoutReset() { }
+    };
+
+    /**
      * Request authentication of a crypto object. This call warms up the fingerprint hardware
      * and starts scanning for a fingerprint. It terminates when
      * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
@@ -680,10 +692,37 @@
             try {
                 mService.resetTimeout(token);
             } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e);
+                Log.v(TAG, "Remote exception in resetTimeout(): ", e);
             }
         } else {
-            Log.w(TAG, "getAuthenticatorId(): Service not connected!");
+            Log.w(TAG, "resetTimeout(): Service not connected!");
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public void addLockoutResetCallback(final LockoutResetCallback callback) {
+        if (mService != null) {
+            try {
+                mService.addLockoutResetCallback(
+                        new IFingerprintServiceLockoutResetCallback.Stub() {
+
+                    @Override
+                    public void onLockoutReset(long deviceId) throws RemoteException {
+                        mHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                callback.onLockoutReset();
+                            }
+                        });
+                    }
+                });
+            } catch (RemoteException e) {
+                Log.v(TAG, "Remote exception in addLockoutResetCallback(): ", e);
+            }
+        } else {
+            Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
         }
     }
 
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 3356354..690a751 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,6 +17,7 @@
 
 import android.os.Bundle;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
 import android.hardware.fingerprint.Fingerprint;
 import java.util.List;
 
@@ -71,4 +72,7 @@
 
     // Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
     void resetTimeout(in byte [] cryptoToken);
+
+    // Add a callback which gets notified when the fingerprint lockout period expired.
+    void addLockoutResetCallback(IFingerprintServiceLockoutResetCallback callback);
 }
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
new file mode 100644
index 0000000..c9a5d59
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.hardware.fingerprint;
+
+import android.hardware.fingerprint.Fingerprint;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+/**
+ * Callback when lockout period expired and clients are allowed to authenticate again.
+ * @hide
+ */
+oneway interface IFingerprintServiceLockoutResetCallback {
+    void onLockoutReset(long deviceId);
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 444f020..4292050 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -291,6 +291,7 @@
         }
 
         synchronized (mInputDevicesLock) {
+            populateInputDevicesLocked();
             int index = findInputDeviceListenerLocked(listener);
             if (index < 0) {
                 mInputDeviceListeners.add(new InputDeviceListenerDelegate(listener, handler));
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 4ad9d6d..bad94fc 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -468,6 +468,7 @@
          * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
          * @see BatteryStats#getCpuSpeedSteps()
          */
+        @Deprecated
         public abstract long getTimeAtCpuSpeed(int step, int which);
 
         public static abstract class Sensor {
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index 017735a..afae9ac 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -23,8 +23,8 @@
 
 // TODO: We don't except too many LocaleLists to exist at the same time, and
 // we need access to the data at native level, so we should pass the data
-// down to the native level, create a mapt of every list seen there, take a
-// pointer back, and just keep that pointed in the Java-level object, so
+// down to the native level, create a map of every list seen there, take a
+// pointer back, and just keep that pointer in the Java-level object, so
 // things could be copied very quickly.
 
 /**
@@ -34,6 +34,7 @@
 public final class LocaleList {
     private final Locale[] mList;
     private static final Locale[] sEmptyList = new Locale[0];
+    private static final LocaleList sEmptyLocaleList = new LocaleList();
 
     public Locale get(int location) {
         return location < mList.length ? mList[location] : null;
@@ -51,6 +52,60 @@
         return mList.length;
     }
 
+    @Override
+    public boolean equals(Object other) {
+        if (other == this)
+            return true;
+        if (!(other instanceof LocaleList))
+            return false;
+        final Locale[] otherList = ((LocaleList) other).mList;
+        if (mList.length != otherList.length)
+            return false;
+        for (int i = 0; i < mList.length; ++i) {
+            if (!mList[i].equals(otherList[i]))
+                return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        for (int i = 0; i < mList.length; ++i) {
+            result = 31 * result + mList[i].hashCode();
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[");
+        for (int i = 0; i < mList.length; ++i) {
+            sb.append(mList[i]);
+            if (i < mList.length - 1) {
+                sb.append(',');
+            }
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public String toLanguageTags() {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < mList.length; ++i) {
+            sb.append(mList[i].toLanguageTag());
+            if (i < mList.length - 1) {
+                sb.append(',');
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * It is almost always better to call {@link #getEmptyLocaleList()} instead which returns
+     * a pre-constructed empty locale list.
+     */
     public LocaleList() {
         mList = sEmptyList;
     }
@@ -59,6 +114,19 @@
      * @throws NullPointerException if any of the input locales is <code>null</code>.
      * @throws IllegalArgumentException if any of the input locales repeat.
      */
+    public LocaleList(@Nullable Locale locale) {
+        if (locale == null) {
+            mList = sEmptyList;
+        } else {
+            mList = new Locale[1];
+            mList[0] = (Locale) locale.clone();
+        }
+    }
+
+    /**
+     * @throws NullPointerException if any of the input locales is <code>null</code>.
+     * @throws IllegalArgumentException if any of the input locales repeat.
+     */
     public LocaleList(@Nullable Locale[] list) {
         if (list == null || list.length == 0) {
             mList = sEmptyList;
@@ -79,4 +147,21 @@
             mList = localeList;
         }
     }
+
+    public static LocaleList getEmptyLocaleList() {
+        return sEmptyLocaleList;
+    }
+
+    public static LocaleList forLanguageTags(@Nullable String list) {
+        if (list == null || list.equals("")) {
+            return getEmptyLocaleList();
+        } else {
+            final String[] tags = list.split(",");
+            final Locale[] localeArray = new Locale[tags.length];
+            for (int i = 0; i < localeArray.length; ++i) {
+                localeArray[i] = Locale.forLanguageTag(tags[i]);
+            }
+            return new LocaleList(localeArray);
+        }
+    }
 }
diff --git a/core/java/android/view/HandlerActionQueue.java b/core/java/android/view/HandlerActionQueue.java
new file mode 100644
index 0000000..4758a34
--- /dev/null
+++ b/core/java/android/view/HandlerActionQueue.java
@@ -0,0 +1,127 @@
+/*
+ * 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.view;
+
+import com.android.internal.util.GrowingArrayUtils;
+
+import android.os.Handler;
+
+import java.util.ArrayList;
+
+/**
+ * Class used to enqueue pending work from Views when no Handler is attached.
+ *
+ * @hide Exposed for test framework only.
+ */
+public class HandlerActionQueue {
+    private HandlerAction[] mActions;
+    private int mCount;
+
+    public void post(Runnable action) {
+        postDelayed(action, 0);
+    }
+
+    public void postDelayed(Runnable action, long delayMillis) {
+        final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
+
+        synchronized (this) {
+            if (mActions == null) {
+                mActions = new HandlerAction[4];
+            }
+            mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
+            mCount++;
+        }
+    }
+
+    public void removeCallbacks(Runnable action) {
+        synchronized (this) {
+            final int count = mCount;
+            int j = 0;
+
+            final HandlerAction[] actions = mActions;
+            for (int i = 0; i < count; i++) {
+                if (actions[i].matches(action)) {
+                    // Remove this action by overwriting it within
+                    // this loop or nulling it out later.
+                    continue;
+                }
+
+                if (j != i) {
+                    // At least one previous entry was removed, so
+                    // this one needs to move to the "new" list.
+                    actions[j] = actions[i];
+                }
+
+                j++;
+            }
+
+            // The "new" list only has j entries.
+            mCount = j;
+
+            // Null out any remaining entries.
+            for (; j < count; j++) {
+                actions[j] = null;
+            }
+        }
+    }
+
+    public void executeActions(Handler handler) {
+        synchronized (this) {
+            final HandlerAction[] actions = mActions;
+            for (int i = 0, count = mCount; i < count; i++) {
+                final HandlerAction handlerAction = actions[i];
+                handler.postDelayed(handlerAction.action, handlerAction.delay);
+            }
+
+            mActions = null;
+            mCount = 0;
+        }
+    }
+
+    public int size() {
+        return mCount;
+    }
+
+    public Runnable getRunnable(int index) {
+        if (index >= mCount) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mActions[index].action;
+    }
+
+    public long getDelay(int index) {
+        if (index >= mCount) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mActions[index].delay;
+    }
+
+    private static class HandlerAction {
+        final Runnable action;
+        final long delay;
+
+        public HandlerAction(Runnable action, long delay) {
+            this.action = action;
+            this.delay = delay;
+        }
+
+        public boolean matches(Runnable otherAction) {
+            return otherAction == null && action == null
+                    || action != null && action.equals(otherAction);
+        }
+    }
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f86adfe..33c51ff 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -97,21 +97,21 @@
      * @param launchTaskBehind True if the token is been launched from behind.
      * @param taskBounds Bounds to use when creating a new Task with the input task Id if
      *                   the task doesn't exist yet.
-     * @return The configuration of the task if it was newly created. null otherwise.
+     * @param configuration Configuration that is being used with this task.
      */
-    Configuration addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
+    void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            in Rect taskBounds);
+            in Rect taskBounds, in Configuration configuration);
     /**
      *
      * @param token The token we are adding to the input task Id.
      * @param taskId The Id of the task we are adding the token to.
      * @param taskBounds Bounds to use when creating a new Task with the input task Id if
      *                   the task doesn't exist yet.
-     * @return The configuration of the task if it was newly created. null otherwise.
+     * @param config Configuration that is being used with this task.
      */
-    Configuration setAppTask(IBinder token, int taskId, in Rect taskBounds);
+    void setAppTask(IBinder token, int taskId, in Rect taskBounds, in Configuration config);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
     void setFocusedApp(IBinder token, boolean moveFocusNow);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 16d9bf3..665069c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3823,6 +3823,12 @@
     private static SparseArray<String> mAttributeMap;
 
     /**
+     * Queue of pending runnables. Used to postpone calls to post() until this
+     * view is attached and has a handler.
+     */
+    private HandlerActionQueue mRunQueue;
+
+    /**
      * @hide
      */
     String mStartActivityRequestWho;
@@ -13010,6 +13016,18 @@
     }
 
     /**
+     * Returns the queue of runnable for this view.
+     *
+     * @return the queue of runnables for this view
+     */
+    private HandlerActionQueue getRunQueue() {
+        if (mRunQueue == null) {
+            mRunQueue = new HandlerActionQueue();
+        }
+        return mRunQueue;
+    }
+
+    /**
      * Gets the view root associated with the View.
      * @return The view root, or null if none.
      * @hide
@@ -13046,8 +13064,10 @@
         if (attachInfo != null) {
             return attachInfo.mHandler.post(action);
         }
-        // Assume that post will succeed later
-        ViewRootImpl.getRunQueue().post(action);
+
+        // Postpone the runnable until we know on which thread it needs to run.
+        // Assume that the runnable will be successfully placed after attach.
+        getRunQueue().post(action);
         return true;
     }
 
@@ -13075,8 +13095,10 @@
         if (attachInfo != null) {
             return attachInfo.mHandler.postDelayed(action, delayMillis);
         }
-        // Assume that post will succeed later
-        ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
+
+        // Postpone the runnable until we know on which thread it needs to run.
+        // Assume that the runnable will be successfully placed after attach.
+        getRunQueue().postDelayed(action, delayMillis);
         return true;
     }
 
@@ -13095,8 +13117,9 @@
             attachInfo.mViewRootImpl.mChoreographer.postCallback(
                     Choreographer.CALLBACK_ANIMATION, action, null);
         } else {
-            // Assume that post will succeed later
-            ViewRootImpl.getRunQueue().post(action);
+            // Postpone the runnable until we know
+            // on which thread it needs to run.
+            getRunQueue().post(action);
         }
     }
 
@@ -13118,8 +13141,9 @@
             attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed(
                     Choreographer.CALLBACK_ANIMATION, action, null, delayMillis);
         } else {
-            // Assume that post will succeed later
-            ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
+            // Postpone the runnable until we know
+            // on which thread it needs to run.
+            getRunQueue().postDelayed(action, delayMillis);
         }
     }
 
@@ -13146,8 +13170,7 @@
                 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
                         Choreographer.CALLBACK_ANIMATION, action, null);
             }
-            // Assume that post will succeed later
-            ViewRootImpl.getRunQueue().removeCallbacks(action);
+            getRunQueue().removeCallbacks(action);
         }
         return true;
     }
@@ -14565,7 +14588,6 @@
      *        this view
      */
     void dispatchAttachedToWindow(AttachInfo info, int visibility) {
-        //System.out.println("Attached! " + this);
         mAttachInfo = info;
         if (mOverlay != null) {
             mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility);
@@ -14581,6 +14603,11 @@
             mAttachInfo.mScrollContainers.add(this);
             mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED;
         }
+        // Transfer all pending runnables.
+        if (mRunQueue != null) {
+            mRunQueue.executeActions(info.mHandler);
+            mRunQueue = null;
+        }
         performCollectViewAttributes(mAttachInfo, visibility);
         onAttachedToWindow();
 
@@ -16866,7 +16893,9 @@
                         Choreographer.CALLBACK_ANIMATION, what, who,
                         Choreographer.subtractFrameDelay(delay));
             } else {
-                ViewRootImpl.getRunQueue().postDelayed(what, delay);
+                // Postpone the runnable until we know
+                // on which thread it needs to run.
+                getRunQueue().postDelayed(what, delay);
             }
         }
     }
@@ -16884,7 +16913,7 @@
                 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
                         Choreographer.CALLBACK_ANIMATION, what, who);
             }
-            ViewRootImpl.getRunQueue().removeCallbacks(what);
+            getRunQueue().removeCallbacks(what);
         }
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8bbaf36..d26e914 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -28,7 +28,6 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
-import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -131,7 +130,7 @@
      */
     static final int MAX_TRACKBALL_DELAY = 250;
 
-    static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
+    static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
 
     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
     static boolean sFirstDrawComplete = false;
@@ -6759,90 +6758,17 @@
         }
     }
 
-    static RunQueue getRunQueue() {
-        RunQueue rq = sRunQueues.get();
+    static HandlerActionQueue getRunQueue() {
+        HandlerActionQueue rq = sRunQueues.get();
         if (rq != null) {
             return rq;
         }
-        rq = new RunQueue();
+        rq = new HandlerActionQueue();
         sRunQueues.set(rq);
         return rq;
     }
 
     /**
-     * The run queue is used to enqueue pending work from Views when no Handler is
-     * attached.  The work is executed during the next call to performTraversals on
-     * the thread.
-     * @hide
-     */
-    static final class RunQueue {
-        private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
-
-        void post(Runnable action) {
-            postDelayed(action, 0);
-        }
-
-        void postDelayed(Runnable action, long delayMillis) {
-            HandlerAction handlerAction = new HandlerAction();
-            handlerAction.action = action;
-            handlerAction.delay = delayMillis;
-
-            synchronized (mActions) {
-                mActions.add(handlerAction);
-            }
-        }
-
-        void removeCallbacks(Runnable action) {
-            final HandlerAction handlerAction = new HandlerAction();
-            handlerAction.action = action;
-
-            synchronized (mActions) {
-                final ArrayList<HandlerAction> actions = mActions;
-
-                while (actions.remove(handlerAction)) {
-                    // Keep going
-                }
-            }
-        }
-
-        void executeActions(Handler handler) {
-            synchronized (mActions) {
-                final ArrayList<HandlerAction> actions = mActions;
-                final int count = actions.size();
-
-                for (int i = 0; i < count; i++) {
-                    final HandlerAction handlerAction = actions.get(i);
-                    handler.postDelayed(handlerAction.action, handlerAction.delay);
-                }
-
-                actions.clear();
-            }
-        }
-
-        private static class HandlerAction {
-            Runnable action;
-            long delay;
-
-            @Override
-            public boolean equals(Object o) {
-                if (this == o) return true;
-                if (o == null || getClass() != o.getClass()) return false;
-
-                HandlerAction that = (HandlerAction) o;
-                return !(action != null ? !action.equals(that.action) : that.action != null);
-
-            }
-
-            @Override
-            public int hashCode() {
-                int result = action != null ? action.hashCode() : 0;
-                result = 31 * result + (int) (delay ^ (delay >>> 32));
-                return result;
-            }
-        }
-    }
-
-    /**
      * Class for managing the accessibility interaction connection
      * based on the global accessibility state.
      */
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index f178c8c..4f4d3e0 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -338,7 +338,7 @@
         }
 
         if (mCpuPowerCalculator == null) {
-            mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
+            mCpuPowerCalculator = new CpuPowerCalculator();
         }
         mCpuPowerCalculator.reset();
 
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index a3ef612..d62f7a6 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -23,54 +23,14 @@
     private static final String TAG = "CpuPowerCalculator";
     private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
 
-    private final double[] mPowerCpuNormal;
-
-    /**
-     * Reusable array for calculations.
-     */
-    private final long[] mSpeedStepTimes;
-
-    public CpuPowerCalculator(PowerProfile profile) {
-        final int speedSteps = profile.getNumSpeedSteps();
-        mPowerCpuNormal = new double[speedSteps];
-        mSpeedStepTimes = new long[speedSteps];
-        for (int p = 0; p < speedSteps; p++) {
-            mPowerCpuNormal[p] = profile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p);
-        }
-    }
-
     @Override
     public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
                              long rawUptimeUs, int statsType) {
-        final int speedSteps = mSpeedStepTimes.length;
-
-        long totalTimeAtSpeeds = 0;
-        for (int step = 0; step < speedSteps; step++) {
-            mSpeedStepTimes[step] = u.getTimeAtCpuSpeed(step, statsType);
-            totalTimeAtSpeeds += mSpeedStepTimes[step];
-        }
-        totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1);
-
         app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
-        if (DEBUG && app.cpuTimeMs != 0) {
-            Log.d(TAG, "UID " + u.getUid() + ": CPU time " + app.cpuTimeMs + " ms");
-        }
-
-        double cpuPowerMaMs = 0;
-        for (int step = 0; step < speedSteps; step++) {
-            final double ratio = (double) mSpeedStepTimes[step] / totalTimeAtSpeeds;
-            final double cpuSpeedStepPower = ratio * app.cpuTimeMs * mPowerCpuNormal[step];
-            if (DEBUG && ratio != 0) {
-                Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
-                        + step + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power="
-                        + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000)));
-            }
-            cpuPowerMaMs += cpuSpeedStepPower;
-        }
-
-        if (DEBUG && cpuPowerMaMs != 0) {
-            Log.d(TAG, "UID " + u.getUid() + ": cpu total power="
-                    + BatteryStatsHelper.makemAh(cpuPowerMaMs / (60 * 60 * 1000)));
+        app.cpuPowerMah = (double) u.getCpuPowerMaUs(statsType) / (60.0 * 60.0 * 1000.0 * 1000.0);
+        if (DEBUG && (app.cpuTimeMs != 0 || app.cpuPowerMah != 0)) {
+            Log.d(TAG, "UID " + u.getUid() + ": CPU time=" + app.cpuTimeMs + " ms power="
+                    + BatteryStatsHelper.makemAh(app.cpuPowerMah));
         }
 
         // Keep track of the package with highest drain.
@@ -108,8 +68,5 @@
             // Statistics may not have been gathered yet.
             app.cpuTimeMs = app.cpuFgTimeMs;
         }
-
-        // Convert the CPU power to mAh
-        app.cpuPowerMah = cpuPowerMaMs / (60 * 60 * 1000);
     }
 }
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index 35eeca7..582c4f1 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -19,6 +19,7 @@
 
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
+import android.view.MotionEvent;
 import android.widget.ActionMenuPresenter;
 import android.widget.ActionMenuView;
 
@@ -53,6 +54,9 @@
 
     protected Animator mVisibilityAnim;
 
+    private boolean mEatingTouch;
+    private boolean mEatingHover;
+
     public AbsActionBarView(Context context) {
         this(context, null);
     }
@@ -97,6 +101,57 @@
         }
     }
 
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        // ActionBarViews always eat touch events, but should still respect the touch event dispatch
+        // contract. If the normal View implementation doesn't want the events, we'll just silently
+        // eat the rest of the gesture without reporting the events to the default implementation
+        // since that's what it expects.
+
+        final int action = ev.getActionMasked();
+        if (action == MotionEvent.ACTION_DOWN) {
+            mEatingTouch = false;
+        }
+
+        if (!mEatingTouch) {
+            final boolean handled = super.onTouchEvent(ev);
+            if (action == MotionEvent.ACTION_DOWN && !handled) {
+                mEatingTouch = true;
+            }
+        }
+
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            mEatingTouch = false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean onHoverEvent(MotionEvent ev) {
+        // Same deal as onTouchEvent() above. Eat all hover events, but still
+        // respect the touch event dispatch contract.
+
+        final int action = ev.getActionMasked();
+        if (action == MotionEvent.ACTION_HOVER_ENTER) {
+            mEatingHover = false;
+        }
+
+        if (!mEatingHover) {
+            final boolean handled = super.onHoverEvent(ev);
+            if (action == MotionEvent.ACTION_HOVER_ENTER && !handled) {
+                mEatingHover = true;
+            }
+        }
+
+        if (action == MotionEvent.ACTION_HOVER_EXIT
+                || action == MotionEvent.ACTION_CANCEL) {
+            mEatingHover = false;
+        }
+
+        return true;
+    }
+
     /**
      * Sets whether the bar should be split right now, no questions asked.
      * @param split true if the bar should split
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 073a2ad..051845f 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.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
+        requireStrongAuth(StrongAuthTracker.STRONG_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,
-                        SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
+                        STRONG_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 requested it.
+         * Strong authentication is required because a device admin has temporarily requested it.
          */
         public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
 
         /**
-         * Some authentication is required because the user has temporarily disabled trust.
+         * Strong authentication is required because the user has temporarily requested it.
          */
-        public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
+        public static final int STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
 
         /**
          * Strong authentication is required because the user has been locked out after too many
@@ -1291,7 +1291,6 @@
         public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
 
         public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT;
-        private static final int ALLOWING_FINGERPRINT = SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
 
         final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
 
@@ -1333,7 +1332,7 @@
          * current strong authentication requirements.
          */
         public boolean isFingerprintAllowedForUser(int userId) {
-            return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
+            return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
         }
 
         /**
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 414cbb4..aef70be 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -83,6 +83,14 @@
   pid_t pid;
   int status;
 
+  // It's necessary to save and restore the errno during this function.
+  // Since errno is stored per thread, changing it here modifies the errno
+  // on the thread on which this signal handler executes. If a signal occurs
+  // between a call and an errno check, it's possible to get the errno set
+  // here.
+  // See b/23572286 for extra information.
+  int saved_errno = errno;
+
   while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
      // Log process-death status that we care about.  In general it is
      // not safe to call LOG(...) from a signal handler because of
@@ -118,6 +126,8 @@
   if (pid < 0 && errno != ECHILD) {
     ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno));
   }
+
+  errno = saved_errno;
 }
 
 // Configures the SIGCHLD handler for the zygote process. This is configured
diff --git a/core/tests/coretests/src/android/view/HandlerActionQueueTest.java b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
new file mode 100644
index 0000000..fd8f23a
--- /dev/null
+++ b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.view;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class HandlerActionQueueTest extends AndroidTestCase {
+
+    @SmallTest
+    public void testPostAndRemove() {
+        HandlerActionQueue runQueue = new HandlerActionQueue();
+        MockRunnable runnable1 = new MockRunnable();
+        MockRunnable runnable2 = new MockRunnable();
+        MockRunnable runnable3 = new MockRunnable();
+
+        runQueue.post(runnable1);
+        runQueue.post(runnable1);
+        runQueue.post(runnable2);
+        runQueue.postDelayed(runnable1, 100);
+        runQueue.postDelayed(null, 500);
+        assertEquals(5, runQueue.size());
+        assertEquals(0, runQueue.getDelay(0));
+        assertEquals(0, runQueue.getDelay(1));
+        assertEquals(0, runQueue.getDelay(2));
+        assertEquals(100, runQueue.getDelay(3));
+        assertEquals(500, runQueue.getDelay(4));
+        assertEquals(500, runQueue.getDelay(4));
+        assertEquals(runnable1, runQueue.getRunnable(0));
+        assertEquals(runnable1, runQueue.getRunnable(1));
+        assertEquals(runnable2, runQueue.getRunnable(2));
+        assertEquals(runnable1, runQueue.getRunnable(3));
+        assertEquals(null, runQueue.getRunnable(4));
+
+        runQueue.removeCallbacks(runnable1);
+        assertEquals(2, runQueue.size());
+        assertEquals(0, runQueue.getDelay(0));
+        assertEquals(500, runQueue.getDelay(1));
+        assertEquals(runnable2, runQueue.getRunnable(0));
+        assertEquals(null, runQueue.getRunnable(1));
+
+        try {
+            assertNull(runQueue.getRunnable(2));
+            assertFalse(true);
+        } catch (IndexOutOfBoundsException e) {
+            // Should throw an exception.
+        }
+
+        runQueue.removeCallbacks(runnable3);
+        assertEquals(2, runQueue.size());
+
+        runQueue.removeCallbacks(runnable2);
+        assertEquals(1, runQueue.size());
+        assertEquals(null, runQueue.getRunnable(0));
+
+        runQueue.removeCallbacks(null);
+        assertEquals(0, runQueue.size());
+    }
+
+    private static class MockRunnable implements Runnable {
+        @Override
+        public void run() {
+
+        }
+    }
+}
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index 2f28700..f682fb8 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -40,10 +40,9 @@
 # For the host
 # =====================================================
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE:= libandroidfw
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_HOST_OS := darwin linux windows
 LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 LOCAL_SRC_FILES:= $(hostSources)
@@ -56,13 +55,10 @@
 # =====================================================
 
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE:= libandroidfw
-LOCAL_MODULE_TAGS := optional
 LOCAL_SRC_FILES:= $(deviceSources)
 LOCAL_C_INCLUDES := \
-    external/zlib \
     system/core/include
 LOCAL_STATIC_LIBRARIES := libziparchive libbase
 LOCAL_SHARED_LIBRARIES := \
diff --git a/media/java/android/mtp/MtpObjectInfo.java b/media/java/android/mtp/MtpObjectInfo.java
index a080c73..64aa997 100644
--- a/media/java/android/mtp/MtpObjectInfo.java
+++ b/media/java/android/mtp/MtpObjectInfo.java
@@ -294,6 +294,11 @@
             mObjectInfo.mThumbPixWidth = objectInfo.mThumbPixWidth;
         }
 
+        public Builder setObjectHandle(int value) {
+            mObjectInfo.mHandle = value;
+            return this;
+        }
+
         public Builder setAssociationDesc(int value) {
             mObjectInfo.mAssociationDesc = value;
             return this;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index 8b92331..f8ec8f1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -56,6 +56,7 @@
 
 public class CopyService extends IntentService {
     public static final String TAG = "CopyService";
+    public static final boolean DEBUG = false;
 
     private static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
     public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
@@ -159,6 +160,7 @@
             // Catch-all to prevent any copy errors from wedging the app.
             Log.e(TAG, "Exceptions occurred during copying", e);
         } finally {
+            if (DEBUG) Log.d(TAG, "Cleaning up after copy");
             ContentProviderClient.releaseQuietly(mSrcClient);
             ContentProviderClient.releaseQuietly(mDstClient);
 
@@ -166,10 +168,12 @@
             mNotificationManager.cancel(mJobId, 0);
 
             if (mFailedFiles.size() > 0) {
+                Log.e(TAG, mFailedFiles.size() + " files failed to copy");
                 final Context context = getApplicationContext();
                 final Intent navigateIntent = new Intent(context, FilesActivity.class);
                 navigateIntent.putExtra(EXTRA_STACK, (Parcelable) stack);
                 navigateIntent.putExtra(EXTRA_FAILURE, FAILURE_COPY);
+                navigateIntent.putExtra(EXTRA_TRANSFER_MODE, transferMode);
                 navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, mFailedFiles);
 
                 final int titleResourceId = (transferMode == TRANSFER_MODE_COPY ?
@@ -186,6 +190,7 @@
                         .setAutoCancel(true);
                 mNotificationManager.notify(mJobId, 0, errorBuilder.build());
             }
+            if (DEBUG) Log.d(TAG, "Done cleaning up");
         }
     }
 
@@ -398,6 +403,9 @@
      */
     private void copy(DocumentInfo srcInfo, DocumentInfo dstDirInfo, int mode)
             throws RemoteException {
+        if (DEBUG) Log.d(TAG, "Copying " + srcInfo.displayName + " (" + srcInfo.derivedUri + ")" +
+            " to " + dstDirInfo.displayName + " (" + dstDirInfo.derivedUri + ")");
+
         final Uri dstUri = DocumentsContract.createDocument(mDstClient, dstDirInfo.derivedUri,
                 srcInfo.mimeType, srcInfo.displayName);
         if (dstUri == null) {
@@ -499,10 +507,28 @@
             srcFile.checkError();
         } catch (IOException e) {
             copyError = e;
+
             try {
-                dstFile.closeWithError(copyError.getMessage());
-            } catch (IOException closeError) {
-                Log.e(TAG, "Error closing destination", closeError);
+                DocumentInfo info = DocumentInfo.fromUri(getContentResolver(), srcUri);
+                mFailedFiles.add(info);
+                Log.e(TAG, "Error while copying " + info.displayName + " (" + info.derivedUri + ")",
+                        copyError);
+            } catch (FileNotFoundException ignore) {
+                // Generate a dummy DocumentInfo so an error still gets reflected in the UI for this
+                // file.
+                DocumentInfo info = new DocumentInfo();
+                info.derivedUri = srcUri;
+                info.displayName = "Unknown [" + srcUri + "]";
+                mFailedFiles.add(info);
+                Log.e(TAG, "Error while copying " + srcUri, copyError);
+            }
+
+            if (dstFile != null) {
+                try {
+                    dstFile.closeWithError(copyError.getMessage());
+                } catch (IOException closeError) {
+                    Log.e(TAG, "Error closing destination", closeError);
+                }
             }
         } finally {
             // This also ensures the file descriptors are closed.
@@ -510,16 +536,6 @@
             IoUtils.closeQuietly(dst);
         }
 
-        if (copyError != null) {
-            // Log errors.
-            Log.e(TAG, "Error while copying " + srcUri.toString(), copyError);
-            try {
-                mFailedFiles.add(DocumentInfo.fromUri(getContentResolver(), srcUri));
-            } catch (FileNotFoundException ignore) {
-                Log.w(TAG, "Source file gone: " + srcUri, copyError);
-                // The source file is gone.
-            }
-        }
 
         if (copyError != null || mIsCancelled) {
             // Clean up half-copied files.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index e15e6e0..ecf03f5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -573,6 +573,9 @@
         }
 
         mRecView.setLayoutManager(layout);
+        // TODO: Once b/23691541 is resolved, use a listener within MultiSelectManager instead of
+        // imperatively calling this function.
+        mModel.mSelectionManager.handleLayoutChanged();
         // setting layout manager automatically invalidates existing ViewHolders.
         mThumbSize = new Point(thumbSize, thumbSize);
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index c27cad3..4284f6f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -250,6 +250,10 @@
         notifySelectionChanged();
     }
 
+    public void handleLayoutChanged() {
+        mBandSelectManager.handleLayoutChanged();
+    }
+
     /**
      * Clears the selection, without notifying anyone.
      */
@@ -1192,6 +1196,18 @@
         }
 
         /**
+         * Handle a change in layout by cleaning up and getting rid of the old model and creating
+         * a new model which will track the new layout.
+         */
+        public void handleLayoutChanged() {
+            mModel.removeOnSelectionChangedListener(this);
+            mModel.stopListening();
+
+            mModel = new BandSelectModel((RuntimeRecyclerViewHelper) mHelper);
+            mModel.addOnSelectionChangedListener(this);
+        }
+
+        /**
          * Processes a MotionEvent by starting, ending, or resizing the band select overlay.
          * @param e
          */
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index fc6117f..cfc232c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -29,6 +29,7 @@
 import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
+import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -472,6 +473,10 @@
         }
     }
 
+    private void handleFingerprintLockoutReset() {
+        updateFingerprintListeningState();
+    }
+
     private void setFingerprintRunningState(int fingerprintRunningState) {
         boolean wasRunning = mFingerprintRunningState == FINGERPRINT_STATE_RUNNING;
         boolean isRunning = fingerprintRunningState == FINGERPRINT_STATE_RUNNING;
@@ -681,6 +686,14 @@
         }
     };
 
+    private final FingerprintManager.LockoutResetCallback mLockoutResetCallback
+            = new FingerprintManager.LockoutResetCallback() {
+        @Override
+        public void onLockoutReset() {
+            handleFingerprintLockoutReset();
+        }
+    };
+
     private FingerprintManager.AuthenticationCallback mAuthenticationCallback
             = new AuthenticationCallback() {
 
@@ -1003,6 +1016,9 @@
 
         mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
         updateFingerprintListeningState();
+        if (mFpm != null) {
+            mFpm.addLockoutResetCallback(mLockoutResetCallback);
+        }
     }
 
     private void updateFingerprintListeningState() {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
new file mode 100644
index 0000000..48d5dcf
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
@@ -0,0 +1,99 @@
+/*
+ * 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.mtp;
+
+import android.database.MatrixCursor;
+import android.mtp.MtpObjectInfo;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+
+import java.util.Date;
+
+final class CursorHelper {
+    static final int DUMMY_HANDLE_FOR_ROOT = 0;
+
+    private CursorHelper() {
+    }
+
+    static void addToCursor(MtpRoot root, MatrixCursor.RowBuilder builder) {
+        final Identifier identifier = new Identifier(
+                root.mDeviceId, root.mStorageId, DUMMY_HANDLE_FOR_ROOT);
+        builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
+        builder.add(Document.COLUMN_DISPLAY_NAME, root.mDescription);
+        builder.add(Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR);
+        builder.add(Document.COLUMN_LAST_MODIFIED, null);
+        builder.add(Document.COLUMN_FLAGS, 0);
+        builder.add(Document.COLUMN_SIZE,
+                (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE));
+    }
+
+    static void addToCursor(MtpObjectInfo objectInfo, Identifier rootIdentifier,
+            MatrixCursor.RowBuilder builder) {
+        final Identifier identifier = new Identifier(
+                rootIdentifier.mDeviceId, rootIdentifier.mStorageId, objectInfo.getObjectHandle());
+        final String mimeType = formatTypeToMimeType(objectInfo.getFormat());
+
+        int flag = 0;
+        if (objectInfo.getProtectionStatus() == 0) {
+            flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
+                    DocumentsContract.Document.FLAG_SUPPORTS_WRITE;
+            if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR) {
+                flag |= DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE;
+            }
+        }
+        if (objectInfo.getThumbCompressedSize() > 0) {
+            flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
+        }
+
+        builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
+        builder.add(Document.COLUMN_DISPLAY_NAME, objectInfo.getName());
+        builder.add(Document.COLUMN_MIME_TYPE, mimeType);
+        builder.add(
+                Document.COLUMN_LAST_MODIFIED,
+                objectInfo.getDateModified() != 0 ? objectInfo.getDateModified() : null);
+        builder.add(Document.COLUMN_FLAGS, flag);
+        builder.add(Document.COLUMN_SIZE, objectInfo.getCompressedSize());
+    }
+
+    static String formatTypeToMimeType(int format) {
+        // TODO: Add complete list of mime types.
+        switch (format) {
+            case 0x3001:
+                return DocumentsContract.Document.MIME_TYPE_DIR;
+            case 0x3009:
+                return "audio/mp3";
+            case 0x3801:
+                return "image/jpeg";
+            default:
+                return "application/octet-stream";
+        }
+    }
+
+    static int mimeTypeToFormatType(String mimeType) {
+        // TODO: Add complete list of mime types.
+        switch (mimeType.toLowerCase()) {
+            case Document.MIME_TYPE_DIR:
+                return 0x3001;
+            case "audio/mp3":
+                return 0x3009;
+            case "image/jpeg":
+                return 0x3801;
+            default:
+                return 0x3000;  // Undefined object.
+        }
+    }
+}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index c430def..d4c4331 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -19,6 +19,7 @@
 import android.content.ContentResolver;
 import android.database.Cursor;
 import android.database.MatrixCursor;
+import android.mtp.MtpObjectInfo;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Process;
@@ -34,6 +35,7 @@
  * Loader for MTP document.
  * At the first request, the loader returns only first NUM_INITIAL_ENTRIES. Then it launches
  * background thread to load the rest documents and caches its result for next requests.
+ * TODO: Rename this class to ObjectInfoLoader
  */
 class DocumentLoader {
     static final int NUM_INITIAL_ENTRIES = 10;
@@ -50,13 +52,13 @@
         mResolver = resolver;
     }
 
-    private static MtpDocument[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
+    private static MtpObjectInfo[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
             throws IOException {
-        final MtpDocument[] documents = new MtpDocument[handles.length];
+        final MtpObjectInfo[] objectInfos = new MtpObjectInfo[handles.length];
         for (int i = 0; i < handles.length; i++) {
-            documents[i] = manager.getDocument(deviceId, handles[i]);
+            objectInfos[i] = manager.getObjectInfo(deviceId, handles[i]);
         }
-        return documents;
+        return objectInfos;
     }
 
     synchronized Cursor queryChildDocuments(String[] columnNames, Identifier parent)
@@ -66,7 +68,7 @@
             int parentHandle = parent.mObjectHandle;
             // Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
             // getObjectHandles if we would like to obtain children under the root.
-            if (parentHandle == MtpDocument.DUMMY_HANDLE_FOR_ROOT) {
+            if (parentHandle == CursorHelper.DUMMY_HANDLE_FOR_ROOT) {
                 parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
             }
             task = new LoaderTask(parent, mMtpManager.getObjectHandles(
@@ -89,14 +91,18 @@
         return task.createCursor(mResolver, columnNames);
     }
 
-    synchronized void clearCache(int deviceId) {
+    synchronized void clearTasks(int deviceId) {
         mTaskList.clearTaskForDevice(deviceId);
     }
 
-    synchronized void clearCache() {
+    synchronized void clearCompletedTasks() {
         mTaskList.clearCompletedTask();
     }
 
+    synchronized void clearTask(Identifier parentIdentifier) {
+        mTaskList.clearTask(parentIdentifier);
+    }
+
     private class BackgroundLoaderThread extends Thread {
         @Override
         public void run() {
@@ -114,16 +120,16 @@
                     deviceId = task.mIdentifier.mDeviceId;
                     handles = task.getUnloadedObjectHandles(NUM_LOADING_ENTRIES);
                 }
-                MtpDocument[] documents;
+                MtpObjectInfo[] objectInfos;
                 try {
-                    documents = loadDocuments(mMtpManager, deviceId, handles);
+                    objectInfos = loadDocuments(mMtpManager, deviceId, handles);
                 } catch (IOException exception) {
-                    documents = null;
+                    objectInfos = null;
                     Log.d(MtpDocumentsProvider.TAG, exception.getMessage());
                 }
                 synchronized (DocumentLoader.this) {
-                    if (documents != null) {
-                        task.fillDocuments(documents);
+                    if (objectInfos != null) {
+                        task.fillDocuments(objectInfos);
                         final boolean shouldNotify =
                                 task.mLastNotified.getTime() <
                                 new Date().getTime() - NOTIFY_PERIOD_MS ||
@@ -177,19 +183,30 @@
                 }
             }
         }
+
+        void clearTask(Identifier parentIdentifier) {
+            for (int i = 0; i < size(); i++) {
+                final LoaderTask task = get(i);
+                if (task.mIdentifier.mDeviceId == parentIdentifier.mDeviceId &&
+                        task.mIdentifier.mObjectHandle == parentIdentifier.mObjectHandle) {
+                    remove(i);
+                    return;
+                }
+            }
+        }
     }
 
     private static class LoaderTask {
         final Identifier mIdentifier;
         final int[] mObjectHandles;
-        final MtpDocument[] mDocuments;
+        final MtpObjectInfo[] mObjectInfos;
         Date mLastNotified;
         int mNumLoaded;
 
         LoaderTask(Identifier identifier, int[] objectHandles) {
             mIdentifier = identifier;
             mObjectHandles = objectHandles;
-            mDocuments = new MtpDocument[mObjectHandles.length];
+            mObjectInfos = new MtpObjectInfo[mObjectHandles.length];
             mNumLoaded = 0;
             mLastNotified = new Date();
         }
@@ -199,7 +216,7 @@
             final Identifier rootIdentifier = new Identifier(
                     mIdentifier.mDeviceId, mIdentifier.mStorageId);
             for (int i = 0; i < mNumLoaded; i++) {
-                mDocuments[i].addToCursor(rootIdentifier, cursor.newRow());
+                CursorHelper.addToCursor(mObjectInfos[i], rootIdentifier, cursor.newRow());
             }
             final Bundle extras = new Bundle();
             extras.putBoolean(DocumentsContract.EXTRA_LOADING, !completed());
@@ -209,7 +226,7 @@
         }
 
         boolean completed() {
-            return mNumLoaded == mDocuments.length;
+            return mNumLoaded == mObjectInfos.length;
         }
 
         int[] getUnloadedObjectHandles(int count) {
@@ -224,9 +241,9 @@
             mLastNotified = new Date();
         }
 
-        void fillDocuments(MtpDocument[] documents) {
-            for (int i = 0; i < documents.length; i++) {
-                mDocuments[mNumLoaded++] = documents[i];
+        void fillDocuments(MtpObjectInfo[] objectInfos) {
+            for (int i = 0; i < objectInfos.length; i++) {
+                mObjectInfos[mNumLoaded++] = objectInfos[i];
             }
         }
 
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
index bd0c837..ae29f52 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
@@ -41,7 +41,7 @@
 
 
     Identifier(int deviceId, int storageId) {
-        this(deviceId, storageId, MtpDocument.DUMMY_HANDLE_FOR_ROOT);
+        this(deviceId, storageId, CursorHelper.DUMMY_HANDLE_FOR_ROOT);
     }
 
     Identifier(int deviceId, int storageId, int objectHandle) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
deleted file mode 100644
index c1d9609..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
+++ /dev/null
@@ -1,132 +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.
- */
-
-package com.android.mtp;
-
-import android.database.MatrixCursor;
-import android.mtp.MtpObjectInfo;
-import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Document;
-
-import java.util.Date;
-
-class MtpDocument {
-    static final int DUMMY_HANDLE_FOR_ROOT = 0;
-
-    private final int mObjectHandle;
-    private final int mFormat;
-    private final String mName;
-    private final Date mDateModified;
-    private final int mSize;
-    private final int mThumbSize;
-    private final boolean mReadOnly;
-
-    /**
-     * Constructor for root document.
-     */
-    MtpDocument(MtpRoot root) {
-        this(DUMMY_HANDLE_FOR_ROOT,
-             0x3001,  // Directory.
-             root.mDescription,
-             null,    // Unknown name.
-             (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE),
-             0,       // Total size.
-             true);   // Writable.
-    }
-
-    MtpDocument(MtpObjectInfo objectInfo) {
-        this(objectInfo.getObjectHandle(),
-             objectInfo.getFormat(),
-             objectInfo.getName(),
-             objectInfo.getDateModified() != 0 ? new Date(objectInfo.getDateModified()) : null,
-             objectInfo.getCompressedSize(),
-             objectInfo.getThumbCompressedSize(),
-             objectInfo.getProtectionStatus() != 0);
-    }
-
-    MtpDocument(int objectHandle,
-                int format,
-                String name,
-                Date dateModified,
-                int size,
-                int thumbSize,
-                boolean readOnly) {
-        this.mObjectHandle = objectHandle;
-        this.mFormat = format;
-        this.mName = name;
-        this.mDateModified = dateModified;
-        this.mSize = size;
-        this.mThumbSize = thumbSize;
-        this.mReadOnly = readOnly;
-    }
-
-    void addToCursor(Identifier rootIdentifier, MatrixCursor.RowBuilder builder) {
-        final Identifier identifier = new Identifier(
-                rootIdentifier.mDeviceId, rootIdentifier.mStorageId, mObjectHandle);
-        final String mimeType = formatTypeToMimeType(mFormat);
-
-        int flag = 0;
-        if (mObjectHandle != DUMMY_HANDLE_FOR_ROOT) {
-            if (mThumbSize > 0) {
-                flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
-            }
-            if (!mReadOnly) {
-                flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
-                        DocumentsContract.Document.FLAG_SUPPORTS_WRITE;
-            }
-        }
-        if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR && !mReadOnly) {
-            flag |= DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE;
-        }
-
-        builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
-        builder.add(Document.COLUMN_DISPLAY_NAME, mName);
-        builder.add(Document.COLUMN_MIME_TYPE, mimeType); 
-        builder.add(
-                Document.COLUMN_LAST_MODIFIED,
-                mDateModified != null ? mDateModified.getTime() : null);
-        builder.add(Document.COLUMN_FLAGS, flag);
-        builder.add(Document.COLUMN_SIZE, mSize);
-    }
-
-    static String formatTypeToMimeType(int format) {
-        // TODO: Add complete list of mime types.
-        switch (format) {
-            case 0x3001:
-                return DocumentsContract.Document.MIME_TYPE_DIR;
-            case 0x3009:
-                return "audio/mp3";
-            case 0x3801:
-                return "image/jpeg";
-            default:
-                return "application/octet-stream";
-        }
-    }
-
-    static int mimeTypeToFormatType(String mimeType) {
-        // TODO: Add complete list of mime types.
-        switch (mimeType.toLowerCase()) {
-            case Document.MIME_TYPE_DIR:
-                return 0x3001;
-            case "audio/mp3":
-                return 0x3009;
-            case "image/jpeg":
-                return 0x3801;
-            default:
-                return 0x3000;  // Undefined object.
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index a3cf3e2..78ed161 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -21,11 +21,12 @@
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.graphics.Point;
+import android.mtp.MtpObjectInfo;
 import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract;
 import android.provider.DocumentsProvider;
 import android.util.Log;
 
@@ -116,37 +117,37 @@
         }
         final Identifier identifier = Identifier.createFromDocumentId(documentId);
 
-        MtpDocument document = null;
-        if (identifier.mObjectHandle != MtpDocument.DUMMY_HANDLE_FOR_ROOT) {
+        if (identifier.mObjectHandle != CursorHelper.DUMMY_HANDLE_FOR_ROOT) {
+            MtpObjectInfo objectInfo;
             try {
-                document = mMtpManager.getDocument(identifier.mDeviceId, identifier.mObjectHandle);
+                objectInfo = mMtpManager.getObjectInfo(
+                        identifier.mDeviceId, identifier.mObjectHandle);
             } catch (IOException e) {
                 throw new FileNotFoundException(e.getMessage());
             }
+            final MatrixCursor cursor = new MatrixCursor(projection);
+            CursorHelper.addToCursor(
+                    objectInfo,
+                    new Identifier(identifier.mDeviceId, identifier.mStorageId),
+                    cursor.newRow());
+            return cursor;
         } else {
             MtpRoot[] roots;
             try {
                 roots = mMtpManager.getRoots(identifier.mDeviceId);
-                if (roots != null) {
-                    for (final MtpRoot root : roots) {
-                        if (identifier.mStorageId == root.mStorageId) {
-                            document = new MtpDocument(root);
-                            break;
-                        }
-                    }
-                }
-                if (document == null) {
-                    throw new FileNotFoundException();
-                }
             } catch (IOException e) {
                 throw new FileNotFoundException(e.getMessage());
             }
+            for (final MtpRoot root : roots) {
+                if (identifier.mStorageId != root.mStorageId)
+                    continue;
+                final MatrixCursor cursor = new MatrixCursor(projection);
+                CursorHelper.addToCursor(root, cursor.newRow());
+                return cursor;
+            }
         }
 
-        final MatrixCursor cursor = new MatrixCursor(projection);
-        document.addToCursor(
-                new Identifier(identifier.mDeviceId, identifier.mStorageId), cursor.newRow());
-        return cursor;
+        throw new FileNotFoundException();
     }
 
     @Override
@@ -173,6 +174,8 @@
                 case "r":
                     return mPipeManager.readDocument(mMtpManager, identifier);
                 case "w":
+                    // TODO: Clear the parent document loader task (if exists) and call notify
+                    // when writing is completed.
                     return mPipeManager.writeDocument(getContext(), mMtpManager, identifier);
                 default:
                     // TODO: Add support for seekable files.
@@ -207,8 +210,10 @@
             final int parentHandle =
                     mMtpManager.getParent(identifier.mDeviceId, identifier.mObjectHandle);
             mMtpManager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
-            notifyChildDocumentsChange(new Identifier(
-                    identifier.mDeviceId, identifier.mStorageId, parentHandle).toDocumentId());
+            final Identifier parentIdentifier = new Identifier(
+                    identifier.mDeviceId, identifier.mStorageId, parentHandle);
+            mDocumentLoader.clearTask(parentIdentifier);
+            notifyChildDocumentsChange(parentIdentifier.toDocumentId());
         } catch (IOException error) {
             throw new FileNotFoundException(error.getMessage());
         }
@@ -216,7 +221,7 @@
 
     @Override
     public void onTrimMemory(int level) {
-        mDocumentLoader.clearCache();
+        mDocumentLoader.clearCompletedTasks();
     }
 
     @Override
@@ -224,11 +229,19 @@
             throws FileNotFoundException {
         try {
             final Identifier parentId = Identifier.createFromDocumentId(parentDocumentId);
+            final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe();
+            pipe[0].close();  // 0 bytes for a new document.
             final int objectHandle = mMtpManager.createDocument(
-                    parentId.mDeviceId, parentId.mStorageId, parentId.mObjectHandle, mimeType,
-                    displayName);
-            final String documentId =  new Identifier(parentId.mDeviceId, parentId.mStorageId,
+                    parentId.mDeviceId,
+                    new MtpObjectInfo.Builder()
+                            .setStorageId(parentId.mStorageId)
+                            .setParent(parentId.mObjectHandle)
+                            .setFormat(CursorHelper.mimeTypeToFormatType(mimeType))
+                            .setName(displayName)
+                            .build(), pipe[1]);
+            final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
                    objectHandle).toDocumentId();
+            mDocumentLoader.clearTask(parentId);
             notifyChildDocumentsChange(parentDocumentId);
             return documentId;
         } catch (IOException error) {
@@ -244,7 +257,7 @@
 
     void closeDevice(int deviceId) throws IOException {
         mMtpManager.closeDevice(deviceId);
-        mDocumentLoader.clearCache(deviceId);
+        mDocumentLoader.clearTasks(deviceId);
         mRootScanner.scanNow();
     }
 
@@ -253,7 +266,7 @@
         for (int deviceId : mMtpManager.getOpenedDeviceIds()) {
             try {
                 mMtpManager.closeDevice(deviceId);
-                mDocumentLoader.clearCache(deviceId);
+                mDocumentLoader.clearTasks(deviceId);
                 closed = true;
             } catch (IOException d) {
                 Log.d(TAG, "Failed to close the MTP device: " + deviceId);
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 6647009..ca78a3e 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -20,6 +20,7 @@
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbDeviceConnection;
 import android.hardware.usb.UsbManager;
+import android.mtp.MtpConstants;
 import android.mtp.MtpDevice;
 import android.mtp.MtpObjectInfo;
 import android.os.ParcelFileDescriptor;
@@ -108,16 +109,12 @@
         return results;
     }
 
-    synchronized MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
+    synchronized MtpObjectInfo getObjectInfo(int deviceId, int objectHandle)
+            throws IOException {
         final MtpDevice device = getDevice(deviceId);
         return device.getObjectInfo(objectHandle);
     }
 
-    synchronized MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        return new MtpDocument(device.getObjectInfo(objectHandle));
-    }
-
     synchronized int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
             throws IOException {
         final MtpDevice device = getDevice(deviceId);
@@ -142,25 +139,20 @@
         }
     }
 
-    // TODO: Remove this method.
-    synchronized int createDocument(int deviceId, int storageId, int parentObjectHandle,
-            String mimeType, String name) throws IOException {
-        final MtpObjectInfo objectInfo = new MtpObjectInfo.Builder()
-                .setName(name)
-                .setStorageId(storageId)
-                .setParent(parentObjectHandle)
-                .setFormat(MtpDocument.mimeTypeToFormatType(mimeType))
-                .build();
-        return createDocument(deviceId, objectInfo);
-    }
-
-    synchronized int createDocument(int deviceId, MtpObjectInfo objectInfo) throws IOException {
+    synchronized int createDocument(int deviceId, MtpObjectInfo objectInfo,
+            ParcelFileDescriptor source) throws IOException {
         final MtpDevice device = getDevice(deviceId);
-        final MtpObjectInfo result = device.sendObjectInfo(objectInfo);
-        if (result == null) {
+        final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo);
+        if (sendObjectInfoResult == null) {
             throw new IOException("Failed to create a document");
         }
-        return result.getObjectHandle();
+        if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) {
+            if (!device.sendObject(sendObjectInfoResult.getObjectHandle(),
+                    sendObjectInfoResult.getCompressedSize(), source)) {
+                throw new IOException("Failed to send contents of a document");
+            }
+        }
+        return sendObjectInfoResult.getObjectHandle();
     }
 
     synchronized int getParent(int deviceId, int objectHandle) throws IOException {
@@ -178,13 +170,6 @@
         device.importFile(objectHandle, target);
     }
 
-    synchronized void sendObject(int deviceId, int objectHandle, int size,
-            ParcelFileDescriptor source) throws IOException {
-        final MtpDevice device = getDevice(deviceId);
-        if (!device.sendObject(objectHandle, size, source))
-            throw new IOException("Failed to send a document");
-    }
-
     private MtpDevice getDevice(int deviceId) throws IOException {
         final MtpDevice device = mDevices.get(deviceId);
         if (device == null) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
index 53f1b65..cd38f1e 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
@@ -139,20 +139,15 @@
                 // Delete the target object info if it already exists (as a placeholder).
                 mManager.deleteDocument(mIdentifier.mDeviceId, mIdentifier.mObjectHandle);
 
-                // Create the target object info with a correct file size.
-                final int targetObjectHandle =
-                        mManager.createDocument(
-                                mIdentifier.mDeviceId,
-                                new MtpObjectInfo.Builder(placeholderObjectInfo)
-                                        .setCompressedSize((int) tempFile.length())
-                                        .build());
-
-                // Upload the object.
+                // Create the target object info with a correct file size and upload the file.
+                final MtpObjectInfo targetObjectInfo =
+                        new MtpObjectInfo.Builder(placeholderObjectInfo)
+                                .setCompressedSize((int) tempFile.length())
+                                .build();
                 final ParcelFileDescriptor tempInputDescriptor = ParcelFileDescriptor.open(
                         tempFile, ParcelFileDescriptor.MODE_READ_ONLY);
-                mManager.sendObject(mIdentifier.mDeviceId,
-                        targetObjectHandle, (int) tempFile.length(), tempInputDescriptor);
-
+                mManager.createDocument(mIdentifier.mDeviceId,
+                        targetObjectInfo, tempInputDescriptor);
             } catch (IOException error) {
                 Log.w(MtpDocumentsProvider.TAG,
                         "Failed to send a file because of: " + error.getMessage());
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index 1e015bd..a012d7f 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.database.Cursor;
+import android.mtp.MtpObjectInfo;
 import android.net.Uri;
 import android.provider.DocumentsContract;
 import android.test.AndroidTestCase;
@@ -31,14 +32,14 @@
 
 @SmallTest
 public class DocumentLoaderTest extends AndroidTestCase {
-    private BlockableTestMtpMaanger mManager;
+    private BlockableTestMtpManager mManager;
     private TestContentResolver mResolver;
     private DocumentLoader mLoader;
     final private Identifier mParentIdentifier = new Identifier(0, 0, 0);
 
     @Override
     public void setUp() {
-        mManager = new BlockableTestMtpMaanger(getContext());
+        mManager = new BlockableTestMtpManager(getContext());
         mResolver = new TestContentResolver();
         mLoader = new DocumentLoader(mManager, mResolver);
     }
@@ -85,22 +86,17 @@
         for (int i = 0; i < childDocuments.length; i++) {
             final int objectHandle = i + 1;
             childDocuments[i] = objectHandle;
-            manager.setDocument(0, objectHandle, new MtpDocument(
-                    objectHandle,
-                    0 /* format */,
-                    "file" + objectHandle,
-                    new Date(),
-                    1024,
-                    0 /* thumbnail size */,
-                    false /* not read only */));
+            manager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                    .setObjectHandle(objectHandle)
+                    .build());
         }
         manager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, childDocuments);
     }
 
-    private static class BlockableTestMtpMaanger extends TestMtpManager {
+    private static class BlockableTestMtpManager extends TestMtpManager {
         final private Map<String, CountDownLatch> blockedDocuments = new HashMap<>();
 
-        BlockableTestMtpMaanger(Context context) {
+        BlockableTestMtpManager(Context context) {
             super(context);
         }
 
@@ -113,7 +109,7 @@
         }
 
         @Override
-        MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
+        MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
             final CountDownLatch latch = blockedDocuments.get(pack(deviceId, objectHandle));
             if (latch != null) {
                 try {
@@ -122,7 +118,7 @@
                     fail();
                 }
             }
-            return super.getDocument(deviceId, objectHandle);
+            return super.getObjectInfo(deviceId, objectHandle);
         }
     }
 }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 1826bd0..cbb72d1 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -17,9 +17,12 @@
 package com.android.mtp;
 
 import android.database.Cursor;
+import android.mtp.MtpConstants;
+import android.mtp.MtpObjectInfo.Builder;
+import android.mtp.MtpObjectInfo;
 import android.net.Uri;
-import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -204,14 +207,14 @@
     }
 
     public void testQueryDocument() throws IOException {
-        mMtpManager.setDocument(0, 2, new MtpDocument(
-                2 /* object handle */,
-                0x3801 /* JPEG */,
-                "image.jpg" /* display name */,
-                new Date(1422716400000L) /* modified date */,
-                1024 * 1024 * 5 /* file size */,
-                1024 * 50 /* thumbnail size */,
-                false /* read only */));
+        mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                .setObjectHandle(2)
+                .setFormat(0x3801)
+                .setName("image.jpg")
+                .setDateModified(1422716400000L)
+                .setCompressedSize(1024 * 1024 * 5)
+                .setThumbCompressedSize(1024 * 50)
+                .build());
         final Cursor cursor = mProvider.queryDocument("0_1_2", null);
         assertEquals(1, cursor.getCount());
 
@@ -229,14 +232,12 @@
     }
 
     public void testQueryDocument_directory() throws IOException {
-        mMtpManager.setDocument(0, 2, new MtpDocument(
-                2 /* object handle */,
-                0x3001 /* directory */,
-                "directory" /* display name */,
-                new Date(1422716400000L) /* modified date */,
-                0 /* file size */,
-                0 /* thumbnail size */,
-                false /* read only */));
+        mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                .setObjectHandle(2)
+                .setFormat(0x3001 /* directory format */)
+                .setName("directory")
+                .setDateModified(1422716400000L)
+                .build());
         final Cursor cursor = mProvider.queryDocument("0_1_2", null);
         assertEquals(1, cursor.getCount());
 
@@ -278,14 +279,14 @@
     public void testQueryChildDocuments() throws Exception {
         mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
 
-        mMtpManager.setDocument(0, 1, new MtpDocument(
-                1 /* object handle */,
-                0x3801 /* JPEG */,
-                "image.jpg" /* display name */,
-                new Date(0) /* modified date */,
-                1024 * 1024 * 5 /* file size */,
-                1024 * 50 /* thumbnail size */,
-                true /* read only */));
+        mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                .setObjectHandle(1)
+                .setFormat(0x3801 /* JPEG */)
+                .setName("image.jpg")
+                .setCompressedSize(1024 * 1024 * 5)
+                .setThumbCompressedSize(5 * 1024)
+                .setProtectionStatus(MtpConstants.PROTECTION_STATUS_READ_ONLY)
+                .build());
 
         final Cursor cursor = mProvider.queryChildDocuments("0_0_0", null, null);
         assertEquals(1, cursor.getCount());
@@ -321,15 +322,10 @@
     }
 
     public void testDeleteDocument() throws FileNotFoundException {
-        mMtpManager.setDocument(0, 1, new MtpDocument(
-                1 /* object handle */,
-                0x3801 /* JPEG */,
-                "image.jpg" /* display name */,
-                new Date(1422716400000L) /* modified date */,
-                1024 * 1024 * 5 /* file size */,
-                1024 * 50 /* thumbnail size */,
-                false /* not read only */));
-        mMtpManager.setParent(0, 1, 2);
+        mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                .setObjectHandle(1)
+                .setParent(2)
+                .build());
         mProvider.deleteDocument("0_0_1");
         assertEquals(1, mResolver.getChangeCount(
                 DocumentsContract.buildChildDocumentsUri(
@@ -337,7 +333,9 @@
     }
 
     public void testDeleteDocument_error() {
-        mMtpManager.setParent(0, 1, 2);
+        mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                .setObjectHandle(2)
+                .build());
         try {
             mProvider.deleteDocument("0_0_1");
             fail();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
index cfb8b04..53018cc 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.mtp;
 
+import android.mtp.MtpObjectInfo;
 import android.os.ParcelFileDescriptor;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -56,7 +57,9 @@
 
     public void testWriteDocument_basic() throws Exception {
         // Create a placeholder file which should be replaced by a real file later.
-        mtpManager.setDocument(0, 1, new MtpDocument(1, 0, "", new Date(), 0, 0, false));
+        mtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                .setObjectHandle(1)
+                .build());
 
         // Upload testing bytes.
         final ParcelFileDescriptor descriptor = mPipeManager.writeDocument(
@@ -69,14 +72,14 @@
 
         // Check if the placeholder file is removed.
         try {
-            final MtpDocument placeholderDocument = mtpManager.getDocument(0, 1);
+            final MtpObjectInfo placeholderDocument = mtpManager.getObjectInfo(0, 1);
             fail();  // The placeholder file has not been deleted.
         } catch (IOException e) {
             // Expected error, as the file is gone.
         }
 
         // Confirm that the target file is created.
-        final MtpDocument targetDocument = mtpManager.getDocument(
+        final MtpObjectInfo targetDocument = mtpManager.getObjectInfo(
                 0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
         assertTrue(targetDocument != null);
 
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index 94b5ba0..5605388 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -40,10 +40,9 @@
     private final Set<Integer> mValidDevices = new HashSet<>();
     private final Set<Integer> mOpenedDevices = new TreeSet<>();
     private final Map<Integer, MtpRoot[]> mRoots = new HashMap<>();
-    private final Map<String, MtpDocument> mDocuments = new HashMap<>();
+    private final Map<String, MtpObjectInfo> mObjectInfos = new HashMap<>();
     private final Map<String, int[]> mObjectHandles = new HashMap<>();
     private final Map<String, byte[]> mThumbnailBytes = new HashMap<>();
-    private final Map<String, Integer> mParents = new HashMap<>();
     private final Map<String, byte[]> mImportFileBytes = new HashMap<>();
 
     TestMtpManager(Context context) {
@@ -54,16 +53,16 @@
         mValidDevices.add(deviceId);
     }
 
-    void setObjectHandles(int deviceId, int storageId, int objectHandle, int[] documents) {
-        mObjectHandles.put(pack(deviceId, storageId, objectHandle), documents);
+    void setObjectHandles(int deviceId, int storageId, int parentHandle, int[] objectHandles) {
+        mObjectHandles.put(pack(deviceId, storageId, parentHandle), objectHandles);
     }
 
     void setRoots(int deviceId, MtpRoot[] roots) {
         mRoots.put(deviceId, roots);
     }
 
-    void setDocument(int deviceId, int objectHandle, MtpDocument document) {
-        mDocuments.put(pack(deviceId, objectHandle), document);
+    void setObjectInfo(int deviceId, MtpObjectInfo objectInfo) {
+        mObjectInfos.put(pack(deviceId, objectInfo.getObjectHandle()), objectInfo);
     }
 
     void setImportFileBytes(int deviceId, int objectHandle, byte[] bytes) {
@@ -78,10 +77,6 @@
         mThumbnailBytes.put(pack(deviceId, objectHandle), bytes);
     }
 
-    void setParent(int deviceId, int objectHandle, int parentObjectHandle) {
-        mParents.put(pack(deviceId, objectHandle), parentObjectHandle);
-    }
-
     @Override
     void openDevice(int deviceId) throws IOException {
         if (!mValidDevices.contains(deviceId) || mOpenedDevices.contains(deviceId)) {
@@ -108,22 +103,13 @@
     }
 
     @Override
-    MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
-        final String key = pack(deviceId, objectHandle);
-        if (mDocuments.containsKey(key)) {
-            return mDocuments.get(key);
-        } else {
-            throw new IOException("getDocument error: " + key);
-        }
-    }
-
-    @Override
     MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
-        final MtpDocument document = getDocument(deviceId, objectHandle);
-        // It's impossible to set an object id of MtpObjectInfo at this stage. Also,
-        // it's hard to get any information from MtpDocument, as it's designed to return them
-        // only via cursors. Rework these.
-        return new MtpObjectInfo.Builder().build();
+        final String key = pack(deviceId, objectHandle);
+        if (mObjectInfos.containsKey(key)) {
+            return mObjectInfos.get(key);
+        } else {
+            throw new IOException("getObjectInfo error: " + key);
+        }
     }
 
     @Override
@@ -151,44 +137,29 @@
     }
 
     @Override
-    int createDocument(int deviceId, MtpObjectInfo objectInfo) throws IOException {
-        // For simplicity, it allows to create only one document, and it always has the hardcoded
-        // CREATED_DOCUMENT_HANDLE document handle.
+    int createDocument(int deviceId, MtpObjectInfo objectInfo, ParcelFileDescriptor source)
+            throws IOException {
         final String key = pack(deviceId, CREATED_DOCUMENT_HANDLE);
-        if (!mDocuments.containsKey(key)) {
-            mDocuments.put(key, new MtpDocument(
-                  CREATED_DOCUMENT_HANDLE,
-                  objectInfo.getFormat(),
-                  objectInfo.getName(),
-                  new Date(objectInfo.getDateModified()),
-                  objectInfo.getCompressedSize(),
-                  objectInfo.getThumbCompressedSize(),
-                  false /* Always writable for testing. */));
-        } else {
+        if (mObjectInfos.containsKey(key)) {
             throw new IOException();
         }
+        mObjectInfos.put(key, objectInfo);
+        if (objectInfo.getFormat() != 0x3001) {
+            try (final ParcelFileDescriptor.AutoCloseInputStream inputStream =
+                    new ParcelFileDescriptor.AutoCloseInputStream(source)) {
+                final byte[] buffer = new byte[objectInfo.getCompressedSize()];
+                if (inputStream.read(buffer, 0, objectInfo.getCompressedSize()) !=
+                        objectInfo.getCompressedSize()) {
+                    throw new IOException();
+                }
+
+                mImportFileBytes.put(pack(deviceId, CREATED_DOCUMENT_HANDLE), buffer);
+            }
+        }
         return CREATED_DOCUMENT_HANDLE;
     }
 
     @Override
-    void sendObject(int deviceId, int objectHandle, int size, ParcelFileDescriptor source)
-            throws IOException {
-        final String key = pack(deviceId, objectHandle);
-        if (!mDocuments.containsKey(key)) {
-            throw new IOException();
-        }
-
-        ParcelFileDescriptor.AutoCloseInputStream inputStream =
-                new ParcelFileDescriptor.AutoCloseInputStream(source);
-        byte[] buffer = new byte[size];
-        if (inputStream.read(buffer, 0, size) != size) {
-            throw new IOException();
-        }
-
-        mImportFileBytes.put(pack(deviceId, objectHandle), buffer);
-    }
-
-    @Override
     byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
         final String key = pack(deviceId, objectHandle);
         if (mThumbnailBytes.containsKey(key)) {
@@ -201,18 +172,18 @@
     @Override
     void deleteDocument(int deviceId, int objectHandle) throws IOException {
         final String key = pack(deviceId, objectHandle);
-        if (mDocuments.containsKey(key)) {
-            mDocuments.remove(key);
+        if (mObjectInfos.containsKey(key)) {
+            mObjectInfos.remove(key);
         } else {
             throw new IOException();
         }
     }
 
     @Override
-    synchronized int getParent(int deviceId, int objectHandle) throws IOException {
+    int getParent(int deviceId, int objectHandle) throws IOException {
         final String key = pack(deviceId, objectHandle);
-        if (mParents.containsKey(key)) {
-            return mParents.get(key);
+        if (mObjectInfos.containsKey(key)) {
+            return mObjectInfos.get(key).getParent();
         } else {
             throw new IOException();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index d30411a..f4439bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -262,14 +262,21 @@
         return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
     }
 
+    /**
+     * Resolves the intent to launch the camera application.
+     */
+    public ResolveInfo resolveCameraIntent() {
+        return mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
+                PackageManager.MATCH_DEFAULT_ONLY,
+                KeyguardUpdateMonitor.getCurrentUser());
+    }
+
     private void updateCameraVisibility() {
         if (mCameraImageView == null) {
             // Things are not set up yet; reply hazy, ask again later
             return;
         }
-        ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
-                PackageManager.MATCH_DEFAULT_ONLY,
-                KeyguardUpdateMonitor.getCurrentUser());
+        ResolveInfo resolved = resolveCameraIntent();
         boolean visible = !isCameraDisabledByDpm() && resolved != null
                 && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance)
                 && mUserSetupComplete;
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 93ecb06..d0a7f8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -166,10 +166,13 @@
         if (mAccessibilityController == null) {
             return;
         }
+        boolean trustManagedOrFingerprintAllowed = mUnlockMethodCache.isTrustManaged()
+                || KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed();
+
         boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
-        boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
+        boolean clickToForceLock = trustManagedOrFingerprintAllowed
                 && !mAccessibilityController.isAccessibilityEnabled();
-        boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
+        boolean longClickToForceLock = trustManagedOrFingerprintAllowed
                 && !clickToForceLock;
         setClickable(clickToForceLock || clickToUnlock);
         setLongClickable(longClickToForceLock);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 3ad7246..814a65e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -21,7 +21,10 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.content.Context;
+import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -62,6 +65,8 @@
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
+import java.util.List;
+
 public class NotificationPanelView extends PanelView implements
         ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
         View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
@@ -2462,7 +2467,28 @@
         getCenterIcon().setLaunchingAffordance(launchingAffordance);
     }
 
-    public boolean canCameraGestureBeLaunched() {
-        return !mAfforanceHelper.isSwipingInProgress();
+    /**
+     * Whether the camera application can be launched for the camera launch gesture.
+     *
+     * @param keyguardIsShowing whether keyguard is being shown
+     */
+    public boolean canCameraGestureBeLaunched(boolean keyguardIsShowing) {
+        ResolveInfo resolveInfo = mKeyguardBottomArea.resolveCameraIntent();
+        String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null)
+                ? null : resolveInfo.activityInfo.packageName;
+        return packageToLaunch != null &&
+               (keyguardIsShowing || !isForegroundApp(packageToLaunch)) &&
+               !mAfforanceHelper.isSwipingInProgress();
+    }
+
+    /**
+     * Return true if the applications with the package name is running in foreground.
+     *
+     * @param pkgName application package name.
+     */
+    private boolean isForegroundApp(String pkgName) {
+        ActivityManager am = getContext().getSystemService(ActivityManager.class);
+        List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
+        return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
     }
 }
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 7b04da0..ab1b597 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -4150,7 +4150,8 @@
 
     @Override
     public void onCameraLaunchGestureDetected() {
-        if (!mNotificationPanel.canCameraGestureBeLaunched()) {
+        if (!mNotificationPanel.canCameraGestureBeLaunched(
+                mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
             return;
         }
         if (!mDeviceInteractive) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 95a8d39..6475cbf 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -421,8 +421,9 @@
                         }
                     }
                 } else {
-                    final boolean vmute = row.ss.level == 0;
-                    mController.setStreamVolume(stream, vmute ? row.lastAudibleLevel : 0);
+                    final boolean vmute = row.ss.level == row.ss.levelMin;
+                    mController.setStreamVolume(stream,
+                            vmute ? row.lastAudibleLevel : row.ss.levelMin);
                 }
                 row.userAttempt = 0;  // reset the grace period, slider should update immediately
             }
@@ -1024,6 +1025,7 @@
                 final int minProgress = mRow.ss.levelMin * 100;
                 if (progress < minProgress) {
                     seekBar.setProgress(minProgress);
+                    progress = minProgress;
                 }
             }
             final int userLevel = getImpliedLevel(seekBar, progress);
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 4288fa2..882899e 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -177,7 +177,7 @@
 
         private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
         private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
-        private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = 60*1000;
+        private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY;
         private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 15*60*1000;
         private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4aef23b..c0ffb56 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17411,8 +17411,10 @@
         }
 
         // Can't call out of the system process with a lock held, so post a message.
-        mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
-                app.instrumentationUiAutomationConnection).sendToTarget();
+        if (app.instrumentationUiAutomationConnection != null) {
+            mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
+                    app.instrumentationUiAutomationConnection).sendToTarget();
+        }
 
         app.instrumentationWatcher = null;
         app.instrumentationUiAutomationConnection = null;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index f50df3a..37ddd4d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3975,8 +3975,7 @@
      * for whatever reason.  Ensures the HistoryRecord is updated with the
      * correct configuration and all other bookkeeping is handled.
      */
-    final boolean ensureActivityConfigurationLocked(ActivityRecord r,
-            int globalChanges) {
+    final boolean ensureActivityConfigurationLocked(ActivityRecord r, int globalChanges) {
         if (mConfigWillChange) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                     "Skipping config check (will change): " + r);
@@ -4589,25 +4588,19 @@
 
     void addConfigOverride(ActivityRecord r, TaskRecord task) {
         final Rect bounds = task.getLaunchBounds();
-        final Configuration config =
-                mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
-                        r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                        (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
-                        r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
-                        bounds);
-        if (config != null) {
-            task.updateOverrideConfiguration(config, bounds);
-        }
+        final Configuration config = task.updateOverrideConfiguration(mStackId, bounds);
+        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
+                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
+                (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
+                r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
+                bounds, config);
         r.taskConfigOverride = task.mOverrideConfig;
     }
 
     private void setAppTask(ActivityRecord r, TaskRecord task) {
         final Rect bounds = task.getLaunchBounds();
-        final Configuration config =
-                mWindowManager.setAppTask(r.appToken, task.taskId, task.getLaunchBounds());
-        if (config != null) {
-            task.updateOverrideConfiguration(config, bounds);
-        }
+        final Configuration config = task.updateOverrideConfiguration(mStackId, bounds);
+        mWindowManager.setAppTask(r.appToken, task.taskId, task.getLaunchBounds(), config);
         r.taskConfigOverride = task.mOverrideConfig;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c86056b..33e0ef8 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -97,7 +97,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
-import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -334,6 +333,9 @@
     // temp. rect used during resize calculation so we don't need to create a new object each time.
     private final Rect tempRect = new Rect();
 
+    private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
+    private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
+
     /**
      * Description of a request to start a new activity, which has been held
      * due to app switches being disabled.
@@ -2917,19 +2919,19 @@
         ActivityRecord r = stack.topRunningActivityLocked(null);
         final boolean resizeTasks = r != null && r.task.mResizeable;
 
-        final IntArray changedTaskIds = new IntArray(stack.numTasks());
-        final List<Configuration> newTaskConfigs = new ArrayList<>(stack.numTasks());
-        stack.mFullscreen = mWindowManager.resizeStack(
-                stackId, bounds, resizeTasks, changedTaskIds, newTaskConfigs);
-        for (int i = changedTaskIds.size() - 1; i >= 0; i--) {
-            final TaskRecord task = anyTaskForIdLocked(changedTaskIds.get(i), false);
-            if (task == null) {
-                Slog.wtf(TAG, "Task in WindowManager, but not in ActivityManager???");
-                continue;
+        mTmpBounds.clear();
+        mTmpConfigs.clear();
+        if (resizeTasks) {
+            ArrayList<TaskRecord> tasks = stack.getAllTasks();
+            for (int i = tasks.size() - 1; i >= 0; i--) {
+                TaskRecord task = tasks.get(i);
+                task.updateOverrideConfiguration(stackId, bounds);
+                mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+                mTmpBounds.put(task.taskId, task.mBounds);
             }
-            task.updateOverrideConfiguration(newTaskConfigs.get(i), bounds);
         }
-
+        stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, resizeTasks, mTmpConfigs,
+                mTmpBounds);
         if (stack.mStackId == DOCKED_STACK_ID) {
             // Dock stack funness...Yay!
             if (stack.mFullscreen) {
@@ -3024,25 +3026,27 @@
             stackId = FREEFORM_WORKSPACE_STACK_ID;
         }
         if (stackId != task.stack.mStackId) {
-            final String reason = "resizeTask";
-            final ActivityStack stack =
-                    moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);
+            moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
         }
 
-        final Configuration overrideConfig = mWindowManager.resizeTask(task.taskId, bounds);
-        if (task.updateOverrideConfiguration(overrideConfig, bounds)) {
+        final Configuration overrideConfig =  task.updateOverrideConfiguration(stackId, bounds);
+        // This variable holds information whether the configuration didn't change in a signficant
+        // way and the activity was kept the way it was. If it's false, it means the activity had
+        // to be relaunched due to configuration change.
+        boolean kept = true;
+        if (overrideConfig != null) {
             ActivityRecord r = task.topRunningActivityLocked(null);
             if (r != null) {
                 final ActivityStack stack = task.stack;
-                final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
-                // And we need to make sure at this point that all other activities
-                // are made visible with the correct configuration.
+                kept = stack.ensureActivityConfigurationLocked(r, 0);
+                // All other activities must be made visible with their correct configuration.
                 ensureActivitiesVisibleLocked(r, 0);
-                if (!updated) {
+                if (!kept) {
                     resumeTopActivitiesLocked(stack, null, null);
                 }
             }
         }
+        mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept);
     }
 
     ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
index 5c4fd13..735c06f 100644
--- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
+++ b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
@@ -234,7 +235,7 @@
                 break;
             }
         }
-        task.setInitialBounds(proposal);
+        task.updateOverrideConfiguration(FREEFORM_WORKSPACE_STACK_ID, proposal);
     }
 
     private boolean shiftedToFar(Rect start, int shiftPolicy) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9cbaec5..12c7b86 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.HOME_STACK_ID;
+import static android.app.ActivityManager.INVALID_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
@@ -52,6 +53,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
+import android.util.DisplayMetrics;
 import android.util.Slog;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.util.XmlUtils;
@@ -63,6 +65,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Objects;
 
 final class TaskRecord {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
@@ -106,6 +109,13 @@
 
     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.
@@ -218,6 +228,8 @@
 
     Configuration mOverrideConfig = Configuration.EMPTY;
 
+    private Rect mTmpRect = new Rect();
+
     TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
             IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
         mService = service;
@@ -271,8 +283,7 @@
             long _firstActiveTime, long _lastActiveTime, long lastTimeMoved,
             boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
             int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
-            int callingUid, String callingPackage, boolean resizeable, boolean privileged,
-            Rect bounds) {
+            int callingUid, String callingPackage, boolean resizeable, boolean privileged) {
         mService = service;
         mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                 TaskPersister.IMAGE_EXTENSION;
@@ -309,7 +320,6 @@
         mCallingPackage = callingPackage;
         mResizeable = resizeable;
         mPrivileged = privileged;
-        mBounds = mLastNonFullscreenBounds = bounds;
     }
 
     void touchActiveTime() {
@@ -1163,7 +1173,8 @@
                 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
                 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
                 taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
-                callingUid, callingPackage, resizeable, privileged, bounds);
+                callingUid, callingPackage, resizeable, privileged);
+        task.updateOverrideConfiguration(INVALID_STACK_ID, bounds);
 
         for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
             activities.get(activityNdx).task = task;
@@ -1173,25 +1184,51 @@
         return task;
     }
 
-    boolean updateOverrideConfiguration(Configuration newConfig, Rect bounds) {
+    /**
+     * Update task's override configuration based on the bounds.
+     * @return Update configuration or null if there is no change.
+     */
+    Configuration updateOverrideConfiguration(int stackId, Rect bounds) {
+        if (stackId == 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.
+            bounds = fitWithinBounds(bounds);
+        }
+        if (Objects.equals(mBounds, bounds)) {
+            return null;
+        }
         Configuration oldConfig = mOverrideConfig;
-        mOverrideConfig = (newConfig == null) ? Configuration.EMPTY : newConfig;
-        // We override the configuration only when the task's dimensions are different from the
-        // display. In this manner, we know that if the override configuration is empty, the task
-        // is necessarily fullscreen.
-        mFullscreen = Configuration.EMPTY.equals(mOverrideConfig);
+
+        mFullscreen = bounds == null;
         if (mFullscreen) {
             if (mBounds != null && stack.mStackId != DOCKED_STACK_ID) {
                 mLastNonFullscreenBounds = mBounds;
             }
             mBounds = null;
+            mOverrideConfig = Configuration.EMPTY;
         } else {
             mBounds = new Rect(bounds);
             if (stack.mStackId != DOCKED_STACK_ID) {
                 mLastNonFullscreenBounds = mBounds;
             }
+
+            final Configuration serviceConfig = mService.mConfiguration;
+            mOverrideConfig = new Configuration(serviceConfig);
+            // TODO(multidisplay): Update Dp to that of display stack is on.
+            final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+            mOverrideConfig.screenWidthDp =
+                    Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
+            mOverrideConfig.screenHeightDp =
+                    Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
+            mOverrideConfig.smallestScreenWidthDp =
+                    Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
+            mOverrideConfig.orientation =
+                    (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
+                            ? Configuration.ORIENTATION_PORTRAIT
+                            : Configuration.ORIENTATION_LANDSCAPE;
         }
-        return !mOverrideConfig.equals(oldConfig);
+        return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
     }
 
     /** Returns the stack that should be used to launch this task. */
@@ -1225,12 +1262,39 @@
         return mLastNonFullscreenBounds;
     }
 
-    void setInitialBounds(Rect rect) {
-        if (mBounds == null) {
-            mBounds = new Rect();
+    /** Fits the tasks within the input bounds adjusting the task bounds as needed.
+     *  @param bounds Bounds to fit the task within. Nothing is done if null.
+     *  @return Returns final configuration after updating with the adjusted bounds.
+     *  */
+    Rect fitWithinBounds(Rect bounds) {
+        if (bounds == null || mBounds == null || bounds.contains(mBounds)) {
+            return bounds;
         }
-        mBounds.set(rect);
-        mLastNonFullscreenBounds = mBounds;
+        mTmpRect.set(mBounds);
+
+        if (mBounds.left < bounds.left || mBounds.right > bounds.right) {
+            final int maxRight = bounds.right - (bounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
+            int horizontalDiff = bounds.left - mBounds.left;
+            if ((horizontalDiff < 0 && mBounds.left >= maxRight)
+                    || (mBounds.left + horizontalDiff >= maxRight)) {
+                horizontalDiff = maxRight - mBounds.left;
+            }
+            mTmpRect.left += horizontalDiff;
+            mTmpRect.right += horizontalDiff;
+        }
+
+        if (mBounds.top < bounds.top || mBounds.bottom > bounds.bottom) {
+            final int maxBottom = bounds.bottom - (bounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
+            int verticalDiff = bounds.top - mBounds.top;
+            if ((verticalDiff < 0 && mBounds.top >= maxBottom)
+                    || (mBounds.top + verticalDiff >= maxBottom)) {
+                verticalDiff = maxBottom - mBounds.top;
+            }
+            mTmpRect.top += verticalDiff;
+            mTmpRect.bottom += verticalDiff;
+        }
+
+        return mTmpRect;
     }
 
     void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 7e46db8..cbb3c39 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -24,7 +24,9 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
 import android.os.Binder;
+import android.os.DeadObjectException;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
@@ -51,7 +53,6 @@
 import android.hardware.fingerprint.IFingerprintDaemon;
 import android.hardware.fingerprint.IFingerprintDaemonCallback;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.view.Display;
 
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
 import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
@@ -60,6 +61,7 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -83,6 +85,8 @@
     private ClientMonitor mAuthClient = null;
     private ClientMonitor mEnrollClient = null;
     private ClientMonitor mRemoveClient = null;
+    private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
+            new ArrayList<>();
     private final AppOpsManager mAppOps;
 
     private static final long MS_PER_SEC = 1000;
@@ -259,6 +263,7 @@
         // 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);
+        notifyLockoutResetMonitors();
     }
 
     private boolean handleFailedAttempt(ClientMonitor clientMonitor) {
@@ -499,6 +504,23 @@
                 opPackageName) == AppOpsManager.MODE_ALLOWED;
     }
 
+    private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
+        if (!mLockoutMonitors.contains(monitor)) {
+            mLockoutMonitors.add(monitor);
+        }
+    }
+
+    private void removeLockoutResetCallback(
+            FingerprintServiceLockoutResetMonitor monitor) {
+        mLockoutMonitors.remove(monitor);
+    }
+
+    private void notifyLockoutResetMonitors() {
+        for (int i = 0; i < mLockoutMonitors.size(); i++) {
+            mLockoutMonitors.get(i).sendLockoutReset();
+        }
+    }
+
     private class ClientMonitor implements IBinder.DeathRecipient {
         IBinder token;
         IFingerprintServiceReceiver receiver;
@@ -614,7 +636,7 @@
                     FingerprintUtils.vibrateFingerprintSuccess(getContext());
                 }
                 result |= true; // we have a valid fingerprint
-                mLockoutReset.run();
+                mHandler.post(mLockoutReset);
             }
             return result;
         }
@@ -654,6 +676,36 @@
         }
     }
 
+    private class FingerprintServiceLockoutResetMonitor {
+
+        private final IFingerprintServiceLockoutResetCallback mCallback;
+
+        public FingerprintServiceLockoutResetMonitor(
+                IFingerprintServiceLockoutResetCallback callback) {
+            mCallback = callback;
+        }
+
+        public void sendLockoutReset() {
+            if (mCallback != null) {
+                try {
+                    mCallback.onLockoutReset(mHalDeviceId);
+                } catch (DeadObjectException e) {
+                    Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
+                    mHandler.post(mRemoveCallbackRunnable);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
+                }
+            }
+        }
+
+        private final Runnable mRemoveCallbackRunnable = new Runnable() {
+            @Override
+            public void run() {
+                removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
+            }
+        };
+    }
+
     private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() {
 
         @Override
@@ -922,7 +974,19 @@
         public void resetTimeout(byte [] token) {
             checkPermission(RESET_FINGERPRINT_LOCKOUT);
             // TODO: confirm security token when we move timeout management into the HAL layer.
-            mLockoutReset.run();
+            mHandler.post(mLockoutReset);
+        }
+
+        @Override
+        public void addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback)
+                throws RemoteException {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    addLockoutResetMonitor(
+                            new FingerprintServiceLockoutResetMonitor(callback));
+                }
+            });
         }
     }
 
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 0a12d5a..cbe61c3 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -46,7 +46,6 @@
 import android.service.notification.ZenModeConfig.EventInfo;
 import android.service.notification.ZenModeConfig.ScheduleInfo;
 import android.service.notification.ZenModeConfig.ZenRule;
-import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
 
@@ -149,6 +148,7 @@
             mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
         }
         mHandler.postMetricsTimer();
+        evaluateZenMode("onSystemReady", true);
     }
 
     public void onUserSwitched(int user) {
@@ -330,13 +330,14 @@
         }
         mConditions.evaluateConfig(config, false /*processSubscriptions*/);  // may modify config
         mConfigs.put(config.user, config);
-        if (config.equals(mConfig)) return true;
         if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
         ZenLog.traceConfig(reason, mConfig, config);
         final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
                 getNotificationPolicy(config));
         mConfig = config;
-        dispatchOnConfigChanged();
+        if (config.equals(mConfig)) {
+            dispatchOnConfigChanged();
+        }
         if (policyChanged){
             dispatchOnPolicyChanged();
         }
@@ -370,9 +371,7 @@
 
     private boolean evaluateZenMode(String reason, boolean setRingerMode) {
         if (DEBUG) Log.d(TAG, "evaluateZenMode");
-        final ArraySet<ZenRule> automaticRules = new ArraySet<ZenRule>();
-        final int zen = computeZenMode(automaticRules);
-        if (zen == mZenMode) return false;
+        final int zen = computeZenMode();
         ZenLog.traceSetZenMode(zen, reason);
         mZenMode = zen;
         updateRingerModeAffectedStreams();
@@ -381,7 +380,9 @@
             applyZenToRingerMode();
         }
         applyRestrictions();
-        mHandler.postDispatchOnZenModeChanged();
+        if (zen != mZenMode) {
+            mHandler.postDispatchOnZenModeChanged();
+        }
         return true;
     }
 
@@ -391,7 +392,7 @@
         }
     }
 
-    private int computeZenMode(ArraySet<ZenRule> automaticRulesOut) {
+    private int computeZenMode() {
         if (mConfig == null) return Global.ZEN_MODE_OFF;
         if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
         int zen = Global.ZEN_MODE_OFF;
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index c75a1d3..66170d4 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -136,9 +136,6 @@
                     case "signer":
                         policies.add(readSignerOrThrow(parser));
                         break;
-                    case "default":
-                        policies.add(readDefaultOrThrow(parser));
-                        break;
                     default:
                         skip(parser);
                 }
@@ -233,45 +230,6 @@
     }
 
     /**
-     * Loop over a default element looking for seinfo child tags. A {@link Policy}
-     * instance will be created and returned in the process. All other tags encountered
-     * will be skipped.
-     *
-     * @param parser an XmlPullParser object representing a default element.
-     * @return the constructed {@link Policy} instance
-     * @throws IOException
-     * @throws XmlPullParserException
-     * @throws IllegalArgumentException if any of the validation checks fail while
-     *         parsing tag values.
-     * @throws IllegalStateException if any of the invariants fail when constructing
-     *         the {@link Policy} instance.
-     */
-    private static Policy readDefaultOrThrow(XmlPullParser parser) throws IOException,
-            XmlPullParserException {
-
-        parser.require(XmlPullParser.START_TAG, null, "default");
-        Policy.PolicyBuilder pb = new Policy.PolicyBuilder();
-        pb.setAsDefaultPolicy();
-
-        while (parser.next() != XmlPullParser.END_TAG) {
-            if (parser.getEventType() != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if ("seinfo".equals(tagName)) {
-                String seinfo = parser.getAttributeValue(null, "value");
-                pb.setGlobalSeinfoOrThrow(seinfo);
-                readSeinfo(parser);
-            } else {
-                skip(parser);
-            }
-        }
-
-        return pb.build();
-    }
-
-    /**
      * Loop over a package element looking for seinfo child tags. If found return the
      * value attribute of the seinfo tag, otherwise return null. All other tags encountered
      * will be skipped.
@@ -337,35 +295,28 @@
 
     /**
      * Applies a security label to a package based on an seinfo tag taken from a matched
-     * policy. All signature based policy stanzas are consulted first and, if no match
-     * is found, the default policy stanza is then consulted. The security label is
-     * attached to the ApplicationInfo instance of the package in the event that a matching
-     * policy was found.
+     * policy. All signature based policy stanzas are consulted and, if no match is
+     * found, the default seinfo label of 'default' (set in ApplicationInfo object) is
+     * used. The security label is attached to the ApplicationInfo instance of the package
+     * in the event that a matching policy was found.
      *
      * @param pkg object representing the package to be labeled.
-     * @return boolean which determines whether a non null seinfo label was assigned
-     *         to the package. A null value simply represents that no policy matched.
      */
-    public static boolean assignSeinfoValue(PackageParser.Package pkg) {
+    public static void assignSeinfoValue(PackageParser.Package pkg) {
         synchronized (sPolicies) {
             for (Policy policy : sPolicies) {
                 String seinfo = policy.getMatchedSeinfo(pkg);
                 if (seinfo != null) {
                     pkg.applicationInfo.seinfo = seinfo;
-                    if (DEBUG_POLICY_INSTALL) {
-                        Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
-                               "seinfo=" + seinfo);
-                    }
-                    return true;
+                    break;
                 }
             }
         }
 
         if (DEBUG_POLICY_INSTALL) {
-            Slog.i(TAG, "package (" + pkg.packageName + ") doesn't match any policy; " +
-                   "seinfo will remain null");
+            Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
+                    "seinfo=" + pkg.applicationInfo.seinfo);
         }
-        return false;
     }
 
     /**
@@ -506,30 +457,16 @@
  *         .build();
  * }
  * </pre>
- * <p>
- * The following is an example of how to use {@link Policy.PolicyBuilder} to create a
- * default based Policy instance.
- * </p>
- * <pre>
- * {@code
- * Policy policy = new Policy.PolicyBuilder()
- *         .setAsDefaultPolicy()
- *         .setGlobalSeinfoOrThrow("default")
- *         .build();
- * }
- * </pre>
  */
 final class Policy {
 
     private final String mSeinfo;
-    private final boolean mDefaultStanza;
     private final Set<Signature> mCerts;
     private final Map<String, String> mPkgMap;
 
     // Use the PolicyBuilder pattern to instantiate
     private Policy(PolicyBuilder builder) {
         mSeinfo = builder.mSeinfo;
-        mDefaultStanza = builder.mDefaultStanza;
         mCerts = Collections.unmodifiableSet(builder.mCerts);
         mPkgMap = Collections.unmodifiableMap(builder.mPkgMap);
     }
@@ -545,15 +482,6 @@
     }
 
     /**
-     * Return whether this policy object represents a default stanza.
-     *
-     * @return A boolean indicating if this object represents a default policy stanza.
-     */
-    public boolean isDefaultStanza() {
-        return mDefaultStanza;
-    }
-
-    /**
      * Return whether this policy object contains package name mapping refinements.
      *
      * @return A boolean indicating if this object has inner package name mappings.
@@ -584,10 +512,6 @@
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        if (mDefaultStanza) {
-            sb.append("defaultStanza=true ");
-        }
-
         for (Signature cert : mCerts) {
             sb.append("cert=" + cert.toCharsString().substring(0, 11) + "... ");
         }
@@ -609,22 +533,15 @@
      * is determined using the following steps:
      * </p>
      * <ul>
-     *   <li> If this Policy instance is defined as a default stanza:
-     *       <ul><li>Return the global seinfo value</li></ul>
+     *   <li> All certs used to sign the apk and all certs stored with this policy
+     *     instance are tested for set equality. If this fails then null is returned.
      *   </li>
-     *   <li> If this Policy instance is defined as a signer stanza:
-     *     <ul>
-     *       <li> All certs used to sign the apk and all certs stored with this policy
-     *         instance are tested for set equality. If this fails then null is returned.
-     *       </li>
-     *       <li> If all certs match then an appropriate inner package stanza is
-     *         searched based on package name alone. If matched, the stored seinfo
-     *         value for that mapping is returned.
-     *       </li>
-     *       <li> If all certs matched and no inner package stanza matches then return
-     *         the global seinfo value. The returned value can be null in this case.
-     *       </li>
-     *     </ul>
+     *   <li> If all certs match then an appropriate inner package stanza is
+     *     searched based on package name alone. If matched, the stored seinfo
+     *     value for that mapping is returned.
+     *   </li>
+     *   <li> If all certs matched and no inner package stanza matches then return
+     *     the global seinfo value. The returned value can be null in this case.
      *   </li>
      * </ul>
      * <p>
@@ -636,37 +553,34 @@
      *         A value of null can also be returned if no match occured.
      */
     public String getMatchedSeinfo(PackageParser.Package pkg) {
-        if (!mDefaultStanza) {
-            // Check for exact signature matches across all certs.
-            Signature[] certs = mCerts.toArray(new Signature[0]);
-            if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
-                return null;
-            }
-
-            // Check for inner package name matches given that the
-            // signature checks already passed.
-            String seinfoValue = mPkgMap.get(pkg.packageName);
-            if (seinfoValue != null) {
-                return seinfoValue;
-            }
+        // Check for exact signature matches across all certs.
+        Signature[] certs = mCerts.toArray(new Signature[0]);
+        if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
+            return null;
         }
 
-        // Return the global seinfo value (even if it's null).
+        // Check for inner package name matches given that the
+        // signature checks already passed.
+        String seinfoValue = mPkgMap.get(pkg.packageName);
+        if (seinfoValue != null) {
+            return seinfoValue;
+        }
+
+        // Return the global seinfo value.
         return mSeinfo;
     }
 
     /**
      * A nested builder class to create {@link Policy} instances. A {@link Policy}
      * class instance represents one valid policy stanza found in a mac_permissions.xml
-     * file. A valid policy stanza is defined to be either a signer or default stanza
-     * which obeys the rules outlined in external/sepolicy/mac_permissions.xml. The
-     * {@link #build} method ensures a set of invariants are upheld enforcing the correct
-     * stanza structure before returning a valid Policy object.
+     * file. A valid policy stanza is defined to be a signer stanza which obeys the rules
+     * outlined in external/sepolicy/mac_permissions.xml. The {@link #build} method
+     * ensures a set of invariants are upheld enforcing the correct stanza structure
+     * before returning a valid Policy object.
      */
     public static final class PolicyBuilder {
 
         private String mSeinfo;
-        private boolean mDefaultStanza;
         private final Set<Signature> mCerts;
         private final Map<String, String> mPkgMap;
 
@@ -676,19 +590,6 @@
         }
 
         /**
-         * Sets this stanza as a default stanza. All policy stanzas are assumed to
-         * be signer stanzas unless this method is explicitly called. Default stanzas
-         * are treated differently with respect to allowable child tags, ordering and
-         * when and how policy decisions are enforced.
-         *
-         * @return The reference to this PolicyBuilder.
-         */
-        public PolicyBuilder setAsDefaultPolicy() {
-            mDefaultStanza = true;
-            return this;
-        }
-
-        /**
          * Adds a signature to the set of certs used for validation checks. The purpose
          * being that all contained certs will need to be matched against all certs
          * contained with an apk.
@@ -710,11 +611,8 @@
 
         /**
          * Set the global seinfo tag for this policy stanza. The global seinfo tag
-         * represents the seinfo element that is used in one of two ways depending on
-         * its context. When attached to a signer tag the global seinfo represents an
-         * assignment when there isn't a further inner package refinement in policy.
-         * When used with a default tag, it represents the only allowable assignment
-         * value.
+         * when attached to a signer tag represents the assignment when there isn't a
+         * further inner package refinement in policy.
          *
          * @param seinfo the seinfo value given as a String.
          * @return The reference to this PolicyBuilder.
@@ -740,9 +638,7 @@
         /**
          * Create a package name to seinfo value mapping. Each mapping represents
          * the seinfo value that will be assigned to the described package name.
-         * These localized mappings allow the global seinfo to be overriden. This
-         * mapping provides no value when used in conjunction with a default stanza;
-         * enforced through the {@link #build} method.
+         * These localized mappings allow the global seinfo to be overriden.
          *
          * @param pkgName the android package name given to the app
          * @param seinfo the seinfo value that will be assigned to the passed pkgName
@@ -799,51 +695,25 @@
          * about the expected structure of a policy stanza.
          * Those invariants are:
          * </p>
-         *    <ul>
-         *      <li> If a default stanza
-         *        <ul>
-         *          <li> an attached global seinfo tag must be present </li>
-         *          <li> no signatures and no package names can be present </li>
-         *        </ul>
-         *      </li>
-         *      <li> If a signer stanza
-         *        <ul>
-         *           <li> at least one cert must be found </li>
-         *           <li> either a global seinfo value is present OR at least one
-         *           inner package mapping must be present BUT not both. </li>
-         *        </ul>
-         *      </li>
-         *    </ul>
-         *
+         * <ul>
+         *   <li> at least one cert must be found </li>
+         *   <li> either a global seinfo value is present OR at least one
+         *     inner package mapping must be present BUT not both. </li>
+         * </ul>
          * @return an instance of {@link Policy} with the options set from this builder
          * @throws IllegalStateException if an invariant is violated.
          */
         public Policy build() {
             Policy p = new Policy(this);
 
-            if (p.mDefaultStanza) {
-                if (p.mSeinfo == null) {
-                    String err = "Missing global seinfo tag with default stanza.";
-                    throw new IllegalStateException(err);
-                }
-                if (p.mCerts.size() != 0) {
-                    String err = "Certs not allowed with default stanza.";
-                    throw new IllegalStateException(err);
-                }
-                if (!p.mPkgMap.isEmpty()) {
-                    String err = "Inner package mappings not allowed with default stanza.";
-                    throw new IllegalStateException(err);
-                }
-            } else {
-                if (p.mCerts.size() == 0) {
-                    String err = "Missing certs with signer tag. Expecting at least one.";
-                    throw new IllegalStateException(err);
-                }
-                if (!(p.mSeinfo == null ^ p.mPkgMap.isEmpty())) {
-                    String err = "Only seinfo tag XOR package tags are allowed within " +
-                            "a signer stanza.";
-                    throw new IllegalStateException(err);
-                }
+            if (p.mCerts.isEmpty()) {
+                String err = "Missing certs with signer tag. Expecting at least one.";
+                throw new IllegalStateException(err);
+            }
+            if (!(p.mSeinfo == null ^ p.mPkgMap.isEmpty())) {
+                String err = "Only seinfo tag XOR package tags are allowed within " +
+                        "a signer stanza.";
+                throw new IllegalStateException(err);
             }
 
             return p;
@@ -858,7 +728,6 @@
  * <ul>
  *   <li> signer stanzas with inner package mappings </li>
  *   <li> signer stanzas with global seinfo tags </li>
- *   <li> default stanza </li>
  * </ul>
  * This comparison also checks for duplicate entries on the input selectors. Any
  * found duplicates will be flagged and can be checked with {@link #foundDuplicate}.
@@ -875,11 +744,6 @@
     @Override
     public int compare(Policy p1, Policy p2) {
 
-        // Give precedence to signature stanzas over default stanzas
-        if (p1.isDefaultStanza() != p2.isDefaultStanza()) {
-            return p1.isDefaultStanza() ? 1 : -1;
-        }
-
         // Give precedence to stanzas with inner package mappings
         if (p1.hasInnerPackages() != p2.hasInnerPackages()) {
             return p1.hasInnerPackages() ? -1 : 1;
@@ -887,7 +751,7 @@
 
         // Check for duplicate entries
         if (p1.getSignatures().equals(p2.getSignatures())) {
-            // Checks if default stanza or a signer w/o inner package names
+            // Checks if signer w/o inner package names
             if (p1.hasGlobalSeinfo()) {
                 duplicateFound = true;
                 Slog.e(SELinuxMMAC.TAG, "Duplicate policy entry: " + p1.toString());
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 9ddbcca..48e205f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4462,7 +4462,7 @@
                     if (mAppsToBeHidden.isEmpty()) {
                         if (dismissKeyguard && !mKeyguardSecure) {
                             mAppsThatDismissKeyguard.add(appToken);
-                        } else if (win.isDrawnLw()) {
+                        } else if (win.isDrawnLw() || win.hasAppShownWindows()) {
                             mWinShowWhenLocked = win;
                             mHideLockScreen = true;
                             mForceStatusBarFromKeyguard = false;
@@ -4496,7 +4496,8 @@
                         mWinDismissingKeyguard = win;
                         mSecureDismissingKeyguard = mKeyguardSecure;
                         mForceStatusBarFromKeyguard = mShowingLockscreen && mKeyguardSecure;
-                    } else if (mAppsToBeHidden.isEmpty() && showWhenLocked && win.isDrawnLw()) {
+                    } else if (mAppsToBeHidden.isEmpty() && showWhenLocked
+                            && (win.isDrawnLw() || win.hasAppShownWindows())) {
                         if (DEBUG_LAYOUT) Slog.v(TAG,
                                 "Setting mHideLockScreen to true by win " + win);
                         mHideLockScreen = true;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 554af28..666d902 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -23,7 +23,6 @@
 
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -41,13 +40,6 @@
      * when no window animation is driving it. */
     private static final int DEFAULT_DIM_DURATION = 200;
 
-    // The amount we divide the height/width of the bounds we are trying to fit the task within
-    // when using the 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;
-
     TaskStack mStack;
     final AppTokenList mAppTokens = new AppTokenList();
     final int mTaskId;
@@ -84,13 +76,13 @@
     // of creating a new object per fullscreen task on a display.
     private static final SparseArray<DimLayer> sSharedFullscreenDimLayers = new SparseArray<>();
 
-    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds) {
+    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
+            Configuration config) {
         mTaskId = taskId;
         mStack = stack;
         mUserId = userId;
         mService = service;
-        mOverrideConfig = Configuration.EMPTY;
-        setBounds(bounds);
+        setBounds(bounds, config);
     }
 
     DisplayContent getDisplayContent() {
@@ -172,43 +164,18 @@
         }
     }
 
-    /** Fits the tasks within the input bounds adjusting the task bounds as needed.
-     *  @param bounds Bounds to fit the task within. Nothing is done if null.
-     *  @return Returns true if the task bounds was adjusted in any way.
-     *  */
-    boolean fitWithinBounds(Rect bounds) {
-        if (bounds == null || bounds.contains(mBounds)) {
-            return false;
-        }
-        mTmpRect2.set(mBounds);
-
-        if (mBounds.left < bounds.left || mBounds.right > bounds.right) {
-            final int maxRight = bounds.right - (bounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
-            int horizontalDiff = bounds.left - mBounds.left;
-            if ((horizontalDiff < 0 && mBounds.left >= maxRight)
-                    || (mBounds.left + horizontalDiff >= maxRight)) {
-                horizontalDiff = maxRight - mBounds.left;
-            }
-            mTmpRect2.left += horizontalDiff;
-            mTmpRect2.right += horizontalDiff;
-        }
-
-        if (mBounds.top < bounds.top || mBounds.bottom > bounds.bottom) {
-            final int maxBottom = bounds.bottom - (bounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
-            int verticalDiff = bounds.top - mBounds.top;
-            if ((verticalDiff < 0 && mBounds.top >= maxBottom)
-                    || (mBounds.top + verticalDiff >= maxBottom)) {
-                verticalDiff = maxBottom - mBounds.top;
-            }
-            mTmpRect2.top += verticalDiff;
-            mTmpRect2.bottom += verticalDiff;
-        }
-
-        return setBounds(mTmpRect2);
-    }
-
     /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
-    boolean setBounds(Rect bounds) {
+    boolean setBounds(Rect bounds, Configuration config) {
+        if (config == null) {
+            config = Configuration.EMPTY;
+        }
+        if (bounds == null && !Configuration.EMPTY.equals(config)) {
+            throw new IllegalArgumentException("null bounds but non empty configuration: "
+                    + config);
+        }
+        if (bounds != null && Configuration.EMPTY.equals(config)) {
+            throw new IllegalArgumentException("non null bounds, but empty configuration");
+        }
         boolean oldFullscreen = mFullscreen;
         int rotation = Surface.ROTATION_0;
         final DisplayContent displayContent = mStack.getDisplayContent();
@@ -241,7 +208,7 @@
         mBounds.set(bounds);
         mRotation = rotation;
         updateDimLayer();
-        updateOverrideConfiguration();
+        mOverrideConfig = mFullscreen ? Configuration.EMPTY : config;
         return true;
     }
 
@@ -249,36 +216,12 @@
         out.set(mBounds);
     }
 
-    private void updateOverrideConfiguration() {
-        final Configuration serviceConfig = mService.mCurConfiguration;
-        if (mFullscreen) {
-            mOverrideConfig = Configuration.EMPTY;
-            return;
-        }
-
-        if (mOverrideConfig == Configuration.EMPTY) {
-            mOverrideConfig  = new Configuration();
-        }
-
-        // TODO(multidisplay): Update Dp to that of display stack is on.
-        final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
-        mOverrideConfig.screenWidthDp =
-                Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
-        mOverrideConfig.screenHeightDp =
-                Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
-        mOverrideConfig.smallestScreenWidthDp =
-                Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
-        mOverrideConfig.orientation =
-                (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
-                        ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
-    }
-
     void updateDisplayInfo(final DisplayContent displayContent) {
         if (displayContent == null) {
             return;
         }
         if (mFullscreen) {
-            setBounds(null);
+            setBounds(null, Configuration.EMPTY);
             return;
         }
         final int newRotation = displayContent.getDisplayInfo().rotation;
@@ -313,7 +256,7 @@
                 mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
                 break;
         }
-        setBounds(mTmpRect2);
+        setBounds(mTmpRect2, mOverrideConfig);
     }
 
     /** Updates the dim layer bounds, recreating it if needed. */
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 25a71d9..a7ef2f8 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -27,6 +27,7 @@
 import android.util.EventLog;
 import android.util.IntArray;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.DisplayInfo;
 
 import com.android.server.EventLogTags;
@@ -96,15 +97,15 @@
 
     /**
      * Set the bounds of the stack and its containing tasks.
-     * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
+     * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
      * @param resizeTasks If true, the tasks within the stack will also be resized.
-     * @param changedTaskIds Output list of Ids of tasks that changed in bounds.
-     * @param newTaskConfigs Output list of new Configuation of the tasks that changed.
+     * @param configs Configuration for individual tasks, keyed by task id.
+     * @param taskBounds Bounds for individual tasks, keyed by task id.
      * @return True if the stack bounds was changed.
      * */
-    boolean setBounds(Rect bounds, boolean resizeTasks, IntArray changedTaskIds,
-            List<Configuration> newTaskConfigs) {
-        if (!setBounds(bounds)) {
+    boolean setBounds(Rect stackBounds, boolean resizeTasks, SparseArray<Configuration> configs,
+            SparseArray<Rect> taskBounds) {
+        if (!setBounds(stackBounds)) {
             return false;
         }
 
@@ -113,20 +114,17 @@
         }
 
         // Update bounds of containing tasks.
-        final Rect newBounds = mFullscreen ? null : mBounds;
         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
             final Task task = mTasks.get(taskNdx);
-            if (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.
-                if (task.fitWithinBounds(newBounds)) {
-                    changedTaskIds.add(task.mTaskId);
-                    newTaskConfigs.add(task.mOverrideConfig);
+            Configuration config = configs.get(task.mTaskId);
+            if (config != null) {
+                Rect bounds = taskBounds.get(task.mTaskId);
+                if (bounds == null) {
+                    bounds = stackBounds;
                 }
-            } else if (task.setBounds(newBounds)) {
-                changedTaskIds.add(task.mTaskId);
-                newTaskConfigs.add(task.mOverrideConfig);
+                task.setBounds(bounds, config);
+            } else {
+                Slog.wtf(TAG, "No config for task: " + task + ", is there a mismatch with AM?");
             }
         }
         return true;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index cf690a5..bf7d1e7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3041,8 +3041,8 @@
         Binder.restoreCallingIdentity(origId);
     }
 
-    private Task createTaskLocked(
-            int taskId, int stackId, int userId, AppWindowToken atoken, Rect bounds) {
+    private Task createTaskLocked(int taskId, int stackId, int userId, AppWindowToken atoken,
+            Rect bounds, Configuration config) {
         if (DEBUG_STACK) Slog.i(TAG, "createTaskLocked: taskId=" + taskId + " stackId=" + stackId
                 + " atoken=" + atoken + " bounds=" + bounds);
         final TaskStack stack = mStackIdToStack.get(stackId);
@@ -3050,17 +3050,17 @@
             throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
         }
         EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
-        Task task = new Task(taskId, stack, userId, this, bounds);
+        Task task = new Task(taskId, stack, userId, this, bounds, config);
         mTaskIdToTask.put(taskId, task);
         stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */, atoken.showForAllUsers);
         return task;
     }
 
     @Override
-    public Configuration addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
+    public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            Rect taskBounds) {
+            Rect taskBounds, Configuration config) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3084,7 +3084,7 @@
             AppWindowToken atoken = findAppWindowToken(token.asBinder());
             if (atoken != null) {
                 Slog.w(TAG, "Attempted to add existing app token: " + token);
-                return null;
+                return;
             }
             atoken = new AppWindowToken(this, token, voiceInteraction);
             atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
@@ -3098,10 +3098,8 @@
                     + " to stack=" + stackId + " task=" + taskId + " at " + addPos);
 
             Task task = mTaskIdToTask.get(taskId);
-            Configuration outConfig = null;
             if (task == null) {
-                task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds);
-                outConfig = task.mOverrideConfig;
+                task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, config);
             }
             task.addAppToken(addPos, atoken);
 
@@ -3110,13 +3108,11 @@
             // Application tokens start out hidden.
             atoken.hidden = true;
             atoken.hiddenRequested = true;
-
-            return outConfig;
         }
     }
 
     @Override
-    public Configuration setAppTask(IBinder token, int taskId, Rect taskBounds) {
+    public void setAppTask(IBinder token, int taskId, Rect taskBounds, Configuration config) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setAppTask()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3126,20 +3122,18 @@
             final AppWindowToken atoken = findAppWindowToken(token);
             if (atoken == null) {
                 Slog.w(TAG, "Attempted to set task id of non-existing app token: " + token);
-                return null;
+                return;
             }
             final Task oldTask = atoken.mTask;
             oldTask.removeAppToken(atoken);
 
             Task newTask = mTaskIdToTask.get(taskId);
-            Configuration outConfig = null;
             if (newTask == null) {
                 newTask = createTaskLocked(
-                        taskId, oldTask.mStack.mStackId, oldTask.mUserId, atoken, taskBounds);
-                outConfig = newTask.mOverrideConfig;
+                        taskId, oldTask.mStack.mStackId, oldTask.mUserId, atoken, taskBounds,
+                        config);
             }
             newTask.addAppToken(Integer.MAX_VALUE /* at top */, atoken);
-            return outConfig;
         }
     }
 
@@ -4599,19 +4593,19 @@
      * @param stackId Id of stack to resize.
      * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
      * @param resizeTasks If true, the tasks within the stack will also be resized.
-     * @param changedTaskIds Output list of Ids of tasks that changed in bounds due to resize.
-     * @param newTaskConfigs Output list of new Configuation of the tasks that changed.
+     * @param configs Configurations for tasks in the resized stack, keyed by task id.
+     * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
      * @return True if the stack is now fullscreen.
      * */
     public boolean resizeStack(int stackId, Rect bounds, boolean resizeTasks,
-            IntArray changedTaskIds, List<Configuration> newTaskConfigs) {
+            SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
         synchronized (mWindowMap) {
             final TaskStack stack = mStackIdToStack.get(stackId);
             if (stack == null) {
                 throw new IllegalArgumentException("resizeStack: stackId " + stackId
                         + " not found.");
             }
-            if (stack.setBounds(bounds, resizeTasks, changedTaskIds, newTaskConfigs)) {
+            if (stack.setBounds(bounds, resizeTasks, configs, taskBounds)) {
                 stack.resizeWindows();
                 stack.getDisplayContent().layoutNeeded = true;
                 performLayoutAndPlaceSurfacesLocked();
@@ -4648,19 +4642,20 @@
      * Returns a {@link Configuration} object that contains configurations settings
      * that should be overridden due to the operation.
      */
-    public Configuration resizeTask(int taskId, Rect bounds) {
+    public void resizeTask(int taskId, Rect bounds, Configuration configuration, boolean relayout) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
             if (task == null) {
                 throw new IllegalArgumentException("resizeTask: taskId " + taskId
                         + " not found.");
             }
-            if (task.setBounds(bounds)) {
+            if (task.setBounds(bounds, configuration)) {
                 task.resizeWindows();
-                task.getDisplayContent().layoutNeeded = true;
-                performLayoutAndPlaceSurfacesLocked();
+                if (relayout) {
+                    task.getDisplayContent().layoutNeeded = true;
+                    performLayoutAndPlaceSurfacesLocked();
+                }
             }
-            return new Configuration(task.mOverrideConfig);
         }
     }
 
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 2d31a78..8a1a553 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -206,8 +206,14 @@
          */
         public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
 
+        /**
+         * Call sends responses through connection.
+         * @hide
+         */
+        public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
+
         //******************************************************************************************
-        // Next CAPABILITY value: 0x00004000
+        // Next CAPABILITY value: 0x00800000
         //******************************************************************************************
 
         /**
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 7b277c5..430760a 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -248,8 +248,15 @@
      */
     public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000;
 
+    /**
+     * Indicates that the connection itself wants to handle any sort of reply response, rather than
+     * relying on SMS.
+     * @hide
+     */
+    public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
+
     //**********************************************************************************************
-    // Next CAPABILITY value: 0x00400000
+    // Next CAPABILITY value: 0x00800000
     //**********************************************************************************************
 
     /**
@@ -388,6 +395,10 @@
         if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
             builder.append(" CAPABILITY_SINGLE_PARTY_CONFERENCE");
         }
+        if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
+            builder.append(" CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION");
+        }
+
         builder.append("]");
         return builder.toString();
     }
@@ -1763,6 +1774,13 @@
     public void onReject() {}
 
     /**
+     * Notifies ths Connection of a request reject with a message.
+     *
+     * @hide
+     */
+    public void onReject(String replyMessage) {}
+
+    /**
      * Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes.
      */
     public void onPostDialContinue(boolean proceed) {}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 383e45b..4e330bdb 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -101,6 +101,7 @@
     private static final int MSG_ANSWER_VIDEO = 17;
     private static final int MSG_MERGE_CONFERENCE = 18;
     private static final int MSG_SWAP_CONFERENCE = 19;
+    private static final int MSG_REJECT_WITH_MESSAGE = 20;
 
     private static Connection sNullConnection;
 
@@ -166,6 +167,14 @@
         }
 
         @Override
+        public void rejectWithMessage(String callId, String message) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = message;
+            mHandler.obtainMessage(MSG_REJECT_WITH_MESSAGE, args).sendToTarget();
+        }
+
+        @Override
         public void disconnect(String callId) {
             mHandler.obtainMessage(MSG_DISCONNECT, callId).sendToTarget();
         }
@@ -296,6 +305,15 @@
                 case MSG_REJECT:
                     reject((String) msg.obj);
                     break;
+                case MSG_REJECT_WITH_MESSAGE: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        reject((String) args.arg1, (String) args.arg2);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
                 case MSG_DISCONNECT:
                     disconnect((String) msg.obj);
                     break;
@@ -681,6 +699,11 @@
         findConnectionForAction(callId, "reject").onReject();
     }
 
+    private void reject(String callId, String rejectWithMessage) {
+        Log.d(this, "reject %s with message", callId);
+        findConnectionForAction(callId, "reject").onReject(rejectWithMessage);
+    }
+
     private void disconnect(String callId) {
         Log.d(this, "disconnect %s", callId);
         if (mConnectionById.containsKey(callId)) {
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index c2e8530..dd253cf 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -50,6 +50,8 @@
 
     void reject(String callId);
 
+    void rejectWithMessage(String callId, String message);
+
     void disconnect(String callId);
 
     void hold(String callId);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index bfb7a50..aa750ef 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -419,6 +419,15 @@
     public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl";
     public static final String KEY_MMS_USER_AGENT_STRING = "userAgent";
 
+    /**
+     * Determines whether the carrier supports making non-emergency phone calls while the phone is
+     * in emergency callback mode.  Default value is {@code true}, meaning that non-emergency calls
+     * are allowed in emergency callback mode.
+     * @hide
+     */
+    public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL =
+            "allow_non_emergency_calls_in_ecm_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -513,6 +522,7 @@
         sDefaults.putString(KEY_MMS_UA_PROF_TAG_NAME_STRING, "x-wap-profile");
         sDefaults.putString(KEY_MMS_UA_PROF_URL_STRING, "");
         sDefaults.putString(KEY_MMS_USER_AGENT_STRING, "");
+        sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
     }
 
     /**
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 6177784..95f676e 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -32,7 +32,7 @@
  */
 public class WindowManagerPermissionTests extends TestCase {
     IWindowManager mWm;
-    
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -51,7 +51,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.resumeKeyDispatching(null);
             fail("IWindowManager.resumeKeyDispatching did not throw SecurityException as"
@@ -61,7 +61,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setEventDispatching(true);
             fail("IWindowManager.setEventDispatching did not throw SecurityException as"
@@ -71,7 +71,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.addWindowToken(null, 0);
             fail("IWindowManager.addWindowToken did not throw SecurityException as"
@@ -81,7 +81,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.removeWindowToken(null);
             fail("IWindowManager.removeWindowToken did not throw SecurityException as"
@@ -91,9 +91,10 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
-            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null);
+            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
+                    Configuration.EMPTY);
             fail("IWindowManager.addAppToken did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
@@ -101,9 +102,9 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
-            mWm.setAppTask(null, 0, null);
+            mWm.setAppTask(null, 0, null, null);
             fail("IWindowManager.setAppGroupId did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
@@ -111,7 +112,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.updateOrientationFromAppTokens(new Configuration(), null);
             fail("IWindowManager.updateOrientationFromAppTokens did not throw SecurityException as"
@@ -121,7 +122,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAppOrientation(null, 0);
             mWm.addWindowToken(null, 0);
@@ -132,7 +133,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setFocusedApp(null, false);
             fail("IWindowManager.setFocusedApp did not throw SecurityException as"
@@ -142,7 +143,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.prepareAppTransition(0, false);
             fail("IWindowManager.prepareAppTransition did not throw SecurityException as"
@@ -152,7 +153,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.executeAppTransition();
             fail("IWindowManager.executeAppTransition did not throw SecurityException as"
@@ -162,7 +163,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAppStartingWindow(null, "foo", 0, null, null, 0, 0, 0, 0, null, false);
             fail("IWindowManager.setAppStartingWindow did not throw SecurityException as"
@@ -172,7 +173,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAppWillBeHidden(null);
             fail("IWindowManager.setAppWillBeHidden did not throw SecurityException as"
@@ -182,7 +183,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAppVisibility(null, false);
             fail("IWindowManager.setAppVisibility did not throw SecurityException as"
@@ -192,7 +193,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.startAppFreezingScreen(null, 0);
             fail("IWindowManager.startAppFreezingScreen did not throw SecurityException as"
@@ -202,7 +203,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.stopAppFreezingScreen(null, false);
             fail("IWindowManager.stopAppFreezingScreen did not throw SecurityException as"
@@ -212,7 +213,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.removeAppToken(null);
             fail("IWindowManager.removeAppToken did not throw SecurityException as"
@@ -236,7 +237,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.reenableKeyguard(token);
             fail("IWindowManager.reenableKeyguard did not throw SecurityException as"
@@ -246,7 +247,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.exitKeyguardSecurely(null);
             fail("IWindowManager.exitKeyguardSecurely did not throw SecurityException as"
@@ -257,7 +258,7 @@
             fail("Unexpected remote exception");
         }
     }
-        
+
     @SmallTest
     public void testSET_ANIMATION_SCALE() {
         try {
@@ -269,7 +270,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAnimationScales(new float[1]);
             fail("IWindowManager.setAnimationScales did not throw SecurityException as"
@@ -280,7 +281,7 @@
             fail("Unexpected remote exception");
         }
     }
-    
+
     @SmallTest
     public void testSET_ORIENTATION() {
         try {
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 769e2a1..b701445 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -54,7 +54,6 @@
     tests/ResourceFilter_test.cpp \
     tests/ResourceTable_test.cpp
 
-aaptHostLdLibs :=
 aaptHostStaticLibs := \
     libandroidfw \
     libpng \
@@ -68,17 +67,13 @@
 aaptCFlags := -DAAPT_VERSION=\"$(BUILD_NUMBER_FROM_FILE)\"
 aaptCFlags += -Wall -Werror
 
-ifeq ($(HOST_OS),linux)
-    aaptHostLdLibs += -lrt -ldl -lpthread
-endif
+aaptHostLdLibs_linux := -lrt -ldl -lpthread
 
 # Statically link libz for MinGW (Win SDK under Linux),
 # and dynamically link for all others.
-ifneq ($(strip $(USE_MINGW)),)
-    aaptHostStaticLibs += libz
-else
-    aaptHostLdLibs += -lz
-endif
+aaptHostStaticLibs_windows := libz
+aaptHostLdLibs_linux += -lz
+aaptHostLdLibs_darwin := -lz
 
 
 # ==========================================================
@@ -87,13 +82,13 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := libaapt
-LOCAL_CFLAGS += -Wno-format-y2k -DSTATIC_ANDROIDFW_FOR_TOOLS $(aaptCFlags)
-LOCAL_CPPFLAGS += $(aaptCppFlags)
-ifeq (darwin,$(HOST_OS))
-LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
-endif
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := -Wno-format-y2k -DSTATIC_ANDROIDFW_FOR_TOOLS $(aaptCFlags)
+LOCAL_CPPFLAGS := $(aaptCppFlags)
+LOCAL_CFLAGS_darwin := -D_DARWIN_UNLIMITED_STREAMS
 LOCAL_SRC_FILES := $(aaptSources)
-LOCAL_STATIC_LIBRARIES += $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES := $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(aaptHostStaticLibs_windows)
 
 include $(BUILD_HOST_STATIC_LIBRARY)
 
@@ -103,11 +98,14 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := aapt
-LOCAL_CFLAGS += $(aaptCFlags)
-LOCAL_CPPFLAGS += $(aaptCppFlags)
-LOCAL_LDLIBS += $(aaptHostLdLibs)
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := $(aaptCFlags)
+LOCAL_CPPFLAGS := $(aaptCppFlags)
+LOCAL_LDLIBS_darwin := $(aaptHostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(aaptHostLdLibs_linux)
 LOCAL_SRC_FILES := $(aaptMain)
-LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES := libaapt $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(aaptHostStaticLibs_windows)
 
 include $(BUILD_HOST_EXECUTABLE)
 
@@ -116,15 +114,16 @@
 # Build the host tests: libaapt_tests
 # ==========================================================
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE := libaapt_tests
-LOCAL_CFLAGS += $(aaptCFlags)
-LOCAL_CPPFLAGS += $(aaptCppFlags)
-LOCAL_LDLIBS += $(aaptHostLdLibs)
-LOCAL_SRC_FILES += $(aaptTests)
-LOCAL_C_INCLUDES += $(LOCAL_PATH)
-LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs)
+LOCAL_CFLAGS := $(aaptCFlags)
+LOCAL_CPPFLAGS := $(aaptCppFlags)
+LOCAL_LDLIBS_darwin := $(aaptHostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(aaptHostLdLibs_linux)
+LOCAL_SRC_FILES := $(aaptTests)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+LOCAL_STATIC_LIBRARIES := libaapt $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(aaptHostStaticLibs_windows)
 
 include $(BUILD_HOST_NATIVE_TEST)
 
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index ead5e7a..d7bfccb 100644
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -1,5 +1,5 @@
-#ifndef AIDL_AST_H
-#define AIDL_AST_H
+#ifndef AIDL_AST_H_
+#define AIDL_AST_H_
 
 #include <string>
 #include <vector>
@@ -368,4 +368,4 @@
     virtual void Write(FILE* to);
 };
 
-#endif // AIDL_AST_H
+#endif // AIDL_AST_H_
diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk
index efd60a2..354563a 100644
--- a/tools/aidl/Android.mk
+++ b/tools/aidl/Android.mk
@@ -6,24 +6,65 @@
 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_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 := \
-	aidl_language_l.l \
-	aidl_language_y.y \
-	aidl.cpp \
-	aidl_language.cpp \
-	options.cpp \
-	search_path.cpp \
-	AST.cpp \
-	Type.cpp \
-	generate_java.cpp \
-	generate_java_binder.cpp \
-	generate_java_rpc.cpp
+    AST.cpp \
+    Type.cpp \
+    aidl.cpp \
+    aidl_language.cpp \
+    aidl_language_l.l \
+    aidl_language_y.y \
+    generate_java.cpp \
+    generate_java_binder.cpp \
+    generate_java_rpc.cpp \
+    options.cpp \
+    search_path.cpp \
 
-LOCAL_CFLAGS := -g
+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)
 
+
+# Unit tests
+include $(CLEAR_VARS)
+LOCAL_MODULE := aidl_unittests
+
+LOCAL_CFLAGS := -g -DUNIT_TEST -Wall -Werror
+LOCAL_SRC_FILES := \
+    options_unittest.cpp \
+    test_main.cpp \
+    tests/test.cpp \
+
+LOCAL_STATIC_LIBRARIES := \
+    libaidl-common \
+    libgmock_host \
+    libgtest_host \
+
+LOCAL_LDLIBS := -lrt
+include $(BUILD_HOST_NATIVE_TEST)
+
 endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index ae12720..d799fca 100644
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -1,5 +1,5 @@
-#ifndef AIDL_TYPE_H
-#define AIDL_TYPE_H
+#ifndef AIDL_TYPE_H_
+#define AIDL_TYPE_H_
 
 #include "AST.h"
 #include <string>
@@ -539,4 +539,4 @@
 
 void register_base_types();
 
-#endif // AIDL_TYPE_H
+#endif // AIDL_TYPE_H_
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index 438007f..a4ecb75 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -162,11 +162,6 @@
 {
 }
 
-static ParserCallbacks g_importCallbacks = {
-    &main_document_parsed,
-    &import_import_parsed
-};
-
 // ==========================================================
 static int
 check_filename(const char* filename, const char* package, buffer_type* name)
@@ -938,7 +933,7 @@
 }
 
 // ==========================================================
-static int
+int
 compile_aidl(Options& options)
 {
     int err = 0, N;
@@ -1068,7 +1063,7 @@
     return err;
 }
 
-static int
+int
 preprocess_aidl(const Options& options)
 {
     vector<string> lines;
@@ -1140,24 +1135,3 @@
     close(fd);
     return 0;
 }
-
-// ==========================================================
-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/aidl.h b/tools/aidl/aidl.h
new file mode 100644
index 0000000..98b15f3
--- /dev/null
+++ b/tools/aidl/aidl.h
@@ -0,0 +1,9 @@
+#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.h b/tools/aidl/aidl_language.h
index de1370c..1be5a9b 100644
--- a/tools/aidl/aidl_language.h
+++ b/tools/aidl/aidl_language.h
@@ -1,5 +1,5 @@
-#ifndef DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
-#define DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
+#ifndef AIDL_AIDL_LANGUAGE_H_
+#define AIDL_AIDL_LANGUAGE_H_
 
 
 typedef enum {
@@ -169,4 +169,4 @@
 #endif
 
 
-#endif // DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
+#endif // AIDL_AIDL_LANGUAGE_H_
diff --git a/tools/aidl/generate_java.h b/tools/aidl/generate_java.h
index 4bfcfeb..ae7983f 100644
--- a/tools/aidl/generate_java.h
+++ b/tools/aidl/generate_java.h
@@ -1,5 +1,5 @@
-#ifndef GENERATE_JAVA_H
-#define GENERATE_JAVA_H
+#ifndef AIDL_GENERATE_JAVA_H_
+#define AIDL_GENERATE_JAVA_H_
 
 #include "aidl_language.h"
 #include "AST.h"
@@ -29,5 +29,5 @@
     int m_index;
 };
 
-#endif // GENERATE_JAVA_H
+#endif // AIDL_GENERATE_JAVA_H_
 
diff --git a/tools/aidl/main.cpp b/tools/aidl/main.cpp
new file mode 100644
index 0000000..7cc2198
--- /dev/null
+++ b/tools/aidl/main.cpp
@@ -0,0 +1,23 @@
+#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
index 7b2daeb..52b0972 100644
--- a/tools/aidl/options.cpp
+++ b/tools/aidl/options.cpp
@@ -48,10 +48,6 @@
         return 0;
     }
 
-    options->task = COMPILE_AIDL;
-    options->failOnParcelable = false;
-    options->autoDepFile = false;
-
     // OPTIONS
     while (i < argc) {
         const char* s = argv[i];
diff --git a/tools/aidl/options.h b/tools/aidl/options.h
index 387e37d..4e95e11 100644
--- a/tools/aidl/options.h
+++ b/tools/aidl/options.h
@@ -1,5 +1,5 @@
-#ifndef DEVICE_TOOLS_AIDL_H
-#define DEVICE_TOOLS_AIDL_H
+#ifndef AIDL_OPTIONS_H_
+#define AIDL_OPTIONS_H_
 
 #include <string.h>
 #include <string>
@@ -15,15 +15,15 @@
 // This struct is the parsed version of the command line options
 struct Options
 {
-    int task;
-    bool failOnParcelable;
+    int task{COMPILE_AIDL};
+    bool failOnParcelable{false};
     vector<string> importPaths;
     vector<string> preprocessedFiles;
     string inputFileName;
     string outputFileName;
     string outputBaseFolder;
     string depFileName;
-    bool autoDepFile;
+    bool autoDepFile{false};
 
     vector<string> filesToPreprocess;
 };
@@ -33,4 +33,4 @@
 // It also prints the usage statement on failure.
 int parse_options(int argc, const char* const* argv, Options *options);
 
-#endif // DEVICE_TOOLS_AIDL_H
+#endif // AIDL_OPTIONS_H_
diff --git a/tools/aidl/options_unittest.cpp b/tools/aidl/options_unittest.cpp
new file mode 100644
index 0000000..fec7f87
--- /dev/null
+++ b/tools/aidl/options_unittest.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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
index 79d2c35..752ed47 100644
--- a/tools/aidl/os.h
+++ b/tools/aidl/os.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _FRAMEWORKS_BASE_TOOLS_AIDL_OS_SEP_H_
-#define _FRAMEWORKS_BASE_TOOLS_AIDL_OS_SEP_H_
+#ifndef AIDL_OS_H_
+#define AIDL_OS_H_
 
 #if defined(_WIN32)
 #define OS_PATH_SEPARATOR '\\'
@@ -23,4 +23,4 @@
 #define OS_PATH_SEPARATOR '/'
 #endif
 
-#endif
+#endif  // AIDL_OS_H_
diff --git a/tools/aidl/search_path.h b/tools/aidl/search_path.h
index 2bf94b1..4fec257 100644
--- a/tools/aidl/search_path.h
+++ b/tools/aidl/search_path.h
@@ -1,5 +1,5 @@
-#ifndef DEVICE_TOOLS_AIDL_SEARCH_PATH_H
-#define DEVICE_TOOLS_AIDL_SEARCH_PATH_H
+#ifndef AIDL_SEARCH_PATH_H_
+#define AIDL_SEARCH_PATH_H_
 
 #include <stdio.h>
 
@@ -19,5 +19,4 @@
 void set_import_paths(const vector<string>& importPaths);
 #endif
 
-#endif // DEVICE_TOOLS_AIDL_SEARCH_PATH_H
-
+#endif // AIDL_SEARCH_PATH_H_
diff --git a/tools/aidl/test_main.cpp b/tools/aidl/test_main.cpp
new file mode 100644
index 0000000..4d820af7
--- /dev/null
+++ b/tools/aidl/test_main.cpp
@@ -0,0 +1,6 @@
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/tools/aidl/tests/test.cpp b/tools/aidl/tests/test.cpp
new file mode 100644
index 0000000..15ae294
--- /dev/null
+++ b/tools/aidl/tests/test.cpp
@@ -0,0 +1,3 @@
+#include <gtest/gtest.h>
+
+TEST(DummyCase, DummyTest) {}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index a8fd91c..ed8b56e 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -74,11 +74,10 @@
     // ---- unused implementation of IWindowManager ----
 
     @Override
-    public Configuration addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
+    public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
             boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
-            Rect arg11) throws RemoteException {
+            Rect arg11, Configuration arg12) throws RemoteException {
         // TODO Auto-generated method stub
-        return Configuration.EMPTY;
     }
 
     @Override
@@ -315,9 +314,9 @@
     }
 
     @Override
-    public Configuration setAppTask(IBinder arg0, int arg1, Rect arg2) throws RemoteException {
+    public void setAppTask(IBinder arg0, int arg1, Rect arg2, Configuration arg3)
+            throws RemoteException {
         // TODO Auto-generated method stub
-        return Configuration.EMPTY;
     }
 
     @Override
diff --git a/tools/split-select/Android.mk b/tools/split-select/Android.mk
index d9ddf08..239bed5 100644
--- a/tools/split-select/Android.mk
+++ b/tools/split-select/Android.mk
@@ -43,7 +43,6 @@
     external/zlib \
     frameworks/base/tools
 
-hostLdLibs :=
 hostStaticLibs := \
     libaapt \
     libandroidfw \
@@ -57,17 +56,13 @@
 
 cFlags := -Wall -Werror
 
-ifeq ($(HOST_OS),linux)
-    hostLdLibs += -lrt -ldl -lpthread
-endif
+hostLdLibs_linux := -lrt -ldl -lpthread
 
 # Statically link libz for MinGW (Win SDK under Linux),
 # and dynamically link for all others.
-ifneq ($(strip $(USE_MINGW)),)
-    hostStaticLibs += libz
-else
-    hostLdLibs += -lz
-endif
+hostStaticLibs_windows := libz
+hostLdLibs_darwin := -lz
+hostLdLibs_linux += -lz
 
 
 # ==========================================================
@@ -75,11 +70,12 @@
 # ==========================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := libsplit-select
+LOCAL_MODULE_HOST_OS := darwin linux windows
 
 LOCAL_SRC_FILES := $(sources)
 
-LOCAL_C_INCLUDES += $(cIncludes)
-LOCAL_CFLAGS += $(cFlags) -D_DARWIN_UNLIMITED_STREAMS
+LOCAL_C_INCLUDES := $(cIncludes)
+LOCAL_CFLAGS := $(cFlags) -D_DARWIN_UNLIMITED_STREAMS
 
 include $(BUILD_HOST_STATIC_LIBRARY)
 
@@ -93,10 +89,12 @@
 
 LOCAL_SRC_FILES := $(testSources)
 
-LOCAL_C_INCLUDES += $(cIncludes)
-LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs)
-LOCAL_LDLIBS += $(hostLdLibs)
-LOCAL_CFLAGS += $(cFlags)
+LOCAL_C_INCLUDES := $(cIncludes)
+LOCAL_STATIC_LIBRARIES := libsplit-select $(hostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
+LOCAL_LDLIBS_darwin := $(hostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(hostLdLibs_linux)
+LOCAL_CFLAGS := $(cFlags)
 
 include $(BUILD_HOST_NATIVE_TEST)
 
@@ -105,13 +103,16 @@
 # ==========================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := split-select
+LOCAL_MODULE_HOST_OS := darwin linux windows
 
 LOCAL_SRC_FILES := $(main)
 
-LOCAL_C_INCLUDES += $(cIncludes)
-LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs)
-LOCAL_LDLIBS += $(hostLdLibs)
-LOCAL_CFLAGS += $(cFlags)
+LOCAL_C_INCLUDES := $(cIncludes)
+LOCAL_STATIC_LIBRARIES := libsplit-select $(hostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
+LOCAL_LDLIBS_darwin := $(hostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(hostLdLibs_linux)
+LOCAL_CFLAGS := $(cFlags)
 
 include $(BUILD_HOST_EXECUTABLE)