Merge "Move registration of AssetManager.mObject to zygote." 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/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 545fa01..ad02569 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -110,8 +110,8 @@
 TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
     StatsService service(nullptr);
     SendConfig(service, MakeConfig());
-    const long start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                                // initialized with.
+    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                             // initialized with.
 
     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 2).get());
@@ -124,8 +124,8 @@
 TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
     StatsService service(nullptr);
     SendConfig(service, MakeConfig());
-    const long start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                                // initialized with.
+    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                             // initialized with.
 
     // Force the uidmap to update at timestamp 2.
     service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
@@ -142,8 +142,8 @@
 TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
     StatsService service(nullptr);
     SendConfig(service, MakeConfig());
-    const long start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                                // initialized with.
+    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                             // initialized with.
     service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())});
 
     // Force the uidmap to update at timestamp 2.
@@ -165,8 +165,8 @@
 TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
     StatsService service(nullptr);
     SendConfig(service, MakeConfig());
-    const long start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                                // initialized with.
+    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                             // initialized with.
     service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())});
 
     // Force the uidmap to update at timestamp 2.
@@ -190,8 +190,8 @@
     // Partial buckets don't occur when app is first installed.
     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
     SendConfig(service, MakeValueMetricConfig(0));
-    const long start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                                // initialized with.
+    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                             // initialized with.
 
     service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
     service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2);
@@ -207,8 +207,8 @@
     // Partial buckets don't occur when app is first installed.
     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
     SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */));
-    const long start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                                // initialized with.
+    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                             // initialized with.
 
     const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
     service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
@@ -230,8 +230,8 @@
     // Partial buckets don't occur when app is first installed.
     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
     SendConfig(service, MakeGaugeMetricConfig(0));
-    const long start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                                // initialized with.
+    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                             // initialized with.
 
     service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
     service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2);
@@ -247,8 +247,8 @@
     // Partial buckets don't occur when app is first installed.
     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1);
     SendConfig(service, MakeGaugeMetricConfig(60 * NS_PER_SEC /* One minute */));
-    const long start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-                                                // initialized with.
+    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                             // initialized with.
 
     const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
     service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
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/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 96c3f85..290651c 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -4105,6 +4105,7 @@
 Lcom/android/org/conscrypt/TrustManagerImpl;-><init>(Ljava/security/KeyStore;)V
 Lcom/android/org/conscrypt/TrustManagerImpl;->checkServerTrusted([Ljava/security/cert/X509Certificate;Ljava/lang/String;Ljava/lang/String;)Ljava/util/List;
 Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;)V
+Ldalvik/system/BaseDexClassLoader;->addDexPath(Ljava/lang/String;Z)V
 Ldalvik/system/BaseDexClassLoader;->getLdLibraryPath()Ljava/lang/String;
 Ldalvik/system/BaseDexClassLoader;->pathList:Ldalvik/system/DexPathList;
 Ldalvik/system/BlockGuard$Policy;->onNetwork()V
@@ -4145,6 +4146,10 @@
 Ldalvik/system/DexPathList;->nativeLibraryPathElements:[Ldalvik/system/DexPathList$NativeLibraryElement;
 Ldalvik/system/DexPathList;->splitPaths(Ljava/lang/String;Z)Ljava/util/List;
 Ldalvik/system/DexPathList;->systemNativeLibraryDirectories:Ljava/util/List;
+Ldalvik/system/SocketTagger;->get()Ldalvik/system/SocketTagger;
+Ldalvik/system/SocketTagger;->tag(Ljava/net/Socket;)V
+Ldalvik/system/SocketTagger;->untag(Ljava/net/Socket;)V
+Ldalvik/system/VMDebug;->allowHiddenApiReflectionFrom(Ljava/lang/Class;)V
 Ldalvik/system/VMDebug;->dumpReferenceTables()V
 Ldalvik/system/VMDebug;->isDebuggerConnected()Z
 Ldalvik/system/VMRuntime;->addressOf(Ljava/lang/Object;)J
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 7032a2f..e469098 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -24,6 +24,7 @@
 import android.hardware.display.VirtualDisplay;
 import android.hardware.input.InputManager;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -111,6 +112,11 @@
          * @see #startActivity(Intent)
          */
         public abstract void onActivityViewDestroyed(ActivityView view);
+        /**
+         * Called when a task is moved to the front of the stack inside the container.
+         * This is a filtered version of {@link TaskStackListener}
+         */
+        public void onTaskMovedToFront(ActivityManager.StackInfo stackInfo) { }
     }
 
     /**
@@ -155,6 +161,28 @@
 
     /**
      * Launch a new activity into this container.
+     * <p>Activity resolved by the provided {@link Intent} must have
+     * {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be
+     * launched here. Also, if activity is not owned by the owner of this container, it must allow
+     * embedding and the caller must have permission to embed.
+     * <p>Note: This class must finish initializing and
+     * {@link StateCallback#onActivityViewReady(ActivityView)} callback must be triggered before
+     * this method can be called.
+     *
+     * @param intent Intent used to launch an activity.
+     * @param user The UserHandle of the user to start this activity for.
+     *
+     *
+     * @see StateCallback
+     * @see #startActivity(PendingIntent)
+     */
+    public void startActivity(@NonNull Intent intent, UserHandle user) {
+        final ActivityOptions options = prepareActivityOptions();
+        getContext().startActivityAsUser(intent, options.toBundle(), user);
+    }
+
+    /**
+     * Launch a new activity into this container.
      * <p>Activity resolved by the provided {@link PendingIntent} must have
      * {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be
      * launched here. Also, if activity is not owned by the owner of this container, it must allow
@@ -303,7 +331,9 @@
         final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
         mVirtualDisplay = displayManager.createVirtualDisplay(
                 DISPLAY_NAME + "@" + System.identityHashCode(this),
-                width, height, getBaseDisplayDensity(), mSurface, 0 /* flags */);
+                width, height, getBaseDisplayDensity(), mSurface,
+                DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
+                        | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
         if (mVirtualDisplay == null) {
             Log.e(TAG, "Failed to initialize ActivityView");
             return;
@@ -317,7 +347,7 @@
             e.rethrowAsRuntimeException();
         }
         mInputForwarder = InputManager.getInstance().createInputForwarder(displayId);
-        mTaskStackListener = new TaskBackgroundChangeListener();
+        mTaskStackListener = new TaskStackListenerImpl();
         try {
             mActivityManager.registerTaskStackListener(mTaskStackListener);
         } catch (RemoteException e) {
@@ -403,8 +433,11 @@
      * A task change listener that detects background color change of the topmost stack on our
      * virtual display and updates the background of the surface view. This background will be shown
      * when surface view is resized, but the app hasn't drawn its content in new size yet.
+     * It also calls StateCallback.onTaskMovedToFront to notify interested parties that the stack
+     * associated with the {@link ActivityView} has had a Task moved to the front. This is useful
+     * when needing to also bring the host Activity to the foreground at the same time.
      */
-    private class TaskBackgroundChangeListener extends TaskStackListener {
+    private class TaskStackListenerImpl extends TaskStackListener {
 
         @Override
         public void onTaskDescriptionChanged(int taskId, ActivityManager.TaskDescription td)
@@ -413,6 +446,31 @@
                 return;
             }
 
+            StackInfo stackInfo = getTopMostStackInfo();
+            if (stackInfo == null) {
+                return;
+            }
+            // Found the topmost stack on target display. Now check if the topmost task's
+            // description changed.
+            if (taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
+                mSurfaceView.setResizeBackgroundColor(td.getBackgroundColor());
+            }
+        }
+
+        @Override
+        public void onTaskMovedToFront(int taskId) throws RemoteException {
+            if (mActivityViewCallback  != null) {
+                StackInfo stackInfo = getTopMostStackInfo();
+                // if StackInfo was null or unrelated to the "move to front" then there's no use
+                // notifying the callback
+                if (stackInfo != null
+                        && taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
+                    mActivityViewCallback.onTaskMovedToFront(stackInfo);
+                }
+            }
+        }
+
+        private StackInfo getTopMostStackInfo() throws RemoteException {
             // Find the topmost task on our virtual display - it will define the background
             // color of the surface view during resizing.
             final int displayId = mVirtualDisplay.getDisplay().getDisplayId();
@@ -426,14 +484,10 @@
                 if (stackInfo.displayId != displayId) {
                     continue;
                 }
-                // Found the topmost stack on target display. Now check if the topmost task's
-                // description changed.
-                if (taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
-                    mSurfaceView.setResizeBackgroundColor(td.getBackgroundColor());
-                }
-                break;
+                // Found the topmost stack on target display.
+                return stackInfo;
             }
+            return null;
         }
     }
-
 }
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..ea08110 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1420,6 +1420,9 @@
      * Activity Action: Start Voice Command.
      * <p>Input: Nothing.
      * <p>Output: Nothing.
+     * <p class="note">
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
@@ -5683,9 +5686,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 98d9bea..10ee728 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -123,6 +123,10 @@
      * Input: Nothing.
      * <p>
      * Output: Nothing.
+     *
+     * <p class="note">
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_APN_SETTINGS = "android.settings.APN_SETTINGS";
@@ -882,6 +886,10 @@
      * Applications can also use {@link android.net.ConnectivityManager#getRestrictBackgroundStatus
      * ConnectivityManager#getRestrictBackgroundStatus()} to determine the
      * status of the background data restrictions for them.
+     *
+     * <p class="note">
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS =
@@ -1148,6 +1156,10 @@
      * Input: Nothing.
      * <p>
      * Output: Nothing.
+     *
+     * <p class="note">
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS
@@ -8902,6 +8914,14 @@
         public static final String PRIV_APP_OOB_ENABLED = "priv_app_oob_enabled";
 
         /**
+         * Comma separated list of privileged package names, which will be running out-of-box APK.
+         * Default: "ALL"
+         *
+         * @hide
+         */
+        public static final String PRIV_APP_OOB_LIST = "priv_app_oob_list";
+
+        /**
          * The interval in milliseconds at which location requests will be throttled when they are
          * coming from the background.
          *
@@ -10417,6 +10437,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/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index 14727f0..00060ab 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -253,7 +253,7 @@
      * @return String containing the OpenMobile API version (e.g. "3.0").
      */
     public @NonNull String getVersion() {
-        return "3.2";
+        return "3.3";
     }
 
     @NonNull ISecureElementListener getListener() {
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index ce94315c..362b94b 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -141,6 +141,10 @@
      * <ul>
      *   <li>{@link #EXTRA_SECURE}
      * </ul>
+     *
+     * <p class="note">
+     * In some cases, a matching Activity may not exist, so ensure you
+     * safeguard against this.
      */
     public static final String ACTION_VOICE_SEARCH_HANDS_FREE =
             "android.speech.action.VOICE_SEARCH_HANDS_FREE";
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/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index a3c7a9e..fbf690f 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -370,6 +370,14 @@
         return snapTarget;
     }
 
+    /**
+     * @return whether or not there are more than 1 split targets that do not include the two
+     * dismiss targets, used in deciding to display the middle target for accessibility
+     */
+    public boolean showMiddleSplitTargetForAccessibility() {
+        return (mTargets.size() - 2) > 1;
+    }
+
     public boolean isFirstSplitTargetAvailable() {
         return mFirstSplitTarget != mMiddleTarget;
     }
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/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f8dd7ac..9da3b21 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -747,6 +747,12 @@
                        jittransitionweightOptBuf,
                        "-Xjittransitionweight:");
 
+    property_get("dalvik.vm.profilebootimage", propBuf, "");
+    if (strcmp(propBuf, "true") == 0) {
+        addOption("-Xps-profile-boot-class-path");
+        addOption("-Xps-profile-aot-code");
+    }
+
     /*
      * Madvise related options.
      */
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..bc43d91 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -506,11 +506,11 @@
     <!-- String containing the apn value for tethering.  May be overriden by secure settings
          TETHER_DUN_APN.  Value is a comma separated series of strings:
          "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type",
-         Or string format of ApnSettingV3.
+         Or string format of ApnSettingV3 or higher.
          note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN"
          Multiple entries are separated by using string-array:
          "<item>[ApnSettingV3]Name,apn,,,,,,,,,123,45,,mms|*,IPV6,IP,true,14,,,,,,,spn,testspn</item>
-          <item>[ApnSettingV3]Name1,apn2,,,,,,,,,123,46,,mms|*,IPV6,IP,true,12,,,,,,,,</item>" -->
+          <item>[ApnSettingV5]Name1,apn2,,,,,,,,,123,46,,mms|*,IPV6,IP,true,12,,,,,,,,,,</item>" -->
     <string-array translatable="false" name="config_tether_apndata">
     </string-array>
 
@@ -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/os/VintfObjectTest.java b/core/tests/coretests/src/android/os/VintfObjectTest.java
index 821ee80..44510c2 100644
--- a/core/tests/coretests/src/android/os/VintfObjectTest.java
+++ b/core/tests/coretests/src/android/os/VintfObjectTest.java
@@ -20,6 +20,9 @@
 import junit.framework.TestCase;
 
 public class VintfObjectTest extends TestCase {
+    /**
+     * Sanity check for {@link VintfObject#report VintfObject.report()}.
+     */
     public void testReport() {
         String[] xmls = VintfObject.report();
         assertTrue(xmls.length > 0);
@@ -28,6 +31,6 @@
                 "<manifest version=\"1.0\" type=\"framework\">"));
         // From /system/compatibility-matrix.xml
         assertTrue(String.join("", xmls).contains(
-                "<compatibility-matrix version=\"1.0\" type=\"framework\">"));
+                "<compatibility-matrix version=\"1.0\" type=\"framework\""));
     }
 }
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ceb58f6..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,
@@ -357,6 +358,7 @@
                     Settings.Global.POWER_MANAGER_CONSTANTS,
                     Settings.Global.PREFERRED_NETWORK_MODE,
                     Settings.Global.PRIV_APP_OOB_ENABLED,
