Merge "Don't do heavy work on UiThread." into oc-dev
diff --git a/api/current.txt b/api/current.txt
index 8d27905..e6363db 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12695,7 +12695,7 @@
     enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_STRIP;
   }
 
-  public class Color {
+  public final class Color {
     ctor public Color();
     method public static int HSVToColor(float[]);
     method public static int HSVToColor(int, float[]);
@@ -12720,6 +12720,7 @@
     method public float getComponent(int);
     method public int getComponentCount();
     method public float[] getComponents();
+    method public float[] getComponents(float[]);
     method public android.graphics.ColorSpace.Model getModel();
     method public float green();
     method public static float green(long);
diff --git a/api/system-current.txt b/api/system-current.txt
index badd31e..03b522d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -11172,6 +11172,7 @@
     method public abstract byte[] getInstantAppCookie();
     method public abstract int getInstantAppCookieMaxSize();
     method public abstract android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String);
+    method public abstract android.content.ComponentName getInstantAppResolverSettingsComponent();
     method public abstract java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
     method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
@@ -11421,6 +11422,7 @@
     field public static final int MATCH_DIRECT_BOOT_UNAWARE = 262144; // 0x40000
     field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
     field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
     field public static final int MATCH_INSTANT = 8388608; // 0x800000
     field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
     field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
@@ -13421,7 +13423,7 @@
     enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_STRIP;
   }
 
-  public class Color {
+  public final class Color {
     ctor public Color();
     method public static int HSVToColor(float[]);
     method public static int HSVToColor(int, float[]);
@@ -13446,6 +13448,7 @@
     method public float getComponent(int);
     method public int getComponentCount();
     method public float[] getComponents();
+    method public float[] getComponents(float[]);
     method public android.graphics.ColorSpace.Model getModel();
     method public float green();
     method public static float green(long);
@@ -44214,6 +44217,7 @@
     method public byte[] getInstantAppCookie();
     method public int getInstantAppCookieMaxSize();
     method public android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String);
+    method public android.content.ComponentName getInstantAppResolverSettingsComponent();
     method public java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
     method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index 3a23cd9..b09136e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -12745,7 +12745,7 @@
     enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_STRIP;
   }
 
-  public class Color {
+  public final class Color {
     ctor public Color();
     method public static int HSVToColor(float[]);
     method public static int HSVToColor(int, float[]);
@@ -12770,6 +12770,7 @@
     method public float getComponent(int);
     method public int getComponentCount();
     method public float[] getComponents();
+    method public float[] getComponents(float[]);
     method public android.graphics.ColorSpace.Model getModel();
     method public float green();
     method public static float green(long);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 286f857..461f9cc 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2630,4 +2630,13 @@
             throw e.rethrowAsRuntimeException();
         }
     }
