Merge "Extend Location setting to show location usage within 24 hours." into pi-dev
diff --git a/api/system-current.txt b/api/system-current.txt
index e54d2f6..20f0ba8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3663,6 +3663,7 @@
   }
 
   public final class ConfigUpdate {
+    field public static final java.lang.String ACTION_UPDATE_CARRIER_ID_DB = "android.os.action.UPDATE_CARRIER_ID_DB";
     field public static final java.lang.String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
     field public static final java.lang.String ACTION_UPDATE_CT_LOGS = "android.intent.action.UPDATE_CT_LOGS";
     field public static final java.lang.String ACTION_UPDATE_INTENT_FIREWALL = "android.intent.action.UPDATE_INTENT_FIREWALL";
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index 6676196..2fc5808 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -46,6 +46,8 @@
 import java.util.List;
 
 public class Media extends BaseCommand {
+    // This doesn't belongs to any package. Setting the package name to empty string.
+    private static final String PACKAGE_NAME = "";
     private ISessionManager mSessionService;
 
     /**
@@ -104,7 +106,7 @@
 
     private void sendMediaKey(KeyEvent event) {
         try {
-            mSessionService.dispatchMediaKeyEvent(event, false);
+            mSessionService.dispatchMediaKeyEvent(PACKAGE_NAME, false, event, false);
         } catch (RemoteException e) {
         }
     }
@@ -264,13 +266,13 @@
                     } else if ("q".equals(line) || "quit".equals(line)) {
                         break;
                     } else if ("play".equals(line)) {
-                        mController.play("");
+                        mController.play(PACKAGE_NAME);
                     } else if ("pause".equals(line)) {
-                        mController.pause("");
+                        mController.pause(PACKAGE_NAME);
                     } else if ("next".equals(line)) {
-                        mController.next("");
+                        mController.next(PACKAGE_NAME);
                     } else if ("previous".equals(line)) {
-                        mController.previous("");
+                        mController.previous(PACKAGE_NAME);
                     } else {
                         System.out.println("Invalid command: " + line);
                     }
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index daafe9c..8487e67 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -503,7 +503,8 @@
 void StatsLogProcessor::WriteDataToDiskLocked(const ConfigKey& key,
                                               const int64_t timestampNs,
                                               const DumpReportReason dumpReportReason) {
-    if (mMetricsManagers.find(key) == mMetricsManagers.end()) {
+    if (mMetricsManagers.find(key) == mMetricsManagers.end() ||
+        !mMetricsManagers.find(key)->second->shouldWriteToDisk()) {
         return;
     }
     ProtoOutputStream proto;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index a940d58..55dde10 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -186,7 +186,6 @@
         flushIfNeededLocked(dumpTimeNs);
     }
 
-    flushIfNeededLocked(dumpTimeNs);
     if (mPastBuckets.empty()) {
         return;
     }
@@ -324,6 +323,10 @@
             triggerPuller = true;
             break;
         }
+        case GaugeMetric::CONDITION_CHANGE_TO_TRUE: {
+            triggerPuller = mCondition;
+            break;
+        }
         default:
             break;
     }
@@ -348,7 +351,7 @@
     flushIfNeededLocked(eventTimeNs);
     mCondition = conditionMet;
 
-    if (mPullTagId != -1 && mCondition) {
+    if (mPullTagId != -1) {
         pullLocked(eventTimeNs);
     }  // else: Push mode. No need to proactively pull the gauge data.
 }
@@ -538,7 +541,14 @@
 size_t GaugeMetricProducer::byteSizeLocked() const {
     size_t totalSize = 0;
     for (const auto& pair : mPastBuckets) {
-        totalSize += pair.second.size() * kBucketSize;
+        for (const auto& bucket : pair.second) {
+            totalSize += bucket.mGaugeAtoms.size() * sizeof(GaugeAtom);
+            for (const auto& atom : bucket.mGaugeAtoms) {
+                if (atom.mFields != nullptr) {
+                    totalSize += atom.mFields->size() * sizeof(FieldValue);
+                }
+            }
+        }
     }
     return totalSize;
 }
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 456da98..e143b5a 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -67,6 +67,10 @@
         return !mAllowedPkg.empty();
     }
 
+    bool shouldWriteToDisk() const {
+        return mNoReportMetricIds.size() != mAllMetricProducers.size();
+    }
+
     void dumpStates(FILE* out, bool verbose);
 
     inline bool isInTtl(const int64_t timestampNs) const {
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index fd36560..9b5d72b 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -234,6 +234,7 @@
   enum SamplingType {
     RANDOM_ONE_SAMPLE = 1;
     ALL_CONDITION_CHANGES = 2;
+    CONDITION_CHANGE_TO_TRUE = 3;
   }
   optional SamplingType sampling_type = 9 [default = RANDOM_ONE_SAMPLE] ;
 
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index 6a69100..7c07366 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -66,6 +66,7 @@
         baseTimeNs, configAddedTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    processor->mStatsPullerManager.ForceClearPullerCache();
 
     int startBucketNum = processor->mMetricsManagers.begin()->second->
             mAllMetricProducers[0]->getCurrentBucketNum();
@@ -211,6 +212,7 @@
         baseTimeNs, configAddedTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    processor->mStatsPullerManager.ForceClearPullerCache();
 
     int startBucketNum = processor->mMetricsManagers.begin()->second->
             mAllMetricProducers[0]->getCurrentBucketNum();
@@ -311,6 +313,7 @@
         baseTimeNs, configAddedTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    processor->mStatsPullerManager.ForceClearPullerCache();
 
     int startBucketNum = processor->mMetricsManagers.begin()->second->
             mAllMetricProducers[0]->getCurrentBucketNum();
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index 98a312f..febc958 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -66,6 +66,7 @@
         baseTimeNs, configAddedTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    processor->mStatsPullerManager.ForceClearPullerCache();
 
     int startBucketNum = processor->mMetricsManagers.begin()->second->
             mAllMetricProducers[0]->getCurrentBucketNum();
@@ -172,6 +173,7 @@
         baseTimeNs, configAddedTimeNs, config, cfgKey);
     EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    processor->mStatsPullerManager.ForceClearPullerCache();
 
     int startBucketNum = processor->mMetricsManagers.begin()->second->
             mAllMetricProducers[0]->getCurrentBucketNum();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 07048f9..21a3c07 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -118,6 +118,13 @@
      */
     public static final int MODE_FOREGROUND = 4;
 
+    /**
+     * Flag for {@link #startWatchingMode(String, String, int, OnOpChangedListener)}:
+     * Also get reports if the foreground state of an op's uid changes.  This only works
+     * when watching a particular op, not when watching a package.
+     * @hide
+     */
+    public static final int WATCH_FOREGROUND_CHANGES = 1 << 0;
 
     /**
      * @hide
@@ -1900,6 +1907,21 @@
 
     /**
      * Monitor for changes to the operating mode for the given op in the given app package.
+     * You can watch op changes only for your UID.
+     *
+     * @param op The operation to monitor, one of OPSTR_*.
+     * @param packageName The name of the application to monitor.
+     * @param flags Option flags: any combination of {@link #WATCH_FOREGROUND_CHANGES} or 0.
+     * @param callback Where to report changes.
+     * @hide
+     */
+    public void startWatchingMode(String op, String packageName, int flags,
+            final OnOpChangedListener callback) {
+        startWatchingMode(strOpToOp(op), packageName, flags, callback);
+    }
+
+    /**
+     * Monitor for changes to the operating mode for the given op in the given app package.
      *
      * <p> If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission
      * you can watch changes only for your UID.
@@ -1911,6 +1933,24 @@
      */
     @RequiresPermission(value=android.Manifest.permission.WATCH_APPOPS, conditional=true)
     public void startWatchingMode(int op, String packageName, final OnOpChangedListener callback) {
+        startWatchingMode(op, packageName, 0, callback);
+    }
+
+    /**
+     * Monitor for changes to the operating mode for the given op in the given app package.
+     *
+     * <p> If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission
+     * you can watch changes only for your UID.
+     *
+     * @param op The operation to monitor, one of OP_*.
+     * @param packageName The name of the application to monitor.
+     * @param flags Option flags: any combination of {@link #WATCH_FOREGROUND_CHANGES} or 0.
+     * @param callback Where to report changes.
+     * @hide
+     */
+    @RequiresPermission(value=android.Manifest.permission.WATCH_APPOPS, conditional=true)
+    public void startWatchingMode(int op, String packageName, int flags,
+            final OnOpChangedListener callback) {
         synchronized (mModeWatchers) {
             IAppOpsCallback cb = mModeWatchers.get(callback);
             if (cb == null) {
@@ -1927,7 +1967,7 @@
                 mModeWatchers.put(callback, cb);
             }
             try {
-                mService.startWatchingMode(op, packageName, cb);
+                mService.startWatchingModeWithFlags(op, packageName, flags, cb);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -2080,6 +2120,19 @@
     }
 
     /**
+     * Like {@link #checkOp} but returns the <em>raw</em> mode associated with the op.
+     * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}.
+     * @hide
+     */
+    public int unsafeCheckOpRaw(String op, int uid, String packageName) {
+        try {
+            return mService.checkOperation(strOpToOp(op), uid, packageName);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Make note of an application performing an operation.  Note that you must pass
      * in both the uid and name of the application to be checked; this function will verify
      * that these two match, and if not, return {@link #MODE_IGNORED}.  If this call
@@ -2217,7 +2270,8 @@
      */
     public int checkOpNoThrow(int op, int uid, String packageName) {
         try {
-            return mService.checkOperation(op, uid, packageName);
+            int mode = mService.checkOperation(op, uid, packageName);
+            return mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : mode;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 4b84ed4..ca3257f 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -736,7 +736,13 @@
         }
 
         if (!libPaths.isEmpty() && SystemProperties.getBoolean(PROPERTY_NAME_APPEND_NATIVE, true)) {
-            ApplicationLoaders.getDefault().addNative(mClassLoader, libPaths);
+            // Temporarily disable logging of disk reads on the Looper thread as this is necessary
+            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+            try {
+                ApplicationLoaders.getDefault().addNative(mClassLoader, libPaths);
+            } finally {
+                StrictMode.setThreadPolicy(oldPolicy);
+            }
         }
 
         if (addedPaths != null && addedPaths.size() > 0) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 327d4fe..f771cbd 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -7015,7 +7015,12 @@
             contentView.setViewLayoutMarginEnd(R.id.notification_messaging,
                     bindResult.getIconMarginEnd());
             contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
-                    mBuilder.resolveContrastColor());
+                    mBuilder.isColorized() ? mBuilder.getPrimaryTextColor()
+                            : mBuilder.resolveContrastColor());
+            contentView.setInt(R.id.status_bar_latest_event_content, "setSenderTextColor",
+                    mBuilder.getPrimaryTextColor());
+            contentView.setInt(R.id.status_bar_latest_event_content, "setMessageTextColor",
+                    mBuilder.getSecondaryTextColor());
             contentView.setBoolean(R.id.status_bar_latest_event_content, "setDisplayImagesAtEnd",
                     displayImagesAtEnd);
             contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index dec2cd4..fe48975 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5683,9 +5683,24 @@
 
 
     /**
-     * If set, resolution of this intent may take place via an instant app not
-     * yet on the device if there does not yet exist an app on device to
-     * resolve it.
+     * If set in an Intent passed to {@link Context#startActivity Context.startActivity()},
+     * this flag will attempt to launch an instant app if no full app on the device can already
+     * handle the intent.
+     * <p>
+     * When attempting to resolve instant apps externally, the following {@link Intent} properties
+     * are supported:
+     * <ul>
+     *     <li>{@link Intent#setAction(String)}</li>
+     *     <li>{@link Intent#addCategory(String)}</li>
+     *     <li>{@link Intent#setData(Uri)}</li>
+     *     <li>{@link Intent#setType(String)}</li>
+     *     <li>{@link Intent#setPackage(String)}</li>
+     *     <li>{@link Intent#addFlags(int)}</li>
+     * </ul>
+     * <p>
+     * In the case that no instant app can be found, the installer will be launched to notify the
+     * user that the intent could not be resolved. On devices that do not support instant apps,
+     * the flag will be ignored.
      */
     public static final int FLAG_ACTIVITY_MATCH_EXTERNAL = 0x00000800;
 
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 07fbfb5..52e28a4 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -16,6 +16,10 @@
 
 package android.content.pm;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.FloatRange;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.res.XmlResourceParser;
@@ -29,7 +33,11 @@
 import android.util.Printer;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
 import java.text.Collator;
+import java.util.BitSet;
 import java.util.Comparator;
 
 /**
@@ -42,6 +50,47 @@
  * in the implementation of Parcelable in subclasses.
  */
 public class PackageItemInfo {
+    private static final int LINE_FEED_CODE_POINT = 10;
+    private static final int NBSP_CODE_POINT = 160;
+
+    /**
+     * Flags for {@link #loadSafeLabel(PackageManager, float, int)}
+     *
+     * @hide
+     */
+    @Retention(SOURCE)
+    @IntDef(flag = true, prefix = "SAFE_LABEL_FLAG_",
+            value = {SAFE_LABEL_FLAG_TRIM, SAFE_LABEL_FLAG_SINGLE_LINE,
+                    SAFE_LABEL_FLAG_FIRST_LINE})
+    public @interface SafeLabelFlags {}
+
+    /**
+     * Remove {@link Character#isWhitespace(int) whitespace} and non-breaking spaces from the edges
+     * of the label.
+     *
+     * @see #loadSafeLabel(PackageManager, float, int)
+     * @hide
+     */
+    public static final int SAFE_LABEL_FLAG_TRIM = 0x1;
+
+    /**
+     * Force entire string into single line of text (no newlines). Cannot be set at the same time as
+     * {@link #SAFE_LABEL_FLAG_FIRST_LINE}.
+     *
+     * @see #loadSafeLabel(PackageManager, float, int)
+     * @hide
+     */
+    public static final int SAFE_LABEL_FLAG_SINGLE_LINE = 0x2;
+
+    /**
+     * Return only first line of text (truncate at first newline). Cannot be set at the same time as
+     * {@link #SAFE_LABEL_FLAG_SINGLE_LINE}.
+     *
+     * @see #loadSafeLabel(PackageManager, float, int)
+     * @hide
+     */
+    public static final int SAFE_LABEL_FLAG_FIRST_LINE = 0x4;
+
     private static final float MAX_LABEL_SIZE_PX = 500f;
     /** The maximum length of a safe label, in characters */
     private static final int MAX_SAFE_LABEL_LENGTH = 50000;
@@ -164,18 +213,7 @@
     }
 
     /**
-     * Same as {@link #loadLabel(PackageManager)} with the addition that
-     * the returned label is safe for being presented in the UI since it
-     * will not contain new lines and the length will be limited to a
-     * reasonable amount. This prevents a malicious party to influence UI
-     * layout via the app label misleading the user into performing a
-     * detrimental for them action. If the label is too long it will be
-     * truncated and ellipsized at the end.
-     *
-     * @param pm A PackageManager from which the label can be loaded; usually
-     * the PackageManager from which you originally retrieved this item
-     * @return Returns a CharSequence containing the item's label. If the
-     * item does not have a label, its name is returned.
+     * Deprecated use loadSafeLabel(PackageManager, float, int) instead
      *
      * @hide
      */
@@ -225,6 +263,216 @@
                 TextUtils.TruncateAt.END);
     }
 
+    private static boolean isNewline(int codePoint) {
+        int type = Character.getType(codePoint);
+        return type == Character.PARAGRAPH_SEPARATOR || type == Character.LINE_SEPARATOR
+                || codePoint == LINE_FEED_CODE_POINT;
+    }
+
+    private static boolean isWhiteSpace(int codePoint) {
+        return Character.isWhitespace(codePoint) || codePoint == NBSP_CODE_POINT;
+    }
+
+    /**
+     * A special string manipulation class. Just records removals and executes the when onString()
+     * is called.
+     */
+    private static class StringWithRemovedChars {
+        /** The original string */
+        private final String mOriginal;
+
+        /**
+         * One bit per char in string. If bit is set, character needs to be removed. If whole
+         * bit field is not initialized nothing needs to be removed.
+         */
+        private BitSet mRemovedChars;
+
+        StringWithRemovedChars(@NonNull String original) {
+            mOriginal = original;
+        }
+
+        /**
+         * Mark all chars in a range {@code [firstRemoved - firstNonRemoved[} (not including
+         * firstNonRemoved) as removed.
+         */
+        void removeRange(int firstRemoved, int firstNonRemoved) {
+            if (mRemovedChars == null) {
+                mRemovedChars = new BitSet(mOriginal.length());
+            }
+
+            mRemovedChars.set(firstRemoved, firstNonRemoved);
+        }
+
+        /**
+         * Remove all characters before {@code firstNonRemoved}.
+         */
+        void removeAllCharBefore(int firstNonRemoved) {
+            if (mRemovedChars == null) {
+                mRemovedChars = new BitSet(mOriginal.length());
+            }
+
+            mRemovedChars.set(0, firstNonRemoved);
+        }
+
+        /**
+         * Remove all characters after and including {@code firstRemoved}.
+         */
+        void removeAllCharAfter(int firstRemoved) {
+            if (mRemovedChars == null) {
+                mRemovedChars = new BitSet(mOriginal.length());
+            }
+
+            mRemovedChars.set(firstRemoved, mOriginal.length());
+        }
+
+        @Override
+        public String toString() {
+            // Common case, no chars removed
+            if (mRemovedChars == null) {
+                return mOriginal;
+            }
+
+            StringBuilder sb = new StringBuilder(mOriginal.length());
+            for (int i = 0; i < mOriginal.length(); i++) {
+                if (!mRemovedChars.get(i)) {
+                    sb.append(mOriginal.charAt(i));
+                }
+            }
+
+            return sb.toString();
+        }
+
+        /**
+         * Return length or the original string
+         */
+        int length() {
+            return mOriginal.length();
+        }
+
+        /**
+         * Return if a certain {@code offset} of the original string is removed
+         */
+        boolean isRemoved(int offset) {
+            return mRemovedChars != null && mRemovedChars.get(offset);
+        }
+
+        /**
+         * Return codePoint of original string at a certain {@code offset}
+         */
+        int codePointAt(int offset) {
+            return mOriginal.codePointAt(offset);
+        }
+    }
+
+    /**
+     * Load, clean up and truncate label before use.
+     *
+     * <p>This method is meant to remove common mistakes and nefarious formatting from strings that
+     * are used in sensitive parts of the UI.
+     *
+     * <p>This method first treats the string like HTML and then ...
+     * <ul>
+     * <li>Removes new lines or truncates at first new line
+     * <li>Trims the white-space off the end
+     * <li>Truncates the string to a given length
+     * </ul>
+     * ... if specified.
+     *
+     * @param ellipsizeDip Assuming maximum length of the string (in dip), assuming font size 42.
+     *                     This is roughly 50 characters for {@code ellipsizeDip == 1000}.<br />
+     *                     Usually ellipsizing should be left to the view showing the string. If a
+     *                     string is used as an input to another string, it might be useful to
+     *                     control the length of the input string though. {@code 0} disables this
+     *                     feature.
+     * @return The safe label
+     * @hide
+     */
+    public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm,
+            @FloatRange(from = 0) float ellipsizeDip, @SafeLabelFlags int flags) {
+        boolean onlyKeepFirstLine = ((flags & SAFE_LABEL_FLAG_FIRST_LINE) != 0);
+        boolean forceSingleLine = ((flags & SAFE_LABEL_FLAG_SINGLE_LINE) != 0);
+        boolean trim = ((flags & SAFE_LABEL_FLAG_TRIM) != 0);
+
+        Preconditions.checkNotNull(pm);
+        Preconditions.checkArgument(ellipsizeDip >= 0);
+        Preconditions.checkFlagsArgument(flags, SAFE_LABEL_FLAG_TRIM | SAFE_LABEL_FLAG_SINGLE_LINE
+                | SAFE_LABEL_FLAG_FIRST_LINE);
+        Preconditions.checkArgument(!(onlyKeepFirstLine && forceSingleLine),
+                "Cannot set SAFE_LABEL_FLAG_SINGLE_LINE and SAFE_LABEL_FLAG_FIRST_LINE at the same "
+                        + "time");
+
+        // loadLabel() always returns non-null
+        String label = loadUnsafeLabel(pm).toString();
+
+        // Treat string as HTML. This
+        // - converts HTML symbols: e.g. &szlig; -> ß
+        // - applies some HTML tags: e.g. <br> -> \n
+        // - removes invalid characters such as \b
+        // - removes html styling, such as <b>
+        // - applies html formatting: e.g. a<p>b</p>c -> a\n\nb\n\nc
+        // - replaces some html tags by "object replacement" markers: <img> -> \ufffc
+        // - Removes leading white space
+        // - Removes all trailing white space beside a single space
+        // - Collapses double white space
+        StringWithRemovedChars labelStr = new StringWithRemovedChars(
+                Html.fromHtml(label).toString());
+
+        int firstNonWhiteSpace = -1;
+        int firstTrailingWhiteSpace = -1;
+
+        // Remove new lines (if requested) and control characters.
+        int labelLength = labelStr.length();
+        for (int offset = 0; offset < labelLength; ) {
+            int codePoint = labelStr.codePointAt(offset);
+            int type = Character.getType(codePoint);
+            int codePointLen = Character.charCount(codePoint);
+            boolean isNewline = isNewline(codePoint);
+
+            if (offset > MAX_SAFE_LABEL_LENGTH || onlyKeepFirstLine && isNewline) {
+                labelStr.removeAllCharAfter(offset);
+                break;
+            } else if (forceSingleLine && isNewline) {
+                labelStr.removeRange(offset, offset + codePointLen);
+            } else if (type == Character.CONTROL && !isNewline) {
+                labelStr.removeRange(offset, offset + codePointLen);
+            } else if (trim && !isWhiteSpace(codePoint)) {
+                // This is only executed if the code point is not removed
+                if (firstNonWhiteSpace == -1) {
+                    firstNonWhiteSpace = offset;
+                }
+                firstTrailingWhiteSpace = offset + codePointLen;
+            }
+
+            offset += codePointLen;
+        }
+
+        if (trim) {
+            // Remove leading and trailing white space
+            if (firstNonWhiteSpace == -1) {
+                // No non whitespace found, remove all
+                labelStr.removeAllCharAfter(0);
+            } else {
+                if (firstNonWhiteSpace > 0) {
+                    labelStr.removeAllCharBefore(firstNonWhiteSpace);
+                }
+                if (firstTrailingWhiteSpace < labelLength) {
+                    labelStr.removeAllCharAfter(firstTrailingWhiteSpace);
+                }
+            }
+        }
+
+        if (ellipsizeDip == 0) {
+            return labelStr.toString();
+        } else {
+            // Truncate
+            final TextPaint paint = new TextPaint();
+            paint.setTextSize(42);
+
+            return TextUtils.ellipsize(labelStr.toString(), paint, ellipsizeDip,
+                    TextUtils.TruncateAt.END);
+        }
+    }
+
     /**
      * Retrieve the current graphical icon associated with this item.  This
      * will call back on the given PackageManager to load the icon from
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 1b80d3d5..9154ce0 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1660,23 +1660,29 @@
      * @see ShutterCallback
      */
     public final boolean enableShutterSound(boolean enabled) {
-        if (!enabled) {
-            IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
-            IAudioService audioService = IAudioService.Stub.asInterface(b);
-            try {
-                if (audioService.isCameraSoundForced()) return false;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Audio service is unavailable for queries");
+        boolean canDisableShutterSound = true;
+        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+        IAudioService audioService = IAudioService.Stub.asInterface(b);
+        try {
+            if (audioService.isCameraSoundForced()) {
+                canDisableShutterSound = false;
             }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Audio service is unavailable for queries");
+        }
+        if (!enabled && !canDisableShutterSound) {
+            return false;
         }
         synchronized (mShutterSoundLock) {
-            if (enabled && mHasAppOpsPlayAudio) {
-                Log.i(TAG, "Shutter sound is not allowed by AppOpsManager");
-                return false;
-            }
+            mShutterSoundEnabledFromApp = enabled;
+            // Return the result of _enableShutterSound(enabled) in all cases.
+            // If the shutter sound can be disabled, disable it when the device is in DnD mode.
             boolean ret = _enableShutterSound(enabled);
-            if (ret) {
-                mShutterSoundEnabledFromApp = enabled;
+            if (enabled && !mHasAppOpsPlayAudio) {
+                Log.i(TAG, "Shutter sound is not allowed by AppOpsManager");
+                if (canDisableShutterSound) {
+                    _enableShutterSound(false);
+                }
             }
             return ret;
         }
@@ -1739,9 +1745,18 @@
             }
             if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) {
                 if (!mHasAppOpsPlayAudio) {
+                    IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+                    IAudioService audioService = IAudioService.Stub.asInterface(b);
+                    try {
+                        if (audioService.isCameraSoundForced()) {
+                            return;
+                        }
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Audio service is unavailable for queries");
+                    }
                     _enableShutterSound(false);
                 } else {
-                    _enableShutterSound(mShutterSoundEnabledFromApp);
+                    enableShutterSound(mShutterSoundEnabledFromApp);
                 }
             }
         }
diff --git a/core/java/android/os/ConfigUpdate.java b/core/java/android/os/ConfigUpdate.java
index dda0ed8..53b1c51 100644
--- a/core/java/android/os/ConfigUpdate.java
+++ b/core/java/android/os/ConfigUpdate.java
@@ -90,6 +90,14 @@
     public static final String ACTION_UPDATE_NETWORK_WATCHLIST
             = "android.intent.action.UPDATE_NETWORK_WATCHLIST";
 
+    /**
+     * Update carrier id config file.
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_UPDATE_CARRIER_ID_DB
+            = "android.os.action.UPDATE_CARRIER_ID_DB";
+
     private ConfigUpdate() {
     }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f149c2e..8543b26 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10425,6 +10425,25 @@
         public static final String ACTIVITY_MANAGER_CONSTANTS = "activity_manager_constants";
 
         /**
+         * App ops specific settings.
+         * This is encoded as a key=value list, separated by commas. Ex:
+         *
+         * "state_settle_time=10000"
+         *
+         * The following keys are supported:
+         *
+         * <pre>
+         * state_settle_time                (long)
+         * </pre>
+         *
+         * <p>
+         * Type: string
+         * @hide
+         * @see com.android.server.AppOpsService.Constants
+         */
+        public static final String APP_OPS_CONSTANTS = "app_ops_constants";
+
+        /**
          * Device Idle (Doze) specific settings.
          * This is encoded as a key=value list, separated by commas. Ex:
          *
diff --git a/core/java/android/security/keystore/recovery/TrustedRootCertificates.java b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
index c5f82c1..a96dab6 100644
--- a/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
+++ b/core/java/android/security/keystore/recovery/TrustedRootCertificates.java
@@ -73,34 +73,34 @@
             "INSECURE_PSWD_";
 
     private static final String GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64 = ""
-            + "MIIFDzCCAvegAwIBAgIQbNdueU2o0vM9gGq4N6bhjzANBgkqhkiG9w0BAQsFADAx"
-            + "MS8wLQYDVQQDEyZHb29nbGUgQ2xvdWQgS2V5IFZhdWx0IFNlcnZpY2UgUm9vdCBD"
-            + "QTAeFw0xODA1MDcxODI0MDJaFw0zODA1MDgxOTI0MDJaMDExLzAtBgNVBAMTJkdv"
-            + "b2dsZSBDbG91ZCBLZXkgVmF1bHQgU2VydmljZSBSb290IENBMIICIjANBgkqhkiG"
-            + "9w0BAQEFAAOCAg8AMIICCgKCAgEArUgzu+4o9yl22eql1BiGBq3gWXooh2ql3J+v"
-            + "Vuzf/ThjzdIg0xkkkw/NAFxYFi49Eo1fa/hf8wCIoAqCEs1lD6tE3cCD3T3+EQPq"
-            + "uh6CB2KmZDJ6mPnXvVUlUuFr0O2MwZkwylqBETzK0x5NCHgL/p47vkjhHx6LqVao"
-            + "bigKlHxszvVi4fkt/qq7KW3YTVxhwdLGEab+OqSfwMxdBLhMfE0K0dvFt8bs8yJA"
-            + "F04DJsMbRChFFBpT17Z0u53iIAAu5qVQhKrQXiIAwgboZqd+JkHLXU1fJeVT5WJO"
-            + "JgoJFWHkdWkHta4mSYlS72J1Q927JD1JdET1kFtH+EDtYAtx7x7F9xAAbb2tMITw"
-            + "s/wwd2rAzZTX/kxRbDlXVLToU05LFYPr+dFV1wvXmi0jlkIxnhdaVBqWC93p528U"
-            + "iUcLpib+HVzMWGdYI3G1NOa/lTp0c8LcbJjapiiVneRQJ3cIqDPOSEnEq40hyZd1"
-            + "jx3JnOxJMwHs8v4s9GIlb3BcOmDvA/Mu09xEMKwpHBm4TFDKXeGHOWha7ccWEECb"
-            + "yO5ncu6XuN2iyz9S+TuMyjZBE552p6Pu5gEC2xk+qab0NGDTHdLKLbyWn3IxdmBH"
-            + "yTr7iPCqmpyHngkC/pbGfvGusc5BpBugsBtlz67m4RWLJ72yAeVPO/ly/8w4orNs"
-            + "GWjn3s0CAwEAAaMjMCEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w"
-            + "DQYJKoZIhvcNAQELBQADggIBAGiWlu+4qyxgPb6RsA0mwR7V21UJ9rEpYhSN+ARp"
-            + "TWGiI22RCJSGK0ZrPGeFQzE2BpnVRdmLTV5jf9JUStjHoPvNYFnwLTJ0E2e9Olj8"
-            + "MrHrAucAUFLhl4woWz0kU/X0EB1j6Y2SXrAaZPiMMpq8BKj3mH1MbV4stZ0kiHUp"
-            + "Zu6PEmrojYG7FKKN30na2xXfiOfl2JusVsyHDqmUn/HjTh6zASKqE6hxE+FJRl2V"
-            + "Q4dcr4SviHtdbimMy2LghLnZ4FE4XhJgRnw9TeRV5C9Sn7pmnAA5X0C8ZXhXvfvr"
-            + "dx4fL3UKlk1Lqlb5skxoK1R9wwr+aNIO+cuR8JA5DmEDWFw5Budh/uWWZlBTyVW2"
-            + "ybbTB6tkmOc8c08XOgxBaKrsXALmJcluabjmN1jp81ae1epeN31jJ4N5IE5aq7Xb"
-            + "TFmKkwpgTTvJmqCR2XzWujlvdbdjfiABliWsnLzLQCP8eZwcM4LA5UK3f1ktHolr"
-            + "1OI9etSOkebE2py8LPYBJWlX36tRAagZhU/NoyOtvhRzq9rb3rbf96APEHKUFsXG"
-            + "9nBEd2BUKZghLKPf+JNCU/2pOGx0jdMcf+K+a1DeG0YzGYMRkFvpN3hvHYrJdByL"
-            + "3kSP3UtD0H2g8Ps7gRLELG2HODxbSn8PV3XtuSvxVanA6uyaaS3AZ6SxeVLvmw50"
-            + "7aYI";
+            + "MIIFJjCCAw6gAwIBAgIJAIobXsJlzhNdMA0GCSqGSIb3DQEBDQUAMCAxHjAcBgNV"
+            + "BAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAyMDIxOTM5MTRaFw0zODAx"
+            + "MjgxOTM5MTRaMCAxHjAcBgNVBAMMFUdvb2dsZSBDcnlwdEF1dGhWYXVsdDCCAiIw"
+            + "DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2OT5i40/H7LINg/lq/0G0hR65P"
+            + "Q4Mud3OnuVt6UIYV2T18+v6qW1yJd5FcnND/ZKPau4aUAYklqJuSVjOXQD0BjgS2"
+            + "98Xa4dSn8Ci1rUR+5tdmrxqbYUdT2ZvJIUMMR6fRoqi+LlAbKECrV+zYQTyLU68w"
+            + "V66hQpAButjJKiZzkXjmKLfJ5IWrNEn17XM988rk6qAQn/BYCCQGf3rQuJeksGmA"
+            + "N1lJOwNYxmWUyouVwqwZthNEWqTuEyBFMkAT+99PXW7oVDc7oU5cevuihxQWNTYq"
+            + "viGB8cck6RW3cmqrDSaJF/E+N0cXFKyYC7FDcggt6k3UrxNKTuySdDEa8+2RTQqU"
+            + "Y9npxBlQE+x9Ig56OI1BG3bSBsGdPgjpyHadZeh2tgk+oqlGsSsum24YxaxuSysT"
+            + "Qfcu/XhyfUXavfmGrBOXerTzIl5oBh/F5aHTV85M2tYEG0qsPPvSpZAWtdJ/2rca"
+            + "OxvhwOL+leZKr8McjXVR00lBsRuKXX4nTUMwya09CO3QHFPFZtZvqjy2HaMOnVLQ"
+            + "I6b6dHEfmsHybzVOe3yPEoFQSU9UhUdmi71kwwoanPD3j9fJHmXTx4PzYYBRf1ZE"
+            + "o+uPgMPk7CDKQFZLjnR40z1uzu3O8aZ3AKZzP+j7T4XQKJLQLmllKtPgLgNdJyib"
+            + "2Glg7QhXH/jBTL6hAgMBAAGjYzBhMB0GA1UdDgQWBBSbZfrqOYH54EJpkdKMZjMc"
+            + "z/Hp+DAfBgNVHSMEGDAWgBSbZfrqOYH54EJpkdKMZjMcz/Hp+DAPBgNVHRMBAf8E"
+            + "BTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQ0FAAOCAgEAKh9nm/vW"
+            + "glMWp3vcCwWwJW286ecREDlI+CjGh5h+f2N4QRrXd/tKE3qQJWCqGx8sFfIUjmI7"
+            + "KYdsC2gyQ2cA2zl0w7pB2QkuqE6zVbnh1D17Hwl19IMyAakFaM9ad4/EoH7oQmqX"
+            + "nF/f5QXGZw4kf1HcgKgoCHWXjqR8MqHOcXR8n6WFqxjzJf1jxzi6Yo2dZ7PJbnE6"
+            + "+kHIJuiCpiHL75v5g1HM41gT3ddFFSrn88ThNPWItT5Z8WpFjryVzank2Yt02LLl"
+            + "WqZg9IC375QULc5B58NMnaiVJIDJQ8zoNgj1yaxqtUMnJX570lotO2OXe4ec9aCQ"
+            + "DIJ84YLM/qStFdeZ9416E80dchskbDG04GuVJKlzWjxAQNMRFhyaPUSBTLLg+kwP"
+            + "t9+AMmc+A7xjtFQLZ9fBYHOBsndJOmeSQeYeckl+z/1WQf7DdwXn/yijon7mxz4z"
+            + "cCczfKwTJTwBh3wR5SQr2vQm7qaXM87qxF8PCAZrdZaw5I80QwkgTj0WTZ2/GdSw"
+            + "d3o5SyzzBAjpwtG+4bO/BD9h9wlTsHpT6yWOZs4OYAKU5ykQrncI8OyavMggArh3"
+            + "/oM58v0orUWINtIc2hBlka36PhATYQiLf+AiWKnwhCaaHExoYKfQlMtXBodNvOK8"
+            + "xqx69x05q/qbHKEcTHrsss630vxrp1niXvA=";
 
     private static final String TEST_ONLY_INSECURE_CERTIFICATE_BASE64 = ""
             + "MIIFMDCCAxigAwIBAgIJAIZ9/G8KQie9MA0GCSqGSIb3DQEBDQUAMCUxIzAhBgNV"
@@ -134,6 +134,8 @@
 
     /**
      * The X509 certificate of the trusted root CA cert for the recoverable key store service.
+     *
+     * TODO: Change it to the production certificate root CA before the final launch.
      */
     private static final X509Certificate GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_CERTIFICATE =
             parseBase64Certificate(GOOGLE_CLOUD_KEY_VAULT_SERVICE_V1_BASE64);
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 2505ea5..0ed9724 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -54,4 +54,6 @@
     void startWatchingActive(in int[] ops, IAppOpsActiveCallback callback);
     void stopWatchingActive(IAppOpsActiveCallback callback);
     boolean isOperationActive(int code, int uid, String packageName);
+
+    void startWatchingModeWithFlags(int op, String packageName, int flags, IAppOpsCallback callback);
 }
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index cbd3ad5..4ee950a 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -68,6 +68,10 @@
      */
     public static final int API_ENFORCEMENT_POLICY_SHIFT =
             Integer.numberOfTrailingZeros(API_ENFORCEMENT_POLICY_MASK);
+    /**
+     * Enable system server ART profiling.
+     */
+    public static final int PROFILE_SYSTEM_SERVER = 1 << 14;
 
     /** No external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 33049be..da19560 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -702,6 +702,12 @@
             ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
             ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
 
+            boolean profileSystemServer = SystemProperties.getBoolean(
+                    "dalvik.vm.profilesystemserver", false);
+            if (profileSystemServer) {
+                parsedArgs.runtimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
+            }
+
             /* Request to fork the system server process */
             pid = Zygote.forkSystemServer(
                     parsedArgs.uid, parsedArgs.gid,
diff --git a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
index ebc2c71..1959301 100644
--- a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
+++ b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
@@ -23,7 +23,7 @@
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.media.AudioManager;
-import android.media.session.MediaSessionLegacyHelper;
+import android.media.session.MediaSessionManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
@@ -48,6 +48,7 @@
     KeyguardManager mKeyguardManager;
     SearchManager mSearchManager;
     TelephonyManager mTelephonyManager;
+    MediaSessionManager mMediaSessionManager;
 
     public PhoneFallbackEventHandler(Context context) {
         mContext = context;
@@ -84,8 +85,7 @@
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_DOWN:
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
-                MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
-                        event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
+                handleVolumeKeyEvent(event);
                 return true;
             }
 
@@ -216,8 +216,7 @@
             case KeyEvent.KEYCODE_VOLUME_DOWN:
             case KeyEvent.KEYCODE_VOLUME_MUTE: {
                 if (!event.isCanceled()) {
-                    MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(
-                            event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
+                    handleVolumeKeyEvent(event);
                 }
                 return true;
             }
@@ -306,12 +305,25 @@
         return mAudioManager;
     }
 
+    MediaSessionManager getMediaSessionManager() {
+        if (mMediaSessionManager == null) {
+            mMediaSessionManager =
+                    (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
+        }
+        return mMediaSessionManager;
+    }
+
     void sendCloseSystemWindows() {
         PhoneWindow.sendCloseSystemWindows(mContext, null);
     }
 
+    private void handleVolumeKeyEvent(KeyEvent keyEvent) {
+        getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(keyEvent,
+                AudioManager.USE_DEFAULT_STREAM_TYPE);
+    }
+
     private void handleMediaKeyEvent(KeyEvent keyEvent) {
-        MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false);
+        getMediaSessionManager().dispatchMediaKeyEventAsSystemService(keyEvent);
     }
 
     private boolean isUserSetupComplete() {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 7ea023e..3fe8f85 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -23,6 +23,7 @@
 
 import android.app.ActivityManager;
 import android.app.SearchManager;
+import android.media.session.MediaSessionManager;
 import android.os.UserHandle;
 
 import android.text.TextUtils;
@@ -74,7 +75,6 @@
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.media.session.MediaController;
-import android.media.session.MediaSessionLegacyHelper;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -252,6 +252,7 @@
 
     private AudioManager mAudioManager;
     private KeyguardManager mKeyguardManager;
+    private MediaSessionManager mMediaSessionManager;
 
     private int mUiOptions = 0;
 
@@ -1873,22 +1874,10 @@
                 // If we have a session send it the volume command, otherwise
                 // use the suggested stream.
                 if (mMediaController != null) {
-                    int direction = 0;
-                    switch (keyCode) {
-                        case KeyEvent.KEYCODE_VOLUME_UP:
-                            direction = AudioManager.ADJUST_RAISE;
-                            break;
-                        case KeyEvent.KEYCODE_VOLUME_DOWN:
-                            direction = AudioManager.ADJUST_LOWER;
-                            break;
-                        case KeyEvent.KEYCODE_VOLUME_MUTE:
-                            direction = AudioManager.ADJUST_TOGGLE_MUTE;
-                            break;
-                    }
-                    mMediaController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI);
+                    mMediaController.dispatchVolumeButtonEventAsSystemService(event);
                 } else {
-                    MediaSessionLegacyHelper.getHelper(getContext()).sendVolumeKeyEvent(
-                            event, mVolumeControlStreamType, false);
+                    getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(event,
+                            mVolumeControlStreamType);
                 }
                 return true;
             }
@@ -1906,7 +1895,7 @@
             case KeyEvent.KEYCODE_MEDIA_RECORD:
             case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
                 if (mMediaController != null) {
-                    if (mMediaController.dispatchMediaButtonEvent(event)) {
+                    if (mMediaController.dispatchMediaButtonEventAsSystemService(event)) {
                         return true;
                     }
                 }
@@ -1948,6 +1937,14 @@
         return mAudioManager;
     }
 
+    private MediaSessionManager getMediaSessionManager() {
+        if (mMediaSessionManager == null) {
+            mMediaSessionManager = (MediaSessionManager) getContext().getSystemService(
+                    Context.MEDIA_SESSION_SERVICE);
+        }
+        return mMediaSessionManager;
+    }
+
     /**
      * A key was released and not handled by anything else in the window.
      *
@@ -1969,12 +1966,10 @@
                 // If we have a session send it the volume command, otherwise
                 // use the suggested stream.
                 if (mMediaController != null) {
-                    final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
-                            | AudioManager.FLAG_FROM_KEY;
-                    mMediaController.adjustVolume(0, flags);
+                    mMediaController.dispatchVolumeButtonEventAsSystemService(event);
                 } else {
-                    MediaSessionLegacyHelper.getHelper(getContext()).sendVolumeKeyEvent(
-                            event, mVolumeControlStreamType, false);
+                    getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(
+                            event, mVolumeControlStreamType);
                 }
                 return true;
             }
@@ -1983,8 +1978,8 @@
                 // doesn't have one of these.  In this case, we execute it here and
                 // eat the event instead, because we have mVolumeControlStreamType
                 // and they don't.
-                MediaSessionLegacyHelper.getHelper(getContext()).sendVolumeKeyEvent(
-                        event, AudioManager.USE_DEFAULT_STREAM_TYPE, false);
+                getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(
+                        event, AudioManager.USE_DEFAULT_STREAM_TYPE);
                 return true;
             }
             // These are all the recognized media key codes in
@@ -2001,7 +1996,7 @@
             case KeyEvent.KEYCODE_MEDIA_RECORD:
             case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
                 if (mMediaController != null) {
-                    if (mMediaController.dispatchMediaButtonEvent(event)) {
+                    if (mMediaController.dispatchMediaButtonEventAsSystemService(event)) {
                         return true;
                     }
                 }
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 0f13078..318bccf 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -418,10 +418,23 @@
      *
      * @param isBgDarker {@code true} if {@code bg} is darker than {@code color}.
      */
-    private static int ensureTextContrast(int color, int bg, boolean isBgDarker) {
+    public static int ensureTextContrast(int color, int bg, boolean isBgDarker) {
+        return ensureContrast(color, bg, isBgDarker, 4.5);
+    }
+
+    /**
+     * Finds a color with sufficient contrast over bg that has the same or darker hue as the
+     * original color, depending on the value of {@code isBgDarker}.
+     *
+     * @param color the color to start searching from
+     * @param bg the color to ensure contrast against
+     * @param isBgDarker {@code true} if {@code bg} is darker than {@code color}
+     * @param minRatio the minimum contrast ratio required
+     */
+    public static int ensureContrast(int color, int bg, boolean isBgDarker, double minRatio) {
         return isBgDarker
-                ? findContrastColorAgainstDark(color, bg, true, 4.5)
-                : findContrastColor(color, bg, true, 4.5);
+                ? findContrastColorAgainstDark(color, bg, true, minRatio)
+                : findContrastColor(color, bg, true, minRatio);
     }
 
     /** Finds a background color for a text view with given text color and hint text color, that
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index b9a8864..7116f3a 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -148,8 +148,6 @@
         }
         mAvatarView.setVisibility(VISIBLE);
         mSenderName.setVisibility(TextUtils.isEmpty(nameOverride) ? GONE : VISIBLE);
-        mTextColor = getNormalTextColor();
-        mSendingTextColor = calculateSendingTextColor();
     }
 
     public void setSending(boolean sending) {
@@ -160,10 +158,6 @@
         }
     }
 
-    private int getNormalTextColor() {
-        return mContext.getColor(R.color.notification_secondary_text_color_light);
-    }
-
     private int calculateSendingTextColor() {
         TypedValue alphaValue = new TypedValue();
         mContext.getResources().getValue(
@@ -363,6 +357,13 @@
         }
     }
 
+    public void setTextColors(int senderTextColor, int messageTextColor) {
+        mTextColor = messageTextColor;
+        mSendingTextColor = calculateSendingTextColor();
+        updateMessageColor();
+        mSenderName.setTextColor(senderTextColor);
+    }
+
     public void setLayoutColor(int layoutColor) {
         if (layoutColor != mLayoutColor){
             mLayoutColor = layoutColor;
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 538ea11..79576bd 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -73,6 +73,8 @@
     private ArrayList<MessagingGroup> mGroups = new ArrayList<>();
     private TextView mTitleView;
     private int mLayoutColor;
+    private int mSenderTextColor;
+    private int mMessageTextColor;
     private int mAvatarSize;
     private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private Paint mTextPaint = new Paint();
@@ -301,6 +303,16 @@
         mIsOneToOne = oneToOne;
     }
 
+    @RemotableViewMethod
+    public void setSenderTextColor(int color) {
+        mSenderTextColor = color;
+    }
+
+    @RemotableViewMethod
+    public void setMessageTextColor(int color) {
+        mMessageTextColor = color;
+    }
+
     public void setUser(Person user) {
         mUser = user;
         if (mUser.getIcon() == null) {
@@ -344,6 +356,7 @@
             }
             newGroup.setDisplayImagesAtEnd(mDisplayImagesAtEnd);
             newGroup.setLayoutColor(mLayoutColor);
+            newGroup.setTextColors(mSenderTextColor, mMessageTextColor);
             Person sender = senders.get(groupIndex);
             CharSequence nameOverride = null;
             if (sender != mUser && mNameReplacement != null) {
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index 3ea6049..df735ae 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -139,18 +139,9 @@
         return throw_exception(env, ImageDecoder::kSourceMalformedData, "Could not open file",
                                nullptr, source);
     }
+
     std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
-
-    if (::lseek(descriptor, 0, SEEK_CUR) == 0) {
-        return native_create(env, std::move(fileStream), source);
-    }
-
-    // FIXME: This allows us to pretend the current location is the beginning,
-    // but it would be better if SkFILEStream allowed treating its starting
-    // point as the beginning.
-    std::unique_ptr<SkStream> stream(SkFrontBufferedStream::Make(std::move(fileStream),
-                SkCodec::MinBufferedBytesNeeded()));
-    return native_create(env, std::move(stream), source);
+    return native_create(env, std::move(fileStream), source);
 }
 
 static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1f8d43c..87d8915 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4262,7 +4262,7 @@
         <receiver android:name="com.android.server.updates.CarrierIdInstallReceiver"
                   android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
-                <action android:name="com.android.internal.intent.action.UPDATE_CARRIER_ID_DB" />
+                <action android:name="android.os.action.UPDATE_CARRIER_ID_DB" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
             </intent-filter>
         </receiver>
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
index fdc9f01..c8864c2 100644
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ b/core/res/res/layout/notification_template_material_ambient.xml
@@ -59,7 +59,7 @@
                 android:singleLine="true"
                 android:ellipsize="marquee"
                 android:fadingEdge="horizontal"
-                android:textSize="24sp"
+                android:textSize="@dimen/notification_ambient_title_text_size"
                 android:textColor="#ffffffff"
             />
             <TextView android:id="@+id/text"
@@ -70,7 +70,7 @@
                 android:layout_weight="1"
                 android:gravity="top|center_horizontal"
                 android:visibility="gone"
-                android:textSize="16sp"
+                android:textSize="@dimen/notification_ambient_text_size"
                 android:textColor="#eeffffff"
                 android:layout_marginTop="4dp"
                 android:ellipsize="end"
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 095a632..79a7b90 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -137,7 +137,7 @@
     <color name="notification_primary_text_color_light">@color/primary_text_default_material_light</color>
     <color name="notification_primary_text_color_dark">@color/primary_text_default_material_dark</color>
     <color name="notification_secondary_text_color_light">@color/primary_text_default_material_light</color>
-    <item name="notification_secondary_text_disabled_alpha" format="float" type="dimen">0.30</item>
+    <item name="notification_secondary_text_disabled_alpha" format="float" type="dimen">0.38</item>
     <color name="notification_secondary_text_color_dark">@color/primary_text_default_material_dark</color>
     <color name="notification_default_color_dark">@color/primary_text_default_material_light</color>
     <color name="notification_default_color_light">#a3202124</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 780cda2..dd869dc 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -665,7 +665,7 @@
 
     <!-- Wifi driver supports IEEE80211AC for softap -->
     <bool translatable="false" name="config_wifi_softap_ieee80211ac_supported">false</bool>
-    
+
     <!-- Flag indicating whether the we should enable the automatic brightness in Settings.
          Software implementation will be used if config_hardware_auto_brightness_available is not set -->
     <bool name="config_automatic_brightness_available">false</bool>
@@ -3423,4 +3423,8 @@
 
     <!-- Package name for ManagedProvisioning which is responsible for provisioning work profiles. -->
     <string name="config_managed_provisioning_package" translatable="false">com.android.managedprovisioning</string>
+
+    <!-- Whether or not swipe up gesture is enabled by default -->
+    <bool name="config_swipe_up_gesture_default">false</bool>
+
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 791f7c6..2e8c7f9 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -374,6 +374,10 @@
     <dimen name="notification_title_text_size">14sp</dimen>
     <!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
     <dimen name="notification_subtext_size">12sp</dimen>
+    <!-- Size of notification text (see TextAppearance.StatusBar.EventContent) -->
+    <dimen name="notification_ambient_text_size">16sp</dimen>
+    <!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
+    <dimen name="notification_ambient_title_text_size">24sp</dimen>
 
     <!-- Top padding for notifications in the standard layout. -->
     <dimen name="notification_top_pad">10dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index de9f3b0..db2aa8e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3301,6 +3301,8 @@
   <java-symbol type="string" name="shortcut_restore_signature_mismatch" />
   <java-symbol type="string" name="shortcut_restore_unknown_issue" />
 
+  <java-symbol type="bool" name="config_swipe_up_gesture_default" />
+
   <!-- From media projection -->
   <java-symbol type="string" name="config_mediaProjectionPermissionDialogComponent" />
   <java-symbol type="string" name="config_batterySaverDeviceSpecificConfig" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 3ce1d13..18bc20c 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -115,6 +115,7 @@
                     Settings.Global.APN_DB_UPDATE_CONTENT_URL,
                     Settings.Global.APN_DB_UPDATE_METADATA_URL,
                     Settings.Global.APP_IDLE_CONSTANTS,
+                    Settings.Global.APP_OPS_CONSTANTS,
                     Settings.Global.APP_STANDBY_ENABLED,
                     Settings.Global.ASSISTED_GPS_ENABLED,
                     Settings.Global.AUDIO_SAFE_VOLUME_STATE,
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 06f5863..b4f52f9 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -37,7 +37,7 @@
  */
 interface ISessionController {
     void sendCommand(String packageName, String command, in Bundle args, in ResultReceiver cb);
-    boolean sendMediaButton(String packageName, in KeyEvent mediaButton);
+    boolean sendMediaButton(String packageName, boolean asSystemService, in KeyEvent mediaButton);
     void registerCallbackListener(in ISessionControllerCallback cb);
     void unregisterCallbackListener(in ISessionControllerCallback cb);
     boolean isTransportControlEnabled();
@@ -46,7 +46,7 @@
     PendingIntent getLaunchPendingIntent();
     long getFlags();
     ParcelableVolumeInfo getVolumeAttributes();
-    void adjustVolume(String packageName, int direction, int flags);
+    void adjustVolume(String packageName, boolean asSystemService, int direction, int flags);
     void setVolumeTo(String packageName, int value, int flags);
 
     // These commands are for the TransportControls
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 56664a9..3578c16 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -34,9 +34,11 @@
 interface ISessionManager {
     ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
     List<IBinder> getSessions(in ComponentName compName, int userId);
-    void dispatchMediaKeyEvent(in KeyEvent keyEvent, boolean needWakeLock);
-    void dispatchVolumeKeyEvent(in KeyEvent keyEvent, int stream, boolean musicOnly);
-    void dispatchAdjustVolume(int suggestedStream, int delta, int flags);
+    void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
+            boolean needWakeLock);
+    void dispatchVolumeKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
+            int stream, boolean musicOnly);
+    void dispatchAdjustVolume(String packageName, int suggestedStream, int delta, int flags);
     void addSessionsListener(in IActiveSessionsListener listener, in ComponentName compName,
             int userId);
     void removeSessionsListener(in IActiveSessionsListener listener);
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 84f85e7..8c34a31 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -126,6 +126,27 @@
      * @return true if the event was sent to the session, false otherwise.
      */
     public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) {
+        return dispatchMediButtonEventInternal(false, keyEvent);
+    }
+
+    /**
+     * Dispatches the media button event as system service to the session. This only effects the
+     * {@link MediaSession.Callback#getCurrentControllerInfo()} and doesn't bypass any permission
+     * check done by the system service.
+     * <p>
+     * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
+     * foreground activity didn't consume the key from the hardware devices.
+     *
+     * @param keyEvent media key event
+     * @return {@code true} if the event was sent to the session, {@code false} otherwise
+     * @hide
+     */
+    public boolean dispatchMediaButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
+        return dispatchMediButtonEventInternal(true, keyEvent);
+    }
+
+    private boolean dispatchMediButtonEventInternal(boolean asSystemService,
+            @NonNull KeyEvent keyEvent) {
         if (keyEvent == null) {
             throw new IllegalArgumentException("KeyEvent may not be null");
         }
@@ -133,7 +154,8 @@
             return false;
         }
         try {
-            return mSessionBinder.sendMediaButton(mContext.getPackageName(), keyEvent);
+            return mSessionBinder.sendMediaButton(mContext.getPackageName(), asSystemService,
+                    keyEvent);
         } catch (RemoteException e) {
             // System is dead. =(
         }
@@ -141,6 +163,52 @@
     }
 
     /**
+     * Dispatches the volume button event as system service to the session. This only effects the
+     * {@link MediaSession.Callback#getCurrentControllerInfo()} and doesn't bypass any permission
+     * check done by the system service.
+     * <p>
+     * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
+     * foreground activity didn't consume the key from the hardware devices.
+     *
+     * @param keyEvent volume key event
+     * @hide
+     */
+    public void dispatchVolumeButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
+        switch (keyEvent.getAction()) {
+            case KeyEvent.ACTION_DOWN: {
+                int direction = 0;
+                switch (keyEvent.getKeyCode()) {
+                    case KeyEvent.KEYCODE_VOLUME_UP:
+                        direction = AudioManager.ADJUST_RAISE;
+                        break;
+                    case KeyEvent.KEYCODE_VOLUME_DOWN:
+                        direction = AudioManager.ADJUST_LOWER;
+                        break;
+                    case KeyEvent.KEYCODE_VOLUME_MUTE:
+                        direction = AudioManager.ADJUST_TOGGLE_MUTE;
+                        break;
+                }
+                try {
+                    mSessionBinder.adjustVolume(mContext.getPackageName(), true, direction,
+                            AudioManager.FLAG_SHOW_UI);
+                } catch (RemoteException e) {
+                    Log.wtf(TAG, "Error calling adjustVolumeBy", e);
+                }
+            }
+
+            case KeyEvent.ACTION_UP: {
+                final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
+                        | AudioManager.FLAG_FROM_KEY;
+                try {
+                    mSessionBinder.adjustVolume(mContext.getPackageName(), true, 0, flags);
+                } catch (RemoteException e) {
+                    Log.wtf(TAG, "Error calling adjustVolumeBy", e);
+                }
+            }
+        }
+    }
+
+    /**
      * Get the current playback state for this session.
      *
      * @return The current PlaybackState or null
@@ -322,7 +390,7 @@
      */
     public void adjustVolume(int direction, int flags) {
         try {
-            mSessionBinder.adjustVolume(mContext.getPackageName(), direction, flags);
+            mSessionBinder.adjustVolume(mContext.getPackageName(), false, direction, flags);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
         }
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 5e8b8ca..6f4f20e 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -122,6 +122,15 @@
             FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
     public @interface SessionFlags { }
 
+    private static final String EXTRA_KEY_CALLING_PACKAGE =
+            "android.media.session.extra.CALLING_PACKAGE";
+    private static final String EXTRA_KEY_CALLING_PID =
+            "android.media.session.extra.CALLING_PID";
+    private static final String EXTRA_KEY_CALLING_UID =
+            "android.media.session.extra.CALLING_UID";
+    private static final String EXTRA_KEY_ORIGINAL_BUNDLE =
+            "android.media.session.extra.ORIGINAL_BUNDLE";
+
     private final Object mLock = new Object();
     private final int mMaxBitmapSize;
 
@@ -520,11 +529,15 @@
      * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
      */
     public final @NonNull RemoteUserInfo getCurrentControllerInfo() {
-        if (mCallback == null || mCallback.mCurrentControllerInfo == null) {
+        return createRemoteUserInfo(getCurrentData());
+    }
+
+    private @NonNull Bundle getCurrentData() {
+        if (mCallback == null || mCallback.mCurrentData == null) {
             throw new IllegalStateException(
                     "This should be called inside of MediaSession.Callback methods");
         }
-        return mCallback.mCurrentControllerInfo;
+        return mCallback.mCurrentData;
     }
 
     /**
@@ -556,7 +569,7 @@
      */
     public String getCallingPackage() {
         if (mCallback != null) {
-            return mCallback.mCurrentControllerInfo.getPackageName();
+            return createRemoteUserInfo(mCallback.mCurrentData).getPackageName();
         }
         return null;
     }
@@ -659,6 +672,57 @@
     }
 
     /**
+     * Creates the extra bundle that includes the caller information.
+     *
+     * @return An extraBundle that contains caller information
+     */
+    private static Bundle createExtraBundle(String packageName, int pid, int uid) {
+        return createExtraBundle(packageName, pid, uid, null);
+    }
+
+    /**
+     * Creates the extra bundle that includes the caller information.
+     *
+     * @param originalBundle bundle
+     * @return An extraBundle that contains caller information
+     */
+    private static Bundle createExtraBundle(String packageName, int pid, int uid,
+            Bundle originalBundle) {
+        Bundle bundle = new Bundle();
+        bundle.putString(EXTRA_KEY_CALLING_PACKAGE, packageName);
+        bundle.putInt(EXTRA_KEY_CALLING_PID, pid);
+        bundle.putInt(EXTRA_KEY_CALLING_UID, uid);
+        if (originalBundle != null) {
+            bundle.putBundle(EXTRA_KEY_ORIGINAL_BUNDLE, originalBundle);
+        }
+        return bundle;
+    }
+
+    /**
+     * Creates the {@link RemoteUserInfo} from the extra bundle created by
+     * {@link #createExtraBundle}.
+     *
+     * @param extraBundle that previously created by createExtraBundle()
+     * @return a RemoteUserInfo
+     */
+    private static RemoteUserInfo createRemoteUserInfo(Bundle extraBundle) {
+        return new RemoteUserInfo(
+                extraBundle.getString(EXTRA_KEY_CALLING_PACKAGE),
+                extraBundle.getInt(EXTRA_KEY_CALLING_PID, INVALID_PID),
+                extraBundle.getInt(EXTRA_KEY_CALLING_UID, INVALID_UID));
+    }
+
+    /**
+     * Gets the original bundle from the extra bundle created by {@link #createExtraBundle}.
+     *
+     * @param extraBundle that previously created by createExtraBundle()
+     * @return a Bundle
+     */
+    private static Bundle getOriginalBundle(Bundle extraBundle) {
+        return extraBundle.getBundle(EXTRA_KEY_ORIGINAL_BUNDLE);
+    }
+
+    /**
      * Return true if this is considered an active playback state.
      *
      * @hide
@@ -755,9 +819,6 @@
         private MediaSession mSession;
         private CallbackMessageHandler mHandler;
         private boolean mMediaPlayPauseKeyPending;
-        private String mCallingPackage;
-        private int mCallingPid;
-        private int mCallingUid;
 
         public Callback() {
         }
@@ -811,8 +872,9 @@
                                 }
                             } else {
                                 mMediaPlayPauseKeyPending = true;
-                                mHandler.sendEmptyMessageDelayed(CallbackMessageHandler
-                                        .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
+                                mHandler.postDelayed(CallbackMessageHandler
+                                                .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
+                                        mSession.getCurrentData(),
                                         ViewConfiguration.getDoubleTapTimeout());
                             }
                             return true;
@@ -1242,22 +1304,6 @@
                 session.dispatchSetVolumeTo(value, createExtraBundle(packageName, pid, uid));
             }
         }
-
-        private Bundle createExtraBundle(String packageName, int pid, int uid) {
-            return createExtraBundle(packageName, pid, uid, null);
-        }
-
-        private Bundle createExtraBundle(String packageName, int pid, int uid,
-                Bundle originalBundle) {
-            Bundle bundle = new Bundle();
-            bundle.putString(CallbackMessageHandler.EXTRA_KEY_CALLING_PACKAGE, packageName);
-            bundle.putInt(CallbackMessageHandler.EXTRA_KEY_CALLING_PID, pid);
-            bundle.putInt(CallbackMessageHandler.EXTRA_KEY_CALLING_UID, uid);
-            if (originalBundle != null) {
-                bundle.putBundle(CallbackMessageHandler.EXTRA_KEY_ORIGINAL_BUNDLE, originalBundle);
-            }
-            return bundle;
-        }
     }
 
     /**
@@ -1379,15 +1425,6 @@
 
     private class CallbackMessageHandler extends Handler {
 
-        private static final String EXTRA_KEY_CALLING_PACKAGE =
-                "android.media.session.extra.CALLING_PACKAGE";
-        private static final String EXTRA_KEY_CALLING_PID =
-                "android.media.session.extra.CALLING_PID";
-        private static final String EXTRA_KEY_CALLING_UID =
-                "android.media.session.extra.CALLING_UID";
-        private static final String EXTRA_KEY_ORIGINAL_BUNDLE =
-                "android.media.session.extra.ORIGINAL_BUNDLE";
-
         private static final int MSG_COMMAND = 1;
         private static final int MSG_MEDIA_BUTTON = 2;
         private static final int MSG_PREPARE = 3;
@@ -1413,8 +1450,7 @@
         private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 23;
 
         private MediaSession.Callback mCallback;
-
-        private RemoteUserInfo mCurrentControllerInfo;
+        private Bundle mCurrentData;
 
         public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
             super(looper, null, true);
@@ -1422,22 +1458,25 @@
             mCallback.mHandler = this;
         }
 
-        public void post(int what, Object obj, Bundle bundle) {
+        public void post(int what, Object obj, Bundle data) {
             Message msg = obtainMessage(what, obj);
-            msg.setData(bundle);
+            msg.setData(data);
             msg.sendToTarget();
         }
 
+        public void postDelayed(int what, Bundle data, long delayMs) {
+            Message msg = obtainMessage(what);
+            msg.setData(data);
+            sendMessageDelayed(msg, delayMs);
+        }
+
         @Override
         public void handleMessage(Message msg) {
             VolumeProvider vp;
-            Bundle bundle = msg.getData();
-            Bundle originalBundle = bundle.getBundle(EXTRA_KEY_ORIGINAL_BUNDLE);
+            Bundle data = msg.getData();
+            Bundle originalBundle = getOriginalBundle(data);
 
-            mCurrentControllerInfo = new RemoteUserInfo(
-                    bundle.getString(EXTRA_KEY_CALLING_PACKAGE),
-                    bundle.getInt(EXTRA_KEY_CALLING_PID, INVALID_PID),
-                    bundle.getInt(EXTRA_KEY_CALLING_UID, INVALID_UID));
+            mCurrentData = data;
 
             switch (msg.what) {
                 case MSG_COMMAND:
@@ -1521,7 +1560,7 @@
                     mCallback.handleMediaPlayPauseKeySingleTapIfPending();
                     break;
             }
-            mCurrentControllerInfo = null;
+            mCurrentData = null;
         }
     }
 }
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index f358103..f54bfc1 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -300,8 +300,28 @@
      * @hide
      */
     public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent, boolean needWakeLock) {
+        dispatchMediaKeyEventInternal(false, keyEvent, needWakeLock);
+    }
+
+    /**
+     * Send a media key event as system component. The receiver will be selected automatically.
+     * <p>
+     * Should be only called by the {@link com.android.internal.policy.PhoneWindow} or
+     * {@link android.view.FallbackEventHandler} when the foreground activity didn't consume the key
+     * from the hardware devices.
+     *
+     * @param keyEvent The KeyEvent to send.
+     * @hide
+     */
+    public void dispatchMediaKeyEventAsSystemService(KeyEvent keyEvent) {
+        dispatchMediaKeyEventInternal(true, keyEvent, false);
+    }
+
+    private void dispatchMediaKeyEventInternal(boolean asSystemService, @NonNull KeyEvent keyEvent,
+            boolean needWakeLock) {
         try {
-            mService.dispatchMediaKeyEvent(keyEvent, needWakeLock);
+            mService.dispatchMediaKeyEvent(mContext.getPackageName(), asSystemService, keyEvent,
+                    needWakeLock);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to send key event.", e);
         }
@@ -311,12 +331,33 @@
      * Send a volume key event. The receiver will be selected automatically.
      *
      * @param keyEvent The volume KeyEvent to send.
-     * @param needWakeLock True if a wake lock should be held while sending the key.
      * @hide
      */
     public void dispatchVolumeKeyEvent(@NonNull KeyEvent keyEvent, int stream, boolean musicOnly) {
+        dispatchVolumeKeyEventInternal(false, keyEvent, stream, musicOnly);
+    }
+
+    /**
+     * Dispatches the volume button event as system service to the session. This only effects the
+     * {@link MediaSession.Callback#getCurrentControllerInfo()} and doesn't bypass any permission
+     * check done by the system service.
+     * <p>
+     * Should be only called by the {@link com.android.internal.policy.PhoneWindow} or
+     * {@link android.view.FallbackEventHandler} when the foreground activity didn't consume the key
+     * from the hardware devices.
+     *
+     * @param keyEvent The KeyEvent to send.
+     * @hide
+     */
+    public void dispatchVolumeKeyEventAsSystemService(@NonNull KeyEvent keyEvent, int streamType) {
+        dispatchVolumeKeyEventInternal(true, keyEvent, streamType, false);
+    }
+
+    private void dispatchVolumeKeyEventInternal(boolean asSystemService, @NonNull KeyEvent keyEvent,
+            int stream, boolean musicOnly) {
         try {
-            mService.dispatchVolumeKeyEvent(keyEvent, stream, musicOnly);
+            mService.dispatchVolumeKeyEvent(mContext.getPackageName(), asSystemService, keyEvent,
+                    stream, musicOnly);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to send volume key event.", e);
         }
@@ -336,7 +377,8 @@
      */
     public void dispatchAdjustVolume(int suggestedStream, int direction, int flags) {
         try {
-            mService.dispatchAdjustVolume(suggestedStream, direction, flags);
+            mService.dispatchAdjustVolume(mContext.getPackageName(), suggestedStream, direction,
+                    flags);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to send adjust volume.", e);
         }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 4c98bb8..1c635c4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -254,6 +254,7 @@
             case Settings.Secure.TOUCH_EXPLORATION_ENABLED:
             case Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
             case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED:
+            case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED:
             case Settings.Secure.UI_NIGHT_MODE:
                 return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0;
             case Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES:
diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk
index bd5b1f2..1ca6afe 100644
--- a/packages/SettingsProvider/test/Android.mk
+++ b/packages/SettingsProvider/test/Android.mk
@@ -10,7 +10,9 @@
     ../src/com/android/providers/settings/SettingsState.java \
     ../src/com/android/providers/settings/SettingsHelper.java
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    truth-prebuilt
 
 LOCAL_JAVA_LIBRARIES := android.test.base
 
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
new file mode 100644
index 0000000..b438e91
--- /dev/null
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsHelperRestoreTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 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.providers.settings;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link SettingsHelper#restoreValue(Context, ContentResolver, ContentValues, Uri,
+ * String, String, int)}. Specifically verifies that we restore critical accessibility settings only
+ * if the user has not already configured these in SUW.
+ */
+@RunWith(AndroidJUnit4.class)
+public class SettingsHelperRestoreTest {
+    private Context mContext;
+    private ContentResolver mContentResolver;
+    private SettingsHelper mSettingsHelper;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getContext();
+        mContentResolver = mContext.getContentResolver();
+        mSettingsHelper = new SettingsHelper(mContext);
+    }
+
+    /** Tests for {@link Settings.Secure#ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED}. */
+    @Test
+    public void
+            restoreAccessibilityDisplayMagnificationNavbarEnabled_alreadyConfigured_doesNotRestore()
+                    throws Exception {
+        // Simulate already configuring setting via SUW.
+        Settings.Secure.putInt(
+                mContentResolver,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
+                1);
+
+        mSettingsHelper.restoreValue(
+                mContext,
+                mContentResolver,
+                new ContentValues(2),
+                Settings.Secure.getUriFor(
+                        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED),
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
+                String.valueOf(0),
+                Build.VERSION.SDK_INT);
+
+        assertThat(
+                        Settings.Secure.getInt(
+                                mContentResolver,
+                                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED))
+                .isEqualTo(1);
+    }
+
+    @Test
+    public void
+            restoreAccessibilityDisplayMagnificationNavbarEnabled_notAlreadyConfigured_restores()
+                    throws Exception {
+        // Simulate system default at boot.
+        Settings.Secure.putInt(
+                mContentResolver,
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
+                0);
+
+        mSettingsHelper.restoreValue(
+                mContext,
+                mContentResolver,
+                new ContentValues(2),
+                Settings.Secure.getUriFor(
+                        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED),
+                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
+                String.valueOf(1),
+                Build.VERSION.SDK_INT);
+
+        assertThat(
+                        Settings.Secure.getInt(
+                                mContentResolver,
+                                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED))
+                .isEqualTo(1);
+    }
+}
diff --git a/packages/SystemUI/res/drawable/smart_reply_button_background.xml b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
index 93adaa0..31119a9 100644
--- a/packages/SystemUI/res/drawable/smart_reply_button_background.xml
+++ b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
@@ -26,7 +26,8 @@
             android:insetBottom="8dp">
             <shape android:shape="rectangle">
                 <corners android:radius="8dp" />