+                    Settings.Global.PRIV_APP_OOB_LIST,
                     Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
                     Settings.Global.RADIO_BLUETOOTH,
                     Settings.Global.RADIO_CELL,
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index c486e68..aa45709 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -2540,19 +2540,20 @@
                     if (position < 0) {
                         return -1;
                     }
-                    if (mPosition != position) {
-                        in.seek(position);
-                        mPosition = position;
-                    }
+                    try {
+                        if (mPosition != position) {
+                            in.seek(position);
+                            mPosition = position;
+                        }
 
-                    int bytesRead = in.read(buffer, offset, size);
-                    if (bytesRead < 0) {
-                        mPosition = -1; // need to seek on next read
-                        return -1;
-                    }
-
-                    mPosition += bytesRead;
-                    return bytesRead;
+                        int bytesRead = in.read(buffer, offset, size);
+                        if (bytesRead >= 0) {
+                            mPosition += bytesRead;
+                            return bytesRead;
+                        }
+                    } catch (IOException e) {}
+                    mPosition = -1; // need to seek on next read
+                    return -1;
                 }
 
                 @Override
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/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index 54a1af4..6a2a04a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -47,8 +47,10 @@
             "com.android.settings.category.ia.development";
     public static final String CATEGORY_NOTIFICATIONS =
             "com.android.settings.category.ia.notifications";
-    public static final String CATEGORY_DO_NOT_DISTURB =
-            "com.android.settings.category.ia.dnd";
+    public static final String CATEGORY_DO_NOT_DISTURB = "com.android.settings.category.ia.dnd";
+    public static final String CATEGORY_GESTURES = "com.android.settings.category.ia.gestures";
+    public static final String CATEGORY_NIGHT_LIGHT =
+            "com.android.settings.category.ia.night_light";
 
     public static final Map<String, String> KEY_COMPAT_MAP;
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
index 06e2ee1..b7699f1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
@@ -67,6 +67,19 @@
         return mWhitelistedApps.contains(pkg);
     }
 
+    public boolean isWhitelisted(String[] pkgs) {
+        if (ArrayUtils.isEmpty(pkgs)) {
+            return false;
+        }
+        for (String pkg : pkgs) {
+            if (isWhitelisted(pkg)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     public boolean isSysWhitelistedExceptIdle(String pkg) {
         return mSysWhitelistedAppsExceptIdle.contains(pkg);
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
index 6025d68..13364ab 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java
@@ -26,6 +26,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.support.annotation.VisibleForTesting;
+import android.text.format.DateUtils;
 import android.util.IconDrawableFactory;
 import android.util.Log;
 import java.util.ArrayList;
@@ -41,7 +42,8 @@
     @VisibleForTesting
     static final String ANDROID_SYSTEM_PACKAGE_NAME = "android";
 
-    private static final int RECENT_TIME_INTERVAL_MILLIS = 15 * 60 * 1000;
+    // Keep last 24 hours of location app information.
+    private static final long RECENT_TIME_INTERVAL_MILLIS = DateUtils.DAY_IN_MILLIS;
 
     @VisibleForTesting
     static final int[] LOCATION_OPS = new int[] {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
index d12473e..f34605c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java
@@ -57,8 +57,10 @@
         allKeys.add(CategoryKey.CATEGORY_SYSTEM);
         allKeys.add(CategoryKey.CATEGORY_SYSTEM_LANGUAGE);
         allKeys.add(CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT);
+        allKeys.add(CategoryKey.CATEGORY_GESTURES);
+        allKeys.add(CategoryKey.CATEGORY_NIGHT_LIGHT);
         // DO NOT REMOVE ANYTHING ABOVE
 
-        assertThat(allKeys.size()).isEqualTo(16);
+        assertThat(allKeys.size()).isEqualTo(18);
     }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
index f591781..0af2c05 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
@@ -61,24 +61,32 @@
 
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_ONE})).isTrue();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_TWO})).isFalse();
 
         mPowerWhitelistBackend.addApp(PACKAGE_TWO);
 
         verify(mDeviceIdleService, atLeastOnce()).addPowerSaveWhitelistApp(PACKAGE_TWO);
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isTrue();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(
+                new String[]{PACKAGE_ONE, PACKAGE_TWO})).isTrue();
 
         mPowerWhitelistBackend.removeApp(PACKAGE_TWO);
 
         verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_TWO);
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_ONE})).isTrue();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_TWO})).isFalse();
 
         mPowerWhitelistBackend.removeApp(PACKAGE_ONE);
 
         verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_ONE);
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse();
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(
+                new String[]{PACKAGE_ONE, PACKAGE_TWO})).isFalse();
     }
 
     @Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
index 5e0fcef..8a54aee 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
@@ -37,8 +37,8 @@
     // App running duration in milliseconds
     private static final int DURATION = 10;
     private static final long ONE_MIN_AGO = NOW - TimeUnit.MINUTES.toMillis(1);
-    private static final long FOURTEEN_MIN_AGO = NOW - TimeUnit.MINUTES.toMillis(14);
-    private static final long TWENTY_MIN_AGO = NOW - TimeUnit.MINUTES.toMillis(20);
+    private static final long TWENTY_THREE_HOURS_AGO = NOW - TimeUnit.HOURS.toMillis(23);
+    private static final long TWO_DAYS_AGO = NOW - TimeUnit.DAYS.toMillis(2);
     private static final String[] TEST_PACKAGE_NAMES =
             {"package_1MinAgo", "package_14MinAgo", "package_20MinAgo"};
 
@@ -74,7 +74,7 @@
         when(mUserManager.getUserProfiles())
                 .thenReturn(Collections.singletonList(new UserHandle(mTestUserId)));
 
-        long[] testRequestTime = {ONE_MIN_AGO, FOURTEEN_MIN_AGO, TWENTY_MIN_AGO};
+        long[] testRequestTime = {ONE_MIN_AGO, TWENTY_THREE_HOURS_AGO, TWO_DAYS_AGO};
         List<PackageOps> appOps = createTestPackageOpsList(TEST_PACKAGE_NAMES, testRequestTime);
         when(mAppOpsManager.getPackagesForOps(RecentLocationApps.LOCATION_OPS)).thenReturn(appOps);
         mockTestApplicationInfos(mTestUserId, TEST_PACKAGE_NAMES);
@@ -91,7 +91,7 @@
         assertThat(requests.get(0).packageName).isEqualTo(TEST_PACKAGE_NAMES[0]);
         assertThat(requests.get(0).requestFinishTime).isEqualTo(ONE_MIN_AGO + DURATION);
         assertThat(requests.get(1).packageName).isEqualTo(TEST_PACKAGE_NAMES[1]);
-        assertThat(requests.get(1).requestFinishTime).isEqualTo(FOURTEEN_MIN_AGO + DURATION);
+        assertThat(requests.get(1).requestFinishTime).isEqualTo(TWENTY_THREE_HOURS_AGO + DURATION);
     }
 
     @Test
@@ -105,7 +105,7 @@
                         ONE_MIN_AGO,
                         DURATION);
         long[] testRequestTime =
-                {ONE_MIN_AGO, FOURTEEN_MIN_AGO, TWENTY_MIN_AGO, ONE_MIN_AGO};
+                {ONE_MIN_AGO, TWENTY_THREE_HOURS_AGO, TWO_DAYS_AGO, ONE_MIN_AGO};
         List<PackageOps> appOps = createTestPackageOpsList(TEST_PACKAGE_NAMES, testRequestTime);
         appOps.add(androidSystemPackageOps);
         when(mAppOpsManager.getPackagesForOps(RecentLocationApps.LOCATION_OPS)).thenReturn(appOps);
@@ -119,7 +119,7 @@
         assertThat(requests.get(0).packageName).isEqualTo(TEST_PACKAGE_NAMES[0]);
         assertThat(requests.get(0).requestFinishTime).isEqualTo(ONE_MIN_AGO + DURATION);
         assertThat(requests.get(1).packageName).isEqualTo(TEST_PACKAGE_NAMES[1]);
-        assertThat(requests.get(1).requestFinishTime).isEqualTo(FOURTEEN_MIN_AGO + DURATION);
+        assertThat(requests.get(1).requestFinishTime).isEqualTo(TWENTY_THREE_HOURS_AGO + DURATION);
     }
 
     private void mockTestApplicationInfos(int userId, String... packageNameList)
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/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index b5d48b4..e902c92 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -42,7 +42,7 @@
             android:singleLine="true"
             android:ellipsize="start"
             android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
-            android:imeOptions="actionSend|flagNoExtractUi|flagNoFullscreen" />
+            android:imeOptions="actionSend" />
 
     <FrameLayout
             android:layout_width="wrap_content"
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/layout/status_bar_mobile_signal_group.xml b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
index c8a5544..7931dfe 100644
--- a/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
@@ -21,62 +21,70 @@
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/mobile_combo"
     android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center_vertical"
-    android:paddingStart="2dp"
-    android:orientation="horizontal">
-    <FrameLayout
-        android:id="@+id/inout_container"
-        android:layout_height="17dp"
+    android:layout_height="match_parent"
+    android:gravity="center_vertical" >
+
+    <com.android.keyguard.AlphaOptimizedLinearLayout
+        android:id="@+id/mobile_group"
         android:layout_width="wrap_content"
-        android:layout_gravity="center_vertical">
-        <ImageView
-            android:id="@+id/mobile_in"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:src="@drawable/ic_activity_down"
-            android:visibility="gone"
-            android:paddingEnd="2dp"
-        />
-        <ImageView
-            android:id="@+id/mobile_out"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:src="@drawable/ic_activity_up"
-            android:paddingEnd="2dp"
-            android:visibility="gone"
-        />
-    </FrameLayout>
-    <ImageView
-        android:id="@+id/mobile_type"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_gravity="center_vertical"
-        android:paddingEnd="1dp"
-        android:visibility="gone" />
-    <Space
-        android:id="@+id/mobile_roaming_space"
         android:layout_height="match_parent"
-        android:layout_width="@dimen/roaming_icon_start_padding"
-        android:visibility="gone"
-    />
-    <FrameLayout
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical">
-        <com.android.systemui.statusbar.AnimatedImageView
-            android:id="@+id/mobile_signal"
-            android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        android:paddingStart="2dp"
+        android:orientation="horizontal" >
+
+        <FrameLayout
+            android:id="@+id/inout_container"
+            android:layout_height="17dp"
             android:layout_width="wrap_content"
-            systemui:hasOverlappingRendering="false"
-        />
+            android:layout_gravity="center_vertical">
+            <ImageView
+                android:id="@+id/mobile_in"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:src="@drawable/ic_activity_down"
+                android:visibility="gone"
+                android:paddingEnd="2dp"
+            />
+            <ImageView
+                android:id="@+id/mobile_out"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:src="@drawable/ic_activity_up"
+                android:paddingEnd="2dp"
+                android:visibility="gone"
+            />
+        </FrameLayout>
         <ImageView