+
+    @Override
+    public ComponentName getInstantAppResolverSettingsComponent() {
+        try {
+            return mPM.getInstantAppResolverSettingsComponent();
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index fb86791..7890a96 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1532,6 +1532,19 @@
             = "android.intent.action.RESOLVE_EPHEMERAL_PACKAGE";
 
     /**
+     * Activity Action: Launch ephemeral settings.
+     *
+     * <p class="note">
+     * This is a protected intent that can only be sent by the system.
+     * </p>
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_EPHEMERAL_RESOLVER_SETTINGS
+            = "android.intent.action.EPHEMERAL_RESOLVER_SETTINGS";
+
+    /**
      * Used as a string extra field with {@link #ACTION_INSTALL_PACKAGE} to install a
      * package.  Specifies the installer package name; this package will receive the
      * {@link #ACTION_APP_ERROR} intent.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 59b022d..147df76 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -630,4 +630,6 @@
     boolean canRequestPackageInstalls(String packageName, int userId);
 
     void deletePreloadsFileCache();
+
+    ComponentName getInstantAppResolverSettingsComponent();
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 71db5d3..136c13b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -153,6 +153,7 @@
             MATCH_UNINSTALLED_PACKAGES,
             MATCH_SYSTEM_ONLY,
             MATCH_DEBUG_TRIAGED_MISSING,
+            MATCH_DISABLED_COMPONENTS,
             MATCH_DISABLED_UNTIL_USED_COMPONENTS,
             MATCH_INSTANT,
             GET_DISABLED_UNTIL_USED_COMPONENTS,
@@ -431,6 +432,7 @@
      * This will not return information on any unbundled update to system components.
      * @hide
      */
+    @SystemApi
     public static final int MATCH_FACTORY_ONLY = 0x00200000;
 
     /**
@@ -3730,6 +3732,7 @@
      *
      * @param flags Additional option flags. Use any combination of
      * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}
      * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
      * to modify the data returned.
      *
@@ -3743,6 +3746,7 @@
      *
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
@@ -3757,6 +3761,7 @@
      *
      * @param flags Additional option flags. Use any combination of
      * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+     * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}
      * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
      * to modify the data returned.
      * @param userId The user for whom the installed applications are to be listed
@@ -3772,6 +3777,7 @@
      *
      * @see #GET_META_DATA
      * @see #GET_SHARED_LIBRARY_FILES
+     * @see #MATCH_DISABLED_COMPONENTS
      * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
      * @see #MATCH_SYSTEM_ONLY
      * @see #MATCH_UNINSTALLED_PACKAGES
@@ -6233,4 +6239,14 @@
      * @see {@link android.provider.Settings#ACTION_MANAGE_EXTERNAL_SOURCES}
      */
     public abstract boolean canRequestPackageInstalls();
+
+    /**
+     * Return the {@link ComponentName} of the activity providing Settings for the Instant App
+     * resolver.
+     *
+     * @see {@link android.content.intent#ACTION_EPHEMERAL_RESOLVER_SETTINGS}
+     * @hide
+     */
+    @SystemApi
+    public abstract ComponentName getInstantAppResolverSettingsComponent();
 }
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 6272822..370af17 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -172,6 +172,7 @@
      * @param packageName The package name.
      * @param userId The user for which to check.
      * @return Whether was launched.
+     * @throws IllegalArgumentException if the package is not found
      */
     public abstract boolean wasPackageEverLaunched(String packageName, int userId);
 
@@ -241,6 +242,7 @@
     public abstract void grantEphemeralAccess(int userId, Intent intent,
             int targetAppId, int ephemeralAppId);
 
+    public abstract boolean isInstantAppInstallerComponent(ComponentName component);
     /**
      * Prunes instant apps and state associated with uninstalled
      * instant apps according to the current platform policy.
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 44309a7..28c2d01 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -520,27 +520,27 @@
     }
 
     private HashMap<String, String> getExtraValueHashMap() {
-        if (mExtraValueHashMapCache == null) {
-            synchronized(this) {
-                if (mExtraValueHashMapCache == null) {
-                    mExtraValueHashMapCache = new HashMap<String, String>();
-                    final String[] pairs = mSubtypeExtraValue.split(EXTRA_VALUE_PAIR_SEPARATOR);
-                    final int N = pairs.length;
-                    for (int i = 0; i < N; ++i) {
-                        final String[] pair = pairs[i].split(EXTRA_VALUE_KEY_VALUE_SEPARATOR);
-                        if (pair.length == 1) {
-                            mExtraValueHashMapCache.put(pair[0], null);
-                        } else if (pair.length > 1) {
-                            if (pair.length > 2) {
-                                Slog.w(TAG, "ExtraValue has two or more '='s");
-                            }
-                            mExtraValueHashMapCache.put(pair[0], pair[1]);
-                        }
+        synchronized (this) {
+            HashMap<String, String> extraValueMap = mExtraValueHashMapCache;
+            if (extraValueMap != null) {
+                return extraValueMap;
+            }
+            extraValueMap = new HashMap<>();
+            final String[] pairs = mSubtypeExtraValue.split(EXTRA_VALUE_PAIR_SEPARATOR);
+            for (int i = 0; i < pairs.length; ++i) {
+                final String[] pair = pairs[i].split(EXTRA_VALUE_KEY_VALUE_SEPARATOR);
+                if (pair.length == 1) {
+                    extraValueMap.put(pair[0], null);
+                } else if (pair.length > 1) {
+                    if (pair.length > 2) {
+                        Slog.w(TAG, "ExtraValue has two or more '='s");
                     }
+                    extraValueMap.put(pair[0], pair[1]);
                 }
             }
+            mExtraValueHashMapCache = extraValueMap;
+            return extraValueMap;
         }
-        return mExtraValueHashMapCache;
     }
 
     /**
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 78d18fd..ab4cce4 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -523,9 +523,17 @@
     /**
      * Sets the height of the popup window in pixels. Can also be {@link #MATCH_PARENT}.
      *
-     * @param height Height of the popup window.
+     * @param height Height of the popup window must be a positive value,
+     *               {@link #MATCH_PARENT}, or {@link #WRAP_CONTENT}.
+     *
+     * @throws IllegalArgumentException if height is set to negative value
      */
     public void setHeight(int height) {
+        if (height < 0 && ViewGroup.LayoutParams.WRAP_CONTENT != height
+                && ViewGroup.LayoutParams.MATCH_PARENT != height) {
+            throw new IllegalArgumentException(
+                   "Invalid height. Must be a positive value, MATCH_PARENT, or WRAP_CONTENT.");
+        }
         mDropDownHeight = height;
     }
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7704519..db234e7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2801,4 +2801,9 @@
 
     <!-- Colon separated list of package names that should be granted Notification Listener access -->
     <string name="config_defaultListenerAccessPackages" translatable="false"></string>
+
+    <!-- Maximum size, specified in pixels, to restrain the display space width to. Height and
+         density will be scaled accordingly to maintain aspect ratio. A value of 0 indicates no
+         constraint will be enforced. -->
+    <integer name="config_maxUiWidth">0</integer>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 868e256..4afa8dc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -189,22 +189,23 @@
     <!-- Displayed to tell the user that they cannot change the caller ID setting. -->
     <string name="CLIRPermanent">You can\'t change the caller ID setting.</string>
 
-    <!-- Displayed to tell the user that data service is blocked by access control. -->
-    <string name="RestrictedOnData">Data service is blocked.</string>
-    <!-- Displayed to tell the user that emergency service is blocked by access control. -->
-    <string name="RestrictedOnEmergency">Emergency service is blocked.</string>
-    <!-- Displayed to tell the user that normal service is blocked by access control. -->
-    <string name="RestrictedOnNormal">Voice service is blocked.</string>
-    <!-- Displayed to tell the user that all emergency and normal voice services are blocked by access control. -->
-    <string name="RestrictedOnAllVoice">All voice services are blocked.</string>
-    <!-- Displayed to tell the user that sms service is blocked by access control. -->
-    <string name="RestrictedOnSms">SMS service is blocked.</string>
-    <!-- Displayed to tell the user that voice/data service is blocked by access control. -->
-    <string name="RestrictedOnVoiceData">Voice/data services are blocked.</string>
-    <!-- Displayed to tell the user that voice and sms service are blocked by access control. -->
-    <string name="RestrictedOnVoiceSms">Voice/SMS services are blocked.</string>
-    <!-- Displayed to tell the user that all service is blocked by access control. -->
-    <string name="RestrictedOnAll">All voice/data/SMS services are blocked.</string>
+    <!-- Notification title to tell the user that data service is blocked by access control. -->
+    <string name="RestrictedOnDataTitle">No data service</string>
+    <!-- Notification title to tell the user that emergency service is blocked by access control. -->
+    <string name="RestrictedOnEmergencyTitle">No emergency service</string>
+    <!-- Notification title to tell the user that normal service is blocked by access control. -->
+    <string name="RestrictedOnNormalTitle">No voice service</string>
+    <!-- Notification title to tell the user that all emergency and normal voice services are blocked by access control. -->
+    <string name="RestrictedOnAllVoiceTitle">No voice/emergency service</string>
+
+    <!-- Notification content to tell the user that data service is blocked by access control. -->
+    <string name="RestrictedOnDataContent">Your carrier has temporarily suspended data service at this location</string>
+    <!-- Notification content to tell the user that emergency service is blocked by access control. -->
+    <string name="RestrictedOnEmergencyContent">Your carrier has temporarily suspended emergency calls at this location</string>
+    <!-- Notification content to tell the user that normal service is blocked by access control. -->
+    <string name="RestrictedOnNormalContent">Your carrier has temporarily suspended voice calls at this location</string>
+    <!-- Notification content to tell the user that all emergency and normal voice services are blocked by access control. -->
+    <string name="RestrictedOnAllVoiceContent">Your carrier has temporarily suspended voice and emergency calls at this location</string>
 
     <!-- Displayed to tell the user that they should switch their network preference. -->
     <string name="NetworkPreferenceSwitchTitle">Can\u2019t reach network</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b23c96c..92436f4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -507,12 +507,16 @@
   <java-symbol type="string" name="Noon" />
   <java-symbol type="string" name="PinMmi" />
   <java-symbol type="string" name="PwdMmi" />
-  <java-symbol type="string" name="RestrictedOnAllVoice" />
-  <java-symbol type="string" name="RestrictedOnData" />
-  <java-symbol type="string" name="RestrictedOnEmergency" />
-  <java-symbol type="string" name="RestrictedOnNormal" />
   <java-symbol type="string" name="NetworkPreferenceSwitchSummary" />
   <java-symbol type="string" name="NetworkPreferenceSwitchTitle" />
+  <java-symbol type="string" name="RestrictedOnAllVoiceTitle" />
+  <java-symbol type="string" name="RestrictedOnDataTitle" />
+  <java-symbol type="string" name="RestrictedOnEmergencyTitle" />
+  <java-symbol type="string" name="RestrictedOnNormalTitle" />
+  <java-symbol type="string" name="RestrictedOnAllVoiceContent" />
+  <java-symbol type="string" name="RestrictedOnDataContent" />
+  <java-symbol type="string" name="RestrictedOnEmergencyContent" />
+  <java-symbol type="string" name="RestrictedOnNormalContent" />
   <java-symbol type="string" name="SetupCallDefault" />
   <java-symbol type="string" name="accept" />
   <java-symbol type="string" name="activity_chooser_view_see_all" />
@@ -2919,6 +2923,9 @@
   <!-- Colon separated list of package names that should be granted Notification Listener access -->
   <java-symbol type="string" name="config_defaultListenerAccessPackages" />
 
+  <!-- maximum width of the display -->
+  <java-symbol type="integer" name="config_maxUiWidth" />
+
   <!-- system notification channels -->
   <java-symbol type="string" name="notification_channel_virtual_keyboard" />
   <java-symbol type="string" name="notification_channel_physical_keyboard" />
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 33d19d4..d69f67d 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -22,6 +22,7 @@
 import android.annotation.HalfFloat;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.Size;
 
 import android.util.Half;
@@ -288,7 +289,7 @@
  * and <code>(1.0, 0.0, 0.0, 0.5)</code>.</p>
  */
 @AnyThread
-public class Color {
+public final class Color {
     @ColorInt public static final int BLACK       = 0xFF000000;
     @ColorInt public static final int DKGRAY      = 0xFF444444;
     @ColorInt public static final int GRAY        = 0xFF888888;
@@ -415,7 +416,7 @@
      * to this color space's color model, plus one extra component for
      * alpha.
      *
-     * @return An integer between 4 and 5
+     * @return The integer 4 or 5
      */
     @IntRange(from = 4, to = 5)
     public int getComponentCount() {
@@ -560,7 +561,37 @@
     @NonNull
     @Size(min = 4, max = 5)
     public float[] getComponents() {
-        return Arrays.copyOf(mComponents, mColorSpace.getComponentCount() + 1);
+        return Arrays.copyOf(mComponents, mComponents.length);
+    }
+
+    /**
+     * Copies this color's components in the supplied array. The last element of the
+     * array is always the alpha component.
+     *
+     * @param components An array of floats whose size must be at least
+     *                  {@link #getComponentCount()}, can be null
+     * @return The array passed as a parameter if not null, or a new array of length
+     *         {@link #getComponentCount()}
+     *
+     * @see #getComponent(int)
+     *
+     * @throws IllegalArgumentException If the specified array's length is less than
+     * {@link #getComponentCount()}
+     */
+    @NonNull
+    @Size(min = 4)
+    public float[] getComponents(@Nullable @Size(min = 4) float[] components) {
+        if (components == null) {
+            return Arrays.copyOf(mComponents, mComponents.length);
+        }
+
+        if (components.length < mComponents.length) {
+            throw new IllegalArgumentException("The specified array's length must be at "
+                    + "least " + mComponents.length);
+        }
+
+        System.arraycopy(mComponents, 0, components, 0, mComponents.length);
+        return components;
     }
 
     /**
@@ -570,7 +601,7 @@
      *
      * <p>If the requested component index is {@link #getComponentCount()},
      * this method returns the alpha component, always in the range
-     * \([0..1\).</p>
+     * \([0..1]\).</p>
      *
      * @see #getComponents()
      *
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 1f49c1a..406f107 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -21,6 +21,7 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.support.annotation.VisibleForTesting;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -39,6 +40,8 @@
 public class QSFragment extends Fragment implements QS {
     private static final String TAG = "QS";
     private static final boolean DEBUG = false;
+    private static final String EXTRA_EXPANDED = "expanded";
+    private static final String EXTRA_LISTENING = "listening";
 
     private final Rect mQsBounds = new Rect();
     private boolean mQsExpanded;
@@ -85,6 +88,35 @@
 
         mQSCustomizer = view.findViewById(R.id.qs_customize);
         mQSCustomizer.setQs(this);
+        if (savedInstanceState != null) {
+            setExpanded(savedInstanceState.getBoolean(EXTRA_EXPANDED));
+            setListening(savedInstanceState.getBoolean(EXTRA_LISTENING));
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mListening) {
+            setListening(false);
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putBoolean(EXTRA_EXPANDED, mQsExpanded);
+        outState.putBoolean(EXTRA_LISTENING, mListening);
+    }
+
+    @VisibleForTesting
+    boolean isListening() {
+        return mListening;
+    }
+
+    @VisibleForTesting
+    boolean isExpanded() {
+        return mQsExpanded;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index a751ef4..6e2add4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -84,12 +84,14 @@
 
     protected void updateIcon(ImageView iv, State state) {
         if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))) {
+            boolean shouldAnimate = iv.isShown() && mAnimationEnabled
+                    && iv.getDrawable() != null;
             Drawable d = state.icon != null
-                    ? iv.isShown() && mAnimationEnabled ? state.icon.getDrawable(mContext)
+                    ? shouldAnimate ? state.icon.getDrawable(mContext)
                     : state.icon.getInvisibleDrawable(mContext) : null;
             int padding = state.icon != null ? state.icon.getPadding() : 0;
             if (d != null) {
-                d.setAutoMirrored(true);
+                d.setAutoMirrored(false);
             }
             iv.setImageDrawable(d);
             iv.setTag(R.id.qs_icon_tag, state.icon);
@@ -114,7 +116,7 @@
         if (state.state != mState) {
             int color = getColor(state.state);
             mState = state.state;
-            if (iv.isShown()) {
+            if (iv.isShown() && mTint != 0) {
                 animateGrayScale(mTint, color, iv);
                 mTint = color;
             } else {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index d77ed3d..673ffc5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -15,8 +15,11 @@
 package com.android.systemui.qs;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
+import android.app.FragmentController;
+import android.app.FragmentManagerNonConfig;
 import android.os.Looper;
 
 import com.android.internal.logging.MetricsLogger;
@@ -24,6 +27,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 
+import android.os.Parcelable;
 import android.testing.AndroidTestingRunner;
 
 import com.android.systemui.SysuiBaseFragmentTest;
@@ -90,4 +94,23 @@
         host.destroy();
         processAllMessages();
     }
+
+    @Test
+    public void testSaveState() {
+        QSFragment qs = (QSFragment) mFragment;
+
+        mFragments.dispatchResume();
+        processAllMessages();
+
+        qs.setListening(true);
+        qs.setExpanded(true);
+        processAllMessages();
+        recreateFragment();
+        processAllMessages();
+
+        // Get the reference to the new fragment.
+        qs = (QSFragment) mFragment;
+        assertTrue(qs.isListening());
+        assertTrue(qs.isExpanded());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
new file mode 100644
index 0000000..59483f2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs.tileimpl;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import android.service.quicksettings.Tile;
+import android.testing.AndroidTestingRunner;
+import android.testing.UiThreadTest;
+import android.widget.ImageView;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.qs.QSTile.Icon;
+import com.android.systemui.plugins.qs.QSTile.State;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+
+@RunWith(AndroidTestingRunner.class)
+@UiThreadTest
+public class QSIconViewImplTest extends SysuiTestCase {
+
+    private QSIconViewImpl mIconView;
+
+    @Before
+    public void setup() {
+        mIconView = new QSIconViewImpl(mContext);
+    }
+
+    @Test
+    public void testNoFirstAnimation() {
+        ImageView iv = mock(ImageView.class);
+        State s = new State();
+        when(iv.isShown()).thenReturn(true);
+
+        // No current icon, only the static drawable should be used.
+        s.icon = mock(Icon.class);
+        when(iv.getDrawable()).thenReturn(null);
+        mIconView.updateIcon(iv, s);
+        verify(s.icon, never()).getDrawable(any());
+        verify(s.icon).getInvisibleDrawable(any());
+
+        // Has icon, should use the standard (animated) form.
+        s.icon = mock(Icon.class);
+        when(iv.getDrawable()).thenReturn(mock(Drawable.class));
+        mIconView.updateIcon(iv, s);
+        verify(s.icon).getDrawable(any());
+        verify(s.icon, never()).getInvisibleDrawable(any());
+    }
+
+    @Test
+    public void testNoFirstFade() {
+        ImageView iv = mock(ImageView.class);
+        State s = new State();
+        s.state = Tile.STATE_ACTIVE;
+        int desiredColor = mIconView.getColor(s.state);
+        when(iv.isShown()).thenReturn(true);
+
+        mIconView.setIcon(iv, s);
+        verify(iv).setImageTintList(argThat(stateList -> stateList.getColors()[0] == desiredColor));
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 4bd06b7..3703744 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -640,6 +640,18 @@
         final Intent ephemeralIntent = new Intent(intent);
         // Don't modify the client's object!
         intent = new Intent(intent);
+        if (componentSpecified
+                && intent.getData() != null
+                && Intent.ACTION_VIEW.equals(intent.getAction())
+                && intent.hasCategory(Intent.CATEGORY_BROWSABLE)
+                && mService.getPackageManagerInternalLocked()
+                        .isInstantAppInstallerComponent(intent.getComponent())) {
+            // intercept intents targeted directly to the ephemeral installer the
+            // ephemeral installer should never be started with a raw URL; instead
+            // adjust the intent so it looks like a "normal" instant app launch
+            intent.setComponent(null /*component*/);
+            componentSpecified = false;
+        }
 
         ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
         if (rInfo == null) {
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index bbad493..1a27a39 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -907,7 +907,12 @@
                     Bundle finalExtras = new Bundle(extras);
                     String packageName = syncAdapterInfo.componentName.getPackageName();
                     // If the app did not run and has no account access, done
-                    if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
+                    try {
+                        if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
+                            continue;
+                        }
+                    } catch (IllegalArgumentException e) {
+                        // Package not found, race with an uninstall
                         continue;
                     }
                     mAccountManagerInternal.requestAccountAccess(account.account,
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 7f75c83..53a8092 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -772,7 +772,12 @@
     private final class SessionStub extends ISession.Stub {
         @Override
         public void destroy() {
-            mService.destroySession(MediaSessionRecord.this);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mService.destroySession(MediaSessionRecord.this);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8cc9375..621e37b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -842,6 +842,8 @@
 
     /** Component used to install ephemeral applications */
     ComponentName mInstantAppInstallerComponent;
+    /** Component used to show resolver settings for Instant Apps */
+    ComponentName mInstantAppResolverSettingsComponent;
     ActivityInfo mInstantAppInstallerActivity;
     final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
 
@@ -2890,6 +2892,7 @@
                 mInstantAppResolverConnection = null;
             }
             updateInstantAppInstallerLocked();
+            mInstantAppResolverSettingsComponent = getEphemeralResolverSettingsLPr();
 
             // Read and update the usage of dex files.
             // Do this at the end of PM init so that all the packages have their
@@ -3196,6 +3199,37 @@
         }
     }
 
+    private @Nullable ComponentName getEphemeralResolverSettingsLPr() {
+        final Intent intent = new Intent(Intent.ACTION_EPHEMERAL_RESOLVER_SETTINGS);
+        intent.addCategory(Intent.CATEGORY_DEFAULT);
+        final int resolveFlags =
+                MATCH_DIRECT_BOOT_AWARE
+                | MATCH_DIRECT_BOOT_UNAWARE
+                | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
+        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
+                resolveFlags, UserHandle.USER_SYSTEM);
+        Iterator<ResolveInfo> iter = matches.iterator();
+        while (iter.hasNext()) {
+            final ResolveInfo rInfo = iter.next();
+            final PackageSetting ps = mSettings.mPackages.get(rInfo.activityInfo.packageName);
+            if (ps != null) {
+                final PermissionsState permissionsState = ps.getPermissionsState();
+                if (permissionsState.hasPermission(Manifest.permission.ACCESS_INSTANT_APPS, 0)) {
+                    continue;
+                }
+            }
+            iter.remove();
+        }
+        if (matches.size() == 0) {
+            return null;
+        } else if (matches.size() == 1) {
+            return matches.get(0).getComponentInfo().getComponentName();
+        } else {
+            throw new RuntimeException(
+                    "There must be at most one ephemeral resolver settings; found " + matches);
+        }
+    }
+
     private void primeDomainVerificationsLPw(int userId) {
         if (DEBUG_DOMAIN_VERIFICATION) {
             Slog.d(TAG, "Priming domain verifications in user " + userId);
@@ -5788,6 +5822,10 @@
                         return false;
                     }
                     if (ps.getInstantApp(userId)) {
+                        if (DEBUG_EPHEMERAL) {
+                            Slog.v(TAG, "DENY instant app installed;"
+                                    + " pkg: " + packageName);
+                        }
                         return false;
                     }
                 }
@@ -6267,7 +6305,6 @@
                         intent, resolvedType, flags, userId), userId);
                 addEphemeral = !ephemeralDisabled
                         && isEphemeralAllowed(intent, result, userId, false /*skipPackageCheck*/);