-                <stroke android:width="1dp" android:color="@color/smart_reply_button_stroke" />
+                <stroke android:width="@dimen/smart_reply_button_stroke_width"
+                        android:color="@color/smart_reply_button_stroke" />
                 <solid android:color="@color/smart_reply_button_background"/>
             </shape>
         </inset>
diff --git a/packages/SystemUI/res/layout/hybrid_notification.xml b/packages/SystemUI/res/layout/hybrid_notification.xml
index bccf207..23e8a15 100644
--- a/packages/SystemUI/res/layout/hybrid_notification.xml
+++ b/packages/SystemUI/res/layout/hybrid_notification.xml
@@ -25,7 +25,6 @@
         android:id="@+id/notification_title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
         android:singleLine="true"
         style="?attr/hybridNotificationTitleStyle"
     />
diff --git a/packages/SystemUI/res/layout/smart_reply_button.xml b/packages/SystemUI/res/layout/smart_reply_button.xml
index a490c4b..9faed18 100644
--- a/packages/SystemUI/res/layout/smart_reply_button.xml
+++ b/packages/SystemUI/res/layout/smart_reply_button.xml
@@ -19,6 +19,7 @@
 <!-- android:paddingHorizontal is set dynamically in SmartReplyView. -->
 <Button xmlns:android="http://schemas.android.com/apk/res/android"
         style="@android:style/Widget.Material.Button"