-            android:id="@+id/mobile_roaming"
+            android:id="@+id/mobile_type"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:paddingEnd="1dp"
+            android:visibility="gone" />
+        <Space
+            android:id="@+id/mobile_roaming_space"
+            android:layout_height="match_parent"
+            android:layout_width="@dimen/roaming_icon_start_padding"
+            android:visibility="gone"
+        />
+        <FrameLayout
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:src="@drawable/stat_sys_roaming"
-            android:contentDescription="@string/data_connection_roaming"
-            android:visibility="gone" />
-    </FrameLayout>
+            android:layout_gravity="center_vertical">
+            <com.android.systemui.statusbar.AnimatedImageView
+                android:id="@+id/mobile_signal"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                systemui:hasOverlappingRendering="false"
+            />
+            <ImageView
+                android:id="@+id/mobile_roaming"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/stat_sys_roaming"
+                android:contentDescription="@string/data_connection_roaming"
+                android:visibility="gone" />
+        </FrameLayout>
+    </com.android.keyguard.AlphaOptimizedLinearLayout>
 </com.android.systemui.statusbar.StatusBarMobileView>
 
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/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
index 5a0dddc..cc536a5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -57,6 +57,7 @@
     public static final int HIT_TARGET_BACK = 1;
     public static final int HIT_TARGET_HOME = 2;
     public static final int HIT_TARGET_OVERVIEW = 3;
+    public static final int HIT_TARGET_ROTATION = 4;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({FLAG_DISABLE_SWIPE_UP,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
index 5b4d652..aa0bcc5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
@@ -241,6 +241,10 @@
         mViewMediatorCallback.resetKeyguard();
     }
 
+    public void resetSecurityContainer() {
+        mSecurityContainer.reset();
+    }
+
     @Override
     public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput) {
         if (mViewMediatorCallback != null) {
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/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index ea3f95e..4b65288 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -26,6 +26,7 @@
 import android.app.KeyguardManager;
 import android.app.WallpaperManager;
 import android.app.admin.DevicePolicyManager;
+import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -699,6 +700,9 @@
                                 UserHandle.USER_ALL);
                 try {
                     WindowManagerGlobal.getWindowManagerService().lockNow(null);
+                    // Lock profiles (if any) on the background thread.
+                    final Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER));
+                    bgHandler.post(() -> lockProfiles());
                 } catch (RemoteException e) {
                     Log.e(TAG, "Error while trying to lock device.", e);
                 }
@@ -716,6 +720,18 @@
         };
     }
 