-
                 // Check for cross profile results.
                 boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
                 xpResolveInfo = queryCrossProfileIntents(
@@ -6323,7 +6360,7 @@
                 } else {
                     // the caller wants to resolve for a particular package; however, there
                     // were no installed results, so, try to find an ephemeral result
-                    addEphemeral =  !ephemeralDisabled
+                    addEphemeral = !ephemeralDisabled
                             && isEphemeralAllowed(
                                     intent, null /*result*/, userId, true /*skipPackageCheck*/);
                     result = new ArrayList<ResolveInfo>();
@@ -23073,6 +23110,13 @@
         }
 
         @Override
+        public boolean isInstantAppInstallerComponent(ComponentName component) {
+            synchronized (mPackages) {
+                return component != null && component.equals(mInstantAppInstallerComponent);
+            }
+        }
+
+        @Override
         public void pruneInstantApps() {
             synchronized (mPackages) {
                 mInstantAppRegistry.pruneInstantAppsLPw();
@@ -23313,4 +23357,9 @@
         }
         return checkUidPermission(appOpPermission, uid) == PERMISSION_GRANTED;
     }
+
+    @Override
+    public ComponentName getInstantAppResolverSettingsComponent() {
+        return mInstantAppResolverSettingsComponent;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 8f391a7..aa85574 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -175,6 +175,7 @@
     private boolean mTmpRecoveringMemory;
     private boolean mUpdateImeTarget;
     private boolean mTmpInitial;
+    private int mMaxUiWidth;
 
     // Mapping from a token IBinder to a WindowToken object on this display.
     private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap();
@@ -1559,6 +1560,39 @@
         }
     }
 