+        android:stateListAnimator="@null"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:minWidth="0dp"
diff --git a/packages/SystemUI/res/layout/smart_reply_view.xml b/packages/SystemUI/res/layout/smart_reply_view.xml
index aa5549f..9fffc72 100644
--- a/packages/SystemUI/res/layout/smart_reply_view.xml
+++ b/packages/SystemUI/res/layout/smart_reply_view.xml
@@ -25,6 +25,7 @@
     android:layout_width="wrap_content"
     systemui:spacing="@dimen/smart_reply_button_spacing"
     systemui:singleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_single_line"
-    systemui:doubleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_double_line">
+    systemui:doubleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_double_line"
+    systemui:buttonStrokeWidth="@dimen/smart_reply_button_stroke_width">
     <!-- smart_reply_button(s) will be added here. -->
 </com.android.systemui.statusbar.policy.SmartReplyView>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index b11266a..2ce9bfc 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -135,6 +135,7 @@
         <attr name="spacing" format="dimension" />
         <attr name="singleLineButtonPaddingHorizontal" format="dimension" />
         <attr name="doubleLineButtonPaddingHorizontal" format="dimension" />
+        <attr name="buttonStrokeWidth" format="dimension" />
     </declare-styleable>
 
     <!-- Used to style rotate suggestion button AVD animations -->
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index efcca63..3472477 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -151,7 +151,8 @@
     <color name="zen_introduction">#ffffffff</color>
 
     <color name="smart_reply_button_text">#5F6368</color>
-    <color name="smart_reply_button_background">#feffffff</color>
+    <color name="smart_reply_button_text_dark_bg">@*android:color/notification_primary_text_color_dark</color>
+    <color name="smart_reply_button_background">#ffffffff</color>
     <color name="smart_reply_button_stroke">#ffdadce0</color>
 
     <!-- Fingerprint dialog colors -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f3fe297..8c3cc42 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -951,6 +951,7 @@
     <dimen name="smart_reply_button_padding_horizontal_single_line">20dp</dimen>
     <dimen name="smart_reply_button_padding_horizontal_double_line">19dp</dimen>
     <dimen name="smart_reply_button_min_height">48dp</dimen>
+    <dimen name="smart_reply_button_stroke_width">1dp</dimen>
     <dimen name="smart_reply_button_font_size">14sp</dimen>
     <dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 95ccc3c..654f407 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -623,6 +623,8 @@
 
     <!-- The overflow indicator shown when a group has more notification inside the group than the visible ones. An example is "+ 3" [CHAR LIMIT=5] -->
     <string name="notification_group_overflow_indicator">+ <xliff:g id="number" example="3">%s</xliff:g></string>
+    <!-- The overflow indicator shown when a group has more notification inside the group than the visible ones. An example is "New message, +3" [CHAR LIMIT=7] -->
+    <string name="notification_group_overflow_indicator_ambient"><xliff:g id="notification_title" example="New message">%s</xliff:g>, +<xliff:g id="overflow" example="+3">%s</xliff:g></string>
 
     <!-- Content description describing how many more notifications are in a group [CHAR LIMIT=NONE] -->
     <plurals name="notification_group_overflow_description">
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index c9b14dc..b3f4534 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -110,7 +110,6 @@
         <item name="android:paddingStart">@*android:dimen/notification_extra_margin_ambient</item>
         <item name="android:paddingEnd">@*android:dimen/notification_extra_margin_ambient</item>
         <item name="android:orientation">vertical</item>
-        <item name="android:paddingBottom">23.5dp</item>
     </style>
 
     <style name="hybrid_notification">
@@ -119,22 +118,28 @@
     </style>
 
     <style name="hybrid_notification_title_ambient">
+        <item name="android:layout_marginTop">@*android:dimen/notification_header_margin_top_ambient</item>
         <item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
         <item name="android:paddingEnd">@*android:dimen/notification_content_margin_end</item>
-        <item name="android:textSize">20sp</item>
+        <item name="android:textAppearance">@*android:style/Notification.Header.Ambient</item>
+        <item name="android:layout_gravity">top|center_horizontal</item>
+        <item name="android:textSize">@*android:dimen/notification_ambient_title_text_size</item>
         <item name="android:textColor">#ffffffff</item>
     </style>
 
     <style name="hybrid_notification_title">
         <item name="android:paddingEnd">4dp</item>
+        <item name="android:textAppearance">@*android:style/TextAppearance.Material.Notification.Title</item>
     </style>
 
     <style name="hybrid_notification_text_ambient">
         <item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
         <item name="android:paddingEnd">@*android:dimen/notification_content_margin_end</item>
-        <item name="android:textSize">16sp</item>
+        <item name="android:textSize">@*android:dimen/notification_ambient_text_size</item>
         <item name="android:textColor">#eeffffff</item>
-        <item name="android:layout_marginTop">4dp</item>
+        <item name="android:gravity">top|center_horizontal</item>
+        <item name="android:ellipsize">end</item>
+        <item name="android:maxLines">3</item>
     </style>
 
     <style name="hybrid_notification_text"
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index a265a5e..0ca0a11 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -74,6 +74,7 @@
 
     private boolean mEnforceBouncer = false;
     private boolean mBouncerOn = false;
+    private boolean mBouncerOffOnDown = false;
     private boolean mSessionActive = false;
     private boolean mIsTouchScreen = true;
     private int mState = StatusBarState.SHADE;
@@ -459,10 +460,19 @@
     public void onTouchEvent(MotionEvent event, int width, int height) {
         if (event.getAction() == MotionEvent.ACTION_DOWN) {
             mIsTouchScreen = event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN);
+            // If the bouncer was not shown during the down event,
+            // we want the entire gesture going to HumanInteractionClassifier
+            mBouncerOffOnDown = !mBouncerOn;
         }