+    private void lockProfiles() {
+        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        final TrustManager tm = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
+        final int currentUserId = getCurrentUser().id;
+        final int[] profileIds = um.getEnabledProfileIds(currentUserId);
+        for (final int id : profileIds) {
+            if (id != currentUserId) {
+                tm.setDeviceLockedForUser(id, true);
+            }
+        }
+    }
+
     private UserInfo getCurrentUser() {
         try {
             return ActivityManager.getService().getCurrentUser();
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/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index c8ee8735..6d677ab 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -180,16 +180,20 @@
         @Override
         public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
             super.onInitializeAccessibilityNodeInfo(host, info);
+            final DividerSnapAlgorithm snapAlgorithm = getSnapAlgorithm();
             if (isHorizontalDivision()) {
                 info.addAction(new AccessibilityAction(R.id.action_move_tl_full,
                         mContext.getString(R.string.accessibility_action_divider_top_full)));
-                if (mSnapAlgorithm.isFirstSplitTargetAvailable()) {
+                if (snapAlgorithm.isFirstSplitTargetAvailable()) {
                     info.addAction(new AccessibilityAction(R.id.action_move_tl_70,
                             mContext.getString(R.string.accessibility_action_divider_top_70)));
                 }
-                info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
+                if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) {
+                    // Only show the middle target if there are more than 1 split target
+                    info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
                         mContext.getString(R.string.accessibility_action_divider_top_50)));
-                if (mSnapAlgorithm.isLastSplitTargetAvailable()) {
+                }
+                if (snapAlgorithm.isLastSplitTargetAvailable()) {
                     info.addAction(new AccessibilityAction(R.id.action_move_tl_30,
                             mContext.getString(R.string.accessibility_action_divider_top_30)));
                 }
@@ -198,13 +202,16 @@
             } else {
                 info.addAction(new AccessibilityAction(R.id.action_move_tl_full,
                         mContext.getString(R.string.accessibility_action_divider_left_full)));
-                if (mSnapAlgorithm.isFirstSplitTargetAvailable()) {
+                if (snapAlgorithm.isFirstSplitTargetAvailable()) {
                     info.addAction(new AccessibilityAction(R.id.action_move_tl_70,
                             mContext.getString(R.string.accessibility_action_divider_left_70)));
                 }
-                info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
+                if (snapAlgorithm.showMiddleSplitTargetForAccessibility()) {
+                    // Only show the middle target if there are more than 1 split target
+                    info.addAction(new AccessibilityAction(R.id.action_move_tl_50,
                         mContext.getString(R.string.accessibility_action_divider_left_50)));
-                if (mSnapAlgorithm.isLastSplitTargetAvailable()) {
+                }
+                if (snapAlgorithm.isLastSplitTargetAvailable()) {
                     info.addAction(new AccessibilityAction(R.id.action_move_tl_30,
                             mContext.getString(R.string.accessibility_action_divider_left_30)));
                 }
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 8adf4bc..991b47e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -469,6 +469,7 @@
         updateNotificationColor();
         if (mMenuRow != null) {
             mMenuRow.onNotificationUpdated(mStatusBarNotification);
+            mMenuRow.setAppName(mAppName);
         }
         if (mIsSummaryWithChildren) {
             mChildrenContainer.recreateNotificationHeader(mExpandClickListener);
@@ -1089,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/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 19980a2..04c500f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.statusbar;
 
+import static com.android.systemui.statusbar.StatusBarIconView.STATE_DOT;
+import static com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN;
+import static com.android.systemui.statusbar.StatusBarIconView.STATE_ICON;
 import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
 import static com.android.systemui.statusbar.policy.DarkIconDispatcher.isInArea;
 
@@ -24,10 +27,14 @@
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import android.widget.LinearLayout;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.AlphaOptimizedLinearLayout;
 import com.android.settingslib.graph.SignalDrawable;
@@ -35,10 +42,14 @@
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
 import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
 
-public class StatusBarMobileView extends AlphaOptimizedLinearLayout implements DarkReceiver,
+public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
         StatusIconDisplayable {
     private static final String TAG = "StatusBarMobileView";
 
+    /// Used to show etc dots
+    private StatusBarIconView mDotView;
+    /// The main icon view
+    private LinearLayout mMobileGroup;
     private String mSlot;
     private MobileIconState mState;
     private SignalDrawable mMobileDrawable;
@@ -47,12 +58,17 @@
     private ImageView mOut;
     private ImageView mMobile, mMobileType, mMobileRoaming;
     private View mMobileRoamingSpace;
+    private int mVisibleState = -1;
 
-    public static StatusBarMobileView fromContext(Context context) {
+    public static StatusBarMobileView fromContext(Context context, String slot) {
         LayoutInflater inflater = LayoutInflater.from(context);
-
-        return (StatusBarMobileView)
+        StatusBarMobileView v = (StatusBarMobileView)
                 inflater.inflate(R.layout.status_bar_mobile_signal_group, null);
+
+        v.setSlot(slot);
+        v.init();
+        v.setVisibleState(STATE_ICON);
+        return v;
     }
 
     public StatusBarMobileView(Context context) {
@@ -72,14 +88,8 @@
         super(context, attrs, defStyleAttr, defStyleRes);
     }
 
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        init();
-    }
-
     private void init() {
+        mMobileGroup = findViewById(R.id.mobile_group);
         mMobile = findViewById(R.id.mobile_signal);
         mMobileType = findViewById(R.id.mobile_type);
         mMobileRoaming = findViewById(R.id.mobile_roaming);
@@ -90,6 +100,18 @@
 
         mMobileDrawable = new SignalDrawable(getContext());
         mMobile.setImageDrawable(mMobileDrawable);
+
+        initDotView();
+    }
+
+    private void initDotView() {
+        mDotView = new StatusBarIconView(mContext, mSlot, null);
+        mDotView.setVisibleState(STATE_DOT);
+
+        int width = mContext.getResources().getDimensionPixelSize(R.dimen.status_bar_icon_size);
+        LayoutParams lp = new LayoutParams(width, width);
+        lp.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
+        addView(mDotView, lp);
     }
 
     public void applyMobileState(MobileIconState state) {
@@ -113,9 +135,9 @@
     private void initViewState() {
         setContentDescription(mState.contentDescription);
         if (!mState.visible) {
-            setVisibility(View.GONE);
+            mMobileGroup.setVisibility(View.GONE);
         } else {
-            setVisibility(View.VISIBLE);
+            mMobileGroup.setVisibility(View.VISIBLE);
         }
         mMobileDrawable.setLevel(mState.strengthId);
         if (mState.typeId > 0) {
@@ -137,7 +159,7 @@
     private void updateState(MobileIconState state) {
         setContentDescription(state.contentDescription);
         if (mState.visible != state.visible) {
-            setVisibility(state.visible ? View.VISIBLE : View.GONE);
+            mMobileGroup.setVisibility(state.visible ? View.VISIBLE : View.GONE);
         }
         if (mState.strengthId != state.strengthId) {
             mMobileDrawable.setLevel(state.strengthId);
@@ -173,6 +195,8 @@
         mOut.setImageTintList(color);
         mMobileType.setImageTintList(color);
         mMobileRoaming.setImageTintList(color);
+        mDotView.setDecorColor(tint);
+        mDotView.setIconColor(tint, false);
     }
 
     @Override
@@ -194,11 +218,12 @@
         mOut.setImageTintList(list);
         mMobileType.setImageTintList(list);
         mMobileRoaming.setImageTintList(list);
+        mDotView.setDecorColor(color);
     }
 
     @Override
     public void setDecorColor(int color) {
-        //TODO: May also not be needed
+        mDotView.setDecorColor(color);
     }
 
     @Override
@@ -208,12 +233,30 @@
 
     @Override
     public void setVisibleState(int state) {
-        //TODO: May not be needed. Mobile is always expected to be visible (not a dot)
+        if (state == mVisibleState) {
+            return;
+        }
+
+        mVisibleState = state;
+        switch (state) {
+            case STATE_ICON:
+                mMobileGroup.setVisibility(View.VISIBLE);
+                mDotView.setVisibility(View.GONE);
+                break;
+            case STATE_DOT:
+                mMobileGroup.setVisibility(View.INVISIBLE);
+                mDotView.setVisibility(View.VISIBLE);
+                break;
+            case STATE_HIDDEN:
+            default:
+                setVisibility(View.INVISIBLE);
+                break;
+        }
     }
 
     @Override
     public int getVisibleState() {
-        return 0;
+        return mVisibleState;
     }
 
     @VisibleForTesting
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/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 46b4078..e0e991b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -237,9 +237,8 @@
 
     public void addMobileView(MobileIconState state) {
         Log.d(TAG, "addMobileView: ");
-        StatusBarMobileView view = StatusBarMobileView.fromContext(mContext);
+        StatusBarMobileView view = StatusBarMobileView.fromContext(mContext, state.slot);
 
-        view.setSlot(state.slot);
         view.applyMobileState(state);
         view.setStaticDrawableColor(mColor);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index f134151..48eb3e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -76,7 +76,7 @@
     protected KeyguardHostView mKeyguardView;
     private final Runnable mResetRunnable = ()-> {
         if (mKeyguardView != null) {
-            mKeyguardView.reset();
+            mKeyguardView.resetSecurityContainer();
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 533d5ec..98f9f1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -88,6 +88,7 @@
 import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_HIDE_BACK_BUTTON;
 import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
 import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_ROTATION;
 
 public class NavigationBarView extends FrameLayout implements PluginListener<NavGesture> {
     final static boolean DEBUG = false;
@@ -116,6 +117,7 @@
     private Rect mHomeButtonBounds = new Rect();
     private Rect mBackButtonBounds = new Rect();
     private Rect mRecentsButtonBounds = new Rect();
+    private Rect mRotationButtonBounds = new Rect();
     private int[] mTmpPosition = new int[2];
 
     private KeyButtonDrawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
@@ -341,6 +343,8 @@
                     mDownHitTarget = HIT_TARGET_HOME;
                 } else if (mRecentsButtonBounds.contains(x, y)) {
                     mDownHitTarget = HIT_TARGET_OVERVIEW;
+                } else if (mRotationButtonBounds.contains(x, y)) {
+                    mDownHitTarget = HIT_TARGET_ROTATION;
                 }
                 break;
         }
@@ -893,6 +897,7 @@
         updateButtonLocationOnScreen(getBackButton(), mBackButtonBounds);
         updateButtonLocationOnScreen(getHomeButton(), mHomeButtonBounds);
         updateButtonLocationOnScreen(getRecentsButton(), mRecentsButtonBounds);
+        updateButtonLocationOnScreen(getRotateSuggestionButton(), mRotationButtonBounds);
         mGestureHelper.onLayout(changed, left, top, right, bottom);
         mRecentsOnboarding.setNavBarHeight(getMeasuredHeight());
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 061677c..65cb56c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -249,7 +249,7 @@
 
 public class StatusBar extends SystemUI implements DemoMode,
         DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
-        OnHeadsUpChangedListener, CommandQueue.Callbacks,
+        OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
         ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter {
     public static final boolean MULTIUSER_DEBUG = false;
 
@@ -785,12 +785,7 @@
         // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
         mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
         mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
-        mZenController.addCallback(new ZenModeController.Callback() {
-            @Override
-            public void onZenChanged(int zen) {
-                updateEmptyShadeView();
-            }
-        });
+        mZenController.addCallback(this);
         mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow,
                 this,
                 mNotificationPanel,
@@ -3376,6 +3371,7 @@
         Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null);
         mDeviceProvisionedController.removeCallback(mUserSetupObserver);
         Dependency.get(ConfigurationController.class).removeCallback(this);
+        mZenController.removeCallback(this);
         mAppOpsListener.destroy();
     }
 
@@ -5536,6 +5532,11 @@
     }
 
     @Override
+    public void onZenChanged(int zen) {
+        updateEmptyShadeView();
+    }
+
+    @Override
     public void showAssistDisclosure() {
         if (mAssistManager != null) {
             mAssistManager.showDisclosure();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 1ba37a9..3b9ee8b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -296,8 +296,7 @@
         }
 
         private StatusBarMobileView onCreateStatusBarMobileView(String slot) {
-            StatusBarMobileView view = StatusBarMobileView.fromContext(mContext);
-            view.setSlot(slot);
+            StatusBarMobileView view = StatusBarMobileView.fromContext(mContext, slot);
             return view;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index 4538977..0811179 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -49,7 +49,7 @@
     private static final String TAG = "StatusIconContainer";
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_OVERFLOW = false;
-    // Max 5 status icons including battery
+    // Max 8 status icons including battery
     private static final int MAX_ICONS = 7;
     private static final int MAX_DOTS = 1;
 
@@ -152,7 +152,7 @@
 
         int visibleCount = mMeasureViews.size();
         int maxVisible = visibleCount <= MAX_ICONS ? MAX_ICONS : MAX_ICONS - 1;
-        int totalWidth = getPaddingStart() + getPaddingEnd();
+        int totalWidth = mPaddingLeft + mPaddingRight;
         boolean trackWidth = true;
 
         // Measure all children so that they report the correct width
@@ -208,8 +208,8 @@
      */
     private void calculateIconTranslations() {
         mLayoutStates.clear();
-        float width = getWidth() - getPaddingEnd();
-        float translationX = width;
+        float width = getWidth();
+        float translationX = width - getPaddingEnd();
         float contentStart = getPaddingStart();
         int childCount = getChildCount();
         // Underflow === don't show content until that index
@@ -344,10 +344,11 @@
                 animate = true;
             }
 
-            icon.setVisibleState(visibleState);
             if (animate) {
                 animateTo(view, animationProperties);
+                icon.setVisibleState(visibleState);
             } else {
+                icon.setVisibleState(visibleState);
                 super.applyToView(view);
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 59bf982..310f14c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -565,6 +565,11 @@
         @Override
         public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
             final InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
+            //if pinned, set imeOption to keep the behavior like in portrait.
+            if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isPinned()) {
+                outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI
+                        | EditorInfo.IME_FLAG_NO_FULLSCREEN;
+            }
 
             if (mShowImeOnInputConnection && inputConnection != null) {
                 final InputMethodManager imm = InputMethodManager.getInstance();
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/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 339c115..2031b27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -36,6 +36,7 @@
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenModeConfig.ZenRule;
 import android.util.Log;
+import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.qs.GlobalSetting;
@@ -112,6 +113,10 @@
 
     @Override
     public void addCallback(Callback callback) {
+        if (callback == null) {
+            Slog.e(TAG, "Attempted to add a null callback.");
+            return;
+        }
         mCallbacks.add(callback);
     }
 
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..bdeb8bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -314,12 +314,11 @@
 
     @Test
     public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception {
-        // Bind notification logs an event, so this counts as one invocation for the metrics logger.
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true,
                 true);
         mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
-        verify(mMetricsLogger, times(2)).count(anyString(), anyInt());
+        verify(mMetricsLogger, times(1)).count(anyString(), anyInt());
     }
 
     @Test
@@ -509,6 +508,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/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
index da8017e..ff65587 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
@@ -105,4 +105,10 @@
 
         assertTrue(mController.areNotificationsHiddenInShade());
     }
-}
\ No newline at end of file
+
+    @Test
+    public void testAddNullCallback() {
+        mController.addCallback(null);
+        mController.fireConfigChanged(null);
+    }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 1541231..7c05b2b 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5818,6 +5818,16 @@
     // Tag used to report whether an activity is being autofilled  on compatibility mode.
     FIELD_AUTOFILL_COMPAT_MODE = 1414;
 
+    // OPEN: Settings > Sound > Switch a2dp devices dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_SWITCH_A2DP_DEVICES = 1415;
+
+    // OPEN: Settings > Sound > Switch hfp devices dialog
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_SWITCH_HFP_DEVICES = 1416;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
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/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 51c0488..9b833f7 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -157,6 +157,9 @@
         }
     };
 
+    @GuardedBy("mLock")
+    private boolean mAllowInstantService;
+
     public AutofillManagerService(Context context) {
         super(context);
         mContext = context;
@@ -518,6 +521,23 @@
         sFullScreenMode = mode;
     }
 
+    // Called by Shell command.
+    boolean getAllowInstantService() {
+        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        synchronized (mLock) {
+            return mAllowInstantService;
+        }
+    }
+
+    // Called by Shell command.
+    void setAllowInstantService(boolean mode) {
+        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+        Slog.i(TAG, "setAllowInstantService(): " + mode);
+        synchronized (mLock) {
+            mAllowInstantService = mode;
+        }
+    }
+
     private void setDebugLocked(boolean debug) {
         com.android.server.autofill.Helper.sDebug = debug;
         android.view.autofill.Helper.sDebug = debug;
@@ -866,7 +886,8 @@
             synchronized (mLock) {
                 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
                 return service.startSessionLocked(activityToken, getCallingUid(), appCallback,
-                        autofillId, bounds, value, hasCallback, flags, componentName, compatMode);
+                        autofillId, bounds, value, hasCallback, componentName, compatMode,
+                        mAllowInstantService, flags);
             }
         }
 
@@ -1202,6 +1223,7 @@
                     mAutofillCompatState.dump(prefix2, pw);
                     pw.print(prefix2); pw.print("from settings: ");
                     pw.println(getWhitelistedCompatModePackagesFromSettings());
+                    pw.print("Allow instant service: "); pw.println(mAllowInstantService);
                 }
                 if (showHistory) {
                     pw.println(); pw.println("Requests history:"); pw.println();
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 6ff9539..d97253e 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;
@@ -341,7 +342,8 @@
     int startSessionLocked(@NonNull IBinder activityToken, int uid,
             @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId,
             @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
-            int flags, @NonNull ComponentName componentName, boolean compatMode) {
+            @NonNull ComponentName componentName, boolean compatMode,
+            boolean bindInstantServiceAllowed, int flags) {
         if (!isEnabledLocked()) {
             return 0;
         }
@@ -371,7 +373,7 @@
         pruneAbandonedSessionsLocked();
 
         final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
-                hasCallback, componentName, compatMode, flags);
+                hasCallback, componentName, compatMode, bindInstantServiceAllowed, flags);
         if (newSession == null) {
             return NO_SESSION;
         }
@@ -490,7 +492,8 @@
     @GuardedBy("mLock")
     private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
             @NonNull IBinder appCallbackToken, boolean hasCallback,
-            @NonNull ComponentName componentName, boolean compatMode, int flags) {
+            @NonNull ComponentName componentName, boolean compatMode,
+            boolean bindInstantServiceAllowed, int flags) {
         // use random ids so that one app cannot know that another app creates sessions
         int sessionId;
         int tries = 0;
@@ -509,7 +512,7 @@
         final Session newSession = new Session(this, mUi, mContext, mHandler, mUserId, mLock,
                 sessionId, uid, activityToken, appCallbackToken, hasCallback, mUiLatencyHistory,
                 mWtfHistory, mInfo.getServiceInfo().getComponentName(), componentName, compatMode,
-                flags);
+                bindInstantServiceAllowed, flags);
         mSessions.put(newSession.id, newSession);
 
         return newSession;
@@ -667,7 +670,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 +918,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/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index c76c8ac..f7b7ceb4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -86,6 +86,9 @@
             pw.println("  get fc_score [--algorithm ALGORITHM] value1 value2");
             pw.println("    Gets the field classification score for 2 fields.");
             pw.println("");
+            pw.println("  get bind-instant-service-allowed");
+            pw.println("    Gets whether binding to services provided by instant apps is allowed");
+            pw.println("");
             pw.println("  set log_level [off | debug | verbose]");
             pw.println("    Sets the Autofill log level.");
             pw.println("");
@@ -98,6 +101,9 @@
             pw.println("  set full_screen_mode [true | false | default]");
             pw.println("    Sets the Fill UI full screen mode");
             pw.println("");
+            pw.println("  set bind-instant-service-allowed [true | false]");
+            pw.println("    Sets whether binding to services provided by instant apps is allowed");
+            pw.println("");
             pw.println("  list sessions [--user USER_ID]");
             pw.println("    Lists all pending sessions.");
             pw.println("");
@@ -123,6 +129,8 @@
                 return getFieldClassificationScore(pw);
             case "full_screen_mode":
                 return getFullScreenMode(pw);
+            case "bind-instant-service-allowed":
+                return getBindInstantService(pw);
             default:
                 pw.println("Invalid set: " + what);
                 return -1;
@@ -141,6 +149,8 @@
                 return setMaxVisibileDatasets();
             case "full_screen_mode":
                 return setFullScreenMode(pw);
+            case "bind-instant-service-allowed":
+                return setBindInstantService(pw);
             default:
                 pw.println("Invalid set: " + what);
                 return -1;
@@ -259,6 +269,30 @@
         }
     }
 
+    private int getBindInstantService(PrintWriter pw) {
+        if (mService.getAllowInstantService()) {
+            pw.println("true");
+        } else {
+            pw.println("false");
+        }
+        return 0;
+    }
+
+    private int setBindInstantService(PrintWriter pw) {
+        final String mode = getNextArgRequired();
+        switch (mode.toLowerCase()) {
+            case "true":
+                mService.setAllowInstantService(true);
+                return 0;
+            case "false":
+                mService.setAllowInstantService(false);
+                return 0;
+            default:
+                pw.println("Invalid mode: " + mode);
+                return -1;
+        }
+    }
+
     private int requestDestroy(PrintWriter pw) {
         if (!isNextArgSessions(pw)) {
             return -1;
diff --git a/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java b/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java
index 9bec856..ba544f1 100644
--- a/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java
+++ b/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java
@@ -15,8 +15,6 @@
  */
 package com.android.server.autofill;
 
-import static android.view.autofill.AutofillManager.FC_SERVICE_TIMEOUT;
-
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sVerbose;
 import static android.service.autofill.AutofillFieldClassificationService.SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS;
@@ -52,8 +50,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
 /**
  * Strategy used to bridge the field classification algorithms provided by a service in an external
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 5372d0c..f781013 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -68,6 +68,9 @@
 
     /**
      * When non-null, overrides whether the UI should be shown on full-screen mode.
+     *
+     * <p>Note: access to this variable is not synchronized because it's "final" on real usage -
+     * it's only set by Shell cmd, for development purposes.
      */
     public static Boolean sFullScreenMode = null;
 
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index f7a4b73..4ded3fe 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -84,6 +84,8 @@
 
     private final Handler mHandler;
 
+    private final boolean mBindInstantServiceAllowed;
+
     private IAutoFillService mAutoFillService;
 
     private boolean mBinding;
@@ -109,13 +111,14 @@
     }
 
     public RemoteFillService(Context context, ComponentName componentName,
-            int userId, FillServiceCallbacks callbacks) {
+            int userId, FillServiceCallbacks callbacks, boolean bindInstantServiceAllowed) {
         mContext = context;
         mCallbacks = callbacks;
         mComponentName = componentName;
         mIntent = new Intent(AutofillService.SERVICE_INTERFACE).setComponent(mComponentName);
         mUserId = userId;
         mHandler = new Handler(FgThread.getHandler().getLooper());
+        mBindInstantServiceAllowed = bindInstantServiceAllowed;
     }
 
     public void destroy() {
@@ -207,6 +210,7 @@
                 .append(String.valueOf(isBound())).println();
         pw.append(prefix).append(tab).append("hasPendingRequest=")
                 .append(String.valueOf(mPendingRequest != null)).println();
+        pw.append(prefix).append("mBindInstantServiceAllowed=").println(mBindInstantServiceAllowed);
         pw.println();
     }
 
@@ -258,12 +262,17 @@
         if (sVerbose) Slog.v(LOG_TAG, "[user: " + mUserId + "] ensureBound()");
         mBinding = true;
 
-        boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection,
-                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+        int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
+        if (mBindInstantServiceAllowed) {
+            flags |= Context.BIND_ALLOW_INSTANT;
+        }
+
+        final boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags,
                 new UserHandle(mUserId));
 
         if (!willBind) {
-            if (sDebug) Slog.d(LOG_TAG, "[user: " + mUserId + "] could not bind to " + mIntent);
+            Slog.w(LOG_TAG, "[user: " + mUserId + "] could not bind to " + mIntent + " using flags "
+                    + flags);
             mBinding = false;
 
             if (!mServiceDied) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 88a679b..73c7172 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -517,7 +517,7 @@
             @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
             @NonNull LocalLog wtfHistory,
             @NonNull ComponentName serviceComponentName, @NonNull ComponentName componentName,
-            boolean compatMode, int flags) {
+            boolean compatMode, boolean bindInstantServiceAllowed, int flags) {
         id = sessionId;
         mFlags = flags;
         this.uid = uid;
@@ -526,7 +526,8 @@
         mLock = lock;
         mUi = ui;
         mHandler = handler;
-        mRemoteFillService = new RemoteFillService(context, serviceComponentName, userId, this);
+        mRemoteFillService = new RemoteFillService(context, serviceComponentName, userId, this,
+                bindInstantServiceAllowed);
         mActivityToken = activityToken;
         mHasCallback = hasCallback;
         mUiLatencyHistory = uiLatencyHistory;
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 2a76055..cff1a84 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -18,7 +18,6 @@
 
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static com.android.server.autofill.Helper.sDebug;
-import static com.android.server.autofill.Helper.sVerbose;
 
 import android.annotation.Nullable;
 import android.graphics.Rect;
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 5c5f0f8..0775abf 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -3023,20 +3023,26 @@
     }
 
     private boolean isBackgroundRestricted(Alarm alarm) {
-        final boolean allowWhileIdle = (alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0;
+        boolean exemptOnBatterySaver = (alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0;
         if (alarm.alarmClock != null) {
-            // Don't block alarm clocks
+            // Don't defer alarm clocks
             return false;
         }
-        if (alarm.operation != null
-                && (alarm.operation.isActivity() || alarm.operation.isForegroundService())) {
-            // Don't block starting foreground components
-            return false;
+        if (alarm.operation != null) {
+            if (alarm.operation.isActivity()) {
+                // Don't defer starting actual UI
+                return false;
+            }
+            if (alarm.operation.isForegroundService()) {
+                // FG service alarms are nearly as important; consult AST policy
+                exemptOnBatterySaver = true;
+            }
         }
         final String sourcePackage = alarm.sourcePackage;
         final int sourceUid = alarm.creatorUid;
         return (mAppStateTracker != null) &&
-                mAppStateTracker.areAlarmsRestricted(sourceUid, sourcePackage, allowWhileIdle);
+                mAppStateTracker.areAlarmsRestricted(sourceUid, sourcePackage,
+                        exemptOnBatterySaver);
     }
 
     private native long init();
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/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index 23c5779..9b001ce 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -1056,9 +1056,9 @@
      * @return whether alarms should be restricted for a UID package-name.
      */
     public boolean areAlarmsRestricted(int uid, @NonNull String packageName,
-            boolean allowWhileIdle) {
+            boolean isExemptOnBatterySaver) {
         return isRestricted(uid, packageName, /*useTempWhitelistToo=*/ false,
-                /* exemptOnBatterySaver =*/ allowWhileIdle);
+                isExemptOnBatterySaver);
     }
 
     /**
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/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 33ca02f..60f1877 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -107,7 +107,6 @@
 
     static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved
     static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer
-    static final String TUNNEL_INTERFACE_PREFIX = "ipsec";
 
     /* Binder context for this service */
     private final Context mContext;
@@ -1270,7 +1269,7 @@
         final int resourceId = mNextResourceId++;
         final int ikey = reserveNetId();
         final int okey = reserveNetId();
-        String intfName = String.format("%s%d", TUNNEL_INTERFACE_PREFIX, resourceId);
+        String intfName = String.format("%s%d", INetd.IPSEC_INTERFACE_PREFIX, resourceId);
 
         try {
             // Calls to netd:
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 58b40b1..48090f2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -466,6 +466,7 @@
 import com.android.server.job.JobSchedulerInternal;
 import com.android.server.pm.Installer;
 import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.dex.DexManager;
 import com.android.server.utils.PriorityDump;
 import com.android.server.vr.VrManagerInternal;
 import com.android.server.wm.PinnedStackWindowController;
@@ -4311,7 +4312,7 @@
             }
 
             if (app.info.isPrivilegedApp() &&
-                    SystemProperties.getBoolean("pm.dexopt.priv-apps-oob", false)) {
+                    DexManager.isPackageSelectedToRunOob(app.pkgList.keySet())) {
                 runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
             }
 
@@ -22994,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;
@@ -23018,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.
@@ -23062,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;
@@ -23074,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) {
@@ -23387,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
@@ -23488,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
@@ -23708,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
@@ -23936,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;
     }
 
     /**
@@ -24911,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) {
@@ -24970,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/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 03d8f39..d7057f4 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -166,7 +166,7 @@
     private SyncManager getSyncManager() {
         synchronized(mSyncManagerLock) {
             try {
-                // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
+                // Try to create the SyncManager, return null if it fails (which it shouldn't).
                 if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
             } catch (SQLiteException e) {
                 Log.e(TAG, "Can't create SyncManager", e);
@@ -199,7 +199,7 @@
         final long identityToken = clearCallingIdentity();
         try {
             if (mSyncManager == null) {
-                pw.println("No SyncManager created!  (Disk full?)");
+                pw.println("SyncManager not available yet");
             } else {
                 mSyncManager.dump(fd, pw, dumpAll);
             }
diff --git a/services/core/java/com/android/server/content/SyncJobService.java b/services/core/java/com/android/server/content/SyncJobService.java
index 9980930..089632d 100644
--- a/services/core/java/com/android/server/content/SyncJobService.java
+++ b/services/core/java/com/android/server/content/SyncJobService.java
@@ -115,7 +115,10 @@
             Slog.v(TAG, "onStopJob called " + params.getJobId() + ", reason: "
                     + params.getStopReason());
         }
-        mLogger.log("onStopJob() ", mLogger.jobParametersToString(params));
+        final boolean readyToSync = SyncManager.readyToSync();
+
+        mLogger.log("onStopJob() ", mLogger.jobParametersToString(params),
+                " readyToSync=", readyToSync);
         synchronized (mLock) {
             final int jobId = params.getJobId();
             mJobParamsMap.remove(jobId);
@@ -124,13 +127,15 @@
             final long nowUptime = SystemClock.uptimeMillis();
             final long runtime = nowUptime - startUptime;
 
+
             if (startUptime == 0) {
                 wtf("Job " + jobId + " start uptime not found: "
                         + " params=" + jobParametersToString(params));
             } else if (runtime > 60 * 1000) {
                 // WTF if startSyncH() hasn't happened, *unless* onStopJob() was called too soon.
                 // (1 minute threshold.)
-                if (!mStartedSyncs.get(jobId)) {
+                // Also don't wtf when it's not ready to sync.
+                if (readyToSync && !mStartedSyncs.get(jobId)) {
                     wtf("Job " + jobId + " didn't start: "
                             + " startUptime=" + startUptime
                             + " nowUptime=" + nowUptime
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 5fa4245..33cf11b 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -91,6 +91,7 @@
 import android.util.Slog;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
@@ -215,6 +216,10 @@
     private static final int SYNC_ADAPTER_CONNECTION_FLAGS = Context.BIND_AUTO_CREATE
             | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT;
 
+    /** Singleton instance. */
+    @GuardedBy("SyncManager.class")
+    private static SyncManager sInstance;
+
     private Context mContext;
 
     private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
@@ -571,6 +576,14 @@
     }
 
     public SyncManager(Context context, boolean factoryTest) {
+        synchronized (SyncManager.class) {
+            if (sInstance == null) {
+                sInstance = this;
+            } else {
+                Slog.wtf(TAG, "SyncManager instantiated multiple times");
+            }
+        }
+
         // Initialize the SyncStorageEngine first, before registering observers
         // and creating threads and so on; it may fail if the disk is full.
         mContext = context;
@@ -2851,6 +2864,16 @@
     }
 
     /**
+     * @return whether the device is ready to run sync jobs.
+     */
+    public static boolean readyToSync() {
+        synchronized (SyncManager.class) {
+            return sInstance != null && sInstance.mProvisioned && sInstance.mBootCompleted
+                    && sInstance.mJobServiceReady;
+        }
+    }
+
+    /**
      * Handles SyncOperation Messages that are posted to the associated
      * HandlerThread.
      */
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/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index ebab1a7..b0be4a9 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -34,6 +34,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.pm.Installer.InstallerException;
+import com.android.server.pm.dex.DexManager;
 import com.android.server.pm.dex.DexoptOptions;
 import com.android.server.pm.dex.DexoptUtils;
 import com.android.server.pm.dex.PackageDexUsage;
@@ -495,10 +496,9 @@
             boolean isUsedByOtherApps) {
         int flags = info.flags;
         boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
-        // When pm.dexopt.priv-apps-oob is true, we only verify privileged apps.
-        if (info.isPrivilegedApp() &&
-            SystemProperties.getBoolean("pm.dexopt.priv-apps-oob", false)) {
-          return "verify";
+        // When a priv app is configured to run out of box, only verify it.
+        if (info.isPrivilegedApp() && DexManager.isPackageSelectedToRunOob(info.packageName)) {
+            return "verify";
         }
         if (vmSafeMode) {
             return getSafeModeCompilerFilter(targetCompilerFilter);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 00d2f74..2650ef0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -578,8 +578,6 @@
 
     private static final String PRODUCT_OVERLAY_DIR = "/product/overlay";
 
-    private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob";
-
     /** Canonical intent used to identify what counts as a "web browser" app */
     private static final Intent sBrowserIntent;
     static {
@@ -2459,7 +2457,7 @@
                 "*dexopt*");
         DexManager.Listener dexManagerListener = DexLogger.getListener(this,
                 installer, mInstallLock);
-        mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock,
+        mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock,
                 dexManagerListener);
         mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
         mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
@@ -10428,11 +10426,7 @@
                 Log.d(TAG, "Scanning package " + pkg.packageName);
         }
 
-        if (Build.IS_DEBUGGABLE &&
-                pkg.isPrivileged() &&
-                SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false)) {
-            PackageManagerServiceUtils.logPackageHasUncompressedCode(pkg);
-        }
+        DexManager.maybeLogUnexpectedPackageDetails(pkg);
 
         // Initialize package source and resource directories
         final File scanFile = new File(pkg.codePath);
@@ -21038,23 +21032,6 @@
                         .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_SYSTEM);
         co.onChange(true);
 