+    /** Sets the maximum width the screen resolution can be */
+    void setMaxUiWidth(int width) {
+        if (DEBUG_DISPLAY) {
+            Slog.v(TAG_WM, "Setting max ui width:" + width + " on display:" + getDisplayId());
+        }
+
+        mMaxUiWidth = width;
+
+        // Update existing metrics.
+        updateBaseDisplayMetrics(mBaseDisplayWidth, mBaseDisplayHeight, mBaseDisplayDensity);
+    }
+
+    /** Update base (override) display metrics. */
+    void updateBaseDisplayMetrics(int baseWidth, int baseHeight, int baseDensity) {
+        mBaseDisplayWidth = baseWidth;
+        mBaseDisplayHeight = baseHeight;
+        mBaseDisplayDensity = baseDensity;
+
+        if (mMaxUiWidth > 0 && mBaseDisplayWidth > mMaxUiWidth) {
+            mBaseDisplayHeight = (mMaxUiWidth * mBaseDisplayHeight) / mBaseDisplayWidth;
+            mBaseDisplayDensity = (mMaxUiWidth * mBaseDisplayDensity) / mBaseDisplayWidth;
+            mBaseDisplayWidth = mMaxUiWidth;
+
+            if (DEBUG_DISPLAY) {
+                Slog.v(TAG_WM, "Applying config restraints:" + mBaseDisplayWidth + "x"
+                        + mBaseDisplayHeight + " at density:" + mBaseDisplayDensity
+                        + " on display:" + getDisplayId());
+            }
+        }
+
+        mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
+    }
+
     void getContentRect(Rect out) {
         out.set(mContentRect);
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index fa9c2a7..0dc74d7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -385,6 +385,7 @@
     final boolean mAllowBootMessages;
 
     final boolean mLimitedAlphaCompositing;
+    final int mMaxUiWidth;
 
     final WindowManagerPolicy mPolicy;
 
@@ -949,6 +950,8 @@
                 com.android.internal.R.integer.config_drawLockTimeoutMillis);
         mAllowAnimationsInLowPowerMode = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowAnimationsInLowPowerMode);
+        mMaxUiWidth = context.getResources().getInteger(
+                com.android.internal.R.integer.config_maxUiWidth);
         mInputManager = inputManager; // Must be before createDisplayContentLocked.
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
         mDisplaySettings = new DisplaySettings();
@@ -4572,6 +4575,9 @@
 
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDefaultDisplayContentLocked();
+            if (mMaxUiWidth > 0) {
+                displayContent.setMaxUiWidth(mMaxUiWidth);
+            }
             readForcedDisplayPropertiesLocked(displayContent);
             mDisplayReady = true;
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
index 9b4de043..70c7e58 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
@@ -26,6 +26,7 @@
 import android.os.Message;
 import android.os.SystemClock;
 import android.util.Log;
+import android.util.LongSparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -44,12 +45,21 @@
 
     // If this value changes, update DevicePolicyManager#retrieveNetworkLogs() javadoc
     private static final int MAX_EVENTS_PER_BATCH = 1200;
-    private static final long BATCH_FINALIZATION_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(90);
-    private static final long BATCH_FINALIZATION_TIMEOUT_ALARM_INTERVAL_MS =
-            TimeUnit.MINUTES.toMillis(30);
+
+    /**
+     * Maximum number of batches to store in memory. If more batches are generated and the DO
+     * doesn't fetch them, we will discard the oldest one.
+     */
+    private static final int MAX_BATCHES = 5;
+
+    private static final long BATCH_FINALIZATION_TIMEOUT_MS = 90 * 60 * 1000; // 1.5h
+    private static final long BATCH_FINALIZATION_TIMEOUT_ALARM_INTERVAL_MS = 30 * 60 * 1000; // 30m
 
     private static final String NETWORK_LOGGING_TIMEOUT_ALARM_TAG = "NetworkLogging.batchTimeout";
 
+    /** Delay after which older batches get discarded after a retrieval. */
+    private static final long RETRIEVED_BATCH_DISCARD_DELAY_MS = 5 * 60 * 1000; // 5m
+
     private final DevicePolicyManagerService mDpm;
     private final AlarmManager mAlarmManager;
 
@@ -66,22 +76,27 @@
 
     static final int LOG_NETWORK_EVENT_MSG = 1;
 