-        if (mSessionActive && !mBouncerOn) {
-            mDataCollector.onTouchEvent(event, width, height);
-            mHumanInteractionClassifier.onTouchEvent(event);
+        if (mSessionActive) {
+            if (!mBouncerOn) {
+                // In case bouncer is "visible", but onFullyShown has not yet been called,
+                // avoid adding the event to DataCollector
+                mDataCollector.onTouchEvent(event, width, height);
+            }
+            if (mBouncerOffOnDown) {
+                mHumanInteractionClassifier.onTouchEvent(event);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index f60e207..d16e1b1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -69,7 +69,8 @@
     private static final boolean RESET_PREFS_FOR_DEBUG = false;
     private static final boolean ONBOARDING_ENABLED = true;
     private static final long SHOW_DELAY_MS = 500;
-    private static final long SHOW_HIDE_DURATION_MS = 300;
+    private static final long SHOW_DURATION_MS = 300;
+    private static final long HIDE_DURATION_MS = 100;
     // Show swipe-up tips after opening overview from home this number of times.
     private static final int SWIPE_UP_SHOW_ON_OVERVIEW_OPENED_FROM_HOME_COUNT = 3;
     // Show quick scrub tips after opening overview this number of times.
@@ -172,6 +173,11 @@
                 }
 
                 @Override
+                public void onQuickStepStarted() {
+                    hide(true);
+                }
+
+                @Override
                 public void onQuickScrubStarted() {
                     boolean alreadySeenQuickScrubsOnboarding = hasSeenQuickScrubOnboarding();
                     if (!alreadySeenQuickScrubsOnboarding) {
@@ -292,7 +298,7 @@
         mHasDismissedQuickScrubTip = false;
         mNumAppsLaunchedSinceSwipeUpTipDismiss = 0;
         mOverviewOpenedCountSinceQuickScrubTipDismiss = 0;
-        hide(false);
+        hide(true);
     }
 
     public void onConfigurationChanged(Configuration newConfiguration) {
@@ -305,15 +311,12 @@
         if (!shouldShow()) {
             return;
         }
-        if (mLayoutAttachedToWindow) {
-            hide(false);
-        }
         mDismissView.setTag(stringRes);
         mLayout.setTag(stringRes);
         mTextView.setText(stringRes);
         // Only show in portrait.
         int orientation = mContext.getResources().getConfiguration().orientation;
-        if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+        if (!mLayoutAttachedToWindow && orientation == Configuration.ORIENTATION_PORTRAIT) {
             mLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
 
             mWindowManager.addView(mLayout, getWindowLayoutParams());
@@ -322,7 +325,7 @@
                     .alpha(1f)
                     .withLayer()
                     .setStartDelay(SHOW_DELAY_MS)
-                    .setDuration(SHOW_HIDE_DURATION_MS)
+                    .setDuration(SHOW_DURATION_MS)
                     .setInterpolator(new DecelerateInterpolator())
                     .start();
         }
@@ -344,7 +347,8 @@
                 mLayout.animate()
                         .alpha(0f)
                         .withLayer()
-                        .setDuration(SHOW_HIDE_DURATION_MS)
+                        .setStartDelay(0)
+                        .setDuration(HIDE_DURATION_MS)
                         .setInterpolator(new AccelerateInterpolator())
                         .withEndAction(() -> mWindowManager.removeViewImmediate(mLayout))
                         .start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 8b6b5fe..364ed80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -581,7 +581,7 @@
         }
     }
 
-    private void setBackgroundTintColor(int color) {
+    protected void setBackgroundTintColor(int color) {
         if (color != mCurrentBackgroundTint) {
             mCurrentBackgroundTint = color;
             if (color == mNormalColor) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 3454fe6..991b47e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1090,6 +1090,15 @@
         }
     }
 
+    @Override
+    protected void setBackgroundTintColor(int color) {
+        super.setBackgroundTintColor(color);
+        NotificationContentView view = getShowingLayout();
+        if (view != null) {
+            view.setBackgroundTintColor(color);
+        }
+    }
+
     public void closeRemoteInput() {
         for (NotificationContentView l : mLayouts) {
             l.closeRemoteInput();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBlockingHelperManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBlockingHelperManager.java
index 20e5f86..1b613cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBlockingHelperManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBlockingHelperManager.java
@@ -23,8 +23,10 @@
 import android.support.annotation.VisibleForTesting;
 import android.util.Log;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.statusbar.notification.NotificationCounters;
 import com.android.systemui.statusbar.phone.StatusBar;
 
 import java.util.Collections;
@@ -97,6 +99,9 @@
             // We don't care about the touch origin (x, y) since we're opening guts without any
             // explicit user interaction.
             manager.openGuts(mBlockingHelperRow, 0, 0, menuRow.getLongpressMenuItem(mContext));
+
+            Dependency.get(MetricsLogger.class)
+                    .count(NotificationCounters.BLOCKING_HELPER_SHOWN, 1);
             return true;
         }
         return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 285f639..8fa1b67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -887,6 +887,12 @@
         mContainingNotification.setContentBackground(customBackgroundColor, animate, this);
     }
 
+    public void setBackgroundTintColor(int color) {
+        if (mExpandedSmartReplyView != null) {
+            mExpandedSmartReplyView.setBackgroundTintColor(color);
+        }
+    }
+
     public int getVisibleType() {
         return mVisibleType;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
index dff5f38..46600cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGutsManager.java
@@ -372,7 +372,7 @@
             @Override
             public void run() {
                 if (row.getWindowToken() == null) {
-                    Log.e(TAG, "Trying to show notification guts, but not attached to "
+                    Log.e(TAG, "Trying to show notification guts in post(), but not attached to "
                             + "window");
                     return;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index ec49f43..98e9268 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -91,22 +91,24 @@
     private boolean mIsForBlockingHelper;
     private boolean mNegativeUserSentiment;
 
-    /** Counter tag that describes how the user exit or quit out of this view. */
-    private String mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_DISMISSED;
+    /**
+     * String that describes how the user exit or quit out of this view, also used as a counter tag.
+     */
+    private String mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
 
     private OnClickListener mOnKeepShowing = v -> {
-        mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
+        mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
         closeControls(v);
     };
 
     private OnClickListener mOnStopOrMinimizeNotifications = v -> {
-        mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
+        mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
         swapContent(false);
     };
 
     private OnClickListener mOnUndo = v -> {
         // Reset exit counter that we'll log and record an undo event separately (not an exit event)
-        mExitReasonCounter = NotificationCounters.BLOCKING_HELPER_DISMISSED;
+        mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
         logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO);
         swapContent(true);
     };
@@ -197,8 +199,6 @@
         bindHeader();
         bindPrompt();
         bindButtons();
-
-        logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_SHOWN);
     }
 
     private void bindHeader() throws RemoteException {
@@ -300,7 +300,9 @@
 
     private void saveImportance() {
         if (!mIsNonblockable) {
-            if (mCheckSaveListener != null) {
+            // Only go through the lock screen/bouncer if the user didn't hit 'Keep showing'.
+            if (mCheckSaveListener != null
+                    && !NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING.equals(mExitReason)) {
                 mCheckSaveListener.checkSave(this::updateImportance, mSbn);
             } else {
                 updateImportance();
@@ -495,7 +497,7 @@
         if (save) {
             saveImportance();
         }
-        logBlockingHelperCounter(mExitReasonCounter);
+        logBlockingHelperCounter(mExitReason);
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
index 3975ec2..a096508 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
@@ -151,6 +151,17 @@
         return reusableView;
     }
 
+    public TextView bindOverflowNumberAmbient(TextView titleView, Notification notification,
+            int number) {
+        String text = mContext.getResources().getString(
+                R.string.notification_group_overflow_indicator_ambient,
+                resolveTitle(notification), number);
+        if (!text.equals(titleView.getText())) {
+            titleView.setText(text);
+        }
+        return titleView;
+    }
+
     public void setOverflowNumberDark(TextView view, boolean dark, boolean fade, long delay) {
         mDozer.setIntensityDark((f)->{
             mDarkAmount = f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 351868d..c279e63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -1,12 +1,17 @@
 package com.android.systemui.statusbar.policy;
 
+import android.annotation.ColorInt;
 import android.app.PendingIntent;
 import android.app.RemoteInput;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.InsetDrawable;
 import android.graphics.drawable.RippleDrawable;
 import android.os.Bundle;
 import android.text.Layout;
@@ -22,6 +27,7 @@
 import android.widget.Button;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.NotificationColorUtil;
 import com.android.keyguard.KeyguardHostView.OnDismissAction;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -75,6 +81,23 @@
 
     private View mSmartReplyContainer;
 
+    @ColorInt
+    private int mCurrentBackgroundColor;
+    @ColorInt
+    private final int mDefaultBackgroundColor;
+    @ColorInt
+    private final int mDefaultStrokeColor;
+    @ColorInt
+    private final int mDefaultTextColor;
+    @ColorInt
+    private final int mDefaultTextColorDarkBg;
+    @ColorInt
+    private final int mRippleColorDarkBg;
+    @ColorInt
+    private final int mRippleColor;
+    private final int mStrokeWidth;
+    private final double mMinStrokeContrast;
+
     public SmartReplyView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mConstants = Dependency.get(SmartReplyConstants.class);
@@ -83,9 +106,21 @@
         mHeightUpperLimit = NotificationUtils.getFontScaledHeight(mContext,
             R.dimen.smart_reply_button_max_height);
 
+        mCurrentBackgroundColor = context.getColor(R.color.smart_reply_button_background);
+        mDefaultBackgroundColor = mCurrentBackgroundColor;
+        mDefaultTextColor = mContext.getColor(R.color.smart_reply_button_text);
+        mDefaultTextColorDarkBg = mContext.getColor(R.color.smart_reply_button_text_dark_bg);
+        mDefaultStrokeColor = mContext.getColor(R.color.smart_reply_button_stroke);
+        mRippleColor = mContext.getColor(R.color.notification_ripple_untinted_color);
+        mRippleColorDarkBg = Color.argb(Color.alpha(mRippleColor),
+                255 /* red */, 255 /* green */, 255 /* blue */);
+        mMinStrokeContrast = NotificationColorUtil.calculateContrast(mDefaultStrokeColor,
+                mDefaultBackgroundColor);
+
         int spacing = 0;
         int singleLineButtonPaddingHorizontal = 0;
         int doubleLineButtonPaddingHorizontal = 0;
+        int strokeWidth = 0;
 
         final TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.SmartReplyView,
                 0, 0);
@@ -102,10 +137,14 @@
                 case R.styleable.SmartReplyView_doubleLineButtonPaddingHorizontal:
                     doubleLineButtonPaddingHorizontal = arr.getDimensionPixelSize(i, 0);
                     break;
+                case R.styleable.SmartReplyView_buttonStrokeWidth:
+                    strokeWidth = arr.getDimensionPixelSize(i, 0);
+                    break;
             }
         }
         arr.recycle();
 
+        mStrokeWidth = strokeWidth;
         mSpacing = spacing;
         mSingleLineButtonPaddingHorizontal = singleLineButtonPaddingHorizontal;
         mDoubleLineButtonPaddingHorizontal = doubleLineButtonPaddingHorizontal;
@@ -139,6 +178,7 @@
             View smartReplyContainer) {
         mSmartReplyContainer = smartReplyContainer;
         removeAllViews();
+        mCurrentBackgroundColor = mDefaultBackgroundColor;
         if (remoteInput != null && pendingIntent != null) {
             CharSequence[] choices = remoteInput.getChoices();
             if (choices != null) {
@@ -194,6 +234,7 @@
             }
         });
 
+        setColors(b, mCurrentBackgroundColor, mDefaultStrokeColor, mDefaultTextColor, mRippleColor);
         return b;
     }
 
@@ -523,6 +564,51 @@
         return lp.show && super.drawChild(canvas, child, drawingTime);
     }
 
+    public void setBackgroundTintColor(int backgroundColor) {
+        if (backgroundColor == mCurrentBackgroundColor) {
+            // Same color ignoring.
+           return;
+        }
+        mCurrentBackgroundColor = backgroundColor;
+
+        final boolean dark = !NotificationColorUtil.isColorLight(backgroundColor);
+
+        int textColor = NotificationColorUtil.ensureTextContrast(
+                dark ? mDefaultTextColorDarkBg : mDefaultTextColor,
+                backgroundColor | 0xff000000, dark);
+        int strokeColor = NotificationColorUtil.ensureContrast(
+                mDefaultStrokeColor, backgroundColor | 0xff000000, dark, mMinStrokeContrast);
+        int rippleColor = dark ? mRippleColorDarkBg : mRippleColor;
+
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final Button child = (Button) getChildAt(i);
+            setColors(child, backgroundColor, strokeColor, textColor, rippleColor);
+        }
+    }
+
+    private void setColors(Button button, int backgroundColor, int strokeColor, int textColor,
+            int rippleColor) {
+        Drawable drawable = button.getBackground();
+        if (drawable instanceof RippleDrawable) {
+            // Mutate in case other notifications are using this drawable.
+            drawable = drawable.mutate();
+            RippleDrawable ripple = (RippleDrawable) drawable;
+            ripple.setColor(ColorStateList.valueOf(rippleColor));
+            Drawable inset = ripple.getDrawable(0);
+            if (inset instanceof InsetDrawable) {
+                Drawable background = ((InsetDrawable) inset).getDrawable();
+                if (background instanceof GradientDrawable) {
+                    GradientDrawable gradientDrawable = (GradientDrawable) background;
+                    gradientDrawable.setColor(backgroundColor);
+                    gradientDrawable.setStroke(mStrokeWidth, strokeColor);
+                }
+            }
+            button.setBackground(drawable);
+        }
+        button.setTextColor(textColor);
+    }
+
     @VisibleForTesting
     static class LayoutParams extends ViewGroup.LayoutParams {
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 8115297..55ec142 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -52,7 +52,7 @@
     private static final int NUMBER_OF_CHILDREN_WHEN_COLLAPSED = 2;
     private static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5;
     private static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8;
-    private static final int NUMBER_OF_CHILDREN_WHEN_AMBIENT = 3;
+    private static final int NUMBER_OF_CHILDREN_WHEN_AMBIENT = 1;
     private static final AnimationProperties ALPHA_FADE_IN = new AnimationProperties() {
         private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
 
@@ -208,9 +208,9 @@
             // We need to measure all children even the GONE ones, such that the heights are
             // calculated correctly as they are used to calculate how many we can fit on the screen.
             boolean isOverflow = i == overflowIndex;
-            child.setSingleLineWidthIndention(isOverflow && mOverflowNumber != null
-                    ? mOverflowNumber.getMeasuredWidth()
-                    : 0);
+            child.setSingleLineWidthIndention(isOverflow && mOverflowNumber != null &&
+                    !mContainingNotification.isShowingAmbient()
+                    ? mOverflowNumber.getMeasuredWidth() : 0);
             child.measure(widthMeasureSpec, newHeightSpec);
             // layout the divider
             View divider = mDividers.get(i);
@@ -394,8 +394,19 @@
         int childCount = mChildren.size();
         int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
         if (childCount > maxAllowedVisibleChildren) {
-            mOverflowNumber = mHybridGroupManager.bindOverflowNumber(
-                    mOverflowNumber, childCount - maxAllowedVisibleChildren);
+            int number = childCount - maxAllowedVisibleChildren;
+            mOverflowNumber = mHybridGroupManager.bindOverflowNumber(mOverflowNumber, number);
+            if (mContainingNotification.isShowingAmbient()) {
+                ExpandableNotificationRow overflowView = mChildren.get(0);
+                HybridNotificationView ambientSingleLineView = overflowView == null ? null
+                        : overflowView.getAmbientSingleLineView();
+                if (ambientSingleLineView != null) {
+                    mHybridGroupManager.bindOverflowNumberAmbient(
+                            ambientSingleLineView.getTitleView(),
+                            mContainingNotification.getStatusBarNotification().getNotification(),
+                            number);
+                }
+            }
             if (mGroupOverFlowState == null) {
                 mGroupOverFlowState = new ViewState();
                 mNeverAppliedGroupState = true;
@@ -617,16 +628,13 @@
         }
         if (mOverflowNumber != null) {
             ExpandableNotificationRow overflowView = mChildren.get(Math.min(
-                    getMaxAllowedVisibleChildren(true /* likeCollpased */), childCount) - 1);
+                    getMaxAllowedVisibleChildren(true /* likeCollapsed */), childCount) - 1);
             mGroupOverFlowState.copyFrom(resultState.getViewStateForView(overflowView));
 
-            if (mContainingNotification.isShowingAmbient() || !mChildrenExpanded) {
-                HybridNotificationView alignView = null;
-                if (mContainingNotification.isShowingAmbient()) {
-                    alignView = overflowView.getAmbientSingleLineView();
-                } else if (mUserLocked) {
-                    alignView = overflowView.getSingleLineView();
-                }
+            if (mContainingNotification.isShowingAmbient()) {
+                mGroupOverFlowState.alpha = 0.0f;
+            } else if (!mChildrenExpanded) {
+                HybridNotificationView alignView = overflowView.getSingleLineView();
                 if (alignView != null) {
                     View mirrorView = alignView.getTextView();
                     if (mirrorView.getVisibility() == GONE) {
@@ -635,9 +643,9 @@
                     if (mirrorView.getVisibility() == GONE) {
                         mirrorView = alignView;
                     }
+                    mGroupOverFlowState.alpha = mirrorView.getAlpha();
                     mGroupOverFlowState.yTranslation += NotificationUtils.getRelativeYOffset(
                             mirrorView, overflowView);
-                    mGroupOverFlowState.alpha = mirrorView.getAlpha();
                 }
             } else {
                 mGroupOverFlowState.yTranslation += mNotificationHeaderMargin;
@@ -881,6 +889,7 @@
 
     public void notifyShowAmbientChanged() {
         updateHeaderVisibility(false);
+        updateGroupOverflow();
     }
 
     private void updateHeaderVisibility(boolean animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 5deebff..176905a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -112,7 +112,6 @@
 import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Objects;
 import java.util.function.BiConsumer;
 
 /**
@@ -4078,23 +4077,20 @@
         int newVisibility = visible ? VISIBLE : GONE;
 
         boolean changedVisibility = oldVisibility != newVisibility;
-        if (changedVisibility || newVisibility != GONE) {
+        if (changedVisibility) {
             if (newVisibility != GONE) {
-                int oldText = mEmptyShadeView.getTextResource();
-                int newText;
-                if (mStatusBar.areNotificationsHidden()) {
-                    newText = R.string.dnd_suppressing_shade_text;
-                } else {
-                    newText = R.string.empty_shade_text;
-                }
-                if (changedVisibility || !Objects.equals(oldText, newText)) {
-                    mEmptyShadeView.setText(newText);
-                    showFooterView(mEmptyShadeView);
-                }
+                showFooterView(mEmptyShadeView);
             } else {
                 hideFooterView(mEmptyShadeView, true);
             }
         }
+
+        int oldTextRes = mEmptyShadeView.getTextResource();
+        int newTextRes = mStatusBar.areNotificationsHidden()
+                ? R.string.dnd_suppressing_shade_text : R.string.empty_shade_text;
+        if (oldTextRes != newTextRes) {
+            mEmptyShadeView.setText(newTextRes);
+        }
     }
 
     public void updateFooterView(boolean visible, boolean showDismissView) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java
index b3dddd5..a6d87af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationBlockingHelperManagerTest.java
@@ -20,6 +20,7 @@
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 
 import android.content.Context;
+import android.support.test.filters.FlakyTest;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -29,6 +30,7 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
@@ -48,6 +50,7 @@
  * Tests for {@link NotificationBlockingHelperManager}.
  */
 @SmallTest
+@FlakyTest
 @org.junit.runner.RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 public class NotificationBlockingHelperManagerTest extends SysuiTestCase {
@@ -56,7 +59,6 @@
 
     private NotificationTestHelper mHelper;
 
-    @Rule public MockitoRule mockito = MockitoJUnit.rule();
     @Mock private NotificationGutsManager mGutsManager;
     @Mock private NotificationEntryManager mEntryManager;
     @Mock private NotificationMenuRow mMenuRow;
@@ -64,20 +66,22 @@
 
     @Before
     public void setUp() {
-        mBlockingHelperManager = new NotificationBlockingHelperManager(mContext);
-        // By default, have the shade visible/expanded.
-        mBlockingHelperManager.setNotificationShadeExpanded(1f);
-
-        mHelper = new NotificationTestHelper(mContext);
+        MockitoAnnotations.initMocks(this);
         when(mGutsManager.openGuts(
                 any(View.class),
                 anyInt(),
                 anyInt(),
                 any(NotificationMenuRowPlugin.MenuItem.class)))
                 .thenReturn(true);
+        when(mMenuRow.getLongpressMenuItem(any(Context.class))).thenReturn(mMenuItem);
         mDependency.injectTestDependency(NotificationGutsManager.class, mGutsManager);
         mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
-        when(mMenuRow.getLongpressMenuItem(any(Context.class))).thenReturn(mMenuItem);
+
+        mHelper = new NotificationTestHelper(mContext);
+
+        mBlockingHelperManager = new NotificationBlockingHelperManager(mContext);
+        // By default, have the shade visible/expanded.
+        mBlockingHelperManager.setNotificationShadeExpanded(1f);
     }
 
     @Test
@@ -89,7 +93,7 @@
 
     @Test
     public void testDismissCurrentBlockingHelper_withDetachedBlockingHelperRow() throws Exception {
-        ExpandableNotificationRow row = spy(createBlockableRowSpy());
+        ExpandableNotificationRow row = createBlockableRowSpy();
         row.setBlockingHelperShowing(true);
         when(row.isAttachedToWindow()).thenReturn(false);
         mBlockingHelperManager.setBlockingHelperRowForTest(row);
@@ -102,7 +106,7 @@
 
     @Test
     public void testDismissCurrentBlockingHelper_withAttachedBlockingHelperRow() throws Exception {
-        ExpandableNotificationRow row = spy(createBlockableRowSpy());
+        ExpandableNotificationRow row = createBlockableRowSpy();
         row.setBlockingHelperShowing(true);
         when(row.isAttachedToWindow()).thenReturn(true);
         mBlockingHelperManager.setBlockingHelperRowForTest(row);
@@ -200,7 +204,7 @@
 
     @Test
     public void testBlockingHelperShowAndDismiss() throws Exception{
-        ExpandableNotificationRow row = spy(createBlockableRowSpy());
+        ExpandableNotificationRow row = createBlockableRowSpy();
         row.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
         when(row.isAttachedToWindow()).thenReturn(true);
 
@@ -227,6 +231,4 @@
         when(row.getIsNonblockable()).thenReturn(false);
         return row;
     }
-
-
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 65fd7f5..cb509e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -509,6 +509,36 @@
                         anyString(), eq(TEST_UID), eq(true));
     }
 
+
+    @Test
+    public void testCloseControls_nonNullCheckSaveListenerDoesntDelayKeepShowing()
+            throws Exception {
+        NotificationInfo.CheckSaveListener listener =
+                mock(NotificationInfo.CheckSaveListener.class);
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
+                10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
+                null /* onSettingsClick */, null /* onAppSettingsClick */ ,
+                false /* isNonblockable */, true /* isForBlockingHelper */,
+                true /* isUserSentimentNegative */);
+
+        NotificationGuts guts = spy(new NotificationGuts(mContext, null));
+        when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
+        doNothing().when(guts).animateClose(anyInt(), anyInt(), anyBoolean());
+        doNothing().when(guts).setExposed(anyBoolean(), anyBoolean());
+        guts.setGutsContent(mNotificationInfo);
+        mNotificationInfo.setGutsParent(guts);
+
+        mNotificationInfo.findViewById(R.id.keep).performClick();
+
+        verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
+        mTestableLooper.processAllMessages();
+        verify(mMockINotificationManager, times(1))
+                .setNotificationsEnabledWithImportanceLockForPackage(
+                        anyString(), eq(TEST_UID), eq(true));
+    }
+
+
     @Test
     public void testCloseControls_blockingHelperDismissedIfShown() throws Exception {
         mNotificationInfo.bindNotification(
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 85b0220..f992049 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -568,8 +568,9 @@
             Context userContext = mContext.createPackageContextAsUser(providerPackage, 0,
                     UserHandle.of(providerUserId));
             PackageManager pm = userContext.getPackageManager();
-            Drawable icon = pm.getApplicationInfo(providerPackage, 0).loadUnbadgedIcon(pm);
+            Drawable icon = pm.getApplicationInfo(providerPackage, 0).loadUnbadgedIcon(pm).mutate();
             // Create a bitmap of the icon which is what the widget's remoteview requires.
+            icon.setColorFilter(mIconUtilities.getDisabledColorFilter());
             return mIconUtilities.createIconBitmap(icon);
         } catch (NameNotFoundException e) {
             Slog.e(TAG, "Fail to get application icon", e);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 6ff9539..4bd8063 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -32,6 +32,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ServiceInfo;
@@ -667,7 +668,10 @@
 
     @NonNull
     CharSequence getServiceLabel() {
-        return mInfo.getServiceInfo().loadLabel(mContext.getPackageManager());
+        final CharSequence label = mInfo.getServiceInfo().loadSafeLabel(
+                mContext.getPackageManager(), 0 /* do not ellipsize */,
+                PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE | PackageItemInfo.SAFE_LABEL_FLAG_TRIM);
+        return label;
     }
 
     @NonNull
@@ -912,6 +916,7 @@
         } else {
             pw.println();
             mInfo.dump(prefix2, pw);
+            pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabel());
         }
         pw.print(prefix); pw.print("Component from settings: ");
             pw.println(getComponentNameFromSettings());
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 13503e6..7f26575 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -21,13 +21,16 @@
 import android.app.ActivityThread;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.UserInfo;
+import android.database.ContentObserver;
 import android.media.AudioAttributes;
+import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Bundle;
@@ -43,9 +46,11 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManagerInternal;
+import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.KeyValueListParser;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -109,9 +114,6 @@
     // Write at most every 30 minutes.
     static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
 
-    // How long we want for a drop in uid state to settle before applying it.
-    static final long STATE_SETTLE_TIME = 10*1000;
-
     // Constant meaning that any UID should be matched when dispatching callbacks
     private static final int UID_ANY = -2;
 
@@ -198,6 +200,75 @@
      */
     private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
 
+    /**
+     * All times are in milliseconds. These constants are kept synchronized with the system
+     * global Settings. Any access to this class or its fields should be done while
+     * holding the AppOpsService lock.
+     */
+    private final class Constants extends ContentObserver {
+        // Key names stored in the settings value.
+        private static final String KEY_STATE_SETTLE_TIME = "state_settle_time";
+
+        /**
+         * How long we want for a drop in uid state to settle before applying it.
+         * @see Settings.Global#APP_OPS_CONSTANTS
+         * @see #KEY_STATE_SETTLE_TIME
+         */
+        public long STATE_SETTLE_TIME;
+
+
+        private final KeyValueListParser mParser = new KeyValueListParser(',');
+        private ContentResolver mResolver;
+
+        public Constants(Handler handler) {
+            super(handler);
+            updateConstants();
+        }
+
+        public void startMonitoring(ContentResolver resolver) {
+            mResolver = resolver;
+            mResolver.registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.DEVICE_IDLE_CONSTANTS),
+                    false, this);
+            updateConstants();
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            updateConstants();
+        }
+
+        private void updateConstants() {
+            synchronized (AppOpsService.this) {
+                try {
+                    if (mResolver != null) {
+                        mParser.setString(Settings.Global.getString(mResolver,
+                                Settings.Global.APP_OPS_CONSTANTS));
+                    } else {
+                        mParser.setString("");
+                    }
+                } catch (IllegalArgumentException e) {
+                    // Failed to parse the settings string, log this and move on
+                    // with defaults.
+                    Slog.e(TAG, "Bad app ops settings", e);
+                }
+
+                STATE_SETTLE_TIME = mParser.getDurationMillis(
+                        KEY_STATE_SETTLE_TIME, 10 * 1000L);
+            }
+        }
+
+        void dump(PrintWriter pw) {
+            pw.println("  Settings:");
+
+            pw.print("    "); pw.print(KEY_STATE_SETTLE_TIME); pw.print("=");
+            TimeUtils.formatDuration(STATE_SETTLE_TIME, pw);
+            pw.println();
+        }
+    }
+
+    private final Constants mConstants;
+
     @VisibleForTesting
     static final class UidState {
         public final int uid;
@@ -210,7 +281,9 @@
         public ArrayMap<String, Ops> pkgOps;
         public SparseIntArray opModes;
 
+        // true indicates there is an interested observer, false there isn't but it has such an op
         public SparseBooleanArray foregroundOps;
+        public boolean hasForegroundWatchers;
 
         public UidState(int uid) {
             this.uid = uid;
@@ -234,8 +307,35 @@
             return mode;
         }
 
-        public void evalForegroundOps() {
+        private void evalForegroundWatchers(int op, SparseArray<ArraySet<ModeCallback>> watchers,
+                SparseBooleanArray which) {
+            boolean curValue = which.get(op, false);
+            ArraySet<ModeCallback> callbacks = watchers.get(op);
+            if (callbacks != null) {
+                for (int cbi = callbacks.size() - 1; !curValue && cbi >= 0; cbi--) {
+                    if ((callbacks.valueAt(cbi).mFlags
+                            & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
+                        hasForegroundWatchers = true;
+                        curValue = true;
+                    }
+                }
+            }
+            which.put(op, curValue);
+        }
+
+        public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
             SparseBooleanArray which = null;
+            hasForegroundWatchers = false;
+            if (opModes != null) {
+                for (int i = opModes.size() - 1; i >= 0; i--) {
+                    if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
+                        if (which == null) {
+                            which = new SparseBooleanArray();
+                        }
+                        evalForegroundWatchers(opModes.keyAt(i), watchers, which);
+                    }
+                }
+            }
             if (pkgOps != null) {
                 for (int i = pkgOps.size() - 1; i >= 0; i--) {
                     Ops ops = pkgOps.valueAt(i);
@@ -244,7 +344,7 @@
                             if (which == null) {
                                 which = new SparseBooleanArray();
                             }
-                            which.put(ops.keyAt(j), true);
+                            evalForegroundWatchers(ops.keyAt(j), watchers, which);
                         }
                     }
                 }
@@ -313,13 +413,15 @@
     final class ModeCallback implements DeathRecipient {
         final IAppOpsCallback mCallback;
         final int mWatchingUid;
+        final int mFlags;
         final int mCallingUid;
         final int mCallingPid;
 
-        ModeCallback(IAppOpsCallback callback, int watchingUid, int callingUid,
+        ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int callingUid,
                 int callingPid) {
             mCallback = callback;
             mWatchingUid = watchingUid;
+            mFlags = flags;
             mCallingUid = callingUid;
             mCallingPid = callingPid;
             try {
@@ -328,6 +430,10 @@
             }
         }
 
+        public boolean isWatchingUid(int uid) {
+            return uid == UID_ANY || mWatchingUid < 0 || mWatchingUid == uid;
+        }
+
         @Override
         public String toString() {
             StringBuilder sb = new StringBuilder(128);
@@ -335,6 +441,8 @@
             sb.append(Integer.toHexString(System.identityHashCode(this)));
             sb.append(" watchinguid=");
             UserHandle.formatUid(sb, mWatchingUid);
+            sb.append(" flags=0x");
+            sb.append(Integer.toHexString(mFlags));
             sb.append(" from uid=");
             UserHandle.formatUid(sb, mCallingUid);
             sb.append(" pid=");
@@ -439,6 +547,7 @@
         LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
         mFile = new AtomicFile(storagePath, "appops");
         mHandler = handler;
+        mConstants = new Constants(mHandler);
         readState();
     }
 
@@ -449,6 +558,7 @@
 
     public void systemReady() {
         synchronized (this) {
+            mConstants.startMonitoring(mContext.getContentResolver());
             boolean changed = false;
             for (int i = mUidStates.size() - 1; i >= 0; i--) {
                 UidState uidState = mUidStates.valueAt(i);
@@ -611,14 +721,16 @@
             final UidState uidState = getUidStateLocked(uid, true);
             final int newState = PROCESS_STATE_TO_UID_STATE[procState];
             if (uidState != null && uidState.pendingState != newState) {
+                final int oldPendingState = uidState.pendingState;
+                uidState.pendingState = newState;
                 if (newState < uidState.state) {
                     // We are moving to a more important state, always do it immediately.
-                    uidState.state = newState;
-                    uidState.pendingStateCommitTime = 0;
+                    commitUidPendingStateLocked(uidState);
                 } else if (uidState.pendingStateCommitTime == 0) {
                     // We are moving to a less important state for the first time,
                     // delay the application for a bit.
-                    uidState.pendingStateCommitTime = SystemClock.uptimeMillis() + STATE_SETTLE_TIME;
+                    uidState.pendingStateCommitTime = SystemClock.uptimeMillis() +
+                            mConstants.STATE_SETTLE_TIME;
                 }
                 if (uidState.startNesting != 0) {
                     // There is some actively running operation...  need to find it
@@ -629,13 +741,12 @@
                         for (int j = ops.size() - 1; j >= 0; j--) {
                             final Op op = ops.valueAt(j);
                             if (op.startNesting > 0) {
-                                op.time[uidState.pendingState] = now;
+                                op.time[oldPendingState] = now;
                                 op.time[newState] = now;
                             }
                         }
                     }
                 }
-                uidState.pendingState = newState;
             }
         }
     }
@@ -867,7 +978,9 @@
                     ModeCallback callback = callbacks.valueAt(i);
                     ArraySet<String> changedPackages = new ArraySet<>();
                     Collections.addAll(changedPackages, uidPackageNames);
-                    callbackSpecs = new ArrayMap<>();
+                    if (callbackSpecs == null) {
+                        callbackSpecs = new ArrayMap<>();
+                    }
                     callbackSpecs.put(callback, changedPackages);
                 }
             }
@@ -932,7 +1045,7 @@
                 if (op.mode != mode) {
                     op.mode = mode;
                     if (uidState != null) {
-                        uidState.evalForegroundOps();
+                        uidState.evalForegroundOps(mOpModeWatchers);
                     }
                     ArraySet<ModeCallback> cbs = mOpModeWatchers.get(code);
                     if (cbs != null) {
@@ -1126,7 +1239,7 @@
                     mUidStates.remove(uidState.uid);
                 }
                 if (uidChanged) {
-                    uidState.evalForegroundOps();
+                    uidState.evalForegroundOps(mOpModeWatchers);
                 }
             }
 
@@ -1148,8 +1261,23 @@
         }
     }
 
+    private void evalAllForegroundOpsLocked() {
+        for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
+            final UidState uidState = mUidStates.valueAt(uidi);
+            if (uidState.foregroundOps != null) {
+                uidState.evalForegroundOps(mOpModeWatchers);
+            }
+        }
+    }
+
     @Override
     public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
+        startWatchingModeWithFlags(op, packageName, 0, callback);
+    }
+
+    @Override
+    public void startWatchingModeWithFlags(int op, String packageName, int flags,
+            IAppOpsCallback callback) {
         int watchedUid = -1;
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
@@ -1166,7 +1294,7 @@
             op = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
             ModeCallback cb = mModeWatchers.get(callback.asBinder());
             if (cb == null) {
-                cb = new ModeCallback(callback, watchedUid, callingUid, callingPid);
+                cb = new ModeCallback(callback, watchedUid, flags, callingUid, callingPid);
                 mModeWatchers.put(callback.asBinder(), cb);
             }
             if (op != AppOpsManager.OP_NONE) {
@@ -1185,6 +1313,7 @@
                 }
                 cbs.add(cb);
             }
+            evalAllForegroundOpsLocked();
         }
     }
 
@@ -1212,6 +1341,7 @@
                     }
                 }
             }
+            evalAllForegroundOpsLocked();
         }
     }
 
@@ -1249,7 +1379,7 @@
             if (op == null) {
                 return AppOpsManager.opToDefaultMode(code);
             }
-            return op.mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : op.mode;
+            return op.mode;
         }
     }
 
@@ -1699,13 +1829,11 @@
         } else {
             if (uidState.pendingStateCommitTime != 0) {
                 if (uidState.pendingStateCommitTime < mLastUptime) {
-                    uidState.state = uidState.pendingState;
-                    uidState.pendingStateCommitTime = 0;
+                    commitUidPendingStateLocked(uidState);
                 } else {
                     mLastUptime = SystemClock.uptimeMillis();
                     if (uidState.pendingStateCommitTime < mLastUptime) {
-                        uidState.state = uidState.pendingState;
-                        uidState.pendingStateCommitTime = 0;
+                        commitUidPendingStateLocked(uidState);
                     }
                 }
             }
@@ -1713,6 +1841,44 @@
         return uidState;
     }
 
+    private void commitUidPendingStateLocked(UidState uidState) {
+        uidState.state = uidState.pendingState;
+        uidState.pendingStateCommitTime = 0;
+        if (uidState.hasForegroundWatchers) {
+            for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
+                if (!uidState.foregroundOps.valueAt(fgi)) {
+                    continue;
+                }
+                final int code = uidState.foregroundOps.keyAt(fgi);
+
+                final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
+                if (callbacks != null) {
+                    for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
+                        final ModeCallback callback = callbacks.valueAt(cbi);
+                        if ((callback.mFlags & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
+                                || !callback.isWatchingUid(uidState.uid)) {
+                            continue;
+                        }
+                        boolean doAllPackages = uidState.opModes != null
+                                && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
+                        if (uidState.pkgOps != null) {
+                            for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
+                                final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
+                                if (doAllPackages || (op != null
+                                        && op.mode == AppOpsManager.MODE_FOREGROUND)) {
+                                    mHandler.sendMessage(PooledLambda.obtainMessage(
+                                            AppOpsService::notifyOpChanged,
+                                            this, callback, code, uidState.uid,
+                                            uidState.pkgOps.keyAt(pkgi)));
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
             boolean uidMismatchExpected) {
         UidState uidState = getUidStateLocked(uid, edit);
@@ -1952,7 +2118,7 @@
                 }
             }
             if (changed) {
-                uidState.evalForegroundOps();
+                uidState.evalForegroundOps(mOpModeWatchers);
             }
         }
     }
@@ -2151,7 +2317,7 @@
         }
         UidState uidState = getUidStateLocked(uid, false);
         if (uidState != null) {
-            uidState.evalForegroundOps();
+            uidState.evalForegroundOps(mOpModeWatchers);
         }
     }
 
@@ -2322,7 +2488,7 @@
             }
         }
 