-        // This observer provides an one directional mapping from Global.PRIV_APP_OOB_ENABLED to
-        // pm.dexopt.priv-apps-oob property. This is only for experiment and should be removed once
-        // it is done.
-        ContentObserver privAppOobObserver = new ContentObserver(mHandler) {
-            @Override
-            public void onChange(boolean selfChange) {
-                int oobEnabled = Global.getInt(resolver, Global.PRIV_APP_OOB_ENABLED, 0);
-                SystemProperties.set(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB,
-                        oobEnabled == 1 ? "true" : "false");
-            }
-        };
-        mContext.getContentResolver().registerContentObserver(
-                Global.getUriFor(Global.PRIV_APP_OOB_ENABLED), false, privAppOobObserver,
-                UserHandle.USER_SYSTEM);
-        // At boot, restore the value from the setting, which persists across reboot.
-        privAppOobObserver.onChange(true);
-
         // Disable any carrier apps. We do this very early in boot to prevent the apps from being
         // disabled after already being started.
         CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
@@ -21143,6 +21120,7 @@
         storage.registerListener(mStorageListener);
 
         mInstallerService.systemReady();
+        mDexManager.systemReady();
         mPackageDexOptimizer.systemReady();
 
         StorageManagerInternal StorageManagerInternal = LocalServices.getService(
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 4b907f4..1aea8f0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -26,7 +26,6 @@
 import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
 
 import com.android.internal.content.NativeLibraryHelper;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
 import com.android.server.EventLogTags;
 import com.android.server.pm.dex.DexManager;
@@ -56,7 +55,6 @@
 import android.util.Log;
 import android.util.PackageUtils;
 import android.util.Slog;
-import android.util.jar.StrictJarFile;
 import android.util.proto.ProtoOutputStream;
 
 import dalvik.system.VMRuntime;
@@ -85,12 +83,10 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.function.Predicate;
 import java.util.zip.GZIPInputStream;
-import java.util.zip.ZipEntry;
 
 /**
  * Class containing helper methods for the PackageManagerService.
@@ -317,61 +313,6 @@
         return maxModifiedTime;
     }
 
-    /**
-     * Checks that the archive located at {@code fileName} has uncompressed dex file and so
-     * files that can be direclty mapped.
-     */
-    public static void logApkHasUncompressedCode(String fileName) {
-        StrictJarFile jarFile = null;
-        try {
-            jarFile = new StrictJarFile(fileName,
-                    false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/);
-            Iterator<ZipEntry> it = jarFile.iterator();
-            while (it.hasNext()) {
-                ZipEntry entry = it.next();
-                if (entry.getName().endsWith(".dex")) {
-                    if (entry.getMethod() != ZipEntry.STORED) {
-                        Slog.w(TAG, "APK " + fileName + " has compressed dex code " +
-                                entry.getName());
-                    } else if ((entry.getDataOffset() & 0x3) != 0) {
-                        Slog.w(TAG, "APK " + fileName + " has unaligned dex code " +
-                                entry.getName());
-                    }
-                } else if (entry.getName().endsWith(".so")) {
-                    if (entry.getMethod() != ZipEntry.STORED) {
-                        Slog.w(TAG, "APK " + fileName + " has compressed native code " +
-                                entry.getName());
-                    } else if ((entry.getDataOffset() & (0x1000 - 1)) != 0) {
-                        Slog.w(TAG, "APK " + fileName + " has unaligned native code " +
-                                entry.getName());
-                    }
-                }
-            }
-        } catch (IOException ignore) {
-            Slog.wtf(TAG, "Error when parsing APK " + fileName);
-        } finally {
-            try {
-                if (jarFile != null) {
-                    jarFile.close();
-                }
-            } catch (IOException ignore) {}
-        }
-        return;
-    }
-
-    /**
-     * Checks that the APKs in the given package have uncompressed dex file and so
-     * files that can be direclty mapped.
-     */
-    public static void logPackageHasUncompressedCode(PackageParser.Package pkg) {
-        logApkHasUncompressedCode(pkg.baseCodePath);
-        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
-            for (int i = 0; i < pkg.splitCodePaths.length; i++) {
-                logApkHasUncompressedCode(pkg.splitCodePaths[i]);
-            }
-        }
-    }
-
     private static File getSettingsProblemFile() {
         File dataDir = Environment.getDataDirectory();
         File systemDir = new File(dataDir, "system");
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/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 1d5c580..0ba7822 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -34,6 +34,7 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -44,6 +45,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.os.RoSystemProperties;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
@@ -106,7 +108,7 @@
         LocalServices.addService(ArtManagerInternal.class, new ArtManagerInternalImpl());
     }
 