-    // threadsafe as it's Handler's thread confined
+    /** Network events accumulated so far to be finalized into a batch at some point. */
     @GuardedBy("this")
-    private ArrayList<NetworkEvent> mNetworkEvents = new ArrayList<NetworkEvent>();
+    private ArrayList<NetworkEvent> mNetworkEvents = new ArrayList<>();
 
+    /**
+     * Up to {@code MAX_BATCHES} finalized batches of logs ready to be retrieved by the DO. Already
+     * retrieved batches are discarded after {@code RETRIEVED_BATCH_DISCARD_DELAY_MS}.
+     */
     @GuardedBy("this")
-    private ArrayList<NetworkEvent> mFullBatch;
+    private final LongSparseArray<ArrayList<NetworkEvent>> mBatches =
+            new LongSparseArray<>(MAX_BATCHES);
 
     @GuardedBy("this")
     private boolean mPaused = false;
 
     // each full batch is represented by its token, which the DPC has to provide back to retrieve it
     @GuardedBy("this")
-    private long mCurrentFullBatchToken;
+    private long mCurrentBatchToken;
 
     @GuardedBy("this")
-    private long mLastRetrievedFullBatchToken;
+    private long mLastRetrievedBatchToken;
 
     NetworkLoggingHandler(Looper looper, DevicePolicyManagerService dpm) {
         super(looper);
@@ -93,7 +108,7 @@
     public void handleMessage(Message msg) {
         switch (msg.what) {
             case LOG_NETWORK_EVENT_MSG: {
-                NetworkEvent networkEvent = msg.getData().getParcelable(NETWORK_EVENT_KEY);
+                final NetworkEvent networkEvent = msg.getData().getParcelable(NETWORK_EVENT_KEY);
                 if (networkEvent != null) {
                     synchronized (NetworkLoggingHandler.this) {
                         mNetworkEvents.add(networkEvent);
@@ -113,6 +128,8 @@
 
     void scheduleBatchFinalization() {
         final long when = SystemClock.elapsedRealtime() + BATCH_FINALIZATION_TIMEOUT_MS;
+        // We use alarm manager and not just postDelayed here to ensure the batch gets finalized
+        // even if the device goes to sleep.
         mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, when,
                 BATCH_FINALIZATION_TIMEOUT_ALARM_INTERVAL_MS, NETWORK_LOGGING_TIMEOUT_ALARM_TAG,
                 mBatchTimeoutAlarmListener, this);
@@ -131,62 +148,80 @@
             return;
         }
 
-        Log.d(TAG, "Resumed network logging. Current batch="
-                + mCurrentFullBatchToken + ", LastRetrievedBatch=" + mLastRetrievedFullBatchToken);
+        Log.d(TAG, "Resumed network logging. Current batch=" + mCurrentBatchToken
+                + ", LastRetrievedBatch=" + mLastRetrievedBatchToken);
         mPaused = false;
 
-        // If there is a full batch ready that the device owner hasn't been notified about, do it
-        // now.
-        if (mFullBatch != null && mFullBatch.size() > 0
-                && mLastRetrievedFullBatchToken != mCurrentFullBatchToken) {
+        // If there is a batch ready that the device owner hasn't been notified about, do it now.
+        if (mBatches.size() > 0 && mLastRetrievedBatchToken != mCurrentBatchToken) {
             scheduleBatchFinalization();
             notifyDeviceOwnerLocked();
         }
     }
 
     synchronized void discardLogs() {
-        mFullBatch = null;
-        mNetworkEvents = new ArrayList<NetworkEvent>();
+        mBatches.clear();
+        mNetworkEvents = new ArrayList<>();
         Log.d(TAG, "Discarded all network logs");
     }
 
     @GuardedBy("this")
     private void finalizeBatchAndNotifyDeviceOwnerLocked() {
         if (mNetworkEvents.size() > 0) {
-            // finalize the batch and start a new one from scratch
-            mFullBatch = mNetworkEvents;
-            mCurrentFullBatchToken++;
-            mNetworkEvents = new ArrayList<NetworkEvent>();
+            // Finalize the batch and start a new one from scratch.
+            if (mBatches.size() >= MAX_BATCHES) {
+                // Remove the oldest batch if we hit the limit.
+                mBatches.removeAt(0);
+            }
+            mCurrentBatchToken++;
+            mBatches.append(mCurrentBatchToken, mNetworkEvents);
+            mNetworkEvents = new ArrayList<>();
             if (!mPaused) {
                 notifyDeviceOwnerLocked();
             }
         } else {
-            // don't notify the DO, since there are no events; DPC can still retrieve
+            // Don't notify the DO, since there are no events; DPC can still retrieve
             // the last full batch if not paused.
             Log.d(TAG, "Was about to finalize the batch, but there were no events to send to"
-                    + " the DPC, the batchToken of last available batch: "
-                    + mCurrentFullBatchToken);
+                    + " the DPC, the batchToken of last available batch: " + mCurrentBatchToken);
         }
-        // regardless of whether the batch was non-empty schedule a new finalization after timeout
+        // Regardless of whether the batch was non-empty schedule a new finalization after timeout.
         scheduleBatchFinalization();
     }
 
+    /** Sends a notification to the DO. Should only be called when there is a batch available. */
     @GuardedBy("this")
     private void notifyDeviceOwnerLocked() {
-        Bundle extras = new Bundle();
-        extras.putLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, mCurrentFullBatchToken);
-        extras.putInt(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_COUNT, mFullBatch.size());
+        final Bundle extras = new Bundle();
+        final int lastBatchSize = mBatches.valueAt(mBatches.size() - 1).size();
+        extras.putLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, mCurrentBatchToken);
+        extras.putInt(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_COUNT, lastBatchSize);
         Log.d(TAG, "Sending network logging batch broadcast to device owner, batchToken: "
-                + mCurrentFullBatchToken);
+                + mCurrentBatchToken);
         mDpm.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE, extras);
     }
 