-        int strModeToMode(String modeStr, PrintWriter err) {
+        static int strModeToMode(String modeStr, PrintWriter err) {
             for (int i = AppOpsManager.MODE_NAMES.length - 1; i >= 0; i--) {
                 if (AppOpsManager.MODE_NAMES[i].equals(modeStr)) {
                     return i;
@@ -2716,6 +2882,10 @@
         pw.println("    Print this help text.");
         pw.println("  --op [OP]");
         pw.println("    Limit output to data associated with the given app op code.");
+        pw.println("  --mode [MODE]");
+        pw.println("    Limit output to data associated with the given app op mode.");
+        pw.println("  --package [PACKAGE]");
+        pw.println("    Limit output to data associated with the given package name.");
     }
 
     private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
@@ -2751,6 +2921,9 @@
         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
 
         int dumpOp = -1;
+        String dumpPackage = null;
+        int dumpUid = -1;
+        int dumpMode = -1;
 
         if (args != null) {
             for (int i=0; i<args.length; i++) {
@@ -2770,6 +2943,34 @@
                     if (dumpOp < 0) {
                         return;
                     }
+                } else if ("--package".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("No argument for --package option");
+                        return;
+                    }
+                    dumpPackage = args[i];
+                    try {
+                        dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
+                                PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
+                                0);
+                    } catch (RemoteException e) {
+                    }
+                    if (dumpUid < 0) {
+                        pw.println("Unknown package: " + dumpPackage);
+                        return;
+                    }
+                    dumpUid = UserHandle.getAppId(dumpUid);
+                } else if ("--mode".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("No argument for --mode option");
+                        return;
+                    }
+                    dumpMode = Shell.strModeToMode(args[i], pw);
+                    if (dumpMode < 0) {
+                        return;
+                    }
                 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
                     pw.println("Unknown option: " + arg);
                     return;
@@ -2782,6 +2983,8 @@
 
         synchronized (this) {
             pw.println("Current AppOps Service state:");
+            mConstants.dump(pw);
+            pw.println();
             final long now = System.currentTimeMillis();
             final long nowElapsed = SystemClock.elapsedRealtime();
             final long nowUptime = SystemClock.uptimeMillis();
@@ -2789,29 +2992,46 @@
             final Date date = new Date();
             boolean needSep = false;
             if (mOpModeWatchers.size() > 0) {
-                needSep = true;
                 boolean printedHeader = false;
                 for (int i=0; i<mOpModeWatchers.size(); i++) {
                     if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
                         continue;
                     }
-                    if (!printedHeader) {
-                        pw.println("  Op mode watchers:");
-                        printedHeader = true;
-                    }
-                    pw.print("    Op "); pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
-                    pw.println(":");
+                    boolean printedOpHeader = false;
                     ArraySet<ModeCallback> callbacks = mOpModeWatchers.valueAt(i);
                     for (int j=0; j<callbacks.size(); j++) {
+                        final ModeCallback cb = callbacks.valueAt(j);
+                        if (dumpPackage != null && cb.mWatchingUid >= 0
+                                && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+                            continue;
+                        }
+                        needSep = true;
+                        if (!printedHeader) {
+                            pw.println("  Op mode watchers:");
+                            printedHeader = true;
+                        }
+                        if (!printedOpHeader) {
+                            pw.print("    Op ");
+                            pw.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
+                            pw.println(":");
+                            printedOpHeader = true;
+                        }
                         pw.print("      #"); pw.print(j); pw.print(": ");
-                        pw.println(callbacks.valueAt(j));
+                        pw.println(cb);
                     }
                 }
             }
-            if (mPackageModeWatchers.size() > 0) {
-                needSep = true;
-                pw.println("  Package mode watchers:");
+            if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
+                boolean printedHeader = false;
                 for (int i=0; i<mPackageModeWatchers.size(); i++) {
+                    if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
+                        continue;
+                    }
+                    needSep = true;
+                    if (!printedHeader) {
+                        pw.println("  Package mode watchers:");
+                        printedHeader = true;
+                    }
                     pw.print("    Pkg "); pw.print(mPackageModeWatchers.keyAt(i));
                     pw.println(":");
                     ArraySet<ModeCallback> callbacks = mPackageModeWatchers.valueAt(i);
@@ -2822,15 +3042,24 @@
                 }
             }
             if (mModeWatchers.size() > 0 && dumpOp < 0) {
-                needSep = true;
-                pw.println("  All op mode watchers:");
+                boolean printedHeader = false;
                 for (int i=0; i<mModeWatchers.size(); i++) {
+                    final ModeCallback cb = mModeWatchers.valueAt(i);
+                    if (dumpPackage != null && cb.mWatchingUid >= 0
+                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+                        continue;
+                    }
+                    needSep = true;
+                    if (!printedHeader) {
+                        pw.println("  All op mode watchers:");
+                        printedHeader = true;
+                    }
                     pw.print("    ");
                     pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
-                    pw.print(": "); pw.println(mModeWatchers.valueAt(i));
+                    pw.print(": "); pw.println(cb);
                 }
             }
-            if (mActiveWatchers.size() > 0) {
+            if (mActiveWatchers.size() > 0 && dumpMode < 0) {
                 needSep = true;
                 boolean printedHeader = false;
                 for (int i = 0; i < mActiveWatchers.size(); i++) {
@@ -2838,9 +3067,14 @@
                     if (activeWatchers.size() <= 0) {
                         continue;
                     }
+                    final ActiveCallback cb = activeWatchers.valueAt(0);
                     if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
                         continue;
                     }
+                    if (dumpPackage != null && cb.mWatchingUid >= 0
+                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+                        continue;
+                    }
                     if (!printedHeader) {
                         pw.println("  All op active watchers:");
                         printedHeader = true;
@@ -2862,10 +3096,10 @@
                     }
                     pw.println("]");
                     pw.print("        ");
-                    pw.println(activeWatchers.valueAt(0));
+                    pw.println(cb);
                 }
             }
-            if (mClients.size() > 0) {
+            if (mClients.size() > 0 && dumpMode < 0) {
                 needSep = true;
                 boolean printedHeader = false;
                 for (int i=0; i<mClients.size(); i++) {
@@ -2878,6 +3112,9 @@
                             if (dumpOp >= 0 && op.op != dumpOp) {
                                 continue;
                             }
+                            if (dumpPackage != null && !dumpPackage.equals(op.packageName)) {
+                                continue;
+                            }
                             if (!printedHeader) {
                                 pw.println("  Clients:");
                                 printedHeader = true;
@@ -2898,7 +3135,8 @@
                     }
                 }
             }
-            if (mAudioRestrictions.size() > 0 && dumpOp < 0) {
+            if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
+                    && dumpMode < 0) {
                 boolean printedHeader = false;
                 for (int o=0; o<mAudioRestrictions.size(); o++) {
                     final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
@@ -2931,19 +3169,44 @@
                 final SparseIntArray opModes = uidState.opModes;
                 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
 
-                if (dumpOp >= 0) {
-                    boolean hasOp = uidState.opModes != null
-                            && uidState.opModes.indexOfKey(dumpOp) >= 0;
-                    if (pkgOps != null) {
-                        for (int pkgi = 0; !hasOp && pkgi < pkgOps.size(); pkgi++) {
-                            Ops ops = pkgOps.valueAt(pkgi);
-                            if (ops != null && ops.indexOfKey(dumpOp) >= 0) {
-                                hasOp = true;
-                                continue;
+                if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
+                    boolean hasOp = dumpOp < 0 || (uidState.opModes != null
+                            && uidState.opModes.indexOfKey(dumpOp) >= 0);
+                    boolean hasPackage = dumpPackage == null;
+                    boolean hasMode = dumpMode < 0;
+                    if (!hasMode && opModes != null) {
+                        for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
+                            if (opModes.valueAt(opi) == dumpMode) {
+                                hasMode = true;
                             }
                         }
                     }
-                    if (!hasOp) {
+                    if (pkgOps != null) {
+                        for (int pkgi = 0;
+                                (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
+                                pkgi++) {
+                            Ops ops = pkgOps.valueAt(pkgi);
+                            if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
+                                hasOp = true;
+                            }
+                            if (!hasMode) {
+                                for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
+                                    if (ops.valueAt(opi).mode == dumpMode) {
+                                        hasMode = true;
+                                    }
+                                }
+                            }
+                            if (!hasPackage && dumpPackage.equals(ops.packageName)) {
+                                hasPackage = true;
+                            }
+                        }
+                    }
+                    if (uidState.foregroundOps != null && !hasOp) {
+                        if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
+                            hasOp = true;
+                        }
+                    }
+                    if (!hasOp || !hasPackage || !hasMode) {
                         continue;
                     }
                 }
@@ -2964,12 +3227,20 @@
                     pw.print("    startNesting=");
                     pw.println(uidState.startNesting);
                 }
-                if (uidState.foregroundOps != null) {
+                if (uidState.foregroundOps != null && (dumpMode < 0
+                        || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
                     pw.println("    foregroundOps:");
                     for (int j = 0; j < uidState.foregroundOps.size(); j++) {
-                        pw.print("    ");
-                        pw.println(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
+                        if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
+                            continue;
+                        }
+                        pw.print("      ");
+                        pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
+                        pw.print(": ");
+                        pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
                     }
+                    pw.print("    hasForegroundWatchers=");
+                    pw.println(uidState.hasForegroundWatchers);
                 }
                 needSep = true;
 
@@ -2981,6 +3252,9 @@
                         if (dumpOp >= 0 && dumpOp != code) {
                             continue;
                         }
+                        if (dumpMode >= 0 && dumpMode != mode) {
+                            continue;
+                        }
                         pw.print("      "); pw.print(AppOpsManager.opToName(code));
                         pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
                     }
@@ -2991,19 +3265,34 @@
                 }
 
                 for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
-                    Ops ops = pkgOps.valueAt(pkgi);
+                    final Ops ops = pkgOps.valueAt(pkgi);
+                    if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
+                        continue;
+                    }
                     boolean printedPackage = false;
                     for (int j=0; j<ops.size(); j++) {
-                        Op op = ops.valueAt(j);
+                        final Op op = ops.valueAt(j);
                         if (dumpOp >= 0 && dumpOp != op.op) {
                             continue;
                         }
+                        if (dumpMode >= 0 && dumpMode != op.mode) {
+                            continue;
+                        }
                         if (!printedPackage) {
                             pw.print("    Package "); pw.print(ops.packageName); pw.println(":");
                             printedPackage = true;
                         }
                         pw.print("      "); pw.print(AppOpsManager.opToName(op.op));
                         pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
+                        final int switchOp = AppOpsManager.opToSwitch(op.op);
+                        if (switchOp != op.op) {
+                            pw.print(" / switch ");
+                            pw.print(AppOpsManager.opToName(switchOp));
+                            final Op switchObj = ops.get(switchOp);
+                            int mode = switchObj != null
+                                    ? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
+                            pw.print("="); pw.print(AppOpsManager.modeToName(mode));
+                        }
                         pw.println("): ");
                         dumpTimesLocked(pw,
                                 "          Access: ",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 72f9d74..797cb4b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -500,24 +500,24 @@
     private static final int MAX_VALIDATION_LOGS = 10;
     private static class ValidationLog {
         final Network mNetwork;
-        final String mNetworkExtraInfo;
+        final String mName;
         final ReadOnlyLocalLog mLog;
 
-        ValidationLog(Network network, String networkExtraInfo, ReadOnlyLocalLog log) {
+        ValidationLog(Network network, String name, ReadOnlyLocalLog log) {
             mNetwork = network;
-            mNetworkExtraInfo = networkExtraInfo;
+            mName = name;
             mLog = log;
         }
     }
     private final ArrayDeque<ValidationLog> mValidationLogs =
             new ArrayDeque<ValidationLog>(MAX_VALIDATION_LOGS);
 
-    private void addValidationLogs(ReadOnlyLocalLog log, Network network, String networkExtraInfo) {
+    private void addValidationLogs(ReadOnlyLocalLog log, Network network, String name) {
         synchronized (mValidationLogs) {
             while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) {
                 mValidationLogs.removeLast();
             }
-            mValidationLogs.addFirst(new ValidationLog(network, networkExtraInfo, log));
+            mValidationLogs.addFirst(new ValidationLog(network, name, log));
         }
     }
 
@@ -2097,7 +2097,7 @@
             synchronized (mValidationLogs) {
                 pw.println("mValidationLogs (most recent first):");
                 for (ValidationLog p : mValidationLogs) {
-                    pw.println(p.mNetwork + " - " + p.mNetworkExtraInfo);
+                    pw.println(p.mNetwork + " - " + p.mName);
                     pw.increaseIndent();
                     p.mLog.dump(fd, pw, args);
                     pw.decreaseIndent();
@@ -4628,8 +4628,10 @@
         synchronized (this) {
             nai.networkMonitor.systemReady = mSystemReady;
         }
-        addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network,
-                networkInfo.getExtraInfo());
+        final String extraInfo = networkInfo.getExtraInfo();
+        final String name = TextUtils.isEmpty(extraInfo)
+                ? nai.networkCapabilities.getSSID() : extraInfo;
+        addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network, name);
         if (DBG) log("registerNetworkAgent " + nai);
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
         return nai.network.netId;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 20b8407..48090f2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -22995,18 +22995,27 @@
         }
     }
 
-    private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
+    private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
             boolean doingAll, long now) {
         if (mAdjSeq == app.adjSeq) {
-            // This adjustment has already been computed.
-            return app.curRawAdj;
+            if (app.adjSeq == app.completedAdjSeq) {
+                // This adjustment has already been computed successfully.
+                return false;
+            } else {
+                // The process is being computed, so there is a cycle. We cannot
+                // rely on this process's state.
+                app.containsCycle = true;
+                return false;
+            }
         }
 
         if (app.thread == null) {
             app.adjSeq = mAdjSeq;
             app.curSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
             app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
-            return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
+            app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ;
+            app.completedAdjSeq = app.adjSeq;
+            return false;
         }
 
         app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
@@ -23019,6 +23028,8 @@
         final int appUid = app.info.uid;
         final int logUid = mCurOomAdjUid;
 
+        int prevAppAdj = app.curAdj;
+
         if (app.maxAdj <= ProcessList.FOREGROUND_APP_ADJ) {
             // The max adjustment doesn't allow this app to be anything
             // below foreground, so it is not worth doing work for it.
@@ -23063,7 +23074,10 @@
                   app.curSchedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
               }
             }
-            return (app.curAdj=app.maxAdj);
+            app.curAdj = app.maxAdj;
+            app.completedAdjSeq = app.adjSeq;
+            // if curAdj is less than prevAppAdj, then this process was promoted
+            return app.curAdj < prevAppAdj;
         }
 
         app.systemNoUi = false;
@@ -23075,6 +23089,8 @@
         int adj;
         int schedGroup;
         int procState;
+        int cachedAdjSeq;
+
         boolean foregroundActivities = false;
         mTmpBroadcastQueue.clear();
         if (PROCESS_STATE_CUR_TOP == ActivityManager.PROCESS_STATE_TOP && app == TOP_APP) {
@@ -23388,9 +23404,9 @@
         // there are applications dependent on our services or providers, but
         // this gives us a baseline and makes sure we don't get into an
         // infinite recursion.
-        app.adjSeq = mAdjSeq;
         app.curRawAdj = adj;
         app.hasStartedServices = false;
+        app.adjSeq = mAdjSeq;
 
         if (mBackupTarget != null && app == mBackupTarget.app) {
             // If possible we want to avoid killing apps while they're being backed up
@@ -23489,8 +23505,15 @@
 
                     if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) {
                         ProcessRecord client = cr.binding.client;
-                        int clientAdj = computeOomAdjLocked(client, cachedAdj,
-                                TOP_APP, doingAll, now);
+                        computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
+                        if (client.containsCycle) {
+                            // We've detected a cycle. We should ignore this connection and allow
+                            // this process to retry computeOomAdjLocked later in case a later-checked
+                            // connection from a client  would raise its priority legitimately.
+                            app.containsCycle = true;
+                            continue;
+                        }
+                        int clientAdj = client.curRawAdj;
                         int clientProcState = client.curProcState;
                         if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
                             // If the other app is cached for any reason, for purposes here
@@ -23709,7 +23732,15 @@
                     // Being our own client is not interesting.
                     continue;
                 }
-                int clientAdj = computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
+                computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now);
+                if (client.containsCycle) {
+                    // We've detected a cycle. We should ignore this connection and allow
+                    // this process to retry computeOomAdjLocked later in case a later-checked
+                    // connection from a client  would raise its priority legitimately.
+                    app.containsCycle = true;
+                    continue;
+                }
+                int clientAdj = client.curRawAdj;
                 int clientProcState = client.curProcState;
                 if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
                     // If the other app is cached for any reason, for purposes here
@@ -23937,8 +23968,10 @@
         app.curSchedGroup = schedGroup;
         app.curProcState = procState;
         app.foregroundActivities = foregroundActivities;
+        app.completedAdjSeq = mAdjSeq;
 
-        return app.curRawAdj;
+        // if curAdj is less than prevAppAdj, then this process was promoted
+        return app.curAdj < prevAppAdj;
     }
 
     /**
@@ -24912,12 +24945,23 @@
         int nextCachedAdj = curCachedAdj+1;
         int curEmptyAdj = ProcessList.CACHED_APP_MIN_ADJ;
         int nextEmptyAdj = curEmptyAdj+2;
+
+        boolean retryCycles = false;
+
+        // need to reset cycle state before calling computeOomAdjLocked because of service connections
+        for (int i=N-1; i>=0; i--) {
+            ProcessRecord app = mLruProcesses.get(i);
+            app.containsCycle = false;
+        }
         for (int i=N-1; i>=0; i--) {
             ProcessRecord app = mLruProcesses.get(i);
             if (!app.killedByAm && app.thread != null) {
                 app.procStateChanged = false;
                 computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now);
 
+                // if any app encountered a cycle, we need to perform an additional loop later
+                retryCycles |= app.containsCycle;
+
                 // If we haven't yet assigned the final cached adj
                 // to the process, do that now.
                 if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
@@ -24971,6 +25015,39 @@
                     }
                 }
 
+
+            }
+        }
+
+        // Cycle strategy:
+        // - Retry computing any process that has encountered a cycle.
+        // - Continue retrying until no process was promoted.
+        // - Iterate from least important to most important.
+        int cycleCount = 0;
+        while (retryCycles) {
+            cycleCount++;
+            retryCycles = false;
+
+            for (int i=0; i<N; i++) {
+                ProcessRecord app = mLruProcesses.get(i);
+                if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
+                    app.adjSeq--;
+                    app.completedAdjSeq--;
+                }
+            }
+
+            for (int i=0; i<N; i++) {
+                ProcessRecord app = mLruProcesses.get(i);
+                if (!app.killedByAm && app.thread != null && app.containsCycle == true) {
+                    if (computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now)) {
+                        retryCycles = true;
+                    }
+                }
+            }
+        }
+        for (int i=N-1; i>=0; i--) {
+            ProcessRecord app = mLruProcesses.get(i);
+            if (!app.killedByAm && app.thread != null) {
                 applyOomAdjLocked(app, true, now, nowElapsed);
 
                 // Count the number of process types.
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b7fde1d..caf52e3 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -149,6 +149,8 @@
     String waitingToKill;       // Process is waiting to be killed when in the bg, and reason
     Object forcingToImportant;  // Token that is forcing this process to be important
     int adjSeq;                 // Sequence id for identifying oom_adj assignment cycles
+    int completedAdjSeq;        // Sequence id for identifying oom_adj assignment cycles
+    boolean containsCycle;      // Whether this app has encountered a cycle in the most recent update
     int lruSeq;                 // Sequence id for identifying LRU update cycles
     CompatibilityInfo compat;   // last used compatibility mode
     IBinder.DeathRecipient deathRecipient; // Who is watching for the death.
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 02459bd..36a2476 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -26,6 +26,7 @@
 import android.net.wifi.WifiInfo;
 import android.os.UserHandle;
 import android.telephony.TelephonyManager;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -131,16 +132,17 @@
         final String tag = tagFor(id);
         final int eventId = notifyType.eventId;
         final int transportType;
-        final String extraInfo;
+        final String name;
         if (nai != null) {
             transportType = getFirstTransportType(nai);
-            extraInfo = nai.networkInfo.getExtraInfo();
+            final String extraInfo = nai.networkInfo.getExtraInfo();
+            name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo;
             // Only notify for Internet-capable networks.
             if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) return;
         } else {
             // Legacy notifications.
             transportType = TRANSPORT_CELLULAR;
-            extraInfo = null;
+            name = null;
         }
 
         // Clear any previous notification with lower priority, otherwise return. http://b/63676954.
@@ -157,9 +159,8 @@
 
         if (DBG) {
             Slog.d(TAG, String.format(
-                    "showNotification tag=%s event=%s transport=%s extraInfo=%s highPrioriy=%s",
-                    tag, nameOf(eventId), getTransportName(transportType), extraInfo,
-                    highPriority));
+                    "showNotification tag=%s event=%s transport=%s name=%s highPriority=%s",
+                    tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
         }
 
         Resources r = Resources.getSystem();
@@ -188,7 +189,7 @@
                     break;
                 default:
                     title = r.getString(R.string.network_available_sign_in, 0);
-                    details = r.getString(R.string.network_available_sign_in_detailed, extraInfo);
+                    details = r.getString(R.string.network_available_sign_in_detailed, name);
                     break;
             }
         } else if (notifyType == NotificationType.NETWORK_SWITCH) {
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 030c915..213ec36 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -189,7 +189,7 @@
         mController = new ColorDisplayController(getContext(), mCurrentUser);
         mController.setListener(this);
 
-        setCoefficientMatrix(getContext(), DisplayTransformManager.isNativeModeEnabled());
+        setCoefficientMatrix(getContext(), DisplayTransformManager.needsLinearColorMatrix());
 
         // Prepare color transformation matrix.
         setMatrix(mController.getColorTemperature(), mMatrixNight);
@@ -293,7 +293,7 @@
             mColorMatrixAnimator.cancel();
         }
 
-        setCoefficientMatrix(getContext(), DisplayTransformManager.isColorModeNative(mode));
+        setCoefficientMatrix(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
         setMatrix(mController.getColorTemperature(), mMatrixNight);
 
         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
@@ -306,13 +306,12 @@
     }
 
     /**
-     * Set coefficients based on native mode. Use DisplayTransformManager#isNativeModeEnabled while
-     * setting is stable; when setting is changing, pass native mode selection directly.
+     * Set coefficients based on whether the color matrix is linear or not.
      */
-    private void setCoefficientMatrix(Context context, boolean isNative) {
-        final String[] coefficients = context.getResources().getStringArray(isNative
-                ? R.array.config_nightDisplayColorTemperatureCoefficientsNative
-                : R.array.config_nightDisplayColorTemperatureCoefficients);
+    private void setCoefficientMatrix(Context context, boolean needsLinear) {
+        final String[] coefficients = context.getResources().getStringArray(needsLinear
+                ? R.array.config_nightDisplayColorTemperatureCoefficients
+                : R.array.config_nightDisplayColorTemperatureCoefficientsNative);
         for (int i = 0; i < 9 && i < coefficients.length; i++) {
             mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
         }
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java
index 57d88e1..57a4f0d 100644
--- a/services/core/java/com/android/server/display/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/DisplayTransformManager.java
@@ -231,21 +231,19 @@
     }
 
     /**
-     * Return true when colors are stretched from the working color space to the
-     * native color space.
+     * Return true when the color matrix works in linear space.
      */
-    public static boolean isNativeModeEnabled() {
+    public static boolean needsLinearColorMatrix() {
         return SystemProperties.getInt(PERSISTENT_PROPERTY_DISPLAY_COLOR,
-                DISPLAY_COLOR_MANAGED) != DISPLAY_COLOR_MANAGED;
+                DISPLAY_COLOR_UNMANAGED) != DISPLAY_COLOR_UNMANAGED;
     }
 
     /**
-     * Return true when the specified colorMode stretches colors from the
-     * working color space to the native color space.
+     * Return true when the specified colorMode requires the color matrix to
+     * work in linear space.
      */
-    public static boolean isColorModeNative(int colorMode) {
-        return !(colorMode == ColorDisplayController.COLOR_MODE_NATURAL ||
-                 colorMode == ColorDisplayController.COLOR_MODE_BOOSTED);
+    public static boolean needsLinearColorMatrix(int colorMode) {
+        return colorMode != ColorDisplayController.COLOR_MODE_SATURATED;
     }
 
     public boolean setColorMode(int colorMode, float[] nightDisplayMatrix) {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 0d1644b..b3aa0bf 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -45,6 +45,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.SystemClock;
@@ -82,6 +83,7 @@
     private final SessionStub mSession;
     private final SessionCb mSessionCb;
     private final MediaSessionService mService;
+    private final Context mContext;
 
     private final Object mLock = new Object();
     private final ArrayList<ISessionControllerCallbackHolder> mControllerCallbackHolders =
@@ -126,8 +128,9 @@
         mSession = new SessionStub();
         mSessionCb = new SessionCb(cb);
         mService = service;
+        mContext = mService.getContext();
         mHandler = new MessageHandler(handlerLooper);
-        mAudioManager = (AudioManager) service.getContext().getSystemService(Context.AUDIO_SERVICE);
+        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
         mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
         mAudioAttrs = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build();
     }
@@ -232,12 +235,17 @@
      * @param packageName The package that made the original volume request.
      * @param pid The pid that made the original volume request.
      * @param uid The uid that made the original volume request.
+     * @param asSystemService {@code true} if the event sent to the session as if it was come from
+     *          the system service instead of the app process. This helps sessions to distinguish
+     *          between the key injection by the app and key events from the hardware devices.
+     *          Should be used only when the volume key events aren't handled by foreground
+     *          activity. {@code false} otherwise to tell session about the real caller.
      * @param direction The direction to adjust volume in.
      * @param flags Any of the flags from {@link AudioManager}.
      * @param useSuggested True to use adjustSuggestedStreamVolume instead of
      */
-    public void adjustVolume(String packageName, int pid, int uid, int direction, int flags,
-            boolean useSuggested) {
+    public void adjustVolume(String packageName, int pid, int uid, boolean asSystemService,
+            int direction, int flags, boolean useSuggested) {
         int previousFlagPlaySound = flags & AudioManager.FLAG_PLAY_SOUND;
         if (isPlaybackActive() || hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
             flags &= ~AudioManager.FLAG_PLAY_SOUND;
@@ -258,7 +266,7 @@
                 Log.w(TAG, "Muting remote playback is not supported");
                 return;
             }
-            mSessionCb.adjustVolume(packageName, pid, uid, direction);
+            mSessionCb.adjustVolume(packageName, pid, uid, asSystemService, direction);
 
             int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
             mOptimisticVolume = volumeBefore + direction;
@@ -418,9 +426,9 @@
         return mSessionCb.mCb;
     }
 
-    public void sendMediaButton(String packageName, int pid, int uid, KeyEvent ke, int sequenceId,
-            ResultReceiver cb) {
-        mSessionCb.sendMediaButton(packageName, pid, uid, ke, sequenceId, cb);
+    public void sendMediaButton(String packageName, int pid, int uid, boolean asSystemService,
+            KeyEvent ke, int sequenceId, ResultReceiver cb) {
+        mSessionCb.sendMediaButton(packageName, pid, uid, asSystemService, ke, sequenceId, cb);
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -698,11 +706,7 @@
     }
 
     private String getPackageName(int uid) {
-        Context context = mService.getContext();
-        if (context == null) {
-            return null;
-        }
-        String[] packages = context.getPackageManager().getPackagesForUid(uid);
+        String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
         if (packages != null && packages.length > 0) {
             return packages[0];
         }
@@ -907,12 +911,17 @@
             mCb = cb;
         }
 
-        public boolean sendMediaButton(String packageName, int pid, int uid, KeyEvent keyEvent,
-                int sequenceId, ResultReceiver cb) {
+        public boolean sendMediaButton(String packageName, int pid, int uid,
+                boolean asSystemService, KeyEvent keyEvent, int sequenceId, ResultReceiver cb) {
             Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
             mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
             try {
-                mCb.onMediaButton(packageName, pid, uid, mediaButtonIntent, sequenceId, cb);
+                if (asSystemService) {
+                    mCb.onMediaButton(mContext.getPackageName(), Process.myPid(),
+                            Process.SYSTEM_UID, mediaButtonIntent, sequenceId, cb);
+                } else {
+                    mCb.onMediaButton(packageName, pid, uid, mediaButtonIntent, sequenceId, cb);
+                }
                 return true;
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
@@ -1079,9 +1088,15 @@
             }
         }
 
-        public void adjustVolume(String packageName, int pid, int uid, int direction) {
+        public void adjustVolume(String packageName, int pid, int uid, boolean asSystemService,
+                int direction) {
             try {
-                mCb.onAdjustVolume(packageName, pid, uid, direction);
+                if (asSystemService) {
+                    mCb.onAdjustVolume(mContext.getPackageName(), Process.myPid(),
+                            Process.SYSTEM_UID, direction);
+                } else {
+                    mCb.onAdjustVolume(packageName, pid, uid, direction);
+                }
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in adjustVolume.", e);
             }
@@ -1105,9 +1120,10 @@
         }
 
         @Override
-        public boolean sendMediaButton(String packageName, KeyEvent mediaButtonIntent) {
+        public boolean sendMediaButton(String packageName, boolean asSystemService,
+                KeyEvent mediaButtonIntent) {
             return mSessionCb.sendMediaButton(packageName, Binder.getCallingPid(),
-                    Binder.getCallingUid(), mediaButtonIntent, 0, null);
+                    Binder.getCallingUid(), asSystemService, mediaButtonIntent, 0, null);
         }
 
         @Override
@@ -1188,13 +1204,14 @@
         }
 
         @Override
-        public void adjustVolume(String packageName, int direction, int flags) {
+        public void adjustVolume(String packageName, boolean asSystemService, int direction,
+                int flags) {
             int pid = Binder.getCallingPid();
             int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionRecord.this.adjustVolume(packageName, pid, uid, direction, flags,
-                        false /* useSuggested */);
+                MediaSessionRecord.this.adjustVolume(packageName, pid, uid, asSystemService,
+                        direction, flags, false /* useSuggested */);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index a3c6c80..a6e9389 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -1093,13 +1093,21 @@
          * registered listeners, or if there was none, broadcast an
          * ACTION_MEDIA_BUTTON intent to the rest of the system.
          *
+         * @param packageName The caller package
+         * @param asSystemService {@code true} if the event sent to the session as if it was come
+         *          from the system service instead of the app process. This helps sessions to
+         *          distinguish between the key injection by the app and key events from the
+         *          hardware devices. Should be used only when the volume key events aren't handled
+         *          by foreground activity. {@code false} otherwise to tell session about the real
+         *          caller.
          * @param keyEvent a non-null KeyEvent whose key code is one of the
          *            supported media buttons
          * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held
          *            while this key event is dispatched.
          */
         @Override
-        public void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
+        public void dispatchMediaKeyEvent(String packageName, boolean asSystemService,
+                KeyEvent keyEvent, boolean needWakeLock) {
             if (keyEvent == null || !KeyEvent.isMediaKey(keyEvent.getKeyCode())) {
                 Log.w(TAG, "Attempted to dispatch null or non-media key event.");
                 return;
@@ -1110,7 +1118,8 @@
             final long token = Binder.clearCallingIdentity();
             try {
                 if (DEBUG) {
-                    Log.d(TAG, "dispatchMediaKeyEvent, pid=" + pid + ", uid=" + uid + ", event="
+                    Log.d(TAG, "dispatchMediaKeyEvent, pkg=" + packageName + " pid=" + pid
+                            + ", uid=" + uid + ", asSystem=" + asSystemService + ", event="
                             + keyEvent);
                 }
                 if (!isUserSetupComplete()) {
@@ -1137,7 +1146,8 @@
                             }
                             try {
                                 mCurrentFullUserRecord.mOnMediaKeyListener.onMediaKey(keyEvent,
-                                        new MediaKeyListenerResultReceiver(keyEvent, needWakeLock));
+                                        new MediaKeyListenerResultReceiver(packageName, pid, uid,
+                                                asSystemService, keyEvent, needWakeLock));
                                 return;
                             } catch (RemoteException e) {
                                 Log.w(TAG, "Failed to send " + keyEvent
@@ -1146,9 +1156,11 @@
                         }
                     }
                     if (!isGlobalPriorityActive && isVoiceKey(keyEvent.getKeyCode())) {
-                        handleVoiceKeyEventLocked(keyEvent, needWakeLock);
+                        handleVoiceKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
+                                needWakeLock);
                     } else {
-                        dispatchMediaKeyEventLocked(keyEvent, needWakeLock);
+                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+                                keyEvent, needWakeLock);
                     }
                 }
             } finally {
@@ -1324,6 +1336,13 @@
          * there's no active global priority session, long-pressess will be sent to the
          * long-press listener instead of adjusting volume.
          *
+         * @param packageName The caller package.
+         * @param asSystemService {@code true} if the event sent to the session as if it was come
+         *          from the system service instead of the app process. This helps sessions to
+         *          distinguish between the key injection by the app and key events from the
+         *          hardware devices. Should be used only when the volume key events aren't handled
+         *          by foreground activity. {@code false} otherwise to tell session about the real
+         *          caller.
          * @param keyEvent a non-null KeyEvent whose key code is one of the
          *            {@link KeyEvent#KEYCODE_VOLUME_UP},
          *            {@link KeyEvent#KEYCODE_VOLUME_DOWN},
@@ -1332,7 +1351,8 @@
          * @param musicOnly true if both UI nor haptic feedback aren't needed when adjust volume.
          */
         @Override
-        public void dispatchVolumeKeyEvent(KeyEvent keyEvent, int stream, boolean musicOnly) {
+        public void dispatchVolumeKeyEvent(String packageName, boolean asSystemService,
+                KeyEvent keyEvent, int stream, boolean musicOnly) {
             if (keyEvent == null ||
                     (keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_UP
                              && keyEvent.getKeyCode() != KeyEvent.KEYCODE_VOLUME_DOWN
@@ -1346,15 +1366,16 @@
             final long token = Binder.clearCallingIdentity();
 
             if (DEBUG_KEY_EVENT) {
-                Log.d(TAG, "dispatchVolumeKeyEvent, pid=" + pid + ", uid=" + uid + ", event="
-                        + keyEvent);
+                Log.d(TAG, "dispatchVolumeKeyEvent, pkg=" + packageName + ", pid=" + pid + ", uid="
+                        + uid + ", asSystem=" + asSystemService + ", event=" + keyEvent);
             }
 
             try {
                 synchronized (mLock) {
                     if (isGlobalPriorityActiveLocked()
                             || mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
-                        dispatchVolumeKeyEventLocked(keyEvent, stream, musicOnly);
+                        dispatchVolumeKeyEventLocked(packageName, pid, uid, asSystemService,
+                                keyEvent, stream, musicOnly);
                     } else {
                         // TODO: Consider the case when both volume up and down keys are pressed
                         //       at the same time.
@@ -1387,11 +1408,12 @@
                                     && mCurrentFullUserRecord.mInitialDownVolumeKeyEvent
                                             .getDownTime() == keyEvent.getDownTime()) {
                                 // Short-press. Should change volume.
-                                dispatchVolumeKeyEventLocked(
+                                dispatchVolumeKeyEventLocked(packageName, pid, uid, asSystemService,
                                         mCurrentFullUserRecord.mInitialDownVolumeKeyEvent,
                                         mCurrentFullUserRecord.mInitialDownVolumeStream,
                                         mCurrentFullUserRecord.mInitialDownMusicOnly);
-                                dispatchVolumeKeyEventLocked(keyEvent, stream, musicOnly);
+                                dispatchVolumeKeyEventLocked(packageName, pid, uid, asSystemService,
+                                        keyEvent, stream, musicOnly);
                             } else {
                                 dispatchVolumeKeyLongPressLocked(keyEvent);
                             }
@@ -1403,8 +1425,8 @@
             }
         }
 
-        private void dispatchVolumeKeyEventLocked(
-                KeyEvent keyEvent, int stream, boolean musicOnly) {
+        private void dispatchVolumeKeyEventLocked(String packageName, int pid, int uid,
+                boolean asSystemService, KeyEvent keyEvent, int stream, boolean musicOnly) {
             boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
             boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP;
             int direction = 0;
@@ -1438,21 +1460,27 @@
                     if (up) {
                         direction = 0;
                     }
-                    dispatchAdjustVolumeLocked(stream, direction, flags);
+                    dispatchAdjustVolumeLocked(packageName, pid, uid, asSystemService, stream,
+                            direction, flags);
                 } else if (isMute) {
                     if (down && keyEvent.getRepeatCount() == 0) {
-                        dispatchAdjustVolumeLocked(stream, AudioManager.ADJUST_TOGGLE_MUTE, flags);
+                        dispatchAdjustVolumeLocked(packageName, pid, uid, asSystemService, stream,
+                                AudioManager.ADJUST_TOGGLE_MUTE, flags);
                     }
                 }
             }
         }
 
         @Override
-        public void dispatchAdjustVolume(int suggestedStream, int delta, int flags) {
+        public void dispatchAdjustVolume(String packageName, int suggestedStream, int delta,
+                int flags) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
-                    dispatchAdjustVolumeLocked(suggestedStream, delta, flags);
+                    dispatchAdjustVolumeLocked(packageName, pid, uid, false,
+                            suggestedStream, delta, flags);
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -1777,7 +1805,8 @@
             return false;
         }
 
-        private void dispatchAdjustVolumeLocked(int suggestedStream, int direction, int flags) {
+        private void dispatchAdjustVolumeLocked(String packageName, int pid, int uid,
+                boolean asSystemService, int suggestedStream, int direction, int flags) {
             MediaSessionRecord session = isGlobalPriorityActiveLocked() ? mGlobalPrioritySession
                     : mCurrentFullUserRecord.mPriorityStack.getDefaultVolumeSession();
 
@@ -1822,12 +1851,13 @@
                     }
                 });
             } else {
-                session.adjustVolume(getContext().getPackageName(), Process.myPid(),
-                        Process.SYSTEM_UID, direction, flags, true);
+                session.adjustVolume(packageName, pid, uid, asSystemService,
+                        direction, flags, true);
             }
         }
 
-        private void handleVoiceKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock) {
+        private void handleVoiceKeyEventLocked(String packageName, int pid, int uid,
+                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
             int action = keyEvent.getAction();
             boolean isLongPress = (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
             if (action == KeyEvent.ACTION_DOWN) {
@@ -1844,14 +1874,17 @@
                     if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
                         // Resend the down then send this event through
                         KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
-                        dispatchMediaKeyEventLocked(downEvent, needWakeLock);
-                        dispatchMediaKeyEventLocked(keyEvent, needWakeLock);
+                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+                                downEvent, needWakeLock);
+                        dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+                                keyEvent, needWakeLock);
                     }
                 }
             }
         }
 
-        private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock) {
+        private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
+                boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
             MediaSessionRecord session = mCurrentFullUserRecord.getMediaButtonSessionLocked();
             if (session != null) {
                 if (DEBUG_KEY_EVENT) {
@@ -1861,17 +1894,13 @@
                     mKeyEventReceiver.aquireWakeLockLocked();
                 }
                 // If we don't need a wakelock use -1 as the id so we won't release it later.
-                session.sendMediaButton(getContext().getPackageName(),
-                        Process.myPid(),
-                        Process.SYSTEM_UID,
-                        keyEvent,
+                session.sendMediaButton(packageName, pid, uid, asSystemService, keyEvent,
                         needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
                         mKeyEventReceiver);
                 if (mCurrentFullUserRecord.mCallback != null) {
                     try {
                         mCurrentFullUserRecord.mCallback.onMediaKeyEventDispatchedToMediaSession(
-                                keyEvent,
-                                new MediaSession.Token(session.getControllerBinder()));
+                                keyEvent, new MediaSession.Token(session.getControllerBinder()));
                     } catch (RemoteException e) {
                         Log.w(TAG, "Failed to send callback", e);
                     }
@@ -1884,6 +1913,10 @@
                 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
                 mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                 mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+                // TODO: Find a way to also send PID/UID in secure way.
+                String callerPackageName =
+                        (asSystemService) ? getContext().getPackageName() : packageName;
+                mediaButtonIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, callerPackageName);
                 try {
                     if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
                         PendingIntent receiver = mCurrentFullUserRecord.mLastMediaButtonReceiver;
@@ -1984,13 +2017,22 @@
         }
 
         private class MediaKeyListenerResultReceiver extends ResultReceiver implements Runnable {
-            private KeyEvent mKeyEvent;
-            private boolean mNeedWakeLock;
+            private final String mPackageName;
+            private final int mPid;
+            private final int mUid;
+            private final boolean mAsSystemService;
+            private final KeyEvent mKeyEvent;
+            private final boolean mNeedWakeLock;
             private boolean mHandled;
 
-            private MediaKeyListenerResultReceiver(KeyEvent keyEvent, boolean needWakeLock) {
+            private MediaKeyListenerResultReceiver(String packageName, int pid, int uid,
+                    boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
                 super(mHandler);
                 mHandler.postDelayed(this, MEDIA_KEY_LISTENER_TIMEOUT);
+                mPackageName = packageName;
+                mPid = pid;
+                mUid = uid;
+                mAsSystemService = asSystemService;
                 mKeyEvent = keyEvent;
                 mNeedWakeLock = needWakeLock;
             }
@@ -2020,9 +2062,11 @@
                 synchronized (mLock) {
                     if (!isGlobalPriorityActiveLocked()
                             && isVoiceKey(mKeyEvent.getKeyCode())) {
-                        handleVoiceKeyEventLocked(mKeyEvent, mNeedWakeLock);
+                        handleVoiceKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
+                                mKeyEvent, mNeedWakeLock);
                     } else {
-                        dispatchMediaKeyEventLocked(mKeyEvent, mNeedWakeLock);
+                        dispatchMediaKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
+                                mKeyEvent, mNeedWakeLock);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index a6dfec7..f082271 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -389,16 +389,11 @@
                     final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
                             false);
                     if (pi != null) {
-                        /*
-                         * Only update overlay settings when an overlay becomes enabled or disabled.
-                         * Enabling or disabling components of a target should not change the
-                         * target's overlays. Since, overlays do not have components, this will only
-                         * update overlay settings if an overlay package becomes enabled or
-                         * disabled.
-                         */
                         mPackageManager.cachePackageInfo(packageName, userId, pi);
                         if (pi.isOverlayPackage()) {
                             mImpl.onOverlayPackageChanged(packageName, userId);
+                        }  else {
+                            mImpl.onTargetPackageChanged(packageName, userId);
                         }
                     }
                 }
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index bb36ab1..3639082 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -212,15 +212,21 @@
         }
     }
 
+    void onTargetPackageChanged(@NonNull final String packageName, final int userId) {
+        if (DEBUG) {
+            Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId);
+        }
+
+        updateAllOverlaysForTarget(packageName, userId, 0);
+    }
+
     void onTargetPackageUpgrading(@NonNull final String packageName, final int userId) {
         if (DEBUG) {
             Slog.d(TAG, "onTargetPackageUpgrading packageName=" + packageName + " userId="
                     + userId);
         }
 
-        if (updateAllOverlaysForTarget(packageName, userId, FLAG_TARGET_IS_UPGRADING)) {
-            mListener.onOverlaysChanged(packageName, userId);
-        }
+        updateAllOverlaysForTarget(packageName, userId, FLAG_TARGET_IS_UPGRADING);
     }
 
     void onTargetPackageUpgraded(@NonNull final String packageName, final int userId) {
@@ -228,9 +234,7 @@
             Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId);
         }
 
-        if (updateAllOverlaysForTarget(packageName, userId, 0)) {
-            mListener.onOverlaysChanged(packageName, userId);
-        }
+        updateAllOverlaysForTarget(packageName, userId, 0);
     }
 
     void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
@@ -688,6 +692,11 @@
     }
 
     interface OverlayChangeListener {
+
+        /**
+         * An event triggered by changes made to overlay state or settings as well as changes that
+         * add or remove target packages of overlays.
+         **/
         void onOverlaysChanged(@NonNull String targetPackage, int userId);
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index a92fbb6..01f84c4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -25,6 +25,7 @@
 import android.accounts.IAccountManager;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
+import android.app.Application;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.IIntentReceiver;
@@ -53,17 +54,20 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.content.pm.VersionedPackage;
+import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.DexMetadataHelper;
+import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.net.Uri;
-import android.os.BaseBundle;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.IUserManager;
 import android.os.ParcelFileDescriptor;
+import android.os.ParcelFileDescriptor.AutoCloseInputStream;
+import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
@@ -78,27 +82,41 @@
 import android.text.format.DateUtils;
 import android.util.ArraySet;
 import android.util.PrintWriterPrinter;
-
 import com.android.internal.content.PackageHelper;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
-
 import dalvik.system.DexFile;
-
-import libcore.io.IoUtils;
-
-import java.io.FileDescriptor;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.net.URISyntaxException;
-import java.util.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.FileAttribute;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.WeakHashMap;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.TimeUnit;
+import libcore.io.IoUtils;
+import libcore.io.Streams;
 
 class PackageManagerShellCommand extends ShellCommand {
     /** Path for streaming APK content */
     private static final String STDIN_PATH = "-";
+    /** Path where ART profiles snapshots are dumped for the shell user */
+    private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/";
 
     final IPackageManager mInterface;
     final private WeakHashMap<String, Resources> mResourceCache =
@@ -167,6 +185,8 @@
                     return runDexoptJob();
                 case "dump-profiles":
                     return runDumpProfiles();
+                case "snapshot-profile":
+                    return runSnapshotProfile();
                 case "uninstall":
                     return runUninstall();
                 case "clear":
@@ -1287,6 +1307,120 @@
         return 0;
     }
 
+    private int runSnapshotProfile() throws RemoteException {
+        PrintWriter pw = getOutPrintWriter();
+
+        // Parse the arguments
+        final String packageName = getNextArg();
+        final boolean isBootImage = "android".equals(packageName);
+
+        String codePath = null;
+        String opt;
+        while ((opt = getNextArg()) != null) {
+            switch (opt) {
+                case "--code-path":
+                    if (isBootImage) {
+                        pw.write("--code-path cannot be used for the boot image.");
+                        return -1;
+                    }
+                    codePath = getNextArg();
+                    break;
+                default:
+                    pw.write("Unknown arg: " + opt);
+                    return -1;
+            }
+        }
+
+        // If no code path was explicitly requested, select the base code path.
+        String baseCodePath = null;
+        if (!isBootImage) {
+            PackageInfo packageInfo = mInterface.getPackageInfo(packageName, /* flags */ 0,
+                    /* userId */0);
+            if (packageInfo == null) {
+                pw.write("Package not found " + packageName);
+                return -1;
+            }
+            baseCodePath = packageInfo.applicationInfo.getBaseCodePath();
+            if (codePath == null) {
+                codePath = baseCodePath;
+            }
+        }
+
+        // Create the profile snapshot.
+        final SnapshotRuntimeProfileCallback callback = new SnapshotRuntimeProfileCallback();
+        // The calling package is needed to debug permission access.
+        final String callingPackage = (Binder.getCallingUid() == Process.ROOT_UID)
+                ? "root" : "com.android.shell";
+        final int profileType = isBootImage
+                ? ArtManager.PROFILE_BOOT_IMAGE : ArtManager.PROFILE_APPS;
+        if (!mInterface.getArtManager().isRuntimeProfilingEnabled(profileType, callingPackage)) {
+            pw.println("Error: Runtime profiling is not enabled");
+            return -1;
+        }
+        mInterface.getArtManager().snapshotRuntimeProfile(profileType, packageName,
+                codePath, callback, callingPackage);
+        if (!callback.waitTillDone()) {
+            pw.println("Error: callback not called");
+            return callback.mErrCode;
+        }
+
+        // Copy the snapshot profile to the output profile file.
+        try (InputStream inStream = new AutoCloseInputStream(callback.mProfileReadFd)) {
+            final String outputFileSuffix = isBootImage || Objects.equals(baseCodePath, codePath)
+                    ? "" : ("-" + new File(codePath).getName());
+            final String outputProfilePath =
+                    ART_PROFILE_SNAPSHOT_DEBUG_LOCATION + packageName + outputFileSuffix + ".prof";
+            try (OutputStream outStream = new FileOutputStream(outputProfilePath)) {
+                Streams.copy(inStream, outStream);
+            }
+        } catch (IOException e) {
+            pw.println("Error when reading the profile fd: " + e.getMessage());
+            e.printStackTrace(pw);
+            return -1;
+        }
+        return 0;
+    }
+
+    private static class SnapshotRuntimeProfileCallback
+            extends ISnapshotRuntimeProfileCallback.Stub {
+        private boolean mSuccess = false;
+        private int mErrCode = -1;
+        private ParcelFileDescriptor mProfileReadFd = null;
+        private CountDownLatch mDoneSignal = new CountDownLatch(1);
+
+        @Override
+        public void onSuccess(ParcelFileDescriptor profileReadFd) {
+            mSuccess = true;
+            try {
+                // We need to dup the descriptor. We are in the same process as system server
+                // and we will be receiving the same object (which will be closed on the
+                // server side).
+                mProfileReadFd = profileReadFd.dup();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            mDoneSignal.countDown();
+        }
+
+        @Override
+        public void onError(int errCode) {
+            mSuccess = false;
+            mErrCode = errCode;
+            mDoneSignal.countDown();
+        }
+
+        boolean waitTillDone() {
+            boolean done = false;
+            try {
+                // The time-out is an arbitrary large value. Since this is a local call the result
+                // will come very fast.
+                done = mDoneSignal.await(10000000, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException ignored) {
+            }
+            return done && mSuccess;
+        }
+    }
+
     private int runUninstall() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         int flags = 0;
@@ -2761,7 +2895,13 @@
         pw.println("");
         pw.println("  dump-profiles TARGET-PACKAGE");
         pw.println("    Dumps method/class profile files to");
-        pw.println("    /data/misc/profman/TARGET-PACKAGE.txt");
+        pw.println("    " + ART_PROFILE_SNAPSHOT_DEBUG_LOCATION + "TARGET-PACKAGE.txt");
+        pw.println("");
+        pw.println("  snapshot-profile TARGET-PACKAGE [--code-path path]");
+        pw.println("    Take a snapshot of the package profiles to");
+        pw.println("    " + ART_PROFILE_SNAPSHOT_DEBUG_LOCATION
+                + "TARGET-PACKAGE[-code-path].prof");
+        pw.println("    If TARGET-PACKAGE=android it will take a snapshot of the boot image");
         pw.println("");
         pw.println("  set-home-activity [--user USER_ID] TARGET-COMPONENT");
         pw.println("    Set the default home activity (aka launcher).");
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index d3526f7..36fc120 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -449,9 +449,10 @@
                                     userId) == PackageManager.PERMISSION_GRANTED) {
                                 EventLog.writeEvent(0x534e4554, "72710897",
                                         newPackage.applicationInfo.uid,
-                                        "Revoking permission", permissionName, "from package",
-                                        packageName, "as the group changed from",
-                                        oldPermissionGroupName, "to", newPermissionGroupName);
+                                        "Revoking permission " + permissionName +
+                                        " from package " + packageName +
+                                        " as the group changed from " + oldPermissionGroupName +
+                                        " to " + newPermissionGroupName);
 
                                 try {
                                     revokeRuntimePermission(permissionName, packageName, false,
@@ -620,9 +621,8 @@
                 enforcePermissionCapLocked(info, tree);
                 bp = new BasePermission(info.name, tree.getSourcePackageName(),
                         BasePermission.TYPE_DYNAMIC);
-            } else if (bp.isDynamic()) {
-                // TODO: switch this back to SecurityException
-                Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
+            } else if (!bp.isDynamic()) {
+                throw new SecurityException("Not allowed to modify non-dynamic permission "
                         + info.name);
             }
             changed = bp.addToTree(fixedLevel, info, tree);
diff --git a/services/core/java/com/android/server/policy/IconUtilities.java b/services/core/java/com/android/server/policy/IconUtilities.java
index b196dec..884d7d4 100644
--- a/services/core/java/com/android/server/policy/IconUtilities.java
+++ b/services/core/java/com/android/server/policy/IconUtilities.java
@@ -16,6 +16,8 @@
 
 package com.android.server.policy;
 
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.PaintDrawable;
@@ -38,24 +40,17 @@
  * Various utilities shared amongst the Launcher's classes.
  */
 public final class IconUtilities {
-    private static final String TAG = "IconUtilities";
-
-    private static final int sColors[] = { 0xffff0000, 0xff00ff00, 0xff0000ff };
 
     private int mIconWidth = -1;
     private int mIconHeight = -1;
     private int mIconTextureWidth = -1;
     private int mIconTextureHeight = -1;
 
-    private final Paint mPaint = new Paint();
-    private final Paint mBlurPaint = new Paint();
-    private final Paint mGlowColorPressedPaint = new Paint();
-    private final Paint mGlowColorFocusedPaint = new Paint();
     private final Rect mOldBounds = new Rect();
     private final Canvas mCanvas = new Canvas();
     private final DisplayMetrics mDisplayMetrics;
 
-    private int mColorIndex = 0;
+    private ColorFilter mDisabledColorFilter;
 
     public IconUtilities(Context context) {
         final Resources resources = context.getResources();
@@ -65,39 +60,10 @@
 
         mIconWidth = mIconHeight = (int) resources.getDimension(android.R.dimen.app_icon_size);
         mIconTextureWidth = mIconTextureHeight = mIconWidth + (int)(blurPx*2);
-
-        mBlurPaint.setMaskFilter(new BlurMaskFilter(blurPx, BlurMaskFilter.Blur.NORMAL));
-
-        TypedValue value = new TypedValue();
-        mGlowColorPressedPaint.setColor(context.getTheme().resolveAttribute(
-                android.R.attr.colorPressedHighlight, value, true) ? value.data : 0xffffc300);
-        mGlowColorPressedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
-        mGlowColorFocusedPaint.setColor(context.getTheme().resolveAttribute(
-                android.R.attr.colorFocusedHighlight, value, true) ? value.data : 0xffff8e00);
-        mGlowColorFocusedPaint.setMaskFilter(TableMaskFilter.CreateClipTable(0, 30));
-
-        ColorMatrix cm = new ColorMatrix();
-        cm.setSaturation(0.2f);
-
         mCanvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.DITHER_FLAG,
                 Paint.FILTER_BITMAP_FLAG));
     }
 
-    public Drawable createIconDrawable(Drawable src) {
-        Bitmap scaled = createIconBitmap(src);
-
-        StateListDrawable result = new StateListDrawable();
-
-        result.addState(new int[] { android.R.attr.state_focused },
-                new BitmapDrawable(createSelectedBitmap(scaled, false)));
-        result.addState(new int[] { android.R.attr.state_pressed },
-                new BitmapDrawable(createSelectedBitmap(scaled, true)));
-        result.addState(new int[0], new BitmapDrawable(scaled));
-
-        result.setBounds(0, 0, mIconTextureWidth, mIconTextureHeight);
-        return result;
-    }
-
     /**
      * Returns a bitmap suitable for the all apps view.  The bitmap will be a power
      * of two sized ARGB_8888 bitmap that can be used as a gl texture.
@@ -150,15 +116,6 @@
         final int left = (textureWidth-width) / 2;
         final int top = (textureHeight-height) / 2;
 
-        if (false) {
-            // draw a big box for the icon for debugging
-            canvas.drawColor(sColors[mColorIndex]);
-            if (++mColorIndex >= sColors.length) mColorIndex = 0;
-            Paint debugPaint = new Paint();
-            debugPaint.setColor(0xffcccc00);
-            canvas.drawRect(left, top, left+width, top+height, debugPaint);
-        }
-
         mOldBounds.set(icon.getBounds());
         icon.setBounds(left, top, left+width, top+height);
         icon.draw(canvas);
@@ -167,24 +124,28 @@
         return bitmap;
     }
 
-    private Bitmap createSelectedBitmap(Bitmap src, boolean pressed) {
-        final Bitmap result = Bitmap.createBitmap(mIconTextureWidth, mIconTextureHeight,
-                Bitmap.Config.ARGB_8888);
-        final Canvas dest = new Canvas(result);
+    public ColorFilter getDisabledColorFilter() {
+        if (mDisabledColorFilter != null) {
+            return mDisabledColorFilter;
+        }
+        ColorMatrix brightnessMatrix = new ColorMatrix();
+        float brightnessF = 0.5f;
+        int brightnessI = (int) (255 * brightnessF);
+        // Brightness: C-new = C-old*(1-amount) + amount
+        float scale = 1f - brightnessF;
+        float[] mat = brightnessMatrix.getArray();
+        mat[0] = scale;
+        mat[6] = scale;
+        mat[12] = scale;
+        mat[4] = brightnessI;
+        mat[9] = brightnessI;
+        mat[14] = brightnessI;
 
-        dest.drawColor(0, PorterDuff.Mode.CLEAR);
+        ColorMatrix filterMatrix = new ColorMatrix();
+        filterMatrix.setSaturation(0);
+        filterMatrix.preConcat(brightnessMatrix);
 
-        int[] xy = new int[2];
-        Bitmap mask = src.extractAlpha(mBlurPaint, xy);
-
-        dest.drawBitmap(mask, xy[0], xy[1],
-                pressed ? mGlowColorPressedPaint : mGlowColorFocusedPaint);
-
-        mask.recycle();
-
-        dest.drawBitmap(src, 0, 0, mPaint);
-        dest.setBitmap(null);
-
-        return result;
+        mDisabledColorFilter = new ColorMatrixColorFilter(filterMatrix);
+        return mDisabledColorFilter;
     }
 }
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index cfce5cf..c04c1fb 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -310,6 +310,11 @@
         return R.string.config_batterySaverDeviceSpecificConfig;
     }
 
+    @VisibleForTesting
+    boolean isAccessibilityEnabled() {
+        return mAccessibilityManager.isEnabled();
+    }
+
     @Override
     public void onChange(boolean selfChange, Uri uri) {
         refreshSettings();
@@ -403,7 +408,7 @@
                 parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "")).toSysFileMap();
 
         // Update the effective policy.
-        mAccessibilityEnabled = mAccessibilityManager.isEnabled();
+        mAccessibilityEnabled = isAccessibilityEnabled();
 
         mVibrationDisabledEffective = mVibrationDisabledConfig
                 && !mAccessibilityEnabled; // Don't disable vibration when accessibility is on.
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 966ca41..ee03aff 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
@@ -31,9 +32,12 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
+import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
+import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_UNSET;
+import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
@@ -1684,12 +1688,24 @@
         }
     }
 
+    private boolean shouldAnimate(int transit) {
+        final boolean isSplitScreenPrimary =
+                getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+        final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN;
+
+        // We animate always if it's not split screen primary, and only some special cases in split
+        // screen primary because it causes issues with stack clipping when we run an un-minimize
+        // animation at the same time.
+        return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation;
+    }
+
     boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
             boolean isVoiceInteraction) {
 
-        if (mService.mDisableTransitionAnimation) {
+        if (mService.mDisableTransitionAnimation || !shouldAnimate(transit)) {
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
-                Slog.v(TAG_WM, "applyAnimation: transition animation is disabled. atoken=" + this);
+                Slog.v(TAG_WM, "applyAnimation: transition animation is disabled or skipped."
+                        + " atoken=" + this);
             }
             cancelAnimation();
             return false;
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 2bf6e92..a7209a0 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -429,9 +429,13 @@
         try {
             mHardwareAddress = mInterfaceParams.macAddr.toByteArray();
             synchronized(this) {
-                // Clear APF memory.
-                byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize];
-                mIpClientCallback.installPacketFilter(zeroes);
+                // Clear the APF memory to reset all counters upon connecting to the first AP
+                // in an SSID. This is limited to APFv4 devices because this large write triggers
+                // a crash on some older devices (b/78905546).
+                if (mApfCapabilities.hasDataAccess()) {
+                    byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize];
+                    mIpClientCallback.installPacketFilter(zeroes);
+                }
 
                 // Install basic filters
                 installNewProgramLocked();
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
index a14b950..b4b34c5 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
@@ -40,6 +40,7 @@
 import android.support.test.filters.SmallTest;
 import android.testing.DexmakerShareClassLoaderRule;
 
+import com.android.internal.app.SuspendedAppActivity;
 import com.android.internal.app.UnlaunchableAppActivity;
 import com.android.server.LocalServices;
 import com.android.server.pm.PackageManagerService;
@@ -150,6 +151,28 @@
     }
 
     @Test
+    public void testSuspendedPackage() {
+        mAInfo.applicationInfo.flags = FLAG_SUSPENDED;
+        final String suspendingPackage = "com.test.suspending.package";
+        final String dialogMessage = "Test Message";
+        when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
+                .thenReturn(suspendingPackage);
+        when(mPackageManagerInternal.getSuspendedDialogMessage(TEST_PACKAGE_NAME, TEST_USER_ID))
+                .thenReturn(dialogMessage);
+        // THEN calling intercept returns true
+        assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
+
+        // Check intent parameters
+        assertEquals(dialogMessage,
+                mInterceptor.mIntent.getStringExtra(SuspendedAppActivity.EXTRA_DIALOG_MESSAGE));
+        assertEquals(suspendingPackage,
+                mInterceptor.mIntent.getStringExtra(SuspendedAppActivity.EXTRA_SUSPENDING_PACKAGE));
+        assertEquals(TEST_PACKAGE_NAME,
+                mInterceptor.mIntent.getStringExtra(SuspendedAppActivity.EXTRA_SUSPENDED_PACKAGE));
+        assertEquals(TEST_USER_ID, mInterceptor.mIntent.getIntExtra(Intent.EXTRA_USER_ID, -1000));
+    }
+
+    @Test
     public void testInterceptQuietProfile() {
         // GIVEN that the user the activity is starting as is currently in quiet mode
         when(mUserManager.isQuietModeEnabled(eq(UserHandle.of(TEST_USER_ID)))).thenReturn(true);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index 90947f4..a9d6c29 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -503,8 +503,7 @@
     @Test
     public void run_sendsEncryptedKeysIfAvailableToSync_withRawPublicKey() throws Exception {
         mRecoverableKeyStoreDb.setRecoveryServiceCertPath(
-                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS,
-                TestData.getInsecureCertPathForEndpoint1());
+                TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_ROOT_CERT_ALIAS, TestData.CERT_PATH_1);
 
         mRecoverableKeyStoreDb.setServerParams(
                 TEST_USER_ID, TEST_RECOVERY_AGENT_UID, TEST_VAULT_HANDLE);
@@ -529,8 +528,7 @@
                 lockScreenHash,
                 keyChainSnapshot.getEncryptedRecoveryKeyBlob(),
                 /*vaultParams=*/ KeySyncUtils.packVaultParams(
-                        TestData.getInsecureCertPathForEndpoint1().getCertificates().get(0)
-                                .getPublicKey(),
+                        TestData.CERT_1_PUBLIC_KEY,
                         counterId,
                         /*maxAttempts=*/ 10,
                         TEST_VAULT_HANDLE));
@@ -539,7 +537,7 @@
         assertThat(keyChainSnapshot.getCounterId()).isEqualTo(counterId);
         assertThat(keyChainSnapshot.getMaxAttempts()).isEqualTo(10);
         assertThat(keyChainSnapshot.getTrustedHardwareCertPath())
-                .isEqualTo(TestData.getInsecureCertPathForEndpoint1());
+                .isEqualTo(TestData.CERT_PATH_1);
         assertThat(keyChainSnapshot.getServerParams()).isEqualTo(TEST_VAULT_HANDLE);
         WrappedApplicationKey keyData = applicationKeys.get(0);
         assertEquals(TEST_APP_KEY_ALIAS, keyData.getAlias());
@@ -807,7 +805,7 @@
     private byte[] decryptThmEncryptedKey(
             byte[] lockScreenHash, byte[] encryptedKey, byte[] vaultParams) throws Exception {
         byte[] locallyEncryptedKey = SecureBox.decrypt(
-                TestData.getInsecurePrivateKeyForEndpoint1(),
+                TestData.CERT_1_PRIVATE_KEY,
                 /*sharedSecret=*/ KeySyncUtils.calculateThmKfHash(lockScreenHash),
                 /*header=*/ KeySyncUtils.concat(THM_ENCRYPTED_RECOVERY_KEY_HEADER, vaultParams),
                 encryptedKey
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index 8e86a87..e82478f 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -101,22 +101,35 @@
     private static final String INSECURE_CERTIFICATE_ALIAS =
             TrustedRootCertificates.TEST_ONLY_INSECURE_CERTIFICATE_ALIAS;
     private static final String TEST_SESSION_ID = "karlin";
-    private static final byte[] TEST_PUBLIC_KEY = TestData.CERT_1_PUBLIC_KEY.getEncoded();
+    private static final byte[] TEST_PUBLIC_KEY = new byte[] {
+        (byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a,
+        (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x02, (byte) 0x01, (byte) 0x06,
+        (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x03,
+        (byte) 0x01, (byte) 0x07, (byte) 0x03, (byte) 0x42, (byte) 0x00, (byte) 0x04, (byte) 0xb8,
+        (byte) 0x00, (byte) 0x11, (byte) 0x18, (byte) 0x98, (byte) 0x1d, (byte) 0xf0, (byte) 0x6e,
+        (byte) 0xb4, (byte) 0x94, (byte) 0xfe, (byte) 0x86, (byte) 0xda, (byte) 0x1c, (byte) 0x07,
+        (byte) 0x8d, (byte) 0x01, (byte) 0xb4, (byte) 0x3a, (byte) 0xf6, (byte) 0x8d, (byte) 0xdc,
+        (byte) 0x61, (byte) 0xd0, (byte) 0x46, (byte) 0x49, (byte) 0x95, (byte) 0x0f, (byte) 0x10,
+        (byte) 0x86, (byte) 0x93, (byte) 0x24, (byte) 0x66, (byte) 0xe0, (byte) 0x3f, (byte) 0xd2,
+        (byte) 0xdf, (byte) 0xf3, (byte) 0x79, (byte) 0x20, (byte) 0x1d, (byte) 0x91, (byte) 0x55,
+        (byte) 0xb0, (byte) 0xe5, (byte) 0xbd, (byte) 0x7a, (byte) 0x8b, (byte) 0x32, (byte) 0x7d,
+        (byte) 0x25, (byte) 0x53, (byte) 0xa2, (byte) 0xfc, (byte) 0xa5, (byte) 0x65, (byte) 0xe1,
+        (byte) 0xbd, (byte) 0x21, (byte) 0x44, (byte) 0x7e, (byte) 0x78, (byte) 0x52, (byte) 0xfa};
     private static final byte[] TEST_SALT = getUtf8Bytes("salt");
     private static final byte[] TEST_SECRET = getUtf8Bytes("password1234");
     private static final byte[] TEST_VAULT_CHALLENGE = getUtf8Bytes("vault_challenge");
     private static final byte[] TEST_VAULT_PARAMS = new byte[] {
         // backend_key
-        (byte) 0x04, (byte) 0x8e, (byte) 0x0c, (byte) 0x11, (byte) 0x4a, (byte) 0x79, (byte) 0x20,
-        (byte) 0x7c, (byte) 0x00, (byte) 0x4c, (byte) 0xd7, (byte) 0xe9, (byte) 0x06, (byte) 0xe2,
-        (byte) 0x58, (byte) 0x21, (byte) 0x45, (byte) 0xfa, (byte) 0x24, (byte) 0xcb, (byte) 0x07,
-        (byte) 0x66, (byte) 0xde, (byte) 0xfd, (byte) 0xf1, (byte) 0x83, (byte) 0xb4, (byte) 0x26,
-        (byte) 0x55, (byte) 0x98, (byte) 0xcb, (byte) 0xa9, (byte) 0xd5, (byte) 0x55, (byte) 0xad,
-        (byte) 0x65, (byte) 0xc5, (byte) 0xff, (byte) 0x5c, (byte) 0xfb, (byte) 0x1c, (byte) 0x4e,
-        (byte) 0x34, (byte) 0x98, (byte) 0x7e, (byte) 0x4f, (byte) 0x96, (byte) 0xa2, (byte) 0xa3,
-        (byte) 0x7e, (byte) 0xf4, (byte) 0x46, (byte) 0x52, (byte) 0x04, (byte) 0xba, (byte) 0x2a,
-        (byte) 0xb9, (byte) 0x47, (byte) 0xbb, (byte) 0xc2, (byte) 0x1e, (byte) 0xdd, (byte) 0x15,
-        (byte) 0x1a, (byte) 0xc0,
+        (byte) 0x04, (byte) 0xb8, (byte) 0x00, (byte) 0x11, (byte) 0x18, (byte) 0x98, (byte) 0x1d,
+        (byte) 0xf0, (byte) 0x6e, (byte) 0xb4, (byte) 0x94, (byte) 0xfe, (byte) 0x86, (byte) 0xda,
+        (byte) 0x1c, (byte) 0x07, (byte) 0x8d, (byte) 0x01, (byte) 0xb4, (byte) 0x3a, (byte) 0xf6,
+        (byte) 0x8d, (byte) 0xdc, (byte) 0x61, (byte) 0xd0, (byte) 0x46, (byte) 0x49, (byte) 0x95,
+        (byte) 0x0f, (byte) 0x10, (byte) 0x86, (byte) 0x93, (byte) 0x24, (byte) 0x66, (byte) 0xe0,
+        (byte) 0x3f, (byte) 0xd2, (byte) 0xdf, (byte) 0xf3, (byte) 0x79, (byte) 0x20, (byte) 0x1d,
+        (byte) 0x91, (byte) 0x55, (byte) 0xb0, (byte) 0xe5, (byte) 0xbd, (byte) 0x7a, (byte) 0x8b,
+        (byte) 0x32, (byte) 0x7d, (byte) 0x25, (byte) 0x53, (byte) 0xa2, (byte) 0xfc, (byte) 0xa5,
+        (byte) 0x65, (byte) 0xe1, (byte) 0xbd, (byte) 0x21, (byte) 0x44, (byte) 0x7e, (byte) 0x78,
+        (byte) 0x52, (byte) 0xfa,
         // counter_id
         (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x34, (byte) 0x00, (byte) 0x00, (byte) 0x00,
         (byte) 0x00,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
index 5d4be1b..64eb49b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java
@@ -29,7 +29,6 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.CertPath;
 import java.security.spec.ECPrivateKeySpec;
-import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.Base64;
 
 import javax.crypto.KeyGenerator;
@@ -38,56 +37,56 @@
 public final class TestData {
 
     private static final String KEY_ALGORITHM = "AES";
-    private static final long DEFAULT_SERIAL = 10001;
+    private static final long DEFAULT_SERIAL = 1000;
     private static final String CERT_PATH_ENCODING = "PkiPath";
 
     private static final String CERT_PATH_1_BASE64 = ""
-            + "MIIIXTCCBRowggMCoAMCAQICEB35ZwzVpI9ssXg9SAehnU0wDQYJKoZIhvcNAQEL"
-            + "BQAwMTEvMC0GA1UEAxMmR29vZ2xlIENsb3VkIEtleSBWYXVsdCBTZXJ2aWNlIFJv"
-            + "b3QgQ0EwHhcNMTgwNTA3MTg1ODEwWhcNMjgwNTA4MTg1ODEwWjA5MTcwNQYDVQQD"
-            + "Ey5Hb29nbGUgQ2xvdWQgS2V5IFZhdWx0IFNlcnZpY2UgSW50ZXJtZWRpYXRlIENB"
-            + "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA73TrvH3j6zEimpcc32tx"
-            + "2iupWwfyzdE5l4Ejc5EBYzx0aZH6b/KDuutwustk0IoyjlGySMBz/21YgWejIm+n"
-            + "duAlpk7WY5kYHp0XWtzdmxZknmWTqugPeNZeiKEjoDmpyIbY6N+f13hQ2RVh+WDT"
-            + "EowQ/i04WBL75chshlIG+3A42g5Qr7DZEKdT9oJQqkntzj0cGyJ5X8BwjeTiJrvY"
-            + "k2Kn/0555/Kpp65G3Rf29VPPU3i67kthAT3SavLBpH03S4WZ+QlfrAiGQziydtz9"
-            + "t7mSk1xefjax5ZWAuJAfCbKfI3VWAcaUr4P57BzmDcSi0jgs1aM3t2BrPfAMRxWv"
-            + "35yDZnrC+HipzkjyDGBfHmFgoglyhc9e/Kj3mSusO0Rq1wguVXKs2hKXRoaGJuHt"
-            + "e3YIwTC1pLznqvolhD1nPoXf8rMzgHRzlc9H8iXsgB1p7975nh5WCPrMDX2eAmYd"
-            + "a0xTMccTeBzIM2ohxQsxlh5rsjXVNU3ihbWkHquzIiwFcAtldP3dMksj0dn/DnYD"
-            + "yokjEgU/z2I216E93x9hmKkEk6Pp7o8t/z6lwMT9FJIuzp7NREnWCSi+e5s2E7FD"
-            + "j6S7xY2zEIUHrmwuuJc0jzJnwdZ+0myinaTmBDvBXR5cU1cmEAZoheCAoRv9Z/6o"
-            + "ASczLF0C4uuVfA5GXcAm14cCAwEAAaMmMCQwDgYDVR0PAQH/BAQDAgGGMBIGA1Ud"
-            + "EwEB/wQIMAYBAf8CAQEwDQYJKoZIhvcNAQELBQADggIBAEPht79yQm8woQbPB1Bs"
-            + "eotkzJtTWTO9fnIWwNiRfQ3vJFXf69ghE77wUS13Ez3FlgNPj0Qxmg5ouE0d2yYV"
-            + "4AUrXnEGZELcyN2XHRXyNK0zXgnr3x6eZyY7QfgGKJgkyja5TS6ZPWGyaLKhClS0"
-            + "AYZSzWJtz0+AkGCdTbmyy7ShdXJ+GfnmssbndZA62VhcjeQmHsDq7V3PKAsp4/B9"
-            + "PzcnTrgkUFNnP1F1pr7JpUUX3xyRFy6gjIrUx1fcOFRxFYPWGLLMZ6P41rafm+M/"
-            + "CbBNr5CY7NrZjr34jLqWycfYes49o9OK44X/wPrxj0Sjg+VrW21+AJ9vrM7DS5hE"
-            + "QX1lDbDtQGkk3N1vgCTo6xt9LXsEu4xUT5bk7YAfpJqM0ltDFPwYAGCbjSkVT/M5"
-            + "JVZkKiUW668Us67x8yZc/5bxbvTA+5xrYhak/VYIBY6qub4J+bKwadw6uBgxnq4P"
-            + "hwgwjfaoJy9YAXCswjCtaE9GwkVmRnJE9vFjJ33IGf37hFTYEHBFy4FomVmQwRFZ"
-            + "TIe7tkKDq9i18F7lzBPJPO6wEG8bxi4csatrjcVHR9erpY5u6ebtkKG8qsan9qzh"
-            + "iWAgSytiT++HejZeoQ+RRgQWjupjdDo5/0oSdQqvaN8Ah6C2J+ecCZ12Lu0FwF+t"
-            + "t9Ie3pF6W8TzxzuMdFWq+afvMIIDOzCCASOgAwIBAgIRAOTj/iNQb6/Qit7zAW9n"
-            + "cL0wDQYJKoZIhvcNAQELBQAwOTE3MDUGA1UEAxMuR29vZ2xlIENsb3VkIEtleSBW"
-            + "YXVsdCBTZXJ2aWNlIEludGVybWVkaWF0ZSBDQTAeFw0xODA1MDcyMjE4MTFaFw0y"
-            + "MzA1MDgyMjE4MTFaMDIxMDAuBgNVBAMTJ0dvb2dsZSBDbG91ZCBLZXkgVmF1bHQg"
-            + "U2VydmljZSBFbmRwb2ludDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI4MEUp5"
-            + "IHwATNfpBuJYIUX6JMsHZt798YO0JlWYy6nVVa1lxf9c+xxONJh+T5aio370RlIE"
-            + "uiq5R7vCHt0VGsCjEDAOMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB"
-            + "AGf6QU58lU+gGzy8hnp0suR/ixC++CExtf39pDHkdfU/e3ui4ROR+pjQ5F7okDFW"
-            + "eKSCNcJZ7tyXMJ9g7/I0qVY8Bj/gRnlVokdl/wD5PiL9GIzqWfnHNe3T+xrAAAgO"
-            + "D0bEmjgwNYmekfUIYQczd04d7ZMGnmAkpVH/0O2mf9q5x9fMlbKuAygUqQ/gmnlg"
-            + "xKfl9DSRWi4oMBOqlKlCRP1XAh3anu92+M/EhsFbyc07CWZY0SByX5M/cHVMLhUX"
-            + "jZHvcYLyOmJWJmXznidgyNeIR6t9yDB55iCt7WSn3qMY+9vA9ELzt8jYpBNaKc0G"
-            + "bWQkRzYWegkf4kMis98eQ3SnAKbRz6669nmuAdxKs9/LK6BlFOFw1xvsTRQ96dBa"
-            + "oiX2XGhou+Im0Td/AMs0Aigz2N+Ujq/yW//35GZQfdGGIYtFbkcltStygjIJyAM1"
-            + "pBhyBBkJhOhRpO4fXh98aq8H5J7R9i5A9WpnDstAxPxcNCDWn0O/WxhPvVZkFTpi"
-            + "NXh9dnlJ/kZe+j+z5ZMaxW435drLPx2AQKjXA9GgGrFPltTUyGycmEGtuxLvSnm/"
-            + "zPlmk5FUk7x2wEr0+bZ3cx0JHHgAtgXpe0jkDi8Bw8O3X7mUOjxVhYU6auiYJezW"
-            + "9LGmweaKwYvS04UCWOReolUVexob9LI/VX1JrrwD3s7k";
-    private static final String CERT_PATH_2_BASE64 = ""
+            + "MIIIPzCCBS8wggMXoAMCAQICAhAAMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMM"
+            + "FUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAyMDMwMDQyMDNaFw0yODAyMDEw"
+            + "MDQyMDNaMC0xKzApBgNVBAMMIkdvb2dsZSBDcnlwdEF1dGhWYXVsdCBJbnRlcm1l"
+            + "ZGlhdGUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDckHib0X6rQyDq"
+            + "k4519b5du0OrCPk30XXKwz+Hz5y4cGZaWKGcHOHWS2X9YApRzO00/EbvFkWVUTVG"
+            + "27wJ54V+C3HHSOAUWHhEgfFWvvHwfn9HTDx1BEk79aQqJ7DuJ06Sn/WOiMtKVAT5"
+            + "6Mi8mekBxpMOrdZqwlcLrUVsZxEHsw5/ceZu4cSWzc7SzlnbNK1cCgyRDGqWf6Gp"
+            + "3hGE86kUOtM1i95RgUIpw+w/z0wxpF6kIyQTjK+KjiYH/RBOJIEcm6sSWZlMotKL"
+            + "Sn2lhf+XL8yUxExIHTosfeb077QWW4w2BB2NZM4wPAO3w4aw33FNigDQc2SQYmnU"
+            + "EYmIcD8kx77+JWCgCxBJc2zTHXtBxWuXAQ+iegt8RO+QD97pd6XKM9xPsAOkcWLp"
+            + "79o+AJol4P5fwvgYM69mM4lwH12v86RI4aptPQOag0KDIHXyKbjaQyAgv30l4KkD"
+            + "pf2uWODhOOTwNbVPYUm3sYUlhBcbyhTk8YqN9sPU4QAao5sKTAYZgB/mlheQypTU"
+            + "wyvqz6bRzGehVB3ltP9gCyKdI04VXEUuUBWk3STyV2REQen5/LKAns6v11Cz22Zr"
+            + "EdCvNLgetnyV7CJsOa/wD/GiUWL2Ta7pzshi9ahJqrrcNPRbAzOLcNKZkFexhzPp"
+            + "onuo/pNrcaRda1frepXxVkmbsgOULwIDAQABo2YwZDAdBgNVHQ4EFgQUd6md2hCP"
+            + "lmf3VkEX5FfDxKBLbaAwHwYDVR0jBBgwFoAUm2X66jmB+eBCaZHSjGYzHM/x6fgw"
+            + "EgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL"
+            + "BQADggIBAFgShhuW+WVTowN080PLf0TWPlHACHHUPghf7rFGxgUjJypCloE84Beg"
+            + "3ROpP5l19CDqZ9OyPzA1z6VAzeGXyFhZvby7G2tZDBRP/v0u8pnSAdC5F8l8Vh2Y"
+            + "GdgE3sZD25vpdBi7P0Ef6LYQetOJXn86PqgmgW1F6lzxDjKCsi9kpeU0AWwDdOVg"
+            + "748wku50o8UEzsVwxzFd9toGlge/nn3FH5J7EuGzAlFwToHqpwTVEegaAd0l9mr5"
+            + "+rS7Urd3X80BHDqCBcXE7Uqbtzw5Y+lmowMCnW0kFN02dC9dLt2c9IxC+9sPIA5e"
+            + "TkrZBkrkTVRGLj2r29j7nC9m5VaKcBqcLZDWy8pRna8yaZprgNdE8d/WTY9nVsic"
+            + "09N8zNF5Q0bhhWa3QonlB9XW5ZqDguiclvn+5TtREzSAtSOyxM+gfG3l0wjOywIk"
+            + "1aFa52RaqAWPL67KOM6G3vKNpMnW5hrmHrijuKxiarGIoZfkZMR5ijK0uFgv3/p6"
+            + "NHL/YQBaHJJhkKet5ThiPxwW9+1k/ZcXVeY26Xh+22Gp/8to7ZW8guPPiN1hfpD+"
+            + "7f1IdSmHDrsZQQ7bfzV0bppsyNNB7e2Ecyw+GQny27nytBLJDGdRBurbwQvzppQO"
+            + "6Qmlk0rfCszh7bGCoCQNxXmuDsQ5BC+pQUqJplTqds1smyi29xs3MIIDCDCB8aAD"
+            + "AgECAgYBYVkuU0cwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwiR29vZ2xlIENy"
+            + "eXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAyMDIwMTAxMDNaFw0yMDAy"
+            + "MDMwMTAxMDNaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhWYXVsdCBJbnN0"
+            + "YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfButJT+htocB40B"
+            + "tDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl4b0hRH54Uvow"
+            + "DQYJKoZIhvcNAQELBQADggIBAJ3PM4GNTNYzMr8E/IGsWZkLx9ARAALqBXz7As59"
+            + "F8y5UcLMqkXD/ewOfBZgF5VzjlAePyE/wSw0wc3xzvrDVVDiZaMBW1DVtSlbn25q"
+            + "00m00mmcUeyyMc7vuRkPoDshIMQTc8+U3yyYsVScSV+B4TvSx6wPZ9FpwnSPjVPD"
+            + "2GkqeMTWszuxNVEWq0wmm0K5lMaX0hfiak+4/IZxOPPGIg2py1KLA/H2gdyeqyJR"
+            + "cAsyEkfwLlushR5T9abSiPsIRcYoX8Ck8Lt+gQ7RCMefnm8CoOBKIfcjuV4PGOoe"
+            + "Xrq57VR5SsOeT07bL+D7B+mohYFI1v2G3WClAE8XgM3q8NoFFvaYmoi0+UcTduil"
+            + "47qvozjdNmjRAgu5j6vMKXEdG5Rqsja8hy0LG1hwfnR0gNiwcZ5Le3GyFnwH1Igq"
+            + "vsGOUM0ohnDUAU0zJY7nG0QYrDYe5/QPRNhWDpYkwHDiqcG28wIQCOTPAZHU2EoS"
+            + "KjSqEG2l0S5JPcor2BEde9ikSkcmK8foxlOHIdFn+n7RNF3bSEfKn1IOuXoqPidm"
+            + "eBQLevqG8KTy/C9CHqlaCNlpbIA9h+WVfsjm2s6JXBu0YbcfoIbJAmSuZVeqB/+Z"
+            + "Vvpfiad/jQWzY49fRnsSmV7VveTFPGtJxC89EadbMAinMZo+72u59319RqN5wsP2"
+            + "Zus8";
+    private static String CERT_PATH_2_BASE64 = ""
             + "MIIFMzCCBS8wggMXoAMCAQICAhAAMA0GCSqGSIb3DQEBCwUAMCAxHjAcBgNVBAMM"
             + "FUdvb2dsZSBDcnlwdEF1dGhWYXVsdDAeFw0xODAyMDMwMDQyMDNaFw0yODAyMDEw"
             + "MDQyMDNaMC0xKzApBgNVBAMMIkdvb2dsZSBDcnlwdEF1dGhWYXVsdCBJbnRlcm1l"
@@ -118,44 +117,194 @@
             + "6Qmlk0rfCszh7bGCoCQNxXmuDsQ5BC+pQUqJplTqds1smyi29xs3";
 
     private static final String THM_CERT_XML_BEFORE_SERIAL = ""
-            + "<certificate>\n"
-            + "  <metadata>\n"
-            + "    <serial>";
-    private static final String THM_CERT_XML_AFTER_SERIAL = ""
-            + "</serial>\n"
-            + "    <creation-time>1525817891</creation-time>\n"
-            + "    <refresh-interval>2592000</refresh-interval>\n"
+            + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+                    + "<certificates>\n"
+                    + "  <metadata>\n"
+                    + "    <serial>\n"
+                    + "      ";
+    private static final String THM_CERT_XML_AFTER_SERIAL = "\n"
+            + "    </serial>\n"
+            + "    <creation-time>\n"
+            + "      1515697631\n"
+            + "    </creation-time>\n"
+            + "    <refresh-interval>\n"
+            + "      2592000\n"
+            + "    </refresh-interval>\n"
             + "    <previous>\n"
-            + "      <serial>10000</serial>\n"
-            + "      <hash>ahyI+59KW2tVxi0inRdUSo1Y8kmx5xK1isDvYfzxWbo=</hash>\n"
+            + "      <serial>\n"
+            + "        0\n"
+            + "      </serial>\n"
+            + "      <hash>\n"
+            + "        47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=\n"
+            + "      </hash>\n"
             + "    </previous>\n"
             + "  </metadata>\n"
             + "  <intermediates>\n"
-            + "    <cert>MIIFGjCCAwKgAwIBAgIQHflnDNWkj2yxeD1IB6GdTTANBgkqhkiG9w0BAQsFADAxMS8wLQYDVQQDEyZHb29nbGUgQ2xvdWQgS2V5IFZhdWx0IFNlcnZpY2UgUm9vdCBDQTAeFw0xODA1MDcxODU4MTBaFw0yODA1MDgxODU4MTBaMDkxNzA1BgNVBAMTLkdvb2dsZSBDbG91ZCBLZXkgVmF1bHQgU2VydmljZSBJbnRlcm1lZGlhdGUgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDvdOu8fePrMSKalxzfa3HaK6lbB/LN0TmXgSNzkQFjPHRpkfpv8oO663C6y2TQijKOUbJIwHP/bViBZ6Mib6d24CWmTtZjmRgenRda3N2bFmSeZZOq6A941l6IoSOgOanIhtjo35/XeFDZFWH5YNMSjBD+LThYEvvlyGyGUgb7cDjaDlCvsNkQp1P2glCqSe3OPRwbInlfwHCN5OImu9iTYqf/Tnnn8qmnrkbdF/b1U89TeLruS2EBPdJq8sGkfTdLhZn5CV+sCIZDOLJ23P23uZKTXF5+NrHllYC4kB8Jsp8jdVYBxpSvg/nsHOYNxKLSOCzVoze3YGs98AxHFa/fnINmesL4eKnOSPIMYF8eYWCiCXKFz178qPeZK6w7RGrXCC5VcqzaEpdGhoYm4e17dgjBMLWkvOeq+iWEPWc+hd/yszOAdHOVz0fyJeyAHWnv3vmeHlYI+swNfZ4CZh1rTFMxxxN4HMgzaiHFCzGWHmuyNdU1TeKFtaQeq7MiLAVwC2V0/d0ySyPR2f8OdgPKiSMSBT/PYjbXoT3fH2GYqQSTo+nujy3/PqXAxP0Uki7Ons1ESdYJKL57mzYTsUOPpLvFjbMQhQeubC64lzSPMmfB1n7SbKKdpOYEO8FdHlxTVyYQBmiF4IChG/1n/qgBJzMsXQLi65V8DkZdwCbXhwIDAQABoyYwJDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBATANBgkqhkiG9w0BAQsFAAOCAgEAQ+G3v3JCbzChBs8HUGx6i2TMm1NZM71+chbA2JF9De8kVd/r2CETvvBRLXcTPcWWA0+PRDGaDmi4TR3bJhXgBStecQZkQtzI3ZcdFfI0rTNeCevfHp5nJjtB+AYomCTKNrlNLpk9YbJosqEKVLQBhlLNYm3PT4CQYJ1NubLLtKF1cn4Z+eayxud1kDrZWFyN5CYewOrtXc8oCynj8H0/NydOuCRQU2c/UXWmvsmlRRffHJEXLqCMitTHV9w4VHEVg9YYssxno/jWtp+b4z8JsE2vkJjs2tmOvfiMupbJx9h6zj2j04rjhf/A+vGPRKOD5WtbbX4An2+szsNLmERBfWUNsO1AaSTc3W+AJOjrG30tewS7jFRPluTtgB+kmozSW0MU/BgAYJuNKRVP8zklVmQqJRbrrxSzrvHzJlz/lvFu9MD7nGtiFqT9VggFjqq5vgn5srBp3Dq4GDGerg+HCDCN9qgnL1gBcKzCMK1oT0bCRWZGckT28WMnfcgZ/fuEVNgQcEXLgWiZWZDBEVlMh7u2QoOr2LXwXuXME8k87rAQbxvGLhyxq2uNxUdH16uljm7p5u2Qobyqxqf2rOGJYCBLK2JP74d6Nl6hD5FGBBaO6mN0Ojn/ShJ1Cq9o3wCHoLYn55wJnXYu7QXAX6230h7ekXpbxPPHO4x0Var5p+8=</cert>\n"
+            + "    <cert>\n"
+            + "      MIIFLzCCAxegAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAwwVR29v\n"
+            + "      Z2xlIENyeXB0QXV0aFZhdWx0MB4XDTE4MDIwMzAwNDIwM1oXDTI4MDIwMTAwNDIw\n"
+            + "      M1owLTErMCkGA1UEAwwiR29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0\n"
+            + "      ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANyQeJvRfqtDIOqTjnX1\n"
+            + "      vl27Q6sI+TfRdcrDP4fPnLhwZlpYoZwc4dZLZf1gClHM7TT8Ru8WRZVRNUbbvAnn\n"
+            + "      hX4LccdI4BRYeESB8Va+8fB+f0dMPHUESTv1pConsO4nTpKf9Y6Iy0pUBPnoyLyZ\n"
+            + "      6QHGkw6t1mrCVwutRWxnEQezDn9x5m7hxJbNztLOWds0rVwKDJEMapZ/oaneEYTz\n"
+            + "      qRQ60zWL3lGBQinD7D/PTDGkXqQjJBOMr4qOJgf9EE4kgRybqxJZmUyi0otKfaWF\n"
+            + "      /5cvzJTETEgdOix95vTvtBZbjDYEHY1kzjA8A7fDhrDfcU2KANBzZJBiadQRiYhw\n"
+            + "      PyTHvv4lYKALEElzbNMde0HFa5cBD6J6C3xE75AP3ul3pcoz3E+wA6RxYunv2j4A\n"
+            + "      miXg/l/C+Bgzr2YziXAfXa/zpEjhqm09A5qDQoMgdfIpuNpDICC/fSXgqQOl/a5Y\n"
+            + "      4OE45PA1tU9hSbexhSWEFxvKFOTxio32w9ThABqjmwpMBhmAH+aWF5DKlNTDK+rP\n"
+            + "      ptHMZ6FUHeW0/2ALIp0jThVcRS5QFaTdJPJXZERB6fn8soCezq/XULPbZmsR0K80\n"
+            + "      uB62fJXsImw5r/AP8aJRYvZNrunOyGL1qEmqutw09FsDM4tw0pmQV7GHM+mie6j+\n"
+            + "      k2txpF1rV+t6lfFWSZuyA5QvAgMBAAGjZjBkMB0GA1UdDgQWBBR3qZ3aEI+WZ/dW\n"
+            + "      QRfkV8PEoEttoDAfBgNVHSMEGDAWgBSbZfrqOYH54EJpkdKMZjMcz/Hp+DASBgNV\n"
+            + "      HRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC\n"
+            + "      AgEAWBKGG5b5ZVOjA3TzQ8t/RNY+UcAIcdQ+CF/usUbGBSMnKkKWgTzgF6DdE6k/\n"
+            + "      mXX0IOpn07I/MDXPpUDN4ZfIWFm9vLsba1kMFE/+/S7ymdIB0LkXyXxWHZgZ2ATe\n"
+            + "      xkPbm+l0GLs/QR/othB604lefzo+qCaBbUXqXPEOMoKyL2Sl5TQBbAN05WDvjzCS\n"
+            + "      7nSjxQTOxXDHMV322gaWB7+efcUfknsS4bMCUXBOgeqnBNUR6BoB3SX2avn6tLtS\n"
+            + "      t3dfzQEcOoIFxcTtSpu3PDlj6WajAwKdbSQU3TZ0L10u3Zz0jEL72w8gDl5OStkG\n"
+            + "      SuRNVEYuPavb2PucL2blVopwGpwtkNbLylGdrzJpmmuA10Tx39ZNj2dWyJzT03zM\n"
+            + "      0XlDRuGFZrdCieUH1dblmoOC6JyW+f7lO1ETNIC1I7LEz6B8beXTCM7LAiTVoVrn\n"
+            + "      ZFqoBY8vrso4zobe8o2kydbmGuYeuKO4rGJqsYihl+RkxHmKMrS4WC/f+no0cv9h\n"
+            + "      AFockmGQp63lOGI/HBb37WT9lxdV5jbpeH7bYan/y2jtlbyC48+I3WF+kP7t/Uh1\n"
+            + "      KYcOuxlBDtt/NXRummzI00Ht7YRzLD4ZCfLbufK0EskMZ1EG6tvBC/OmlA7pCaWT\n"
+            + "      St8KzOHtsYKgJA3Fea4OxDkEL6lBSommVOp2zWybKLb3Gzc=\n"
+            + "    </cert>\n"
             + "  </intermediates>\n"
             + "  <endpoints>\n"
-            // The public key is chosen by using the following hash as the first 32 bytes (x-axis)
-            //     SHA256("Google Cloud Key Vault Service Test Endpoint") = 8e0c114a79207c004cd7e906e2582145fa24cb0766defdf183b4265598cba9d5
-            // so its private key is unknown.
-            + "    <cert>MIIDOzCCASOgAwIBAgIRAOTj/iNQb6/Qit7zAW9ncL0wDQYJKoZIhvcNAQELBQAwOTE3MDUGA1UEAxMuR29vZ2xlIENsb3VkIEtleSBWYXVsdCBTZXJ2aWNlIEludGVybWVkaWF0ZSBDQTAeFw0xODA1MDcyMjE4MTFaFw0yMzA1MDgyMjE4MTFaMDIxMDAuBgNVBAMTJ0dvb2dsZSBDbG91ZCBLZXkgVmF1bHQgU2VydmljZSBFbmRwb2ludDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI4MEUp5IHwATNfpBuJYIUX6JMsHZt798YO0JlWYy6nVVa1lxf9c+xxONJh+T5aio370RlIEuiq5R7vCHt0VGsCjEDAOMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAGf6QU58lU+gGzy8hnp0suR/ixC++CExtf39pDHkdfU/e3ui4ROR+pjQ5F7okDFWeKSCNcJZ7tyXMJ9g7/I0qVY8Bj/gRnlVokdl/wD5PiL9GIzqWfnHNe3T+xrAAAgOD0bEmjgwNYmekfUIYQczd04d7ZMGnmAkpVH/0O2mf9q5x9fMlbKuAygUqQ/gmnlgxKfl9DSRWi4oMBOqlKlCRP1XAh3anu92+M/EhsFbyc07CWZY0SByX5M/cHVMLhUXjZHvcYLyOmJWJmXznidgyNeIR6t9yDB55iCt7WSn3qMY+9vA9ELzt8jYpBNaKc0GbWQkRzYWegkf4kMis98eQ3SnAKbRz6669nmuAdxKs9/LK6BlFOFw1xvsTRQ96dBaoiX2XGhou+Im0Td/AMs0Aigz2N+Ujq/yW//35GZQfdGGIYtFbkcltStygjIJyAM1pBhyBBkJhOhRpO4fXh98aq8H5J7R9i5A9WpnDstAxPxcNCDWn0O/WxhPvVZkFTpiNXh9dnlJ/kZe+j+z5ZMaxW435drLPx2AQKjXA9GgGrFPltTUyGycmEGtuxLvSnm/zPlmk5FUk7x2wEr0+bZ3cx0JHHgAtgXpe0jkDi8Bw8O3X7mUOjxVhYU6auiYJezW9LGmweaKwYvS04UCWOReolUVexob9LI/VX1JrrwD3s7k</cert>\n"
+            + "    <cert>\n"
+            + "      MIIDCDCB8aADAgECAgYBYVkuU0cwDQYJKoZIhvcNAQELBQAwLTErMCkGA1UEAwwi\n"
+            + "      R29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0ZTAeFw0xODAyMDIwMTAx\n"
+            + "      MDNaFw0yMDAyMDMwMTAxMDNaMCkxJzAlBgNVBAMTHkdvb2dsZSBDcnlwdEF1dGhW\n"
+            + "      YXVsdCBJbnN0YW5jZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLgAERiYHfBu\n"
+            + "      tJT+htocB40BtDr2jdxh0EZJlQ8QhpMkZuA/0t/zeSAdkVWw5b16izJ9JVOi/KVl\n"
+            + "      4b0hRH54UvowDQYJKoZIhvcNAQELBQADggIBAJ3PM4GNTNYzMr8E/IGsWZkLx9AR\n"
+            + "      AALqBXz7As59F8y5UcLMqkXD/ewOfBZgF5VzjlAePyE/wSw0wc3xzvrDVVDiZaMB\n"
+            + "      W1DVtSlbn25q00m00mmcUeyyMc7vuRkPoDshIMQTc8+U3yyYsVScSV+B4TvSx6wP\n"
+            + "      Z9FpwnSPjVPD2GkqeMTWszuxNVEWq0wmm0K5lMaX0hfiak+4/IZxOPPGIg2py1KL\n"
+            + "      A/H2gdyeqyJRcAsyEkfwLlushR5T9abSiPsIRcYoX8Ck8Lt+gQ7RCMefnm8CoOBK\n"
+            + "      IfcjuV4PGOoeXrq57VR5SsOeT07bL+D7B+mohYFI1v2G3WClAE8XgM3q8NoFFvaY\n"
+            + "      moi0+UcTduil47qvozjdNmjRAgu5j6vMKXEdG5Rqsja8hy0LG1hwfnR0gNiwcZ5L\n"
+            + "      e3GyFnwH1IgqvsGOUM0ohnDUAU0zJY7nG0QYrDYe5/QPRNhWDpYkwHDiqcG28wIQ\n"
+            + "      COTPAZHU2EoSKjSqEG2l0S5JPcor2BEde9ikSkcmK8foxlOHIdFn+n7RNF3bSEfK\n"
+            + "      n1IOuXoqPidmeBQLevqG8KTy/C9CHqlaCNlpbIA9h+WVfsjm2s6JXBu0YbcfoIbJ\n"
+            + "      AmSuZVeqB/+ZVvpfiad/jQWzY49fRnsSmV7VveTFPGtJxC89EadbMAinMZo+72u5\n"
+            + "      9319RqN5wsP2Zus8\n"
+            + "    </cert>\n"
             + "  </endpoints>\n"
-            + "</certificate>\n";
+            + "</certificates>\n";
     private static final String THM_SIG_XML = ""
+            + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
             + "<signature>\n"
-            + "  <intermediates></intermediates>\n"
-            + "  <certificate>MIIFGjCCAwKgAwIBAgIQHflnDNWkj2yxeD1IB6GdTTANBgkqhkiG9w0BAQsFADAxMS8wLQYDVQQDEyZHb29nbGUgQ2xvdWQgS2V5IFZhdWx0IFNlcnZpY2UgUm9vdCBDQTAeFw0xODA1MDcxODU4MTBaFw0yODA1MDgxODU4MTBaMDkxNzA1BgNVBAMTLkdvb2dsZSBDbG91ZCBLZXkgVmF1bHQgU2VydmljZSBJbnRlcm1lZGlhdGUgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDvdOu8fePrMSKalxzfa3HaK6lbB/LN0TmXgSNzkQFjPHRpkfpv8oO663C6y2TQijKOUbJIwHP/bViBZ6Mib6d24CWmTtZjmRgenRda3N2bFmSeZZOq6A941l6IoSOgOanIhtjo35/XeFDZFWH5YNMSjBD+LThYEvvlyGyGUgb7cDjaDlCvsNkQp1P2glCqSe3OPRwbInlfwHCN5OImu9iTYqf/Tnnn8qmnrkbdF/b1U89TeLruS2EBPdJq8sGkfTdLhZn5CV+sCIZDOLJ23P23uZKTXF5+NrHllYC4kB8Jsp8jdVYBxpSvg/nsHOYNxKLSOCzVoze3YGs98AxHFa/fnINmesL4eKnOSPIMYF8eYWCiCXKFz178qPeZK6w7RGrXCC5VcqzaEpdGhoYm4e17dgjBMLWkvOeq+iWEPWc+hd/yszOAdHOVz0fyJeyAHWnv3vmeHlYI+swNfZ4CZh1rTFMxxxN4HMgzaiHFCzGWHmuyNdU1TeKFtaQeq7MiLAVwC2V0/d0ySyPR2f8OdgPKiSMSBT/PYjbXoT3fH2GYqQSTo+nujy3/PqXAxP0Uki7Ons1ESdYJKL57mzYTsUOPpLvFjbMQhQeubC64lzSPMmfB1n7SbKKdpOYEO8FdHlxTVyYQBmiF4IChG/1n/qgBJzMsXQLi65V8DkZdwCbXhwIDAQABoyYwJDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBATANBgkqhkiG9w0BAQsFAAOCAgEAQ+G3v3JCbzChBs8HUGx6i2TMm1NZM71+chbA2JF9De8kVd/r2CETvvBRLXcTPcWWA0+PRDGaDmi4TR3bJhXgBStecQZkQtzI3ZcdFfI0rTNeCevfHp5nJjtB+AYomCTKNrlNLpk9YbJosqEKVLQBhlLNYm3PT4CQYJ1NubLLtKF1cn4Z+eayxud1kDrZWFyN5CYewOrtXc8oCynj8H0/NydOuCRQU2c/UXWmvsmlRRffHJEXLqCMitTHV9w4VHEVg9YYssxno/jWtp+b4z8JsE2vkJjs2tmOvfiMupbJx9h6zj2j04rjhf/A+vGPRKOD5WtbbX4An2+szsNLmERBfWUNsO1AaSTc3W+AJOjrG30tewS7jFRPluTtgB+kmozSW0MU/BgAYJuNKRVP8zklVmQqJRbrrxSzrvHzJlz/lvFu9MD7nGtiFqT9VggFjqq5vgn5srBp3Dq4GDGerg+HCDCN9qgnL1gBcKzCMK1oT0bCRWZGckT28WMnfcgZ/fuEVNgQcEXLgWiZWZDBEVlMh7u2QoOr2LXwXuXME8k87rAQbxvGLhyxq2uNxUdH16uljm7p5u2Qobyqxqf2rOGJYCBLK2JP74d6Nl6hD5FGBBaO6mN0Ojn/ShJ1Cq9o3wCHoLYn55wJnXYu7QXAX6230h7ekXpbxPPHO4x0Var5p+8=</certificate>\n"
-            + "  <value>WkmYBCY4heNutMf3tEbyg+Omm+MvWF4EoDmv2vCd259oy3t8URqDqu5vEi3TqQguX0GO3r5mRKCcEYged121xJltC6zShbDMZZNAlB6sqvS6/vIVBBx5jKecUaEpRuQ4ruTyF93YXDi7DgaCNGaYCjkDrnr8lSAyelZl2tfe2BbpOMiwH1fNvI6Xmb++iyMmZGoJo91ovucC635SnnULNUtivL2CjLgU3mKb2uZMB8XPr1t1FOTJEA81ghDU+p3ZrPLxLB3KBTtfAwPQyqStRuY8+3bnPqi7VWeZgfoesvJiPF6q1PraoaL/inlRFo7wr37CS9EtNR/k5cq1UJ4/4Ernvj5k2Zw/IclzYHUGSd3ljCOTJJB6cDtR7WDqprlr1J4nr9hf1Ya4DFJmlX3FXix43Dw6lfk/1gCiWu0y2i1A2NCn0QRxuPh5b385Epj98QlZnd2roB2GfzchJTAxI+oeLc3CowkyLDS5jjuTMERbKbPpkhQu9gtskYtB0I4fEGOMn17+ZrXRcTPJexCS2NGgSqiF4X9Fwe+9XRg3Nk+SoUj9gBCysP8UeSz1POZHQIlZ24mQzxOK2hwGwDtxVchGCrNyf8rh5bZE2hUKHYNH9UWQ+YWrieKeulfP+o1wL9NLZOTz3SHcV/kCv5WqgynzkrKf382FwunxF56NapA=</value>\n"
+            + "  <intermediates>\n"
+            + "  </intermediates>\n"
+            + "  <certificate>\n"
+            + "    MIIFLzCCAxegAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAwwVR29v\n"
+            + "    Z2xlIENyeXB0QXV0aFZhdWx0MB4XDTE4MDIwMzAwNDIwM1oXDTI4MDIwMTAwNDIw\n"
+            + "    M1owLTErMCkGA1UEAwwiR29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0\n"
+            + "    ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANyQeJvRfqtDIOqTjnX1\n"
+            + "    vl27Q6sI+TfRdcrDP4fPnLhwZlpYoZwc4dZLZf1gClHM7TT8Ru8WRZVRNUbbvAnn\n"
+            + "    hX4LccdI4BRYeESB8Va+8fB+f0dMPHUESTv1pConsO4nTpKf9Y6Iy0pUBPnoyLyZ\n"
+            + "    6QHGkw6t1mrCVwutRWxnEQezDn9x5m7hxJbNztLOWds0rVwKDJEMapZ/oaneEYTz\n"
+            + "    qRQ60zWL3lGBQinD7D/PTDGkXqQjJBOMr4qOJgf9EE4kgRybqxJZmUyi0otKfaWF\n"
+            + "    /5cvzJTETEgdOix95vTvtBZbjDYEHY1kzjA8A7fDhrDfcU2KANBzZJBiadQRiYhw\n"
+            + "    PyTHvv4lYKALEElzbNMde0HFa5cBD6J6C3xE75AP3ul3pcoz3E+wA6RxYunv2j4A\n"
+            + "    miXg/l/C+Bgzr2YziXAfXa/zpEjhqm09A5qDQoMgdfIpuNpDICC/fSXgqQOl/a5Y\n"
+            + "    4OE45PA1tU9hSbexhSWEFxvKFOTxio32w9ThABqjmwpMBhmAH+aWF5DKlNTDK+rP\n"
+            + "    ptHMZ6FUHeW0/2ALIp0jThVcRS5QFaTdJPJXZERB6fn8soCezq/XULPbZmsR0K80\n"
+            + "    uB62fJXsImw5r/AP8aJRYvZNrunOyGL1qEmqutw09FsDM4tw0pmQV7GHM+mie6j+\n"
+            + "    k2txpF1rV+t6lfFWSZuyA5QvAgMBAAGjZjBkMB0GA1UdDgQWBBR3qZ3aEI+WZ/dW\n"
+            + "    QRfkV8PEoEttoDAfBgNVHSMEGDAWgBSbZfrqOYH54EJpkdKMZjMcz/Hp+DASBgNV\n"
+            + "    HRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC\n"
+            + "    AgEAWBKGG5b5ZVOjA3TzQ8t/RNY+UcAIcdQ+CF/usUbGBSMnKkKWgTzgF6DdE6k/\n"
+            + "    mXX0IOpn07I/MDXPpUDN4ZfIWFm9vLsba1kMFE/+/S7ymdIB0LkXyXxWHZgZ2ATe\n"
+            + "    xkPbm+l0GLs/QR/othB604lefzo+qCaBbUXqXPEOMoKyL2Sl5TQBbAN05WDvjzCS\n"
+            + "    7nSjxQTOxXDHMV322gaWB7+efcUfknsS4bMCUXBOgeqnBNUR6BoB3SX2avn6tLtS\n"
+            + "    t3dfzQEcOoIFxcTtSpu3PDlj6WajAwKdbSQU3TZ0L10u3Zz0jEL72w8gDl5OStkG\n"
+            + "    SuRNVEYuPavb2PucL2blVopwGpwtkNbLylGdrzJpmmuA10Tx39ZNj2dWyJzT03zM\n"
+            + "    0XlDRuGFZrdCieUH1dblmoOC6JyW+f7lO1ETNIC1I7LEz6B8beXTCM7LAiTVoVrn\n"
+            + "    ZFqoBY8vrso4zobe8o2kydbmGuYeuKO4rGJqsYihl+RkxHmKMrS4WC/f+no0cv9h\n"
+            + "    AFockmGQp63lOGI/HBb37WT9lxdV5jbpeH7bYan/y2jtlbyC48+I3WF+kP7t/Uh1\n"
+            + "    KYcOuxlBDtt/NXRummzI00Ht7YRzLD4ZCfLbufK0EskMZ1EG6tvBC/OmlA7pCaWT\n"
+            + "    St8KzOHtsYKgJA3Fea4OxDkEL6lBSommVOp2zWybKLb3Gzc=\n"
+            + "  </certificate>\n"
+            + "  <value>\n"
+            + "    uKJ4W8BPCdVaIBe2ZiMxxk5L5vGBV9QwaOEGU80LgtA/gEqkiO2IMUBlQJFqvvhh6RSph5lWpLuv\n"
+            + "    /Xt7WBzDsZOcxXNffg2+pWNpbpwZdHohlwQEI1OqiVYVnfG4euAkzeWZZLsRUuAjHfcWVIzDoSoK\n"
+            + "    wC+gqdUQHBV+pWyn6PXVslS0JIldeegbiwF076M1D7ybeCABXoQelSZRHkx1szO8UnxSR3X7Cemu\n"
+            + "    p9De/7z9+WPPclqybINVIPy6Kvl8mHrGSlzawQRDKtoMrJa8bo93PookF8sbg5EoGapV0yNpMEiA\n"
+            + "    spq3DEcdXB6mGDGPnLbS2WXq4zjKopASRKkZvOMdgfS6NdUMDtKS1TsOrv2KKTkLnGYfvdAeWiMg\n"
+            + "    oFbuyYQ0mnDlLH1UW6anI8RxXn+wmdyZA+/ksapGvRmkvz0Mb997WzqNl7v7UTr0SU3Ws01hFsm6\n"
+            + "    lW++MsotkyfpR9mWB8/dqVNVShLmIlt7U/YFVfziYSrVdjcAdIlgJ6Ihxb92liQHOU+Qr1YDOmm1\n"
+            + "    JSnhlQVvFxWZG7hm5laNL6lqXz5VV6Gk5IeLtMb8kdHz3zj4ascdldapVPLJIa5741GNNgQNU0nH\n"
+            + "    FhAyKk0zN7PbL1/XGWPU+s5lai4HE6JM2CKA7jE7cYrdaDZxbba+9iWzQ4YEBDr5Z3OoloK5dvs=\n"
+            + "  </value>\n"
             + "</signature>\n";
 
-    public static final CertPath CERT_PATH_1;
-    public static final CertPath CERT_PATH_2;
     public static final PublicKey CERT_1_PUBLIC_KEY;
+    public static final PrivateKey CERT_1_PRIVATE_KEY;
 
     static {
         try {
-            CERT_PATH_1 = decodeCertPath(CERT_PATH_1_BASE64);
-            CERT_PATH_2 = decodeCertPath(CERT_PATH_2_BASE64);
-            CERT_1_PUBLIC_KEY = CERT_PATH_1.getCertificates().get(0).getPublicKey();
+            CERT_1_PUBLIC_KEY =
+                    SecureBox.decodePublicKey(
+                            new byte[] {
+                                (byte) 0x04, (byte) 0xb8, (byte) 0x00, (byte) 0x11, (byte) 0x18,
+                                (byte) 0x98, (byte) 0x1d, (byte) 0xf0, (byte) 0x6e, (byte) 0xb4,
+                                (byte) 0x94, (byte) 0xfe, (byte) 0x86, (byte) 0xda, (byte) 0x1c,
+                                (byte) 0x07, (byte) 0x8d, (byte) 0x01, (byte) 0xb4, (byte) 0x3a,
+                                (byte) 0xf6, (byte) 0x8d, (byte) 0xdc, (byte) 0x61, (byte) 0xd0,
+                                (byte) 0x46, (byte) 0x49, (byte) 0x95, (byte) 0x0f, (byte) 0x10,
+                                (byte) 0x86, (byte) 0x93, (byte) 0x24, (byte) 0x66, (byte) 0xe0,
+                                (byte) 0x3f, (byte) 0xd2, (byte) 0xdf, (byte) 0xf3, (byte) 0x79,
+                                (byte) 0x20, (byte) 0x1d, (byte) 0x91, (byte) 0x55, (byte) 0xb0,
+                                (byte) 0xe5, (byte) 0xbd, (byte) 0x7a, (byte) 0x8b, (byte) 0x32,
+                                (byte) 0x7d, (byte) 0x25, (byte) 0x53, (byte) 0xa2, (byte) 0xfc,
+                                (byte) 0xa5, (byte) 0x65, (byte) 0xe1, (byte) 0xbd, (byte) 0x21,
+                                (byte) 0x44, (byte) 0x7e, (byte) 0x78, (byte) 0x52, (byte) 0xfa
+                            });
+            CERT_1_PRIVATE_KEY =
+                    decodePrivateKey(
+                            new byte[] {
+                                (byte) 0x70, (byte) 0x01, (byte) 0xc7, (byte) 0x87, (byte) 0x32,
+                                (byte) 0x2f, (byte) 0x1c, (byte) 0x9a, (byte) 0x6e, (byte) 0xb1,
+                                (byte) 0x91, (byte) 0xca, (byte) 0x4e, (byte) 0xb5, (byte) 0x44,
+                                (byte) 0xba, (byte) 0xc8, (byte) 0x68, (byte) 0xc6, (byte) 0x0a,
+                                (byte) 0x76, (byte) 0xcb, (byte) 0xd3, (byte) 0x63, (byte) 0x67,
+                                (byte) 0x7c, (byte) 0xb0, (byte) 0x11, (byte) 0x82, (byte) 0x65,
+                                (byte) 0x77, (byte) 0x01
+                            });
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    public static byte[] getCertPath1Bytes() {
+        try {
+            return CertUtils.decodeBase64(CERT_PATH_1_BASE64);
+        } catch (Exception e){
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static byte[] getCertPath2Bytes() {
+        try {
+            return CertUtils.decodeBase64(CERT_PATH_2_BASE64);
+        } catch (Exception e){
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static final CertPath CERT_PATH_1;
+    public static final CertPath CERT_PATH_2;
+
+    static {
+        try {
+            CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+            CERT_PATH_1 = certFactory.generateCertPath(
+                    new ByteArrayInputStream(getCertPath1Bytes()), CERT_PATH_ENCODING);
+            CERT_PATH_2 = certFactory.generateCertPath(
+                    new ByteArrayInputStream(getCertPath2Bytes()), CERT_PATH_ENCODING);
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -174,6 +323,13 @@
         return THM_SIG_XML.getBytes(StandardCharsets.UTF_8);
     }
 
+    private static PrivateKey decodePrivateKey(byte[] keyBytes) throws Exception {
+        assertThat(keyBytes.length).isEqualTo(32);
+        BigInteger priv = new BigInteger(/*signum=*/ 1, keyBytes);
+        KeyFactory keyFactory = KeyFactory.getInstance("EC");
+        return keyFactory.generatePrivate(new ECPrivateKeySpec(priv, SecureBox.EC_PARAM_SPEC));
+    }
+
     public static SecretKey generateKey() throws Exception {
         KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
         keyGenerator.init(/*keySize=*/ 256);
@@ -420,10 +576,6 @@
             + "2nxygOQKtfb0EPTvVYMErvWrA69rr+wPMSWPetvcDGEZ8hWFr3iRtduExC9sRqnV"
             + "5DhvZROQSZQtQ+Ja6g8BehUC9gPCES93EOQUYPpRQEeD1CE+1IKTyuH+ApynIKSj"
             + "5+U1x+OE3UZYTTzEck/TJxTm+Sv4FfCvpwdmDAMTjEZXfuFR+7+5Og==";
-    private static final String INSECURE_PRIVATE_KEY_FOR_ENDPOINT1_BASE64 = ""
-            + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgdCqcARU7lWJVXKY/"
-            + "+DTlFC0dzcTvh1ufkfZdnoZoR7ShRANCAAS3S6JtfbCyXlLSA+WZHwk0Rr2hdjJX"
-            + "xGeJLnsAbVkESmoGL9wG2Qty2InpFQ9jFFJHvGR8a73RMQVqmNxwQvFh";
 
     public static byte[] getInsecureCertXmlBytesWithEndpoint1(int serial) {
         String str = INSECURE_CERT_XML_HEADER;
@@ -451,13 +603,6 @@
         return decodeCertPath(INSECURE_CERT_PATH_FOR_ENDPOINT2_BASE64);
     }
 
-    public static PrivateKey getInsecurePrivateKeyForEndpoint1() throws Exception {
-        byte[] keyBytes = Base64.getDecoder().decode(INSECURE_PRIVATE_KEY_FOR_ENDPOINT1_BASE64);
-        KeyFactory kf = KeyFactory.getInstance("EC");
-        PKCS8EncodedKeySpec skSpec = new PKCS8EncodedKeySpec(keyBytes);
-        return kf.generatePrivate(skSpec);
-    }
-
     private static CertPath decodeCertPath(String base64CertPath) throws Exception {
         byte[] certPathBytes = Base64.getDecoder().decode(base64CertPath);
         CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
diff --git a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
index 20cf733..761c1f1 100644
--- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.power;
 
+import android.os.PowerManager;
 import android.os.PowerManager.ServiceType;
 import android.os.PowerSaveState;
 import android.os.Handler;
@@ -41,7 +42,8 @@
     private static final float DEFAULT_BRIGHTNESS_FACTOR = 0.5f;
     private static final float PRECISION = 0.001f;
     private static final int GPS_MODE = 0;
-    private static final int DEFAULT_GPS_MODE = 0;
+    private static final int DEFAULT_GPS_MODE =
+            PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
     private static final String BATTERY_SAVER_CONSTANTS = "vibration_disabled=true,"
             + "animation_disabled=false,"
             + "soundtrigger_disabled=true,"
@@ -69,6 +71,10 @@
             return mDeviceSpecificConfigResId;
         }
 
+        @Override
+        boolean isAccessibilityEnabled() {
+            return mMockAccessibilityEnabled;
+        }
 
         @VisibleForTesting
         void onChange() {
@@ -83,11 +89,15 @@
     private final ArrayMap<String, String> mMockGlobalSettings = new ArrayMap<>();
     private int mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_1;
 
+    private boolean mMockAccessibilityEnabled;
+
     public void setUp() throws Exception {
         super.setUp();
         MockitoAnnotations.initMocks(this);
         mBatterySaverPolicy = new BatterySaverPolicyForTest(mHandler);
         mBatterySaverPolicy.systemReady(getContext());
+
+        mMockAccessibilityEnabled = false;
     }
 
     @SmallTest
@@ -101,6 +111,12 @@
     }
 
     @SmallTest
+    public void testGetBatterySaverPolicy_PolicyVibration_WithAccessibilityEnabled() {
+        mMockAccessibilityEnabled = true;
+        testServiceDefaultValue_unchanged(ServiceType.VIBRATION);
+    }
+
+    @SmallTest
     public void testGetBatterySaverPolicy_PolicySound_DefaultValueCorrect() {
         testServiceDefaultValue(ServiceType.SOUND);
     }
@@ -117,7 +133,7 @@
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicyAnimation_DefaultValueCorrect() {
-        testServiceDefaultValue(ServiceType.ANIMATION);
+        testServiceDefaultValue_unchanged(ServiceType.ANIMATION);
     }
 
     @SmallTest
@@ -144,11 +160,7 @@
 
     @SmallTest
     public void testGetBatterySaverPolicy_PolicyScreenBrightness_DefaultValueCorrect() {
-        testServiceDefaultValue(ServiceType.SCREEN_BRIGHTNESS);
-
-        PowerSaveState stateOn =
-                mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS, true);
-        assertThat(stateOn.brightnessFactor).isWithin(PRECISION).of(DEFAULT_BRIGHTNESS_FACTOR);
+        testServiceDefaultValue_unchanged(ServiceType.SCREEN_BRIGHTNESS);
     }
 
     @SmallTest
@@ -222,6 +234,17 @@
         assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
     }
 
+    private void testServiceDefaultValue_unchanged(@ServiceType int type) {
+        mBatterySaverPolicy.updateConstantsLocked("", "");
+        final PowerSaveState batterySaverStateOn =
+                mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_ON);
+        assertThat(batterySaverStateOn.batterySaverEnabled).isFalse();
+
+        final PowerSaveState batterySaverStateOff =
+                mBatterySaverPolicy.getBatterySaverPolicy(type, BATTERY_SAVER_OFF);
+        assertThat(batterySaverStateOff.batterySaverEnabled).isFalse();
+    }
+
     public void testDeviceSpecific() {
         mDeviceSpecificConfigResId = R.string.config_batterySaverDeviceSpecificConfig_1;
         mMockGlobalSettings.put(Global.BATTERY_SAVER_CONSTANTS, "");
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index f4bb32d..bafb0a2 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -828,7 +828,12 @@
     // internalClearGlobalStateLocked() cleans up the telephony and power save listeners.
     private void internalClearGlobalStateLocked() {
         // Unregister from call state changes.
-        mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+        long token = Binder.clearCallingIdentity();
+        try {
+            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
 
         // Unregister from power save mode changes.
         if (mPowerSaveModeListener != null) {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index a9389be..ece646c 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1016,6 +1016,8 @@
             if (iSub != null) {
                 // FIXME: This returns 1 on success, 0 on error should should we return it?
                 iSub.addSubInfoRecord(iccId, slotIndex);
+            } else {
+                logd("[addSubscriptionInfoRecord]- ISub service is null");
             }
         } catch (RemoteException ex) {
             // ignore it
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
index 00bf33a..b185a26 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
@@ -435,9 +435,10 @@
             if (!file.getName().endsWith(".properties")) {
                 continue;
             }
-            try {
+
+            try (FileInputStream in = new FileInputStream(file)) {
                 Properties properties = new Properties();
-                properties.load(new FileInputStream(file));
+                properties.load(in);
                 createModelInfo(properties);
                 loadedModel = true;
             } catch (Exception e) {