-    private boolean checkPermission(int callingUid, String callingPackage) {
+    private boolean checkAndroidPermissions(int callingUid, String callingPackage) {
         // Callers always need this permission
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.READ_RUNTIME_PROFILES, TAG);
@@ -125,11 +127,51 @@
         }
     }
 
+    /**
+     * Checks if the calling user is the shell user and if it is, it checks if it can
+     * to take a profile snapshot of the give package:
+     *   - on debuggable builds the shell user can take profile snapshots of any app.
+     *   - on non-debuggable builds the shell user can only take snapshots of debuggable apps.
+     *
+     * Returns true iff the callingUid is the shell uid and the shell is allowed snapshot profiles.
+     *
+     * Note that the root users will go through the regular {@link #checkAndroidPermissions) checks.
+     */
+    private boolean checkShellPermissions(@ProfileType int profileType, String packageName,
+            int callingUid) {
+        if (callingUid != Process.SHELL_UID) {
+            return false;
+        }
+        if (RoSystemProperties.DEBUGGABLE) {
+            return true;
+        }
+        if (profileType == ArtManager.PROFILE_BOOT_IMAGE) {
+            // The shell cannot profile the boot image on non-debuggable builds.
+            return false;
+        }
+        PackageInfo info = null;
+        try {
+            info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0);
+        } catch (RemoteException ignored) {
+            // Should not happen.
+        }
+        if (info == null) {
+            return false;
+        }
+
+        // On user builds the shell can only profile debuggable apps.
+        return (info.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE)
+                == ApplicationInfo.FLAG_DEBUGGABLE;
+    }
+
+
     @Override
     public void snapshotRuntimeProfile(@ProfileType int profileType, @Nullable String packageName,
             @Nullable String codePath, @NonNull ISnapshotRuntimeProfileCallback callback,
             String callingPackage) {
-        if (!checkPermission(Binder.getCallingUid(), callingPackage)) {
+        int callingUid = Binder.getCallingUid();
+        if (!checkShellPermissions(profileType, packageName, callingUid) &&
+                !checkAndroidPermissions(callingUid, callingPackage)) {
             try {
                 callback.onError(ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR);
             } catch (RemoteException ignored) {
@@ -266,7 +308,8 @@
 
     @Override
     public boolean isRuntimeProfilingEnabled(@ProfileType int profileType, String callingPackage) {
-        if (!checkPermission(Binder.getCallingUid(), callingPackage)) {
+        int callingUid = Binder.getCallingUid();
+        if (callingUid != Process.SHELL_UID && !checkAndroidPermissions(callingUid, callingPackage)) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 3e63fb4..392d4d8 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -16,17 +16,25 @@
 
 package com.android.server.pm.dex;
 
+import android.content.ContentResolver;
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageParser;
+import android.database.ContentObserver;
+import android.os.Build;
 import android.os.FileUtils;
 import android.os.RemoteException;
 import android.os.storage.StorageManager;
+import android.os.SystemProperties;
 import android.os.UserHandle;
-
+import android.provider.Settings.Global;
 import android.util.Slog;
+import android.util.jar.StrictJarFile;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.pm.Installer;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.PackageDexOptimizer;
@@ -36,13 +44,16 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.zip.ZipEntry;
 
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
@@ -59,8 +70,14 @@
 public class DexManager {
     private static final String TAG = "DexManager";
 
+    private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob";
+    private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST =
+            "pm.dexopt.priv-apps-oob-list";
+
     private static final boolean DEBUG = false;
 
+    private final Context mContext;
+
     // Maps package name to code locations.
     // It caches the code locations for the installed packages. This allows for
     // faster lookups (no locks) when finding what package owns the dex file.
@@ -106,8 +123,9 @@
                 String dexPath, int storageFlags);
     }
 
-    public DexManager(IPackageManager pms, PackageDexOptimizer pdo,
+    public DexManager(Context context, IPackageManager pms, PackageDexOptimizer pdo,
             Installer installer, Object installLock, Listener listener) {
+      mContext = context;
       mPackageCodeLocationsCache = new HashMap<>();
       mPackageDexUsage = new PackageDexUsage();
       mPackageManager = pms;
@@ -117,6 +135,10 @@
       mListener = listener;
     }
 
+    public void systemReady() {
+        registerSettingObserver();
+    }
+
     /**
      * Notify about dex files loads.
      * Note that this method is invoked when apps load dex files and it should
@@ -641,6 +663,141 @@
         mPackageDexUsage.writeNow();
     }
 
+    private void registerSettingObserver() {
+        final ContentResolver resolver = mContext.getContentResolver();
+
+        // This observer provides a one directional mapping from Global.PRIV_APP_OOB_ENABLED to
+        // pm.dexopt.priv-apps-oob property. This is only for experiment and should be removed once
+        // it is done.
+        ContentObserver privAppOobObserver = new ContentObserver(null) {
+            @Override
+            public void onChange(boolean selfChange) {
+                int oobEnabled = Global.getInt(resolver, Global.PRIV_APP_OOB_ENABLED, 0);
+                SystemProperties.set(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB,
+                        oobEnabled == 1 ? "true" : "false");
+            }
+        };
+        resolver.registerContentObserver(
+                Global.getUriFor(Global.PRIV_APP_OOB_ENABLED), false, privAppOobObserver,
+                UserHandle.USER_SYSTEM);
+        // At boot, restore the value from the setting, which persists across reboot.
+        privAppOobObserver.onChange(true);
+
+        ContentObserver privAppOobListObserver = new ContentObserver(null) {
+            @Override
+            public void onChange(boolean selfChange) {
+                String oobList = Global.getString(resolver, Global.PRIV_APP_OOB_LIST);
+                if (oobList == null) {
+                    oobList = "ALL";
+                }
+                SystemProperties.set(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST, oobList);
+            }
+        };
+        resolver.registerContentObserver(
+                Global.getUriFor(Global.PRIV_APP_OOB_LIST), false, privAppOobListObserver,
+                UserHandle.USER_SYSTEM);
+        // At boot, restore the value from the setting, which persists across reboot.
+        privAppOobListObserver.onChange(true);
+    }
+
+    /**
+     * Returns whether the given package is in the list of privilaged apps that should run out of
+     * box. This only makes sense if PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB is true. Note that when
+     * the the OOB list is empty, all priv apps will run in OOB mode.
+     */
+    public static boolean isPackageSelectedToRunOob(String packageName) {
+        return isPackageSelectedToRunOob(Arrays.asList(packageName));
+    }
+
+    /**
+     * Returns whether any of the given packages are in the list of privilaged apps that should run
+     * out of box. This only makes sense if PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB is true. Note that
+     * when the the OOB list is empty, all priv apps will run in OOB mode.
+     */
+    public static boolean isPackageSelectedToRunOob(Collection<String> packageNamesInSameProcess) {
+        if (!SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false)) {
+            return false;
+        }
+        String oobListProperty = SystemProperties.get(
+                PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST, "ALL");
+        if ("ALL".equals(oobListProperty)) {
+            return true;
+        }
+        for (String oobPkgName : oobListProperty.split(",")) {
+            if (packageNamesInSameProcess.contains(oobPkgName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Generates package related log if the package has code stored in unexpected way.
+     */
+    public static void maybeLogUnexpectedPackageDetails(PackageParser.Package pkg) {
+        if (!Build.IS_DEBUGGABLE) {
+            return;
+        }
+
+        if (pkg.isPrivileged() && isPackageSelectedToRunOob(pkg.packageName)) {
+            logIfPackageHasUncompressedCode(pkg);
+        }
+    }
+
+    /**
+     * Generates log if the APKs in the given package have uncompressed dex file and so
+     * files that can be direclty mapped.
+     */
+    private static void logIfPackageHasUncompressedCode(PackageParser.Package pkg) {
+        logIfApkHasUncompressedCode(pkg.baseCodePath);
+        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+            for (int i = 0; i < pkg.splitCodePaths.length; i++) {
+                logIfApkHasUncompressedCode(pkg.splitCodePaths[i]);
+            }
+        }
+    }
+
+    /**
+     * Generates log if the archive located at {@code fileName} has uncompressed dex file and so
+     * files that can be direclty mapped.
+     */
+    private static void logIfApkHasUncompressedCode(String fileName) {
+        StrictJarFile jarFile = null;
+        try {
+            jarFile = new StrictJarFile(fileName,
+                    false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/);
+            Iterator<ZipEntry> it = jarFile.iterator();
+            while (it.hasNext()) {
+                ZipEntry entry = it.next();
+                if (entry.getName().endsWith(".dex")) {
+                    if (entry.getMethod() != ZipEntry.STORED) {
+                        Slog.w(TAG, "APK " + fileName + " has compressed dex code " +
+                                entry.getName());
+                    } else if ((entry.getDataOffset() & 0x3) != 0) {
+                        Slog.w(TAG, "APK " + fileName + " has unaligned dex code " +
+                                entry.getName());
+                    }
+                } else if (entry.getName().endsWith(".so")) {
+                    if (entry.getMethod() != ZipEntry.STORED) {
+                        Slog.w(TAG, "APK " + fileName + " has compressed native code " +
+                                entry.getName());
+                    } else if ((entry.getDataOffset() & (0x1000 - 1)) != 0) {
+                        Slog.w(TAG, "APK " + fileName + " has unaligned native code " +
+                                entry.getName());
+                    }
+                }
+            }
+        } catch (IOException ignore) {
+            Slog.wtf(TAG, "Error when parsing APK " + fileName);
+        } finally {
+            try {
+                if (jarFile != null) {
+                    jarFile.close();
+                }
+            } catch (IOException ignore) {}
+        }
+    }
+
     public static class RegisterDexModuleResult {
         public RegisterDexModuleResult() {
             this(false, null);
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/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 553b4fe..9da6917 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -426,9 +426,13 @@
             removeAnimation(taskAdapter);
         }
 
+        // Clear any pending failsafe runnables
+        mService.mH.removeCallbacks(mFailsafeRunnable);
+
         // Clear references to the runner
         unlinkToDeathOfRunner();
         mRunner = null;
+        mCanceled = true;
 
         // Clear associated input consumers
         mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ab93a8a..729dba5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5525,9 +5525,11 @@
         // If there is a profile owner, redirect to that; otherwise query the device owner.
         ComponentName aliasChooser = getProfileOwner(caller.getIdentifier());
         if (aliasChooser == null && caller.isSystem()) {
-            ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
-            if (deviceOwnerAdmin != null) {
-                aliasChooser = deviceOwnerAdmin.info.getComponent();
+            synchronized (getLockObject()) {
+                final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
+                if (deviceOwnerAdmin != null) {
+                    aliasChooser = deviceOwnerAdmin.info.getComponent();
+                }
             }
         }
         if (aliasChooser == null) {
@@ -5906,35 +5908,41 @@
 
     private void forceWipeDeviceNoLock(boolean wipeExtRequested, String reason, boolean wipeEuicc) {
         wtfIfInLock();
-
-        if (wipeExtRequested) {
-            StorageManager sm = (StorageManager) mContext.getSystemService(
-                    Context.STORAGE_SERVICE);
-            sm.wipeAdoptableDisks();
-        }
+        boolean success = false;
         try {
+            if (wipeExtRequested) {
+                StorageManager sm = (StorageManager) mContext.getSystemService(
+                    Context.STORAGE_SERVICE);
+                sm.wipeAdoptableDisks();
+            }
             mInjector.recoverySystemRebootWipeUserData(
-                    /*shutdown=*/ false, reason, /*force=*/ true, /*wipeEuicc=*/ wipeEuicc);
+                /*shutdown=*/ false, reason, /*force=*/ true, /*wipeEuicc=*/ wipeEuicc);
+            success = true;
         } catch (IOException | SecurityException e) {
             Slog.w(LOG_TAG, "Failed requesting data wipe", e);
+        } finally {
+            if (!success) SecurityLog.writeEvent(SecurityLog.TAG_WIPE_FAILURE);
         }
     }
 
     private void forceWipeUser(int userId, String wipeReasonForUser) {
+        boolean success = false;
         try {
             IActivityManager am = mInjector.getIActivityManager();
             if (am.getCurrentUser().id == userId) {
                 am.switchUser(UserHandle.USER_SYSTEM);
             }
 
-            boolean userRemoved = mUserManagerInternal.removeUserEvenWhenDisallowed(userId);
-            if (!userRemoved) {
+            success = mUserManagerInternal.removeUserEvenWhenDisallowed(userId);
+            if (!success) {
                 Slog.w(LOG_TAG, "Couldn't remove user " + userId);
             } else if (isManagedProfile(userId)) {
                 sendWipeProfileNotification(wipeReasonForUser);
             }
         } catch (RemoteException re) {
             // Shouldn't happen
+        } finally {
+            if (!success) SecurityLog.writeEvent(SecurityLog.TAG_WIPE_FAILURE);
         }
     }
 
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/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 36d0c8b..147347d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -111,7 +111,8 @@
                 DELEGATE_LAST_CLASS_LOADER_NAME);
 
         mDexManager = new DexManager(
-            mPM, /*PackageDexOptimizer*/ null, mInstaller, mInstallLock, mListener);
+            /*Context*/ null, mPM, /*PackageDexOptimizer*/ null, mInstaller, mInstallLock,
+            mListener);
 
         // Foo and Bar are available to user0.
         // Only Bar is available to user1;
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/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index fbf6691..a2af9b8 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -19,6 +19,9 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
+import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.verify;
@@ -82,6 +85,25 @@
         verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
     }
 
+    @Test
+    public void testCancelAfterRemove_expectIgnored() throws Exception {
+        final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        AnimationAdapter adapter = mController.addAnimation(appWindow.getTask(),
+                false /* isRecentTaskInvisible */);
+        adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+
+        // Remove the app window so that the animation target can not be created
+        appWindow.removeImmediately();
+        mController.startAnimation();
+        mController.cleanupAnimation(REORDER_KEEP_IN_PLACE);
+        try {
+            mController.cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "test");
+        } catch (Exception e) {
+            fail("Unexpected failure when canceling animation after finishing it");
+        }
+    }
+
     private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
         verify(binder, atLeast(0)).asBinder();
         verifyNoMoreInteractions(binder);
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) {
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 026b54f..280afade 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -109,23 +109,3 @@
     ],
     static_libs: ["libstatssocket"],
 }
-
-cc_library_static {
-    name: "libstatssocket",
-    srcs: [
-        "stats_event_list.c",
-        "statsd_writer.c",
-    ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-DLIBLOG_LOG_TAG=1006",
-        "-DWRITE_TO_STATSD=1",
-        "-DWRITE_TO_LOGD=0",
-    ],
-    export_include_dirs: ["include"],
-    shared_libs: [
-        "liblog",
-    ],
-}
-
diff --git a/tools/stats_log_api_gen/include/stats_event_list.h b/tools/stats_log_api_gen/include/stats_event_list.h
deleted file mode 100644
index c198d97..0000000
--- a/tools/stats_log_api_gen/include/stats_event_list.h
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_STATS_LOG_STATS_EVENT_LIST_H
-#define ANDROID_STATS_LOG_STATS_EVENT_LIST_H
-
-#include <log/log_event_list.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-void reset_log_context(android_log_context ctx);
-int write_to_logger(android_log_context context, log_id_t id);
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef __cplusplus
-/**
- * A copy of android_log_event_list class.
- *
- * android_log_event_list is going to be deprecated soon, so copy it here to
- * avoid creating dependency on upstream code. TODO(b/78304629): Rewrite this
- * code.
- */
-class stats_event_list {
-private:
-    android_log_context ctx;
-    int ret;
-
-    stats_event_list(const stats_event_list&) = delete;
-    void operator=(const stats_event_list&) = delete;
-
-public:
-    explicit stats_event_list(int tag) : ret(0) {
-        ctx = create_android_logger(static_cast<uint32_t>(tag));
-    }
-    explicit stats_event_list(log_msg& log_msg) : ret(0) {
-        ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
-                                        log_msg.entry.len - sizeof(uint32_t));
-    }
-    ~stats_event_list() { android_log_destroy(&ctx); }
-
-    int close() {
-        int retval = android_log_destroy(&ctx);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return retval;
-    }
-
-    /* To allow above C calls to use this class as parameter */
-    operator android_log_context() const { return ctx; }
-
-    /* return errors or transmit status */
-    int status() const { return ret; }
-
-    int begin() {
-        int retval = android_log_write_list_begin(ctx);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret;
-    }
-    int end() {
-        int retval = android_log_write_list_end(ctx);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret;
-    }
-
-    stats_event_list& operator<<(int32_t value) {
-        int retval = android_log_write_int32(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    stats_event_list& operator<<(uint32_t value) {
-        int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    stats_event_list& operator<<(bool value) {
-        int retval = android_log_write_int32(ctx, value ? 1 : 0);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    stats_event_list& operator<<(int64_t value) {
-        int retval = android_log_write_int64(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    stats_event_list& operator<<(uint64_t value) {
-        int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    stats_event_list& operator<<(const char* value) {
-        int retval = android_log_write_string8(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-#if defined(_USING_LIBCXX)
-    stats_event_list& operator<<(const std::string& value) {
-        int retval = android_log_write_string8_len(ctx, value.data(),
-                                                   value.length());
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-#endif
-
-    stats_event_list& operator<<(float value) {
-        int retval = android_log_write_float32(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    int write(log_id_t id = LOG_ID_EVENTS) {
-        /* facilitate -EBUSY retry */
-        if ((ret == -EBUSY) || (ret > 0)) {
-            ret = 0;
-        }
-        int retval = write_to_logger(ctx, id);
-        /* existing errors trump transmission errors */
-        if (!ret) {
-            ret = retval;
-        }
-        return ret;
-    }
-
-    /*
-     * Append<Type> methods removes any integer promotion
-     * confusion, and adds access to string with length.
-     * Append methods are also added for all types for
-     * convenience.
-     */
-
-    bool AppendInt(int32_t value) {
-        int retval = android_log_write_int32(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret >= 0;
-    }
-
-    bool AppendLong(int64_t value) {
-        int retval = android_log_write_int64(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret >= 0;
-    }
-
-    bool AppendString(const char* value) {
-        int retval = android_log_write_string8(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret >= 0;
-    }
-
-    bool AppendString(const char* value, size_t len) {
-        int retval = android_log_write_string8_len(ctx, value, len);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret >= 0;
-    }
-
-#if defined(_USING_LIBCXX)
-    bool AppendString(const std::string& value) {
-        int retval = android_log_write_string8_len(ctx, value.data(),
-                                                   value.length());
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret;
-    }
-
-    bool Append(const std::string& value) {
-        int retval = android_log_write_string8_len(ctx, value.data(),
-                                                   value.length());
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret;
-    }
-#endif
-
-    bool AppendFloat(float value) {
-        int retval = android_log_write_float32(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret >= 0;
-    }
-
-    template <typename Tvalue>
-    bool Append(Tvalue value) {
-        *this << value;
-        return ret >= 0;
-    }
-
-    bool Append(const char* value, size_t len) {
-        int retval = android_log_write_string8_len(ctx, value, len);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret >= 0;
-    }
-
-    android_log_list_element read() { return android_log_read_next(ctx); }
-    android_log_list_element peek() { return android_log_peek_next(ctx); }
-};
-
-#endif
-#endif  // ANDROID_STATS_LOG_STATS_EVENT_LIST_H
diff --git a/tools/stats_log_api_gen/stats_event_list.c b/tools/stats_log_api_gen/stats_event_list.c
deleted file mode 100644
index 0a342a8..0000000
--- a/tools/stats_log_api_gen/stats_event_list.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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.
- */
-
-#include "include/stats_event_list.h"
-
-#include <string.h>
-#include "statsd_writer.h"
-
-#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
-
-typedef struct {
-    uint32_t tag;
-    unsigned pos; /* Read/write position into buffer */
-    unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements   */
-    unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1];  /* pos for list counter */
-    unsigned list_nest_depth;
-    unsigned len; /* Length or raw buffer. */
-    bool overflow;
-    bool list_stop; /* next call decrement list_nest_depth and issue a stop */
-    enum {
-        kAndroidLoggerRead = 1,
-        kAndroidLoggerWrite = 2,
-    } read_write_flag;
-    uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
-} android_log_context_internal;
-
-extern struct android_log_transport_write statsdLoggerWrite;
-
-static int __write_to_statsd_init(struct iovec* vec, size_t nr);
-static int (*write_to_statsd)(struct iovec* vec,
-                              size_t nr) = __write_to_statsd_init;
-
-// Similar to create_android_logger(), but instead of allocation a new buffer,
-// this function resets the buffer for resuse.
-void reset_log_context(android_log_context ctx) {
-    if (!ctx) {
-        return;
-    }
-    android_log_context_internal* context =
-            (android_log_context_internal*)(ctx);
-    uint32_t tag = context->tag;
-    memset(context, 0, sizeof(android_log_context_internal));
-
-    context->tag = tag;
-    context->read_write_flag = kAndroidLoggerWrite;
-    size_t needed = sizeof(uint8_t) + sizeof(uint8_t);
-    if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
-        context->overflow = true;
-    }
-    /* Everything is a list */
-    context->storage[context->pos + 0] = EVENT_TYPE_LIST;
-    context->list[0] = context->pos + 1;
-    context->pos += needed;
-}
-
-int stats_write_list(android_log_context ctx) {
-    android_log_context_internal* context;
-    const char* msg;
-    ssize_t len;
-
-    context = (android_log_context_internal*)(ctx);
-    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
-        return -EBADF;
-    }
-
-    if (context->list_nest_depth) {
-        return -EIO;
-    }
-
-    /* NB: if there was overflow, then log is truncated. Nothing reported */
-    context->storage[1] = context->count[0];
-    len = context->len = context->pos;
-    msg = (const char*)context->storage;
-    /* it's not a list */
-    if (context->count[0] <= 1) {
-        len -= sizeof(uint8_t) + sizeof(uint8_t);
-        if (len < 0) {
-            len = 0;
-        }
-        msg += sizeof(uint8_t) + sizeof(uint8_t);
-    }
-
-    struct iovec vec[2];
-    vec[0].iov_base = &context->tag;
-    vec[0].iov_len = sizeof(context->tag);
-    vec[1].iov_base = (void*)msg;
-    vec[1].iov_len = len;
-    return write_to_statsd(vec, 2);
-}
-
-int write_to_logger(android_log_context ctx, log_id_t id) {
-    int retValue = 0;
-
-    if (WRITE_TO_LOGD) {
-        retValue = android_log_write_list(ctx, id);
-    }
-
-    if (WRITE_TO_STATSD) {
-        // log_event_list's cast operator is overloaded.
-        int ret = stats_write_list(ctx);
-        // In debugging phase, we may write to both logd and statsd. Prefer to
-        // return statsd socket write error code here.
-        if (ret < 0) {
-            retValue = ret;
-        }
-    }
-
-    return retValue;
-}
-
-/* log_init_lock assumed */
-static int __write_to_statsd_initialize_locked() {
-    if (!statsdLoggerWrite.open || ((*statsdLoggerWrite.open)() < 0)) {
-        if (statsdLoggerWrite.close) {
-            (*statsdLoggerWrite.close)();
-            return -ENODEV;
-        }
-    }
-    return 1;
-}
-
-static int __write_to_stats_daemon(struct iovec* vec, size_t nr) {
-    int ret, save_errno;
-    struct timespec ts;
-    size_t len, i;
-
-    for (len = i = 0; i < nr; ++i) {
-        len += vec[i].iov_len;
-    }
-    if (!len) {
-        return -EINVAL;
-    }
-
-    save_errno = errno;
-    clock_gettime(CLOCK_REALTIME, &ts);
-
-    ret = 0;
-
-    ssize_t retval;
-    retval = (*statsdLoggerWrite.write)(&ts, vec, nr);
-    if (ret >= 0) {
-        ret = retval;
-    }
-
-    errno = save_errno;
-    return ret;
-}
-
-static int __write_to_statsd_init(struct iovec* vec, size_t nr) {
-    int ret, save_errno = errno;
-
-    statsd_writer_init_lock();
-
-    if (write_to_statsd == __write_to_statsd_init) {
-        ret = __write_to_statsd_initialize_locked();
-        if (ret < 0) {
-            statsd_writer_init_unlock();
-            errno = save_errno;
-            return ret;
-        }
-
-        write_to_statsd = __write_to_stats_daemon;
-    }
-
-    statsd_writer_init_unlock();
-
-    ret = write_to_statsd(vec, nr);
-    errno = save_errno;
-    return ret;
-}
\ No newline at end of file
diff --git a/tools/stats_log_api_gen/statsd_writer.c b/tools/stats_log_api_gen/statsd_writer.c
deleted file mode 100644
index 3e10358..0000000
--- a/tools/stats_log_api_gen/statsd_writer.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * 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.
- */
-#include "statsd_writer.h"
-
-#include <cutils/sockets.h>
-#include <endian.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-#include <stdarg.h>
-#include <stdatomic.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <time.h>
-#include <unistd.h>
-
-/* branchless on many architectures. */
-#define min(x, y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
-
-static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
-
-void statsd_writer_init_lock() {
-    /*
-     * If we trigger a signal handler in the middle of locked activity and the
-     * signal handler logs a message, we could get into a deadlock state.
-     */
-    pthread_mutex_lock(&log_init_lock);
-}
-
-int statd_writer_trylock() {
-    return pthread_mutex_trylock(&log_init_lock);
-}
-
-void statsd_writer_init_unlock() {
-    pthread_mutex_unlock(&log_init_lock);
-}
-
-static int statsdAvailable();
-static int statsdOpen();
-static void statsdClose();
-static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr);
-
-struct android_log_transport_write statsdLoggerWrite = {
-        .name = "statsd",
-        .sock = -EBADF,
-        .available = statsdAvailable,
-        .open = statsdOpen,
-        .close = statsdClose,
-        .write = statsdWrite,
-};
-
-/* log_init_lock assumed */
-static int statsdOpen() {
-    int i, ret = 0;
-
-    i = atomic_load(&statsdLoggerWrite.sock);
-    if (i < 0) {
-        int sock = TEMP_FAILURE_RETRY(
-                socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
-        if (sock < 0) {
-            ret = -errno;
-        } else {
-            struct sockaddr_un un;
-            memset(&un, 0, sizeof(struct sockaddr_un));
-            un.sun_family = AF_UNIX;
-            strcpy(un.sun_path, "/dev/socket/statsdw");
-
-            if (TEMP_FAILURE_RETRY(connect(sock, (struct sockaddr*)&un,
-                                           sizeof(struct sockaddr_un))) < 0) {
-                ret = -errno;
-                switch (ret) {
-                    case -ENOTCONN:
-                    case -ECONNREFUSED:
-                    case -ENOENT:
-                        i = atomic_exchange(&statsdLoggerWrite.sock, ret);
-                    /* FALLTHRU */
-                    default:
-                        break;
-                }
-                close(sock);
-            } else {
-                ret = atomic_exchange(&statsdLoggerWrite.sock, sock);
-                if ((ret >= 0) && (ret != sock)) {
-                    close(ret);
-                }
-                ret = 0;
-            }
-        }
-    }
-
-    return ret;
-}
-
-static void __statsdClose(int negative_errno) {
-    int sock = atomic_exchange(&statsdLoggerWrite.sock, negative_errno);
-    if (sock >= 0) {
-        close(sock);
-    }
-}
-
-static void statsdClose() {
-    __statsdClose(-EBADF);
-}
-
-static int statsdAvailable() {
-    if (atomic_load(&statsdLoggerWrite.sock) < 0) {
-        if (access("/dev/socket/statsdw", W_OK) == 0) {
-            return 0;
-        }
-        return -EBADF;
-    }
-    return 1;
-}
-
-static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) {
-    ssize_t ret;
-    int sock;
-    static const unsigned headerLength = 1;
-    struct iovec newVec[nr + headerLength];
-    android_log_header_t header;
-    size_t i, payloadSize;
-    static atomic_int dropped;
-
-    sock = atomic_load(&statsdLoggerWrite.sock);
-    if (sock < 0)
-        switch (sock) {
-            case -ENOTCONN:
-            case -ECONNREFUSED:
-            case -ENOENT:
-                break;
-            default:
-                return -EBADF;
-        }
-    /*
-     *  struct {
-     *      // what we provide to socket
-     *      android_log_header_t header;
-     *      // caller provides
-     *      union {
-     *          struct {
-     *              char     prio;
-     *              char     payload[];
-     *          } string;
-     *          struct {
-     *              uint32_t tag
-     *              char     payload[];
-     *          } binary;
-     *      };
-     *  };
-     */
-
-    header.tid = gettid();
-    header.realtime.tv_sec = ts->tv_sec;
-    header.realtime.tv_nsec = ts->tv_nsec;
-
-    newVec[0].iov_base = (unsigned char*)&header;
-    newVec[0].iov_len = sizeof(header);
-
-    // If we dropped events before, try to tell statsd.
-    if (sock >= 0) {
-        int32_t snapshot =
-                atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
-        if (snapshot) {
-            android_log_event_int_t buffer;
-            header.id = LOG_ID_STATS;
-            buffer.header.tag = htole32(LIBLOG_LOG_TAG);
-            buffer.payload.type = EVENT_TYPE_INT;
-            buffer.payload.data = htole32(snapshot);
-
-            newVec[headerLength].iov_base = &buffer;
-            newVec[headerLength].iov_len = sizeof(buffer);
-
-            ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
-            if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
-                atomic_fetch_add_explicit(&dropped, snapshot,
-                                          memory_order_relaxed);
-            }
-        }
-    }
-
-    header.id = LOG_ID_STATS;
-
-    for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
-        newVec[i].iov_base = vec[i - headerLength].iov_base;
-        payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
-
-        if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
-            newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
-            if (newVec[i].iov_len) {
-                ++i;
-            }
-            break;
-        }
-    }
-
-    /*
-     * The write below could be lost, but will never block.
-     *
-     * ENOTCONN occurs if statsd has died.
-     * ENOENT occurs if statsd is not running and socket is missing.
-     * ECONNREFUSED occurs if we can not reconnect to statsd.
-     * EAGAIN occurs if statsd is overloaded.
-     */
-    if (sock < 0) {
-        ret = sock;
-    } else {
-        ret = TEMP_FAILURE_RETRY(writev(sock, newVec, i));
-        if (ret < 0) {
-            ret = -errno;
-        }
-    }
-    switch (ret) {
-        case -ENOTCONN:
-        case -ECONNREFUSED:
-        case -ENOENT:
-            if (statd_writer_trylock()) {
-                return ret; /* in a signal handler? try again when less stressed
-                             */
-            }
-            __statsdClose(ret);
-            ret = statsdOpen();
-            statsd_writer_init_unlock();
-
-            if (ret < 0) {
-                return ret;
-            }
-
-            ret = TEMP_FAILURE_RETRY(
-                    writev(atomic_load(&statsdLoggerWrite.sock), newVec, i));
-            if (ret < 0) {
-                ret = -errno;
-            }
-        /* FALLTHRU */
-        default:
-            break;
-    }
-
-    if (ret > (ssize_t)sizeof(header)) {
-        ret -= sizeof(header);
-    } else if (ret == -EAGAIN) {
-        atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
-    }
-
-    return ret;
-}
diff --git a/tools/stats_log_api_gen/statsd_writer.h b/tools/stats_log_api_gen/statsd_writer.h
deleted file mode 100644
index 1043afb..0000000
--- a/tools/stats_log_api_gen/statsd_writer.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef ANDROID_STATS_LOG_STATS_WRITER_H
-#define ANDROID_STATS_LOG_STATS_WRITER_H
-
-#include <pthread.h>
-#include <stdatomic.h>
-#include <sys/socket.h>
-
-/**
- * Internal lock should not be exposed. This is bad design.
- * TODO: rewrite it in c++ code and encapsulate the functionality in a
- * StatsdWriter class.
- */
-void statsd_writer_init_lock();
-int statsd_writer_init_trylock();
-void statsd_writer_init_unlock();
-
-struct android_log_transport_write {
-    const char* name; /* human name to describe the transport */
-    atomic_int sock;
-    int (*available)(); /* Does not cause resources to be taken */
-    int (*open)(); /* can be called multiple times, reusing current resources */
-    void (*close)(); /* free up resources */
-    /* write log to transport, returns number of bytes propagated, or -errno */
-    int (*write)(struct timespec* ts, struct iovec* vec, size_t nr);
-};
-
-
-#endif  // ANDROID_STATS_LOG_STATS_WRITER_H