-    synchronized List<NetworkEvent> retrieveFullLogBatch(long batchToken) {
-        if (batchToken != mCurrentFullBatchToken) {
+    synchronized List<NetworkEvent> retrieveFullLogBatch(final long batchToken) {
+        final int index = mBatches.indexOfKey(batchToken);
+        if (index < 0) {
+            // Invalid token or batch has already been discarded.
             return null;
         }
-        mLastRetrievedFullBatchToken = mCurrentFullBatchToken;
-        return mFullBatch;
+
+        // Schedule this and older batches to be discarded after a delay to lessen memory load
+        // without interfering with the admin's ability to collect logs out-of-order.
+        // It isn't critical and we allow it to be delayed further if the phone sleeps, so we don't
+        // use the alarm manager here.
+        postDelayed(() -> {
+            synchronized(this) {
+                while (mBatches.size() > 0 && mBatches.keyAt(0) <= batchToken) {
+                    mBatches.removeAt(0);
+                }
+            }
+        }, RETRIEVED_BATCH_DISCARD_DELAY_MS);
+
+        mLastRetrievedBatchToken = batchToken;
+        return mBatches.valueAt(index);
     }
 }
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index dd94a21..1729cee 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -254,6 +254,48 @@
         assertEquals(window1, sWm.mRoot.computeFocusedWindow());
     }
 
+    /**
+     * This tests setting the maximum ui width on a display.
+     */
+    @Test
+    public void testMaxUiWidth() throws Exception {
+        final int baseWidth = 1440;
+        final int baseHeight = 2560;
+        final int baseDensity = 300;
+
+        sDisplayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
+
+        final int maxWidth = 300;
+        final int resultingHeight = (maxWidth * baseHeight) / baseWidth;
+        final int resultingDensity = (maxWidth * baseDensity) / baseWidth;
+
+        sDisplayContent.setMaxUiWidth(maxWidth);
+        verifySizes(sDisplayContent, maxWidth, resultingHeight, resultingDensity);
+
+        // Assert setting values again does not change;
+        sDisplayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
+        verifySizes(sDisplayContent, maxWidth, resultingHeight, resultingDensity);
+
+        final int smallerWidth = 200;
+        final int smallerHeight = 400;
+        final int smallerDensity = 100;
+
+        // Specify smaller dimension, verify that it is honored
+        sDisplayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity);
+        verifySizes(sDisplayContent, smallerWidth, smallerHeight, smallerDensity);
+
+        // Verify that setting the max width to a greater value than the base width has no effect
+        sDisplayContent.setMaxUiWidth(maxWidth);
+        verifySizes(sDisplayContent, smallerWidth, smallerHeight, smallerDensity);
+    }
+
+    private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
+                             int expectedBaseHeight, int expectedBaseDensity) {
+        assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
+        assertEquals(displayContent.mBaseDisplayHeight, expectedBaseHeight);
+        assertEquals(displayContent.mBaseDisplayDensity, expectedBaseDensity);
+    }
+
     private void assertForAllWindowsOrder(List<WindowState> expectedWindows) {
         final LinkedList<WindowState> actualWindows = new LinkedList();
 
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index f1cf441..d69f933 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -554,7 +554,7 @@
                 boolean usbDataUnlocked) {
             if (DEBUG) {
                 Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
-                        + "forceRestart=" + forceRestart);
+                        + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked);
             }
 
             if (usbDataUnlocked != mUsbDataUnlocked) {
@@ -878,7 +878,12 @@
                     setEnabledFunctions(functions, false, msg.arg1 == 1);
                     break;
                 case MSG_UPDATE_USER_RESTRICTIONS:
-                    setEnabledFunctions(mCurrentFunctions, false, mUsbDataUnlocked);
+                    // Restart the USB stack if USB transfer is enabled but no longer allowed.
+                    final boolean forceRestart = mUsbDataUnlocked
+                            && isUsbDataTransferActive()
+                            && !isUsbTransferAllowed();
+                    setEnabledFunctions(
+                            mCurrentFunctions, forceRestart, mUsbDataUnlocked && !forceRestart);
                     break;
                 case MSG_SYSTEM_READY:
                     updateUsbNotification();
@@ -902,12 +907,10 @@
                 case MSG_USER_SWITCHED: {
                     if (mCurrentUser != msg.arg1) {
                         // Restart the USB stack and re-apply user restrictions for MTP or PTP.
-                        final boolean active = UsbManager.containsFunction(mCurrentFunctions,
-                                UsbManager.USB_FUNCTION_MTP)
-                                || UsbManager.containsFunction(mCurrentFunctions,
-                                UsbManager.USB_FUNCTION_PTP);
-                        if (mUsbDataUnlocked && active && mCurrentUser != UserHandle.USER_NULL) {
-                            Slog.v(TAG, "Current user switched to " + mCurrentUser
+                        if (mUsbDataUnlocked
+                                && isUsbDataTransferActive()
+                                && mCurrentUser != UserHandle.USER_NULL) {
+                            Slog.v(TAG, "Current user switched to " + msg.arg1
                                     + "; resetting USB host stack for MTP or PTP");
                             // avoid leaking sensitive data from previous user
                             setEnabledFunctions(mCurrentFunctions, true, false);
@@ -928,6 +931,11 @@
             }
         }
 
+        private boolean isUsbDataTransferActive() {
+            return UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)
+                    || UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP);
+        }
+
         public UsbAccessory getCurrentAccessory() {
             return mCurrentAccessory;
         }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 506f406..960a2d9 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -1118,4 +1118,12 @@
     public int getInstallReason(String packageName, UserHandle user) {
         throw new UnsupportedOperationException();
     }
+
+    /**
+     * @hide
+     */
+    @Override
+    public ComponentName getInstantAppResolverSettingsComponent() {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/tests/testables/src/android/testing/BaseFragmentTest.java b/tests/testables/src/android/testing/BaseFragmentTest.java
index 53841d5..b09bcde 100644
--- a/tests/testables/src/android/testing/BaseFragmentTest.java
+++ b/tests/testables/src/android/testing/BaseFragmentTest.java
@@ -133,14 +133,7 @@
     public void testRecreate() {
         mFragments.dispatchResume();
         processAllMessages();
-        mFragments.dispatchPause();
-        Parcelable p = mFragments.saveAllState();
-        mFragments.dispatchDestroy();
-
-        mFragments = FragmentController.createController(new HostCallbacks());
-        mFragments.attachHost(null);
-        mFragments.restoreAllState(p, (FragmentManagerNonConfig) null);
-        mFragments.dispatchResume();
+        recreateFragment();
         processAllMessages();
     }
 
@@ -154,6 +147,18 @@
         processAllMessages();
     }
 
+    protected void recreateFragment() {
+        mFragments.dispatchPause();
+        Parcelable p = mFragments.saveAllState();
+        mFragments.dispatchDestroy();
+
+        mFragments = FragmentController.createController(new HostCallbacks());
+        mFragments.attachHost(null);
+        mFragments.restoreAllState(p, (FragmentManagerNonConfig) null);
+        mFragments.dispatchResume();
+        mFragment = mFragments.getFragmentManager().findFragmentById(VIEW_ID);
+    }
+
     protected void attachFragmentToWindow() {
         ViewUtils.attachView(mView);
         TestableLooper.get(this).processMessages(1);
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 3330b1a..2bf5206 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1403,7 +1403,8 @@
             String8 src = it.getFile()->getPrintableSource();
             err = compileXmlFile(bundle, assets, String16(it.getBaseName()),
                     it.getFile(), &table, xmlFlags);
-            if (err == NO_ERROR) {
+            // Only verify IDs if there was no error and the file is non-empty.
+            if (err == NO_ERROR && it.getFile()->hasData()) {
                 ResXMLTree block;
                 block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true);
                 checkForIds(src, block);
@@ -1550,7 +1551,7 @@
             String8 src = it.getFile()->getPrintableSource();
             err = compileXmlFile(bundle, assets, String16(it.getBaseName()),
                     it.getFile(), &table, xmlFlags);
-            if (err == NO_ERROR) {
+            if (err == NO_ERROR && it.getFile()->hasData()) {
                 ResXMLTree block;
                 block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true);
                 checkForIds(src, block);
@@ -1598,7 +1599,7 @@
         err = compileXmlFile(bundle, assets, workItem.resourceName, workItem.xmlRoot,
                              workItem.file, &table, xmlCompilationFlags);
 
-        if (err == NO_ERROR) {
+        if (err == NO_ERROR && workItem.file->hasData()) {
             assets->addResource(workItem.resPath.getPathLeaf(),
                                 workItem.resPath,
                                 workItem.file,
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 391aa47..221f3c2 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -78,6 +78,17 @@
                         ResourceTable* table,
                         int options)
 {
+    if (table->versionForCompat(bundle, resourceName, target, root)) {
+        // The file was versioned, so stop processing here.
+        // The resource entry has already been removed and the new one added.
+        // Remove the assets entry.
+        sp<AaptDir> resDir = assets->getDirs().valueFor(String8("res"));
+        sp<AaptDir> dir = resDir->getDirs().valueFor(target->getGroupEntry().toDirName(
+                target->getResourceType()));
+        dir->removeFile(target->getPath().getPathLeaf());
+        return NO_ERROR;
+    }
+
     if ((options&XML_COMPILE_STRIP_WHITESPACE) != 0) {
         root->removeWhitespace(true, NULL);
     } else  if ((options&XML_COMPILE_COMPACT_WHITESPACE) != 0) {
@@ -4758,6 +4769,77 @@
     return false;
 }
 
+bool ResourceTable::versionForCompat(const Bundle* bundle, const String16& resourceName,
+                                         const sp<AaptFile>& target, const sp<XMLNode>& root) {
+    XMLNode* node = root.get();
+    while (node->getType() != XMLNode::TYPE_ELEMENT) {
+        // We're assuming the root element is what we're looking for, which can only be under a
+        // bunch of namespace declarations.
+        if (node->getChildren().size() != 1) {
+          // Not sure what to do, bail.
+          return false;
+        }
+        node = node->getChildren().itemAt(0).get();
+    }
+
+    if (node->getElementNamespace().size() != 0) {
+        // Not something we care about.
+        return false;
+    }
+
+    int versionedSdk = 0;
+    if (node->getElementName() == String16("adaptive-icon")) {
+        versionedSdk = SDK_O;
+    }
+
+    const int minSdkVersion = getMinSdkVersion(bundle);
+    const ConfigDescription config(target->getGroupEntry().toParams());
+    if (versionedSdk <= minSdkVersion || versionedSdk <= config.sdkVersion) {
+        return false;
+    }
+
+    sp<ConfigList> cl = getConfigList(String16(mAssets->getPackage()),
+            String16(target->getResourceType()), resourceName);
+    if (!shouldGenerateVersionedResource(cl, config, versionedSdk)) {
+        return false;
+    }
+
+    // Remove the original entry.
+    cl->removeEntry(config);
+
+    // We need to wholesale version this file.
+    ConfigDescription newConfig(config);
+    newConfig.sdkVersion = versionedSdk;
+    sp<AaptFile> newFile = new AaptFile(target->getSourceFile(),
+            AaptGroupEntry(newConfig), target->getResourceType());
+    String8 resPath = String8::format("res/%s/%s.xml",
+            newFile->getGroupEntry().toDirName(target->getResourceType()).string(),
+            String8(resourceName).string());
+    resPath.convertToResPath();
+
+    // Add a resource table entry.
+    addEntry(SourcePos(),
+            String16(mAssets->getPackage()),
+            String16(target->getResourceType()),
+            resourceName,
+            String16(resPath),
+            NULL,
+            &newConfig);
+
+    // Schedule this to be compiled.
+    CompileResourceWorkItem item;
+    item.resourceName = resourceName;
+    item.resPath = resPath;
+    item.file = newFile;
+    item.xmlRoot = root->clone();
+    item.needsCompiling = false;    // This step occurs after we parse/assign, so we don't need
+                                    // to do it again.
+    mWorkQueue.push(item);
+
+    // Now mark the old entry as deleted.
+    return true;
+}
+
 status_t ResourceTable::modifyForCompat(const Bundle* bundle,
                                         const String16& resourceName,
                                         const sp<AaptFile>& target,
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index cf1e992..aff22d4 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -203,6 +203,9 @@
     size_t numLocalResources() const;
     bool hasResources() const;
 
+    bool versionForCompat(const Bundle* bundle, const String16& resourceName,
+                          const sp<AaptFile>& file, const sp<XMLNode>& root);
+
     status_t modifyForCompat(const Bundle* bundle);
     status_t modifyForCompat(const Bundle* bundle,
                              const String16& resourceName,
@@ -431,6 +434,10 @@
             mEntries.add(config, entry);
         }
         
+        void removeEntry(const ResTable_config& config) {
+            mEntries.removeItem(config);
+        }
+
         const DefaultKeyedVector<ConfigDescription, sp<Entry> >& getEntries() const { return mEntries; }
     private:
         const String16 mName;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index 906ebb1..53c3f90 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -916,4 +916,9 @@
     public boolean canRequestPackageInstalls() {
         return false;
     }
+
+    @Override
+    public ComponentName getInstantAppResolverSettingsComponent() {
+        return null;
+    }
 }
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 10ffd8a..1852feb 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -81,8 +81,6 @@
 
     boolean disableNetwork(int netId);
 
-    boolean pingSupplicant();
-
     void startScan(in ScanSettings requested, in WorkSource ws);
 
     List<ScanResult> getScanResults(String callingPackage);