Merge "Match current colors for device default car theme"
diff --git a/api/current.txt b/api/current.txt
index eda30a7..4f39e25 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4433,11 +4433,12 @@
   }
 
   public final class AutomaticZenRule implements android.os.Parcelable {
-    ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
-    ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, android.service.notification.ZenPolicy, boolean);
+    ctor public deprecated AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
+    ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.content.ComponentName, android.net.Uri, android.service.notification.ZenPolicy, int, boolean);
     ctor public AutomaticZenRule(android.os.Parcel);
     method public int describeContents();
     method public android.net.Uri getConditionId();
+    method public android.content.ComponentName getConfigurationActivity();
     method public long getCreationTime();
     method public int getInterruptionFilter();
     method public java.lang.String getName();
@@ -4445,6 +4446,7 @@
     method public android.service.notification.ZenPolicy getZenPolicy();
     method public boolean isEnabled();
     method public void setConditionId(android.net.Uri);
+    method public void setConfigurationActivity(android.content.ComponentName);
     method public void setEnabled(boolean);
     method public void setInterruptionFilter(int);
     method public void setName(java.lang.String);
@@ -5773,16 +5775,19 @@
     method public void notifyAsPackage(java.lang.String, java.lang.String, int, android.app.Notification);
     method public boolean removeAutomaticZenRule(java.lang.String);
     method public void revokeNotificationDelegate();
+    method public void setAutomaticZenRuleState(java.lang.String, android.service.notification.Condition);
     method public final void setInterruptionFilter(int);
     method public void setNotificationDelegate(java.lang.String);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
     method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
     field public static final java.lang.String ACTION_APP_BLOCK_STATE_CHANGED = "android.app.action.APP_BLOCK_STATE_CHANGED";
+    field public static final java.lang.String ACTION_AUTOMATIC_ZEN_RULE = "android.app.action.AUTOMATIC_ZEN_RULE";
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED = "android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
+    field public static final java.lang.String EXTRA_AUTOMATIC_RULE_ID = "android.app.extra.AUTOMATIC_RULE_ID";
     field public static final java.lang.String EXTRA_BLOCKED_STATE = "android.app.extra.BLOCKED_STATE";
     field public static final java.lang.String EXTRA_NOTIFICATION_CHANNEL_GROUP_ID = "android.app.extra.NOTIFICATION_CHANNEL_GROUP_ID";
     field public static final java.lang.String EXTRA_NOTIFICATION_CHANNEL_ID = "android.app.extra.NOTIFICATION_CHANNEL_ID";
@@ -5798,6 +5803,8 @@
     field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
     field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
+    field public static final java.lang.String META_DATA_AUTOMATIC_RULE_TYPE = "android.app.automatic.ruleType";
+    field public static final java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.app.zen.automatic.ruleInstanceLimit";
   }
 
   public static class NotificationManager.Policy implements android.os.Parcelable {
@@ -41009,10 +41016,10 @@
     field public final java.lang.String summary;
   }
 
-  public abstract class ConditionProviderService extends android.app.Service {
+  public abstract deprecated class ConditionProviderService extends android.app.Service {
     ctor public ConditionProviderService();
-    method public final void notifyCondition(android.service.notification.Condition);
-    method public final void notifyConditions(android.service.notification.Condition...);
+    method public final deprecated void notifyCondition(android.service.notification.Condition);
+    method public final deprecated void notifyConditions(android.service.notification.Condition...);
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract void onConnected();
     method public void onRequestConditions(int);
@@ -41020,10 +41027,10 @@
     method public abstract void onUnsubscribe(android.net.Uri);
     method public static final void requestRebind(android.content.ComponentName);
     method public final void requestUnbind();
-    field public static final java.lang.String EXTRA_RULE_ID = "android.service.notification.extra.RULE_ID";
-    field public static final java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
-    field public static final java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
-    field public static final java.lang.String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
+    field public static final deprecated java.lang.String EXTRA_RULE_ID = "android.service.notification.extra.RULE_ID";
+    field public static final deprecated java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
+    field public static final deprecated java.lang.String META_DATA_RULE_INSTANCE_LIMIT = "android.service.zen.automatic.ruleInstanceLimit";
+    field public static final deprecated java.lang.String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
 
@@ -43351,9 +43358,12 @@
 
   public static final class VideoProfile.CameraCapabilities implements android.os.Parcelable {
     ctor public VideoProfile.CameraCapabilities(int, int);
+    ctor public VideoProfile.CameraCapabilities(int, int, boolean, float);
     method public int describeContents();
     method public int getHeight();
+    method public float getMaxZoom();
     method public int getWidth();
+    method public boolean isZoomSupported();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telecom.VideoProfile.CameraCapabilities> CREATOR;
   }
@@ -46931,7 +46941,7 @@
     ctor public deprecated Scene(android.view.ViewGroup, android.view.ViewGroup);
     method public void enter();
     method public void exit();
-    method public static android.transition.Scene getCurrentScene(android.view.View);
+    method public static android.transition.Scene getCurrentScene(android.view.ViewGroup);
     method public static android.transition.Scene getSceneForLayout(android.view.ViewGroup, int, android.content.Context);
     method public android.view.ViewGroup getSceneRoot();
     method public void setEnterAction(java.lang.Runnable);
diff --git a/api/system-current.txt b/api/system-current.txt
index fc139a7..a83c32d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -853,6 +853,7 @@
     method public void addRoleHolderAsUser(java.lang.String, java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
     method public boolean addRoleHolderFromController(java.lang.String, java.lang.String);
     method public void clearRoleHoldersAsUser(java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
+    method public java.util.List<java.lang.String> getHeldRolesFromController(java.lang.String);
     method public java.util.List<java.lang.String> getRoleHolders(java.lang.String);
     method public java.util.List<java.lang.String> getRoleHoldersAsUser(java.lang.String, android.os.UserHandle);
     method public void removeOnRoleHoldersChangedListenerAsUser(android.app.role.OnRoleHoldersChangedListener, android.os.UserHandle);
diff --git a/api/test-current.txt b/api/test-current.txt
index 627ef22..d534501 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1197,7 +1197,7 @@
     field public static final java.lang.String KEY_USER_SENTIMENT = "key_user_sentiment";
   }
 
-  public abstract class ConditionProviderService extends android.app.Service {
+  public abstract deprecated class ConditionProviderService extends android.app.Service {
     method public boolean isBound();
   }
 
diff --git a/cmds/bu/src/com/android/commands/bu/Backup.java b/cmds/bu/src/com/android/commands/bu/Backup.java
index 834658d..373677e 100644
--- a/cmds/bu/src/com/android/commands/bu/Backup.java
+++ b/cmds/bu/src/com/android/commands/bu/Backup.java
@@ -16,13 +16,17 @@
 
 package com.android.commands.bu;
 
+import android.annotation.UserIdInt;
 import android.app.backup.IBackupManager;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.system.OsConstants;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.IOException;
 import java.util.ArrayList;
 
@@ -33,35 +37,50 @@
     int mNextArg;
     IBackupManager mBackupManager;
 
+    @VisibleForTesting
+    Backup(IBackupManager backupManager) {
+        mBackupManager = backupManager;
+    }
+
+    Backup() {
+        mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService("backup"));
+    }
+
     public static void main(String[] args) {
-        Log.d(TAG, "Beginning: " + args[0]);
-        mArgs = args;
         try {
-            new Backup().run();
+            new Backup().run(args);
         } catch (Exception e) {
             Log.e(TAG, "Error running backup/restore", e);
         }
         Log.d(TAG, "Finished.");
     }
 
-    public void run() {
-        mBackupManager = IBackupManager.Stub.asInterface(ServiceManager.getService("backup"));
+    public void run(String[] args) {
         if (mBackupManager == null) {
             Log.e(TAG, "Can't obtain Backup Manager binder");
             return;
         }
 
+        Log.d(TAG, "Beginning: " + args[0]);
+        mArgs = args;
+
+        int userId = parseUserId();
+        if (!isBackupActiveForUser(userId)) {
+            Log.e(TAG, "BackupManager is not available for user " + userId);
+            return;
+        }
+
         String arg = nextArg();
         if (arg.equals("backup")) {
-            doBackup(OsConstants.STDOUT_FILENO);
+            doBackup(OsConstants.STDOUT_FILENO, userId);
         } else if (arg.equals("restore")) {
-            doRestore(OsConstants.STDIN_FILENO);
+            doRestore(OsConstants.STDIN_FILENO, userId);
         } else {
             showUsage();
         }
     }
 
-    private void doBackup(int socketFd) {
+    private void doBackup(int socketFd, @UserIdInt int userId) {
         ArrayList<String> packages = new ArrayList<String>();
         boolean saveApks = false;
         boolean saveObbs = false;
@@ -105,6 +124,10 @@
                     doKeyValue = true;
                 } else if ("-nokeyvalue".equals(arg)) {
                     doKeyValue = false;
+                } else if ("-user".equals(arg)) {
+                    // User ID has been processed in run(), ignore the next argument.
+                    nextArg();
+                    continue;
                 } else {
                     Log.w(TAG, "Unknown backup flag " + arg);
                     continue;
@@ -128,7 +151,7 @@
         try {
             fd = ParcelFileDescriptor.adoptFd(socketFd);
             String[] packArray = new String[packages.size()];
-            mBackupManager.adbBackup(fd, saveApks, saveObbs, saveShared, doWidgets, doEverything,
+            mBackupManager.adbBackup(userId, fd, saveApks, saveObbs, saveShared, doWidgets, doEverything,
                     allIncludesSystem, doCompress, doKeyValue, packages.toArray(packArray));
         } catch (RemoteException e) {
             Log.e(TAG, "Unable to invoke backup manager for backup");
@@ -143,12 +166,12 @@
         }
     }
 
-    private void doRestore(int socketFd) {
+    private void doRestore(int socketFd, @UserIdInt int userId) {
         // No arguments to restore
         ParcelFileDescriptor fd = null;
         try {
             fd = ParcelFileDescriptor.adoptFd(socketFd);
-            mBackupManager.adbRestore(fd);
+            mBackupManager.adbRestore(userId, fd);
         } catch (RemoteException e) {
             Log.e(TAG, "Unable to invoke backup manager for restore");
         } finally {
@@ -160,11 +183,31 @@
         }
     }
 
+    private @UserIdInt int parseUserId() {
+        for (int argNumber = 0; argNumber < mArgs.length - 1; argNumber++) {
+            if ("-user".equals(mArgs[argNumber])) {
+                return UserHandle.parseUserArg(mArgs[argNumber + 1]);
+            }
+        }
+
+        return UserHandle.USER_SYSTEM;
+    }
+
+    private boolean isBackupActiveForUser(int userId) {
+        try {
+            return mBackupManager.isBackupServiceActive(userId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not access BackupManager: " + e.toString());
+            return false;
+        }
+    }
+
     private static void showUsage() {
-        System.err.println(" backup [-f FILE] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all]");
-        System.err.println("        [-system|-nosystem] [-keyvalue|-nokeyvalue] [PACKAGE...]");
+        System.err.println(" backup [-user USER_ID] [-f FILE] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared]");
+        System.err.println("        [-all] [-system|-nosystem] [-keyvalue|-nokeyvalue] [PACKAGE...]");
         System.err.println("     write an archive of the device's data to FILE [default=backup.adb]");
         System.err.println("     package list optional if -all/-shared are supplied");
+        System.err.println("     -user: user ID for which to perform the operation (default - system user)");
         System.err.println("     -apk/-noapk: do/don't back up .apk files (default -noapk)");
         System.err.println("     -obb/-noobb: do/don't back up .obb files (default -noobb)");
         System.err.println("     -shared|-noshared: do/don't back up shared storage (default -noshared)");
@@ -172,7 +215,8 @@
         System.err.println("     -system|-nosystem: include system apps in -all (default -system)");
         System.err.println("     -keyvalue|-nokeyvalue: include apps that perform key/value backups.");
         System.err.println("         (default -nokeyvalue)");
-        System.err.println(" restore FILE             restore device contents from FILE");
+        System.err.println(" restore [-user USER_ID] FILE       restore device contents from FILE");
+        System.err.println("     -user: user ID for which to perform the operation (default - system user)");
     }
 
     private String nextArg() {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 2d0e8bc..5899e0cf 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -169,6 +169,8 @@
         DocsUIRootVisitedReported docs_ui_root_visited = 110;
         DocsUIStartupMsReported docs_ui_startup_ms = 111;
         DocsUIUserActionReported docs_ui_user_action_reported = 112;
+        WifiEnabledStateChanged wifi_enabled_state_changed = 113;
+        WifiRunningStateChanged wifi_running_state_changed = 114;
     }
 
     // Pulled events will start at field 10000.
@@ -871,6 +873,39 @@
 }
 
 /**
+ * Logs when Wifi is toggled on/off.
+ * Note that Wifi may still perform certain functions (e.g. location scanning) even when disabled.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message WifiEnabledStateChanged {
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 1;
+}
+
+/**
+ * Logs when an app causes Wifi to run. In this context, 'to run' means to use Wifi Client Mode.
+ * TODO: Include support for Hotspot, perhaps by using an extra field to denote 'mode'.
+ * Note that Wifi Scanning is monitored separately in WifiScanStateChanged.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message WifiRunningStateChanged {
+    repeated AttributionNode attribution_node = 1;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 2;
+}
+
+/**
  * Logs wifi locks held by an app.
  *
  * Logged from:
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 16b7e79..5fea90b 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -106,14 +106,14 @@
         // Add to set.
         mConfigs[key.GetUid()].insert(key);
 
-        for (sp<ConfigListener> listener : mListeners) {
+        for (const sp<ConfigListener>& listener : mListeners) {
             broadcastList.push_back(listener);
         }
     }
 
     const int64_t timestampNs = getElapsedRealtimeNs();
     // Tell everyone
-    for (sp<ConfigListener> listener : broadcastList) {
+    for (const sp<ConfigListener>& listener : broadcastList) {
         listener->OnConfigUpdated(timestampNs, key, config);
     }
 }
@@ -137,7 +137,7 @@
         if (uidIt != mConfigs.end() && uidIt->second.find(key) != uidIt->second.end()) {
             // Remove from map
             uidIt->second.erase(key);
-            for (sp<ConfigListener> listener : mListeners) {
+            for (const sp<ConfigListener>& listener : mListeners) {
                 broadcastList.push_back(listener);
             }
         }
@@ -153,7 +153,7 @@
         remove_saved_configs(key);
     }
 
-    for (sp<ConfigListener> listener:broadcastList) {
+    for (const sp<ConfigListener>& listener:broadcastList) {
         listener->OnConfigRemoved(key);
     }
 }
@@ -183,7 +183,7 @@
 
         mConfigs.erase(uidIt);
 
-        for (sp<ConfigListener> listener : mListeners) {
+        for (const sp<ConfigListener>& listener : mListeners) {
             broadcastList.push_back(listener);
         }
     }
@@ -191,7 +191,7 @@
     // Remove separately so if they do anything in the callback they can't mess up our iteration.
     for (auto& key : removed) {
         // Tell everyone
-        for (sp<ConfigListener> listener:broadcastList) {
+        for (const sp<ConfigListener>& listener:broadcastList) {
             listener->OnConfigRemoved(key);
         }
     }
@@ -213,7 +213,7 @@
         }
 
         mConfigReceivers.clear();
-        for (sp<ConfigListener> listener : mListeners) {
+        for (const sp<ConfigListener>& listener : mListeners) {
             broadcastList.push_back(listener);
         }
     }
@@ -221,7 +221,7 @@
     // Remove separately so if they do anything in the callback they can't mess up our iteration.
     for (auto& key : removed) {
         // Tell everyone
-        for (sp<ConfigListener> listener:broadcastList) {
+        for (const sp<ConfigListener>& listener:broadcastList) {
             listener->OnConfigRemoved(key);
         }
     }
diff --git a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
index c8c3920..d822959 100644
--- a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
+++ b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
@@ -281,7 +281,7 @@
                              (long long)state.residencyInMsecSinceBoot,
                              (long long)state.totalTransitions,
                              state.supportedOnlyInSuspend ? 1 : 0);
-                        for (auto voter : state.voters) {
+                        for (const auto& voter : state.voters) {
                             auto voterPtr = make_shared<LogEvent>(
                                 android::util::SUBSYSTEM_SLEEP_STATE,
                                 wallClockTimestampNs, elapsedTimestampNs);
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index ac34f47..dd969c0 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -412,7 +412,7 @@
 // Returns the total byte size of all metrics managed by a single config source.
 size_t MetricsManager::byteSize() {
     size_t totalSize = 0;
-    for (auto metricProducer : mAllMetricProducers) {
+    for (const auto& metricProducer : mAllMetricProducers) {
         totalSize += metricProducer->byteSize();
     }
     return totalSize;
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index b317361..180a1ae 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -598,7 +598,7 @@
         }
         noReportMetricIds.insert(no_report_metric);
     }
-    for (auto it : allMetricProducers) {
+    for (const auto& it : allMetricProducers) {
         uidMap.addListener(it);
     }
     return true;
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 59f3f04..e9c43cd 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -152,7 +152,7 @@
     // listener removes itself before we call it. It's then the listener's job to handle it (expect
     // the callback to be called after listener is removed, and the listener should properly
     // ignore it).
-    for (auto weakPtr : broadcastList) {
+    for (const auto& weakPtr : broadcastList) {
         auto strongPtr = weakPtr.promote();
         if (strongPtr != NULL) {
             strongPtr->onUidMapReceived(timestamp);
@@ -200,7 +200,7 @@
         StatsdStats::getInstance().setUidMapChanges(mChanges.size());
     }
 
-    for (auto weakPtr : broadcastList) {
+    for (const auto& weakPtr : broadcastList) {
         auto strongPtr = weakPtr.promote();
         if (strongPtr != NULL) {
             strongPtr->notifyAppUpgrade(timestamp, appName, uid, versionCode);
@@ -269,7 +269,7 @@
         getListenerListCopyLocked(&broadcastList);
     }
 
-    for (auto weakPtr : broadcastList) {
+    for (const auto& weakPtr : broadcastList) {
         auto strongPtr = weakPtr.promote();
         if (strongPtr != NULL) {
             strongPtr->notifyAppRemoved(timestamp, app, uid);
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index 79bed52..960fbda 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -71,12 +71,12 @@
                          const std::shared_ptr<DimToValMap>& currentBucket,
                          const std::set<const MetricDimensionKey>& trueList,
                          const std::set<const MetricDimensionKey>& falseList) {
-    for (MetricDimensionKey key : trueList) {
+    for (const MetricDimensionKey& key : trueList) {
         if (!tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) {
             return false;
         }
     }
-    for (MetricDimensionKey key : falseList) {
+    for (const MetricDimensionKey& key : falseList) {
         if (tracker.detectAnomaly(bucketNum, key, getBucketValue(currentBucket, key))) {
             return false;
         }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 2b81c86..17529a6 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -794,12 +794,25 @@
 
     @Override
     public List<ModuleInfo> getInstalledModules(int flags) {
-        return null;
+        try {
+            return mPM.getInstalledModules(flags);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     @Override
     public ModuleInfo getModuleInfo(String packageName, int flags) throws NameNotFoundException {
-        return null;
+        try {
+            ModuleInfo mi = mPM.getModuleInfo(packageName, flags);
+            if (mi != null) {
+                return mi;
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        throw new NameNotFoundException("No module info for package: " + packageName);
     }
 
     @SuppressWarnings("unchecked")
@@ -3002,7 +3015,6 @@
         }
     }
 
-    @Override
     public void sendDeviceCustomizationReadyBroadcast() {
         try {
             mPM.sendDeviceCustomizationReadyBroadcast();
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index e2f2075..fe23e21 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -20,10 +20,14 @@
 
 import android.app.NotificationManager.InterruptionFilter;
 import android.content.ComponentName;
+import android.content.Intent;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.service.notification.ZenPolicy;
+import android.service.notification.Condition;
+
+import com.android.internal.util.Preconditions;
 
 import java.util.Objects;
 
@@ -40,6 +44,7 @@
     private @InterruptionFilter int interruptionFilter;
     private Uri conditionId;
     private ComponentName owner;
+    private ComponentName configurationActivity;
     private long creationTime;
     private ZenPolicy mZenPolicy;
     private boolean mModified = false;
@@ -49,39 +54,51 @@
      *
      * @param name The name of the rule.
      * @param owner The Condition Provider service that owns this rule.
-     * @param conditionId A representation of the state that should cause the Condition Provider
-     *                    service to apply the given interruption filter.
      * @param interruptionFilter The interruption filter defines which notifications are allowed to
      *                           interrupt the user (e.g. via sound &amp; vibration) while this rule
      *                           is active.
      * @param enabled Whether the rule is enabled.
+     * @deprecated use {@link #AutomaticZenRule(String, ComponentName, ComponentName, Uri,
+     * ZenPolicy, int, boolean)}.
      */
+    @Deprecated
     public AutomaticZenRule(String name, ComponentName owner, Uri conditionId,
             int interruptionFilter, boolean enabled) {
-        this.name = name;
-        this.owner = owner;
-        this.conditionId = conditionId;
-        this.interruptionFilter = interruptionFilter;
-        this.enabled = enabled;
+        this(name, owner, null, conditionId, null, interruptionFilter, enabled);
     }
 
     /**
      * Creates an automatic zen rule.
      *
      * @param name The name of the rule.
-     * @param owner The Condition Provider service that owns this rule.
-     * @param conditionId A representation of the state that should cause the Condition Provider
-     *                    service to apply the given interruption filter.
+     * @param owner The Condition Provider service that owns this rule. This can be null if you're
+     *              using {@link NotificationManager#setAutomaticZenRuleState(String, Condition)}
+     *              instead of {@link android.service.notification.ConditionProviderService}.
+     * @param configurationActivity An activity that handles
+     *                              {@link NotificationManager#ACTION_AUTOMATIC_ZEN_RULE} that shows
+     *                              the user
+     *                              more information about this rule and/or allows them to
+     *                              configure it. This is required if you are not using a
+     *                              {@link android.service.notification.ConditionProviderService}.
+     *                              If you are, it overrides the information specified in your
+     *                              manifest.
+     * @param conditionId A representation of the state that should cause your app to apply the
+     *                    given interruption filter.
+     * @param interruptionFilter The interruption filter defines which notifications are allowed to
+     *                           interrupt the user (e.g. via sound &amp; vibration) while this rule
+     *                           is active.
      * @param policy The policy defines which notifications are allowed to interrupt the user
-     *               while this rule is active
+     *               while this rule is active. This overrides the global policy while this rule is
+     *               action ({@link Condition#STATE_TRUE}).
      * @param enabled Whether the rule is enabled.
      */
-    public AutomaticZenRule(String name, ComponentName owner, Uri conditionId, ZenPolicy policy,
-            boolean enabled) {
+    public AutomaticZenRule(String name, ComponentName owner, ComponentName configurationActivity,
+            Uri conditionId, ZenPolicy policy, int interruptionFilter, boolean enabled) {
         this.name = name;
         this.owner = owner;
+        this.configurationActivity = configurationActivity;
         this.conditionId = conditionId;
-        this.interruptionFilter = INTERRUPTION_FILTER_PRIORITY;
+        this.interruptionFilter = interruptionFilter;
         this.enabled = enabled;
         this.mZenPolicy = policy;
     }
@@ -89,18 +106,10 @@
     /**
      * @hide
      */
-    public AutomaticZenRule(String name, ComponentName owner, Uri conditionId,
-            int interruptionFilter, boolean enabled, long creationTime) {
-        this(name, owner, conditionId, interruptionFilter, enabled);
-        this.creationTime = creationTime;
-    }
-
-    /**
-     * @hide
-     */
-    public AutomaticZenRule(String name, ComponentName owner, Uri conditionId, ZenPolicy policy,
-            boolean enabled, long creationTime) {
-        this(name, owner, conditionId, policy, enabled);
+    public AutomaticZenRule(String name, ComponentName owner, ComponentName configurationActivity,
+            Uri conditionId, ZenPolicy policy, int interruptionFilter, boolean enabled,
+            long creationTime) {
+        this(name, owner, configurationActivity, conditionId, policy, interruptionFilter, enabled);
         this.creationTime = creationTime;
     }
 
@@ -112,6 +121,7 @@
         interruptionFilter = source.readInt();
         conditionId = source.readParcelable(null);
         owner = source.readParcelable(null);
+        configurationActivity = source.readParcelable(null);
         creationTime = source.readLong();
         mZenPolicy = source.readParcelable(null);
         mModified = source.readInt() == ENABLED;
@@ -125,6 +135,14 @@
     }
 
     /**
+     * Returns the {@link ComponentName} of the activity that shows configuration options
+     * for this rule.
+     */
+    public ComponentName getConfigurationActivity() {
+        return configurationActivity;
+    }
+
+    /**
      * Returns the representation of the state that causes this rule to become active.
      */
     public Uri getConditionId() {
@@ -218,6 +236,15 @@
         this.mZenPolicy = zenPolicy;
     }
 
+    /**
+     * Sets the configuration activity - an activity that handles
+     * {@link NotificationManager#ACTION_AUTOMATIC_ZEN_RULE} that shows the user more information
+     * about this rule and/or allows them to configure it.
+     */
+    public void setConfigurationActivity(ComponentName componentName) {
+        this.configurationActivity = componentName;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -235,6 +262,7 @@
         dest.writeInt(interruptionFilter);
         dest.writeParcelable(conditionId, 0);
         dest.writeParcelable(owner, 0);
+        dest.writeParcelable(configurationActivity, 0);
         dest.writeLong(creationTime);
         dest.writeParcelable(mZenPolicy, 0);
         dest.writeInt(mModified ? ENABLED : DISABLED);
@@ -248,6 +276,7 @@
                 .append(",interruptionFilter=").append(interruptionFilter)
                 .append(",conditionId=").append(conditionId)
                 .append(",owner=").append(owner)
+                .append(",configActivity=").append(configurationActivity)
                 .append(",creationTime=").append(creationTime)
                 .append(",mZenPolicy=").append(mZenPolicy)
                 .append(']').toString();
@@ -264,14 +293,15 @@
                 && other.interruptionFilter == interruptionFilter
                 && Objects.equals(other.conditionId, conditionId)
                 && Objects.equals(other.owner, owner)
-                && other.creationTime == creationTime
-                && Objects.equals(other.mZenPolicy, mZenPolicy);
+                && Objects.equals(other.mZenPolicy, mZenPolicy)
+                && Objects.equals(other.configurationActivity, configurationActivity)
+                && other.creationTime == creationTime;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, creationTime,
-                mZenPolicy, mModified);
+        return Objects.hash(enabled, name, interruptionFilter, conditionId, owner,
+                configurationActivity, mZenPolicy, mModified, creationTime);
     }
 
     public static final Parcelable.Creator<AutomaticZenRule> CREATOR
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index e508d42..00567523 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -164,6 +164,7 @@
     boolean removeAutomaticZenRule(String id);
     boolean removeAutomaticZenRules(String packageName);
     int getRuleInstanceCount(in ComponentName owner);
+    void setAutomaticZenRuleState(String id, in Condition condition);
 
     byte[] getBackupPayload(int user);
     void applyRestore(in byte[] payload, int user);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 25fa897..306c366 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -41,6 +41,7 @@
 import android.os.StrictMode;
 import android.os.UserHandle;
 import android.provider.Settings.Global;
+import android.service.notification.Condition;
 import android.service.notification.StatusBarNotification;
 import android.service.notification.ZenModeConfig;
 import android.util.Log;
@@ -262,6 +263,68 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Importance {}
 
+    /**
+     * Activity Action: Launch an Automatic Zen Rule configuration screen
+     * <p>
+     * Input: Optionally, {@link #EXTRA_AUTOMATIC_RULE_ID}, if the configuration screen for an
+     * existing rule should be displayed. If the rule id is missing or null, apps should display
+     * a configuration screen where users can create a new instance of the rule.
+     * <p>
+     * Output: Nothing
+     * <p>
+     *     You can have multiple activities handling this intent, if you support multiple
+     *     {@link AutomaticZenRule rules}. In order for the system to properly display all of your
+     *     rule types so that users can create new instances or configure existing ones, you need
+     *     to add some extra metadata ({@link #META_DATA_AUTOMATIC_RULE_TYPE})
+     *     to your activity tag in your manifest. If you'd like to limit the number of rules a user
+     *     can create from this flow, you can additionally optionally include
+     *     {@link #META_DATA_RULE_INSTANCE_LIMIT}.
+     *
+     *     For example,
+     *     &lt;meta-data
+     *         android:name="android.app.zen.automatic.ruleType"
+     *         android:value="@string/my_condition_rule">
+     *     &lt;/meta-data>
+     *     &lt;meta-data
+     *         android:name="android.app.zen.automatic.ruleInstanceLimit"
+     *         android:value="1">
+     *     &lt;/meta-data>
+     * </p>
+     * </p>
+     *
+     * @see {@link #addAutomaticZenRule(AutomaticZenRule)}
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_AUTOMATIC_ZEN_RULE =
+            "android.app.action.AUTOMATIC_ZEN_RULE";
+
+    /**
+     * Used as an optional string extra on {@link #ACTION_AUTOMATIC_ZEN_RULE} intents. If
+     * provided, contains the id of the {@link AutomaticZenRule} (as returned from
+     * {@link NotificationManager#addAutomaticZenRule(AutomaticZenRule)}) for which configuration
+     * settings should be displayed.
+     */
+    public static final String EXTRA_AUTOMATIC_RULE_ID = "android.app.extra.AUTOMATIC_RULE_ID";
+
+    /**
+     * A required {@code meta-data} tag for activities that handle
+     * {@link #ACTION_AUTOMATIC_ZEN_RULE}.
+     *
+     * This tag should contain a localized name of the type of the zen rule provided by the
+     * activity.
+     */
+    public static final String META_DATA_AUTOMATIC_RULE_TYPE = "android.app.automatic.ruleType";
+
+    /**
+     * An optional {@code meta-data} tag for activities that handle
+     * {@link #ACTION_AUTOMATIC_ZEN_RULE}.
+     *
+     * This tag should contain the maximum number of rule instances that
+     * can be created for this rule type. Omit or enter a value <= 0 to allow unlimited instances.
+     */
+    public static final String META_DATA_RULE_INSTANCE_LIMIT =
+            "android.app.zen.automatic.ruleInstanceLimit";
+
     /** Value signifying that the user has not expressed a per-app visibility override value.
      * @hide */
     public static final int VISIBILITY_NO_OVERRIDE = -1000;
@@ -859,14 +922,10 @@
             List<ZenModeConfig.ZenRule> rules = service.getZenRules();
             Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
             for (ZenModeConfig.ZenRule rule : rules) {
-                if (rule.zenPolicy == null) {
-                    ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
-                            rule.conditionId, zenModeToInterruptionFilter(rule.zenMode),
-                            rule.enabled, rule.creationTime));
-                } else {
-                    ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
-                            rule.conditionId, rule.zenPolicy, rule.enabled, rule.creationTime));
-                }
+                ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
+                        rule.configurationActivity, rule.conditionId, rule.zenPolicy,
+                        zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
+                        rule.creationTime));
             }
             return ruleMap;
         } catch (RemoteException e) {
@@ -936,6 +995,26 @@
     }
 
     /**
+     * Informs the notification manager that the state of an {@link AutomaticZenRule} has changed.
+     * Use this method to put the system into Do Not Disturb mode or request that it exits Do Not
+     * Disturb mode. The calling app must own the provided {@link android.app.AutomaticZenRule}.
+     * <p>
+     *     This method can be used in conjunction with or as a replacement to
+     *     {@link android.service.notification.ConditionProviderService#notifyCondition(Condition)}.
+     * </p>
+     * @param id The id of the rule whose state should change
+     * @param condition The new state of this rule
+     */
+    public void setAutomaticZenRuleState(String id, Condition condition) {
+        INotificationManager service = getService();
+        try {
+            service.setAutomaticZenRuleState(id, condition);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Deletes the automatic zen rule with the given id.
      *
      * <p>
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 0afb98f..f1e6b06 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -189,8 +189,11 @@
      * completed.
      *
      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     * If the {@code userId} is different from the calling user id, then the caller must hold the
+     * android.permission.INTERACT_ACROSS_USERS_FULL permission.
      *
-     * @param fd The file descriptor to which a 'tar' file stream is to be written
+     * @param userId User id for which backup should be performed.
+     * @param fd The file descriptor to which a 'tar' file stream is to be written.
      * @param includeApks If <code>true</code>, the resulting tar stream will include the
      *     application .apk files themselves as well as their data.
      * @param includeObbs If <code>true</code>, the resulting tar stream will include any
@@ -209,7 +212,7 @@
      * @param packageNames The package names of the apps whose data (and optionally .apk files)
      *     are to be backed up.  The <code>allApps</code> parameter supersedes this.
      */
-    void adbBackup(in ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
+    void adbBackup(int userId, in ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
             boolean includeShared, boolean doWidgets, boolean allApps, boolean allIncludesSystem,
             boolean doCompress, boolean doKeyValue, in String[] packageNames);
 
@@ -227,8 +230,12 @@
      * Currently only used by the 'adb restore' command.
      *
      * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     * If the {@code userId} is different from the calling user id, then the caller must hold the
+     * android.permission.INTERACT_ACROSS_USERS_FULL.
+     *
+     * @param userId User id for which restore should be performed.
      */
-    void adbRestore(in ParcelFileDescriptor fd);
+    void adbRestore(int userId, in ParcelFileDescriptor fd);
 
     /**
      * Confirm that the requested full backup/restore operation can proceed.  The system will
diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl
index 4ce0f31..0c9b41bf 100644
--- a/core/java/android/app/role/IRoleManager.aidl
+++ b/core/java/android/app/role/IRoleManager.aidl
@@ -48,4 +48,6 @@
     boolean addRoleHolderFromController(in String roleName, in String packageName);
 
     boolean removeRoleHolderFromController(in String roleName, in String packageName);
+
+    List<String> getHeldRolesFromController(in String packageName);
 }
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index 5d101ab..2d630a6 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -542,6 +542,27 @@
         }
     }
 
+
+    /**
+     * Returns the list of all roles that the given package is currently holding
+     *
+     * @param packageName the package name
+     * @return the list of role names
+     *
+     * @hide
+     */
+    @RequiresPermission(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)
+    @SystemApi
+    @NonNull
+    public List<String> getHeldRolesFromController(@NonNull String packageName) {
+        Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+        try {
+            return mService.getHeldRolesFromController(packageName);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private static class RoleManagerCallbackDelegate extends IRoleManagerCallback.Stub {
 
         @NonNull
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index eea2b88..a4ea513 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -36,6 +36,7 @@
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.KeySet;
+import android.content.pm.ModuleInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ProviderInfo;
@@ -680,4 +681,8 @@
     boolean isPackageStateProtected(String packageName, int userId);
 
     void sendDeviceCustomizationReadyBroadcast();
+
+    List<ModuleInfo> getInstalledModules(int flags);
+
+    ModuleInfo getModuleInfo(String packageName, int flags);
 }
diff --git a/core/java/android/content/pm/ModuleInfo.aidl b/core/java/android/content/pm/ModuleInfo.aidl
new file mode 100644
index 0000000..cc13bf1
--- /dev/null
+++ b/core/java/android/content/pm/ModuleInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 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 android.content.pm;
+
+parcelable ModuleInfo;
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index af7e93e..30d9804 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -29,7 +29,7 @@
 
 /**
  * The current condition of an {@link android.app.AutomaticZenRule}, provided by the
- * {@link ConditionProviderService} that owns the rule. Used to tell the system to enter Do Not
+ * app that owns the rule. Used to tell the system to enter Do Not
  * Disturb mode and request that the system exit Do Not Disturb mode.
  */
 public final class Condition implements Parcelable {
@@ -48,8 +48,8 @@
 
     /**
      * Indicates that Do Not Disturb should be turned off. Note that all Conditions from all
-     * {@link ConditionProviderService} providers must be off for Do Not Disturb to be turned off on
-     * the device.
+     * {@link android.app.AutomaticZenRule} providers must be off for Do Not Disturb to be turned
+     * off on the device.
      */
     public static final int STATE_FALSE = 0;
     /**
@@ -154,7 +154,7 @@
     public void writeToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
-        // id is guarantreed not to be null.
+        // id is guaranteed not to be null.
         proto.write(ConditionProto.ID, id.toString());
         proto.write(ConditionProto.SUMMARY, summary);
         proto.write(ConditionProto.LINE_1, line1);
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index 5203c8f..45480cb 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -59,7 +59,16 @@
  *
  *  <p> Condition providers cannot be bound by the system on
  * {@link ActivityManager#isLowRamDevice() low ram} devices</p>
+ *
+ * @deprecated Instead of using an automatically bound service, use
+ * {@link android.app.NotificationManager#setAutomaticZenRuleState(String, Condition)} to tell the
+ * system about the state of your rule. In order to maintain a link from
+ * Settings to your rule configuration screens, provide a configuration activity that handles
+ * {@link android.app.NotificationManager#ACTION_AUTOMATIC_ZEN_RULE} on your
+ * {@link android.app.AutomaticZenRule} via
+ * {@link android.app.AutomaticZenRule#setConfigurationActivity(ComponentName)}.
  */
+@Deprecated
 public abstract class ConditionProviderService extends Service {
     private final String TAG = ConditionProviderService.class.getSimpleName()
             + "[" + getClass().getSimpleName() + "]";
@@ -79,26 +88,38 @@
     /**
      * The name of the {@code meta-data} tag containing a localized name of the type of zen rules
      * provided by this service.
+     *
+     * @deprecated see {@link android.app.NotificationManager#META_DATA_AUTOMATIC_RULE_TYPE}.
      */
+    @Deprecated
     public static final String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
 
     /**
      * The name of the {@code meta-data} tag containing the {@link ComponentName} of an activity
      * that allows users to configure the conditions provided by this service.
+     *
+     * @deprecated see {@link android.app.NotificationManager#ACTION_AUTOMATIC_ZEN_RULE}.
      */
+    @Deprecated
     public static final String META_DATA_CONFIGURATION_ACTIVITY =
             "android.service.zen.automatic.configurationActivity";
 
     /**
      * The name of the {@code meta-data} tag containing the maximum number of rule instances that
      * can be created for this rule type. Omit or enter a value <= 0 to allow unlimited instances.
+     *
+     * @deprecated see {@link android.app.NotificationManager#META_DATA_RULE_INSTANCE_LIMIT}.
      */
+    @Deprecated
     public static final String META_DATA_RULE_INSTANCE_LIMIT =
             "android.service.zen.automatic.ruleInstanceLimit";
 
     /**
      * A String rule id extra passed to {@link #META_DATA_CONFIGURATION_ACTIVITY}.
+     *
+     * @deprecated see {@link android.app.NotificationManager#EXTRA_AUTOMATIC_RULE_ID}.
      */
+    @Deprecated
     public static final String EXTRA_RULE_ID = "android.service.notification.extra.RULE_ID";
 
     /**
@@ -171,7 +192,11 @@
      * service that has an {@link android.app.AutomaticZenRule#getConditionId()} equal to this
      * {@link Condition#id}.
      * @param condition the condition that has changed.
+     *
+     * @deprecated see
+     * {@link android.app.NotificationManager#setAutomaticZenRuleState(String, Condition)}.
      */
+    @Deprecated
     public final void notifyCondition(Condition condition) {
         if (condition == null) return;
         notifyConditions(new Condition[]{ condition });
@@ -181,7 +206,11 @@
      * Informs the notification manager that the state of one or more Conditions has changed. See
      * {@link #notifyCondition(Condition)} for restrictions.
      * @param conditions the changed conditions.
+     *
+     * @deprecated see
+     *       {@link android.app.NotificationManager#setAutomaticZenRuleState(String, Condition)}.
      */
+    @Deprecated
     public final void notifyConditions(Condition... conditions) {
         if (!isBound() || conditions == null) return;
         try {
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 0e2ae83..6792c69 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -142,6 +142,7 @@
     private static final String RULE_ATT_SNOOZING = "snoozing";
     private static final String RULE_ATT_NAME = "name";
     private static final String RULE_ATT_COMPONENT = "component";
+    private static final String RULE_ATT_CONFIG_ACTIVITY = "configActivity";
     private static final String RULE_ATT_ZEN = "zen";
     private static final String RULE_ATT_CONDITION_ID = "conditionId";
     private static final String RULE_ATT_CREATION_TIME = "creationTime";
@@ -269,7 +270,7 @@
         return buffer.toString();
     }
 
-    private Diff diff(ZenModeConfig to) {
+    public Diff diff(ZenModeConfig to) {
         final Diff d = new Diff();
         if (to == null) {
             return d.addLine("config", "delete");
@@ -623,7 +624,6 @@
     public static ZenRule readRuleXml(XmlPullParser parser) {
         final ZenRule rt = new ZenRule();
         rt.enabled = safeBoolean(parser, RULE_ATT_ENABLED, true);
-        rt.snoozing = safeBoolean(parser, RULE_ATT_SNOOZING, false);
         rt.name = parser.getAttributeValue(null, RULE_ATT_NAME);
         final String zen = parser.getAttributeValue(null, RULE_ATT_ZEN);
         rt.zenMode = tryParseZenMode(zen, -1);
@@ -633,6 +633,12 @@
         }
         rt.conditionId = safeUri(parser, RULE_ATT_CONDITION_ID);
         rt.component = safeComponentName(parser, RULE_ATT_COMPONENT);
+        rt.configurationActivity = safeComponentName(parser, RULE_ATT_CONFIG_ACTIVITY);
+        rt.pkg = (rt.component != null)
+                ? rt.component.getPackageName()
+                : (rt.configurationActivity != null)
+                        ? rt.configurationActivity.getPackageName()
+                        : null;
         rt.creationTime = safeLong(parser, RULE_ATT_CREATION_TIME, 0);
         rt.enabler = parser.getAttributeValue(null, RULE_ATT_ENABLER);
         rt.condition = readConditionXml(parser);
@@ -649,7 +655,6 @@
 
     public static void writeRuleXml(ZenRule rule, XmlSerializer out) throws IOException {
         out.attribute(null, RULE_ATT_ENABLED, Boolean.toString(rule.enabled));
-        out.attribute(null, RULE_ATT_SNOOZING, Boolean.toString(rule.snoozing));
         if (rule.name != null) {
             out.attribute(null, RULE_ATT_NAME, rule.name);
         }
@@ -657,6 +662,10 @@
         if (rule.component != null) {
             out.attribute(null, RULE_ATT_COMPONENT, rule.component.flattenToString());
         }
+        if (rule.configurationActivity != null) {
+            out.attribute(null, RULE_ATT_CONFIG_ACTIVITY,
+                    rule.configurationActivity.flattenToString());
+        }
         if (rule.conditionId != null) {
             out.attribute(null, RULE_ATT_CONDITION_ID, rule.conditionId.toString());
         }
@@ -1452,12 +1461,15 @@
         public Uri conditionId;          // required for automatic
         public Condition condition;      // optional
         public ComponentName component;  // optional
+        public ComponentName configurationActivity; // optional
         public String id;                // required for automatic (unique)
         @UnsupportedAppUsage
         public long creationTime;        // required for automatic
-        public String enabler;          // package name, only used for manual rules.
+        // package name, only used for manual rules when they have turned DND on.
+        public String enabler;
         public ZenPolicy zenPolicy;
         public boolean modified;    // rule has been modified from initial creation
+        public String pkg;
 
         public ZenRule() { }
 
@@ -1471,6 +1483,7 @@
             conditionId = source.readParcelable(null);
             condition = source.readParcelable(null);
             component = source.readParcelable(null);
+            configurationActivity = source.readParcelable(null);
             if (source.readInt() == 1) {
                 id = source.readString();
             }
@@ -1480,6 +1493,7 @@
             }
             zenPolicy = source.readParcelable(null);
             modified = source.readInt() == 1;
+            pkg = source.readString();
         }
 
         @Override
@@ -1501,6 +1515,7 @@
             dest.writeParcelable(conditionId, 0);
             dest.writeParcelable(condition, 0);
             dest.writeParcelable(component, 0);
+            dest.writeParcelable(configurationActivity, 0);
             if (id != null) {
                 dest.writeInt(1);
                 dest.writeString(id);
@@ -1516,6 +1531,7 @@
             }
             dest.writeParcelable(zenPolicy, 0);
             dest.writeInt(modified ? 1 : 0);
+            dest.writeString(pkg);
         }
 
         @Override
@@ -1528,7 +1544,9 @@
                     .append(",zenMode=").append(Global.zenModeToString(zenMode))
                     .append(",conditionId=").append(conditionId)
                     .append(",condition=").append(condition)
+                    .append(",pkg=").append(pkg)
                     .append(",component=").append(component)
+                    .append(",configActivity=").append(configurationActivity)
                     .append(",creationTime=").append(creationTime)
                     .append(",enabler=").append(enabler)
                     .append(",zenPolicy=").append(zenPolicy)
@@ -1537,6 +1555,7 @@
         }
 
         /** @hide */
+        // TODO: add configuration activity
         public void writeToProto(ProtoOutputStream proto, long fieldId) {
             final long token = proto.start(fieldId);
 
@@ -1600,6 +1619,9 @@
             if (!Objects.equals(component, to.component)) {
                 d.addLine(item, "component", component, to.component);
             }
+            if (!Objects.equals(configurationActivity, to.configurationActivity)) {
+                d.addLine(item, "configActivity", configurationActivity, to.configurationActivity);
+            }
             if (!Objects.equals(id, to.id)) {
                 d.addLine(item, "id", id, to.id);
             }
@@ -1615,6 +1637,9 @@
             if (modified != to.modified) {
                 d.addLine(item, "modified", modified, to.modified);
             }
+            if (pkg != to.pkg) {
+                d.addLine(item, "pkg", pkg, to.pkg);
+            }
         }
 
         @Override
@@ -1629,20 +1654,22 @@
                     && Objects.equals(other.conditionId, conditionId)
                     && Objects.equals(other.condition, condition)
                     && Objects.equals(other.component, component)
+                    && Objects.equals(other.configurationActivity, configurationActivity)
                     && Objects.equals(other.id, id)
                     && Objects.equals(other.enabler, enabler)
                     && Objects.equals(other.zenPolicy, zenPolicy)
+                    && Objects.equals(other.pkg, pkg)
                     && other.modified == modified;
         }
 
         @Override
         public int hashCode() {
             return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
-                    component, id, enabler, zenPolicy, modified);
+                    component, configurationActivity, pkg, id, enabler, zenPolicy, modified);
         }
 
         public boolean isAutomaticActive() {
-            return enabled && !snoozing && component != null && isTrueOrUnknown();
+            return enabled && !snoozing && pkg != null && isTrueOrUnknown();
         }
 
         public boolean isTrueOrUnknown() {
diff --git a/core/java/android/transition/Scene.java b/core/java/android/transition/Scene.java
index b1fc17a..8d4db54 100644
--- a/core/java/android/transition/Scene.java
+++ b/core/java/android/transition/Scene.java
@@ -96,7 +96,7 @@
      * the hierarchy specified by the layoutId resource file.
      *
      * <p>This method is hidden because layoutId-based scenes should be
-     * created by the caching factory method {@link Scene#getCurrentScene(View)}.</p>
+     * created by the caching factory method {@link Scene#getCurrentScene(ViewGroup)}.</p>
      *
      * @param sceneRoot The root of the hierarchy in which scene changes
      * and transitions will take place.
@@ -194,28 +194,28 @@
     }
 
     /**
-     * Set the scene that the given view is in. The current scene is set only
-     * on the root view of a scene, not for every view in that hierarchy. This
+     * Set the scene that the given ViewGroup is in. The current scene is set only
+     * on the root ViewGroup of a scene, not for every view in that hierarchy. This
      * information is used by Scene to determine whether there is a previous
      * scene which should be exited before the new scene is entered.
      *
-     * @param sceneRoot The view on which the current scene is being set
+     * @param sceneRoot The ViewGroup on which the current scene is being set
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
-    static void setCurrentScene(@NonNull View sceneRoot, @Nullable Scene scene) {
+    static void setCurrentScene(@NonNull ViewGroup sceneRoot, @Nullable Scene scene) {
         sceneRoot.setTagInternal(com.android.internal.R.id.current_scene, scene);
     }
 
     /**
-     * Gets the current {@link Scene} set on the given view. A scene is set on a view
-     * only if that view is the scene root.
+     * Gets the current {@link Scene} set on the given ViewGroup. A scene is set on a ViewGroup
+     * only if that ViewGroup is the scene root.
      *
-     * @param sceneRoot The view on which the current scene will be returned
-     * @return The current Scene set on this view. A value of null indicates that
+     * @param sceneRoot The ViewGroup on which the current scene will be returned
+     * @return The current Scene set on this ViewGroup. A value of null indicates that
      * no Scene is currently set.
      */
     @Nullable
-    public static Scene getCurrentScene(@NonNull View sceneRoot) {
+    public static Scene getCurrentScene(@NonNull ViewGroup sceneRoot) {
         return (Scene) sceneRoot.getTag(com.android.internal.R.id.current_scene);
     }
 
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 9227249..699b34a 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1471,8 +1471,8 @@
     // Note: don't need to use locked suffix because mContext is final.
     private AutofillClient getClient() {
         final AutofillClient client = mContext.getAutofillClient();
-        if (client == null && sDebug) {
-            Log.d(TAG, "No AutofillClient for " + mContext.getPackageName() + " on context "
+        if (client == null && sVerbose) {
+            Log.v(TAG, "No AutofillClient for " + mContext.getPackageName() + " on context "
                     + mContext);
         }
         return client;
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 7032081..ff4591f 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -418,7 +418,7 @@
     }
     endmntent(fp);
 
-    for (auto path : toUnmount) {
+    for (const auto& path : toUnmount) {
         if (umount2(path.c_str(), MNT_DETACH)) {
             ALOGW("Failed to unmount %s: %s", path.c_str(), strerror(errno));
         }
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 38caa36..9277dae 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3640,4 +3640,6 @@
          (android.view.InputEventCompatProcessor). -->
     <string name="config_inputEventCompatProcessorOverrideClassName" translatable="false"></string>
 
+    <!-- Component name for the default module metadata provider on this device -->
+    <string name="config_defaultModuleMetadataProvider">com.android.modulemetadata</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f959b44..d68681d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3519,4 +3519,6 @@
   <java-symbol type="dimen" name="rounded_corner_radius" />
   <java-symbol type="dimen" name="rounded_corner_radius_top" />
   <java-symbol type="dimen" name="rounded_corner_radius_bottom" />
+
+  <java-symbol type="string" name="config_defaultModuleMetadataProvider" />
 </resources>
diff --git a/libs/androidfw/TEST_MAPPING b/libs/androidfw/TEST_MAPPING
new file mode 100644
index 0000000..a58b47f
--- /dev/null
+++ b/libs/androidfw/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+  "presubmit": [
+    {
+      "name": "libandroidfw_tests",
+      "host": true
+    }
+  ]
+}
\ No newline at end of file
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 441356b..22d587a 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -365,6 +365,6 @@
 // structs with size fields (like Res_value, ResTable_entry) should be
 // backwards and forwards compatible (aka checking the size field against
 // sizeof(Res_value) might not be backwards compatible.
-TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
+// TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
 
 }  // namespace android
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 0503f36..6585bfc 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -208,6 +208,7 @@
         "FrameInfoVisualizer.cpp",
         "GpuMemoryTracker.cpp",
         "HardwareBitmapUploader.cpp",
+        "HWUIProperties.sysprop",
         "Interpolator.cpp",
         "JankTracker.cpp",
         "Layer.cpp",
diff --git a/libs/hwui/HWUIProperties.sysprop b/libs/hwui/HWUIProperties.sysprop
new file mode 100644
index 0000000..42191ca
--- /dev/null
+++ b/libs/hwui/HWUIProperties.sysprop
@@ -0,0 +1,9 @@
+owner: Platform
+module: "android.uirenderer"
+prop {
+    api_name: "use_vulkan"
+    type: Boolean
+    prop_name: "ro.hwui.use_vulkan"
+    scope: Public
+    access: Readonly
+}
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 8067313..046ffc4 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -18,6 +18,7 @@
 #include "Debug.h"
 #include "DeviceInfo.h"
 #include "SkTraceEventCommon.h"
+#include "HWUIProperties.sysprop.h"
 
 #include <algorithm>
 #include <cstdlib>
@@ -174,8 +175,13 @@
     if (sRenderPipelineType != RenderPipelineType::NotInitialized) {
         return sRenderPipelineType;
     }
+    bool useVulkan = use_vulkan().value_or(false);
     char prop[PROPERTY_VALUE_MAX];
-    property_get(PROPERTY_RENDERER, prop, "skiagl");
+    if (useVulkan) {
+        property_get(PROPERTY_RENDERER, prop, "skiavk");
+    } else {
+        property_get(PROPERTY_RENDERER, prop, "skiagl");
+    }
     if (!strcmp(prop, "skiavk")) {
         ALOGD("Skia Vulkan Pipeline");
         sRenderPipelineType = RenderPipelineType::SkiaVulkan;
diff --git a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
index 0d87776..d189a93 100644
--- a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
@@ -76,7 +76,7 @@
                             paint.setStrokeWidth(strokeWidth);
                             // fill column with each op
                             int middleCount = canvas.save(SaveFlags::MatrixClip);
-                            for (auto op : ops) {
+                            for (const auto& op : ops) {
                                 int innerCount = canvas.save(SaveFlags::MatrixClip);
                                 canvas.clipRect(0, 0, cellSize, cellSize, SkClipOp::kIntersect);
                                 canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index ee6beba..b11eaa9 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -251,7 +251,7 @@
 }
 
 TEST(PathParser, parseStringForData) {
-    for (TestData testData : sTestDataSet) {
+    for (const TestData& testData : sTestDataSet) {
         PathParser::ParseResult result;
         // Test generated path data against the given data.
         PathData pathData;
@@ -271,7 +271,7 @@
 }
 
 TEST(VectorDrawableUtils, createSkPathFromPathData) {
-    for (TestData testData : sTestDataSet) {
+    for (const TestData& testData : sTestDataSet) {
         SkPath expectedPath;
         testData.skPathLamda(&expectedPath);
         SkPath actualPath;
@@ -281,7 +281,7 @@
 }
 
 TEST(PathParser, parseAsciiStringForSkPath) {
-    for (TestData testData : sTestDataSet) {
+    for (const TestData& testData : sTestDataSet) {
         PathParser::ParseResult result;
         size_t length = strlen(testData.pathString);
         // Check the return value as well as the SkPath generated.
@@ -304,8 +304,8 @@
 }
 
 TEST(VectorDrawableUtils, morphPathData) {
-    for (TestData fromData : sTestDataSet) {
-        for (TestData toData : sTestDataSet) {
+    for (const TestData& fromData : sTestDataSet) {
+        for (const TestData& toData : sTestDataSet) {
             bool canMorph = VectorDrawableUtils::canMorph(fromData.pathData, toData.pathData);
             if (fromData.pathData == toData.pathData) {
                 EXPECT_TRUE(canMorph);
@@ -319,8 +319,8 @@
 
 TEST(VectorDrawableUtils, interpolatePathData) {
     // Interpolate path data with itself and every other path data
-    for (TestData fromData : sTestDataSet) {
-        for (TestData toData : sTestDataSet) {
+    for (const TestData& fromData : sTestDataSet) {
+        for (const TestData& toData : sTestDataSet) {
             PathData outData;
             bool success = VectorDrawableUtils::interpolatePathData(&outData, fromData.pathData,
                                                                     toData.pathData, 0.5);
@@ -331,7 +331,7 @@
 
     float fractions[] = {0, 0.00001, 0.28, 0.5, 0.7777, 0.9999999, 1};
     // Now try to interpolate with a slightly modified version of self and expect success
-    for (TestData fromData : sTestDataSet) {
+    for (const TestData& fromData : sTestDataSet) {
         PathData toPathData = fromData.pathData;
         for (size_t i = 0; i < toPathData.points.size(); i++) {
             toPathData.points[i]++;
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
index 88b8dd8..fbd863d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
@@ -11,13 +11,12 @@
  * 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
+ * limitations under the License.
  */
 
 package com.android.systemui.plugins;
 
-import android.hardware.Sensor;
-import android.hardware.TriggerEventListener;
+import android.hardware.SensorListener;
 
 import com.android.systemui.plugins.annotations.ProvidesInterface;
 
@@ -31,26 +30,30 @@
     int VERSION = 1;
 
     /**
-     * Registers for trigger events from the sensor. Trigger events are one-shot and need to
-     * re-registered in order for them to be fired again.
+     * Registers for sensor events. Events will be sent until the listener is unregistered.
      * @param sensor
      * @param listener
-     * @see android.hardware.SensorManager#requestTriggerSensor(
-     *     android.hardware.TriggerEventListener, android.hardware.Sensor)
+     * @see android.hardware.SensorManager#registerListener(SensorListener, int)
      */
-    void registerTriggerEvent(Sensor sensor, TriggerEventListener listener);
+    void registerListener(Sensor sensor, SensorEventListener listener);
 
     /**
-     * Unregisters trigger events from the sensor.
+     * Unregisters events from the sensor.
      * @param sensor
      * @param listener
      */
-    void unregisterTriggerEvent(Sensor sensor, TriggerEventListener listener);
+    void unregisterListener(Sensor sensor, SensorEventListener listener);
 
-    interface TriggerEventListener {
-        void onTrigger(TriggerEvent event);
+    /**
+     * Listener triggered whenever the Sensor has new data.
+     */
+    interface SensorEventListener {
+        void onSensorChanged(SensorEvent event);
     }
 
+    /**
+     * Sensor that can be defined in a plugin.
+     */
     class Sensor {
         public static final int TYPE_WAKE_LOCK_SCREEN = 1;
         public static final int TYPE_WAKE_DISPLAY = 2;
@@ -67,29 +70,32 @@
         }
     }
 
-    class TriggerEvent {
+    /**
+     * Event sent by a {@link Sensor}.
+     */
+    class SensorEvent {
         Sensor mSensor;
         int mVendorType;
         float[] mValues;
 
         /**
-         * Creates a trigger event
+         * Creates a sensor event.
          * @param sensor The type of sensor, e.g. TYPE_WAKE_LOCK_SCREEN
          * @param vendorType The vendor type, which should be unique for each type of sensor,
          *                   e.g. SINGLE_TAP = 1, DOUBLE_TAP = 2, etc.
          */
-        public TriggerEvent(Sensor sensor, int vendorType) {
+        public SensorEvent(Sensor sensor, int vendorType) {
             this(sensor, vendorType, null);
         }
 
         /**
-         * Creates a trigger event
+         * Creates a sensor event.
          * @param sensor The type of sensor, e.g. TYPE_WAKE_LOCK_SCREEN
          * @param vendorType The vendor type, which should be unique for each type of sensor,
          *                   e.g. SINGLE_TAP = 1, DOUBLE_TAP = 2, etc.
          * @param values Values captured by the sensor.
          */
-        public TriggerEvent(Sensor sensor, int vendorType, float[] values) {
+        public SensorEvent(Sensor sensor, int vendorType, float[] values) {
             mSensor = sensor;
             mVendorType = vendorType;
             mValues = values;
diff --git a/packages/SystemUI/res/drawable/ic_5g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_5g_mobiledata.xml
new file mode 100644
index 0000000..2aa6e57f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_5g_mobiledata.xml
@@ -0,0 +1,27 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="14dp"
+    android:height="17dp"
+    android:viewportWidth="14"
+    android:viewportHeight="17">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M13.9,12.24l-0.22,0.27c-0.63,0.73 -1.55,1.1 -2.76,1.1c-1.08,0 -1.92,-0.36 -2.53,-1.07s-0.93,-1.72 -0.94,-3.02V7.56c0,-1.39 0.28,-2.44 0.84,-3.13s1.39,-1.04 2.51,-1.04c0.95,0 1.69,0.26 2.23,0.79s0.83,1.28 0.89,2.26h-1.25c-0.05,-0.62 -0.22,-1.1 -0.52,-1.45s-0.74,-0.52 -1.34,-0.52c-0.72,0 -1.24,0.23 -1.57,0.7S8.72,6.37 8.71,7.4v2.03c0,1 0.19,1.77 0.57,2.31c0.38,0.54 0.93,0.8 1.65,0.8c0.67,0 1.19,-0.16 1.54,-0.49l0.18,-0.17V9.59h-1.82V8.52h3.07V12.24z"/>
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M1.15,8.47l0.43,-4.96h4.33v1.17H2.6L2.37,7.39C2.78,7.1 3.22,6.96 3.69,6.96c0.77,0 1.38,0.3 1.83,0.9s0.66,1.41 0.66,2.43c0,1.03 -0.24,1.84 -0.72,2.43S4.32,13.6 3.48,13.6c-0.75,0 -1.36,-0.24 -1.83,-0.73s-0.74,-1.16 -0.81,-2.02h1.13c0.07,0.57 0.23,1 0.49,1.29c0.26,0.29 0.59,0.43 1.01,0.43c0.47,0 0.84,-0.2 1.1,-0.61c0.26,-0.41 0.4,-0.96 0.4,-1.65c0,-0.65 -0.14,-1.18 -0.43,-1.59S3.88,8.09 3.4,8.09c-0.4,0 -0.72,0.1 -0.96,0.31L2.11,8.73L1.15,8.47z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_5g_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_5g_plus_mobiledata.xml
new file mode 100644
index 0000000..10bbcc7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_5g_plus_mobiledata.xml
@@ -0,0 +1,33 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:viewportWidth="22"
+    android:viewportHeight="17"
+    android:width="22dp"
+    android:height="17dp">
+  <group>
+    <group>
+      <path android:fillColor="#FF000000"
+          android:pathData="M1.03 8.47l0.43-4.96h4.33v1.17H2.48L2.25 7.39C2.66 7.1 3.1 6.96 3.57 6.96c0.77 0 1.38 0.3 1.83 0.9 s0.66 1.41 0.66 2.43c0 1.03-0.24 1.84-0.72 2.43S4.2 13.6 3.36 13.6c-0.75 0-1.36-0.24-1.83-0.73s-0.74-1.16-0.81-2.02h1.13 c0.07 0.57 0.23 1 0.49 1.29s0.59 0.43 1.01 0.43c0.47 0 0.84-0.2 1.1-0.61c0.26-0.41 0.4-0.96 0.4-1.65 c0-0.65-0.14-1.18-0.43-1.59S3.76 8.09 3.28 8.09c-0.4 0-0.72 0.1-0.96 0.31L1.99 8.73L1.03 8.47z"/>
+    </group>
+    <group>
+      <path android:fillColor="#FF000000"
+          android:pathData="M 18.93,5.74 L 18.93,3.39 L 17.63,3.39 L 17.63,5.74 L 15.28,5.74 L 15.28,7.04 L 17.63,7.04 L 17.63,9.39 L 18.93,9.39 L 18.93,7.04 L 21.28,7.04 L 21.28,5.74 z"/>
+    </group>
+    <path android:fillColor="#FF000000"
+        android:pathData="M13.78 12.24l-0.22 0.27c-0.63 0.73-1.55 1.1-2.76 1.1c-1.08 0-1.92-0.36-2.53-1.07s-0.93-1.72-0.94-3.02V7.56 c0-1.39 0.28-2.44 0.84-3.13s1.39-1.04 2.51-1.04c0.95 0 1.69 0.26 2.23 0.79s0.83 1.28 0.89 2.26h-1.25 c-0.05-0.62-0.22-1.1-0.52-1.45s-0.74-0.52-1.34-0.52c-0.72 0-1.24 0.23-1.57 0.7S8.6 6.37 8.59 7.4v2.03c0 1 0.19 1.77 0.57 2.31 c0.38 0.54 0.93 0.8 1.65 0.8c0.67 0 1.19-0.16 1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z"/>
+  </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml
deleted file mode 100644
index a72e9b8..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="32dp"
-    android:height="29.5dp"
-    android:viewportWidth="25.6"
-    android:viewportHeight="23.6">
-    <group
-        android:translateX="0.8"
-        android:translateY="-1.1">
-        <path
-            android:pathData="M23.66,8.11c0.39,-0.48 0.29,-1.19 -0.22,-1.54C21.67,5.36 17.55,3 12,3 6.44,3 2.33,5.36 0.56,6.57c-0.51,0.35 -0.61,1.06 -0.23,1.54L11.16,21.6c0.42,0.53 1.23,0.53 1.66,0L23.66,8.11z"
-            android:fillColor="#FFFFFFFF"/>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_full_0.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_full_0.xml
deleted file mode 100644
index 53e4efc..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_full_0.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="32.0dp"
-    android:height="29.5dp"
-    android:viewportWidth="25.6"
-    android:viewportHeight="23.6">
-    <group
-        android:translateX="0.8"
-        android:translateY="-0.9">
-        <path
-            android:pathData="M23.66,8.11c0.39,-0.48 0.29,-1.19 -0.22,-1.54C21.67,5.36 17.55,3 12,3 6.44,3 2.33,5.36 0.56,6.57c-0.51,0.35 -0.61,1.06 -0.23,1.54L11.16,21.6c0.42,0.53 1.23,0.53 1.66,0L23.66,8.11z"
-            android:fillColor="#4DFFFFFF"/>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_full_1.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_full_1.xml
deleted file mode 100644
index 8294183..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_full_1.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="32dp"
-    android:height="29.5dp"
-    android:viewportWidth="25.6"
-    android:viewportHeight="23.6">
-    <group
-        android:translateX="0.8"
-        android:translateY="-0.9">
-        <path
-            android:pathData="M23.66,8.11c0.39,-0.48 0.29,-1.19 -0.22,-1.54C21.67,5.36 17.55,3 12,3 6.44,3 2.33,5.36 0.56,6.57c-0.51,0.35 -0.61,1.06 -0.23,1.54L11.16,21.6c0.42,0.53 1.23,0.53 1.66,0L23.66,8.11z"
-            android:fillColor="#4DFFFFFF"/>
-        <path
-            android:pathData="M12.82,21.6l5.11,-6.36A8.942,8.942 0,0 0,12 13c-2.28,0 -4.35,0.85 -5.94,2.25l5.1,6.35c0.43,0.53 1.23,0.53 1.66,0z"
-            android:fillColor="#FFFFFFFF"/>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_full_2.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_full_2.xml
deleted file mode 100644
index 3d59cf2..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_full_2.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="32dp"
-    android:height="29.5dp"
-    android:viewportWidth="25.6"
-    android:viewportHeight="23.6">
-    <group
-        android:translateX="0.8"
-        android:translateY="-0.9">
-        <path
-            android:pathData="M23.66,8.11c0.39,-0.48 0.29,-1.19 -0.22,-1.54C21.67,5.36 17.55,3 12,3 6.44,3 2.33,5.36 0.56,6.57c-0.51,0.35 -0.61,1.06 -0.23,1.54L11.16,21.6c0.42,0.53 1.23,0.53 1.66,0L23.66,8.11z"
-            android:fillColor="#4DFFFFFF"/>
-        <path
-            android:pathData="M12.82,21.6l6.99,-8.7C17.71,11.1 14.99,10 12,10c-2.99,0 -5.72,1.1 -7.82,2.91l6.98,8.7c0.43,0.52 1.23,0.52 1.66,-0.01z"
-            android:fillColor="#FFFFFFFF"/>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_full_3.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_full_3.xml
deleted file mode 100644
index 21313b8..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_full_3.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="32dp"
-    android:height="29.5dp"
-    android:viewportWidth="25.6"
-    android:viewportHeight="23.6">
-    <group
-        android:translateX="0.8"
-        android:translateY="-0.9">
-        <path
-            android:pathData="M23.66,8.11c0.39,-0.48 0.29,-1.19 -0.22,-1.54C21.67,5.36 17.55,3 12,3 6.44,3 2.33,5.36 0.56,6.57c-0.51,0.35 -0.61,1.06 -0.23,1.54L11.16,21.6c0.42,0.53 1.23,0.53 1.66,0L23.66,8.11z"
-            android:fillColor="#4DFFFFFF"/>
-        <path
-            android:pathData="M12.82,21.6l8.25,-10.26A13.961,13.961 0,0 0,12 8c-3.46,0 -6.63,1.26 -9.07,3.35l8.23,10.26c0.43,0.52 1.23,0.52 1.66,-0.01z"
-            android:fillColor="#FFFFFFFF"/>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_full_4.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_full_4.xml
deleted file mode 100644
index fd763ff..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_full_4.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="32dp"
-    android:height="29.5dp"
-    android:viewportWidth="25.6"
-    android:viewportHeight="23.6">
-    <group
-        android:translateX="0.8"
-        android:translateY="-0.9">
-        <path
-            android:pathData="M23.66,8.11c0.39,-0.48 0.29,-1.19 -0.22,-1.54C21.67,5.36 17.55,3 12,3 6.44,3 2.33,5.36 0.56,6.57c-0.51,0.35 -0.61,1.06 -0.23,1.54L11.16,21.6c0.42,0.53 1.23,0.53 1.66,0L23.66,8.11z"
-            android:fillColor="#FFFFFFFF"/>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d457307..07375ad 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -406,6 +406,12 @@
     <!-- Content description of the data connection type LTE+. [CHAR LIMIT=NONE] -->
     <string name="data_connection_lte_plus">LTE+</string>
 
+    <!-- Content description of the data connection type 5G. [CHAR LIMIT=NONE] -->
+    <string name="data_connection_5g" translate="false">5G</string>
+
+    <!-- Content description of the data connection type 5G+. [CHAR LIMIT=NONE] -->
+    <string name="data_connection_5g_plus" translate="false">5G+</string>
+
     <!-- Content description of the data connection type CDMA. [CHAR LIMIT=NONE] -->
     <string name="data_connection_cdma">1X</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index eda3c59..4fb1bc5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -44,8 +44,7 @@
     public static final int PULSE_REASON_SENSOR_PICKUP = 3;
     public static final int PULSE_REASON_SENSOR_DOUBLE_TAP = 4;
     public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5;
-    public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 6;
-    public static final int REASON_SENSOR_WAKE_UP = 7;
+    public static final int REASON_SENSOR_WAKE_UP = 6;
 
     private static boolean sRegisterKeyguardCallback = true;
 
@@ -212,7 +211,6 @@
             case PULSE_REASON_SENSOR_PICKUP: return "pickup";
             case PULSE_REASON_SENSOR_DOUBLE_TAP: return "doubletap";
             case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress";
-            case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakeLockScreen";
             case REASON_SENSOR_WAKE_UP: return "wakeup";
             default: throw new IllegalArgumentException("bad reason: " + pulseReason);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 7e77843..c2676d0 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -17,7 +17,6 @@
 package com.android.systemui.doze;
 
 import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_DISPLAY;
-import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
 
 import android.annotation.AnyThread;
 import android.app.ActivityManager;
@@ -26,7 +25,6 @@
 import android.content.Context;
 import android.database.ContentObserver;
 import android.hardware.Sensor;
-import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.hardware.TriggerEvent;
@@ -114,14 +112,7 @@
                         DozeLog.PULSE_REASON_SENSOR_LONG_PRESS,
                         true /* reports touch coordinates */,
                         true /* touchscreen */),
-                new PluginTriggerSensor(
-                        new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN),
-                        Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
-                        true /* configured */,
-                        DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
-                        false /* reports touch coordinates */,
-                        false /* touchscreen */),
-                new PluginTriggerSensor(
+                new PluginSensor(
                         new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY),
                         Settings.Secure.DOZE_WAKE_SCREEN_GESTURE,
                         true /* configured */,
@@ -272,7 +263,7 @@
         }
 
         @Override
-        public void onSensorChanged(SensorEvent event) {
+        public void onSensorChanged(android.hardware.SensorEvent event) {
             if (DEBUG) Log.d(TAG, "onSensorChanged " + event);
 
             mCurrentlyFar = event.values[0] >= event.sensor.getMaximumRange();
@@ -417,7 +408,7 @@
 
         protected String triggerEventToString(TriggerEvent event) {
             if (event == null) return null;
-            final StringBuilder sb = new StringBuilder("TriggerEvent[")
+            final StringBuilder sb = new StringBuilder("SensorEvent[")
                     .append(event.timestamp).append(',')
                     .append(event.sensor.getName());
             if (event.values != null) {
@@ -432,23 +423,19 @@
     /**
      * A Sensor that is injected via plugin.
      */
-    private class PluginTriggerSensor extends TriggerSensor {
+    private class PluginSensor extends TriggerSensor {
 
         private final SensorManagerPlugin.Sensor mPluginSensor;
-        private final SensorManagerPlugin.TriggerEventListener mTriggerEventListener = (event) -> {
+        private final SensorManagerPlugin.SensorEventListener mTriggerEventListener = (event) -> {
             DozeLog.traceSensor(mContext, mPulseReason);
             mHandler.post(mWakeLock.wrap(() -> {
-                if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event));
-                mRegistered = false;
+                if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event));
                 mCallback.onSensorPulse(mPulseReason, true /* sensorPerformsProxCheck */, -1, -1,
                         event.getValues());
-                if (!mRegistered) {
-                    updateListener();  // reregister, this sensor only fires once
-                }
             }));
         };
 
-        PluginTriggerSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
+        PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
                 int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) {
             super(null, setting, configured, pulseReason, reportsTouchCoordinates,
                     requiresTouchscreen);
@@ -460,13 +447,13 @@
             if (!mConfigured) return;
             AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager;
             if (mRequested && !mDisabled && enabledBySetting() && !mRegistered) {
-                asyncSensorManager.requestPluginTriggerSensor(mPluginSensor, mTriggerEventListener);
+                asyncSensorManager.registerPluginListener(mPluginSensor, mTriggerEventListener);
                 mRegistered = true;
-                if (DEBUG) Log.d(TAG, "requestPluginTriggerSensor");
+                if (DEBUG) Log.d(TAG, "registerPluginListener");
             } else if (mRegistered) {
-                asyncSensorManager.cancelPluginTriggerSensor(mPluginSensor, mTriggerEventListener);
+                asyncSensorManager.unregisterPluginListener(mPluginSensor, mTriggerEventListener);
                 mRegistered = false;
-                if (DEBUG) Log.d(TAG, "cancelPluginTriggerSensor");
+                if (DEBUG) Log.d(TAG, "unregisterPluginListener");
             }
         }
 
@@ -479,7 +466,7 @@
                     .append(", mSensor=").append(mPluginSensor).append("}").toString();
         }
 
-        private String triggerEventToString(SensorManagerPlugin.TriggerEvent event) {
+        private String triggerEventToString(SensorManagerPlugin.SensorEvent event) {
             if (event == null) return null;
             final StringBuilder sb = new StringBuilder("PluginTriggerEvent[")
                     .append(event.getSensor()).append(',')
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index afe9a74..1da8976 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -53,6 +53,12 @@
     /** adb shell am broadcast -a com.android.systemui.doze.pulse com.android.systemui */
     private static final String PULSE_ACTION = "com.android.systemui.doze.pulse";
 
+    /**
+     * Last value sent by the wake-display sensor.
+     * Assuming that the screen should start on.
+     */
+    private static boolean sWakeDisplaySensorState = true;
+
     private final Context mContext;
     private final DozeMachine mMachine;
     private final DozeSensors mDozeSensors;
@@ -128,7 +134,6 @@
         boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
         boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
         boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS;
-        boolean isWakeLockScreen = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN;
         boolean isWakeDisplay = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP;
         boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0;
 
@@ -145,14 +150,6 @@
                 if (isDoubleTap) {
                     mDozeHost.onDoubleTap(screenX, screenY);
                     mMachine.wakeUp();
-                } else if (isWakeLockScreen) {
-                    if (wakeEvent) {
-                        mDozeHost.setPassiveInterrupt(true);
-                        mMachine.wakeUp();
-                        DozeLog.traceLockScreenWakeUp(wakeEvent);
-                    } else {
-                        if (DEBUG) Log.d(TAG, "Unpulsing");
-                    }
                 } else if (isPickup) {
                     mDozeHost.setPassiveInterrupt(true);
                     mMachine.wakeUp();
@@ -199,6 +196,7 @@
         DozeMachine.State state = mMachine.getState();
         boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
         boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
+        sWakeDisplaySensorState = wake;
 
         if (wake) {
             proximityCheckThenCall((result) -> {
@@ -234,6 +232,9 @@
                 }
                 mDozeSensors.setListening(true);
                 mDozeHost.setPassiveInterrupt(false);
+                if (newState == DozeMachine.State.DOZE_AOD && !sWakeDisplaySensorState) {
+                    onWakeScreen(false);
+                }
                 break;
             case DOZE_AOD_PAUSED:
             case DOZE_AOD_PAUSING:
diff --git a/packages/SystemUI/src/com/android/systemui/doze/LockScreenWakeUpController.java b/packages/SystemUI/src/com/android/systemui/doze/LockScreenWakeUpController.java
new file mode 100644
index 0000000..ebfafce
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/LockScreenWakeUpController.java
@@ -0,0 +1,121 @@
+/*
+ * 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.systemui.doze;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.hardware.AmbientDisplayConfiguration;
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.SensorManagerPlugin;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.util.AsyncSensorManager;
+
+/**
+ * Controller responsible for waking up or making the device sleep based on ambient sensors.
+ */
+public class LockScreenWakeUpController implements StatusBarStateController.StateListener,
+        SensorManagerPlugin.SensorEventListener {
+
+    private static final String TAG = LockScreenWakeUpController.class.getSimpleName();
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final AsyncSensorManager mAsyncSensorManager;
+    private final SensorManagerPlugin.Sensor mSensor;
+    private final AmbientDisplayConfiguration mAmbientConfiguration;
+    private final PowerManager mPowerManager;
+    private final DozeHost mDozeHost;
+    private final Handler mHandler;
+    private boolean mRegistered;
+    private boolean mDozing;
+
+    public LockScreenWakeUpController(Context context, DozeHost dozeHost) {
+        this(Dependency.get(AsyncSensorManager.class),
+                new SensorManagerPlugin.Sensor(SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN),
+                new AmbientDisplayConfiguration(context),
+                context.getSystemService(PowerManager.class),
+                dozeHost, Dependency.get(StatusBarStateController.class), new Handler());
+    }
+
+    @VisibleForTesting
+    public LockScreenWakeUpController(AsyncSensorManager asyncSensorManager,
+            SensorManagerPlugin.Sensor sensor, AmbientDisplayConfiguration ambientConfiguration,
+            PowerManager powerManager, DozeHost dozeHost,
+            StatusBarStateController statusBarStateController, Handler handler) {
+        mAsyncSensorManager = asyncSensorManager;
+        mSensor = sensor;
+        mAmbientConfiguration = ambientConfiguration;
+        mPowerManager = powerManager;
+        mDozeHost = dozeHost;
+        mHandler = handler;
+        statusBarStateController.addCallback(this);
+    }
+
+    @Override
+    public void onStateChanged(int newState) {
+        boolean isLockScreen = newState == StatusBarState.KEYGUARD
+                || newState == StatusBarState.SHADE_LOCKED;
+
+        if (!mAmbientConfiguration.wakeLockScreenGestureEnabled(UserHandle.USER_CURRENT)) {
+            if (mRegistered) {
+                mAsyncSensorManager.unregisterPluginListener(mSensor, this);
+                mRegistered = false;
+            }
+            return;
+        }
+
+        if (isLockScreen && !mRegistered) {
+            mAsyncSensorManager.registerPluginListener(mSensor, this);
+            mRegistered = true;
+        } else if (!isLockScreen && mRegistered) {
+            mAsyncSensorManager.unregisterPluginListener(mSensor, this);
+            mRegistered = false;
+        }
+    }
+
+    @Override
+    public void onDozingChanged(boolean isDozing) {
+        mDozing = isDozing;
+    }
+
+    @Override
+    public void onSensorChanged(SensorManagerPlugin.SensorEvent event) {
+        mHandler.post(()-> {
+            float[] rawValues = event.getValues();
+            boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0;
+
+            DozeLog.traceLockScreenWakeUp(wakeEvent);
+            if (wakeEvent && mDozing) {
+                mDozeHost.setPassiveInterrupt(true);
+                if (DEBUG) Log.d(TAG, "Wake up.");
+                mPowerManager.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
+            } else if (!wakeEvent && !mDozing) {
+                if (DEBUG) Log.d(TAG, "Nap time.");
+                mPowerManager.goToSleep(SystemClock.uptimeMillis(),
+                        PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
+            } else if (DEBUG) {
+                Log.d(TAG, "Skip sensor event. Wake? " + wakeEvent + " dozing: " + mDozing);
+            }
+        });
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index d8f7b71..6939ae7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -47,6 +47,7 @@
 import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.WifiIcons;
 
 import java.util.List;
 
@@ -190,7 +191,7 @@
         } else if (!state.value) {
             state.slash.isSlashed = true;
             state.state = Tile.STATE_INACTIVE;
-            state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disabled);
+            state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_DISABLED);
             state.label = r.getString(R.string.quick_settings_wifi_label);
         } else if (wifiConnected) {
             state.icon = ResourceIcon.get(cb.wifiSignalIconId);
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 a508f1b..6caea1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -148,6 +148,7 @@
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.doze.DozeReceiver;
+import com.android.systemui.doze.LockScreenWakeUpController;
 import com.android.systemui.fragments.ExtensionFragmentListener;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -581,6 +582,7 @@
     protected NotificationPresenter mPresenter;
     private NotificationActivityStarter mNotificationActivityStarter;
     private boolean mPulsing;
+    private LockScreenWakeUpController mLockScreenWakeUpController;
 
     @Override
     public void onActiveStateChanged(int code, int uid, String packageName, boolean active) {
@@ -984,6 +986,7 @@
         for (int i = 0; i < pattern.length; i++) {
             mCameraLaunchGestureVibePattern[i] = pattern[i];
         }
+        mLockScreenWakeUpController = new LockScreenWakeUpController(mContext, mDozeServiceHost);
 
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
index 6ee6cb2..53d0228 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java
@@ -28,7 +28,6 @@
 import com.android.settingslib.wifi.AccessPoint;
 import com.android.settingslib.wifi.WifiTracker;
 import com.android.settingslib.wifi.WifiTracker.WifiListener;
-import com.android.systemui.R;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -43,13 +42,7 @@
     // network credentials.  This is used by quick settings for secured networks.
     private static final String EXTRA_START_CONNECT_SSID = "wifi_start_connect_ssid";
 
-    private static final int[] ICONS = {
-        R.drawable.ic_qs_wifi_full_0,
-        R.drawable.ic_qs_wifi_full_1,
-        R.drawable.ic_qs_wifi_full_2,
-        R.drawable.ic_qs_wifi_full_3,
-        R.drawable.ic_qs_wifi_full_4,
-    };
+    private static final int[] ICONS = WifiIcons.WIFI_FULL_ICONS;
 
     private final Context mContext;
     private final ArrayList<AccessPointCallback> mCallbacks = new ArrayList<AccessPointCallback>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index e943261..3deede0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -22,6 +22,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.provider.Settings.Global;
+import android.telephony.NetworkRegistrationState;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
@@ -437,7 +438,13 @@
                 mCurrentState.level = mSignalStrength.getLevel();
             }
         }
-        if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
+
+        // When the device is camped on a 5G Non-Standalone network, the data network type is still
+        // LTE. In this case, we first check which 5G icon should be shown.
+        MobileIconGroup nr5GIconGroup = getNr5GIconGroup();
+        if (nr5GIconGroup != null) {
+            mCurrentState.iconGroup = nr5GIconGroup;
+        } else if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
             mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);
         } else {
             mCurrentState.iconGroup = mDefaultIcons;
@@ -464,6 +471,36 @@
         notifyListenersIfNecessary();
     }
 
+    private MobileIconGroup getNr5GIconGroup() {
+        if (mServiceState == null) return null;
+
+        int nrStatus = mServiceState.getNrStatus();
+        if (nrStatus == NetworkRegistrationState.NR_STATUS_CONNECTED) {
+            // Check if the NR 5G is using millimeter wave and the icon is config.
+            if (mServiceState.getNrFrequencyRange() == ServiceState.FREQUENCY_RANGE_MMWAVE) {
+                if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED_MMWAVE)) {
+                    return mConfig.nr5GIconMap.get(Config.NR_CONNECTED_MMWAVE);
+                }
+            }
+
+            // If NR 5G is not using millimeter wave or there is no icon for millimeter wave, we
+            // check the normal 5G icon.
+            if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED)) {
+                return mConfig.nr5GIconMap.get(Config.NR_CONNECTED);
+            }
+        } else if (nrStatus == NetworkRegistrationState.NR_STATUS_NOT_RESTRICTED) {
+            if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED)) {
+                return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED);
+            }
+        } else if (nrStatus == NetworkRegistrationState.NR_STATUS_RESTRICTED) {
+            if (mConfig.nr5GIconMap.containsKey(Config.NR_RESTRICTED)) {
+                return mConfig.nr5GIconMap.get(Config.NR_RESTRICTED);
+            }
+        }
+
+        return null;
+    }
+
     private boolean isDataDisabled() {
         return !mPhone.getDataEnabled(mSubscriptionInfo.getSubscriptionId());
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 70a3589..bc43120 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -60,15 +60,19 @@
 import com.android.systemui.R;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+import com.android.systemui.statusbar.policy.MobileSignalController.MobileIconGroup;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 
 /** Platform implementation of the network controller. **/
 public class NetworkControllerImpl extends BroadcastReceiver
@@ -1029,6 +1033,13 @@
 
     @VisibleForTesting
     static class Config {
+        static final int NR_CONNECTED_MMWAVE = 1;
+        static final int NR_CONNECTED = 2;
+        static final int NR_NOT_RESTRICTED = 3;
+        static final int NR_RESTRICTED = 4;
+
+        Map<Integer, MobileIconGroup> nr5GIconMap = new HashMap<>();
+
         boolean showAtLeast3G = false;
         boolean alwaysShowCdmaRssi = false;
         boolean show4gForLte = false;
@@ -1037,6 +1048,19 @@
         boolean inflateSignalStrengths = false;
         boolean alwaysShowDataRatIcon = false;
 
+        /**
+         * Mapping from NR 5G status string to an integer. The NR 5G status string should match
+         * those in carrier config.
+         */
+        private static final Map<String, Integer> NR_STATUS_STRING_TO_INDEX;
+        static {
+            NR_STATUS_STRING_TO_INDEX = new HashMap<>(4);
+            NR_STATUS_STRING_TO_INDEX.put("connected_mmwave", NR_CONNECTED_MMWAVE);
+            NR_STATUS_STRING_TO_INDEX.put("connected", NR_CONNECTED);
+            NR_STATUS_STRING_TO_INDEX.put("not_restricted", NR_NOT_RESTRICTED);
+            NR_STATUS_STRING_TO_INDEX.put("restricted", NR_RESTRICTED);
+        }
+
         static Config readConfig(Context context) {
             Config config = new Config();
             Resources res = context.getResources();
@@ -1061,8 +1085,46 @@
                         CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL);
                 config.hideLtePlus = b.getBoolean(
                         CarrierConfigManager.KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL);
+                String nr5GIconConfiguration =
+                        b.getString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING);
+                if (!TextUtils.isEmpty(nr5GIconConfiguration)) {
+                    String[] nr5GIconConfigPairs = nr5GIconConfiguration.trim().split(",");
+                    for (String pair : nr5GIconConfigPairs) {
+                        add5GIconMapping(pair, config);
+                    }
+                }
             }
+
             return config;
         }
+
+        /**
+         * Add a mapping from NR 5G status to the 5G icon. All the icon resources come from
+         * {@link TelephonyIcons}.
+         *
+         * @param keyValuePair the NR 5G status and icon name separated by a colon.
+         * @param config container that used to store the parsed configs.
+         */
+        @VisibleForTesting
+        static void add5GIconMapping(String keyValuePair, Config config) {
+            String[] kv = (keyValuePair.trim().toLowerCase()).split(":");
+
+            if (kv.length != 2) {
+                if (DEBUG) Log.e(TAG, "Invalid 5G icon configuration, config = " + keyValuePair);
+                return;
+            }
+
+            String key = kv[0], value = kv[1];
+
+            // There is no icon config for the specific 5G status.
+            if (value.equals("none")) return;
+
+            if (NR_STATUS_STRING_TO_INDEX.containsKey(key)
+                    && TelephonyIcons.ICON_NAME_TO_ICON.containsKey(value)) {
+                config.nr5GIconMap.put(
+                        NR_STATUS_STRING_TO_INDEX.get(key),
+                        TelephonyIcons.ICON_NAME_TO_ICON.get(value));
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index bd76820..7347f66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -19,6 +19,9 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.MobileSignalController.MobileIconGroup;
 
+import java.util.HashMap;
+import java.util.Map;
+
 class TelephonyIcons {
     //***** Data connection icons
     static final int FLIGHT_MODE_ICON = R.drawable.stat_sys_airplane_mode;
@@ -33,6 +36,8 @@
     static final int ICON_4G = R.drawable.ic_4g_mobiledata;
     static final int ICON_4G_PLUS = R.drawable.ic_4g_plus_mobiledata;
     static final int ICON_1X = R.drawable.ic_1x_mobiledata;
+    static final int ICON_5G = R.drawable.ic_5g_mobiledata;
+    static final int ICON_5G_PLUS = R.drawable.ic_5g_plus_mobiledata;
 
     static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup(
             "CARRIER_NETWORK_CHANGE",
@@ -199,6 +204,34 @@
             TelephonyIcons.ICON_LTE_PLUS,
             true);
 
+    static final MobileIconGroup NR_5G = new MobileIconGroup(
+            "5G",
+            null,
+            null,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0,
+            0,
+            0,
+            0,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.data_connection_5g,
+            TelephonyIcons.ICON_5G,
+            true);
+
+    static final MobileIconGroup NR_5G_PLUS = new MobileIconGroup(
+            "5G_PLUS",
+            null,
+            null,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0,
+            0,
+            0,
+            0,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.data_connection_5g_plus,
+            TelephonyIcons.ICON_5G_PLUS,
+            true);
+
     static final MobileIconGroup DATA_DISABLED = new MobileIconGroup(
             "DataDisabled",
             null,
@@ -211,5 +244,27 @@
             R.string.cell_data_off_content_description,
             0,
             false);
+
+    /** Mapping icon name(lower case) to the icon object. */
+    static final Map<String, MobileIconGroup> ICON_NAME_TO_ICON;
+    static {
+        ICON_NAME_TO_ICON = new HashMap<>();
+        ICON_NAME_TO_ICON.put("carrier_network_change", CARRIER_NETWORK_CHANGE);
+        ICON_NAME_TO_ICON.put("3g", THREE_G);
+        ICON_NAME_TO_ICON.put("wfc", WFC);
+        ICON_NAME_TO_ICON.put("unknown", UNKNOWN);
+        ICON_NAME_TO_ICON.put("e", E);
+        ICON_NAME_TO_ICON.put("1x", ONE_X);
+        ICON_NAME_TO_ICON.put("g", G);
+        ICON_NAME_TO_ICON.put("h", H);
+        ICON_NAME_TO_ICON.put("h+", H_PLUS);
+        ICON_NAME_TO_ICON.put("4g", FOUR_G);
+        ICON_NAME_TO_ICON.put("4g+", FOUR_G_PLUS);
+        ICON_NAME_TO_ICON.put("lte", LTE);
+        ICON_NAME_TO_ICON.put("lte+", LTE_PLUS);
+        ICON_NAME_TO_ICON.put("5g", NR_5G);
+        ICON_NAME_TO_ICON.put("5g_plus", NR_5G_PLUS);
+        ICON_NAME_TO_ICON.put("datadisable", DATA_DISABLED);
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
index 374408d..f629863 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiIcons.java
@@ -32,19 +32,24 @@
               R.drawable.stat_sys_wifi_signal_4_fully }
         };
 
+    static final int[] WIFI_FULL_ICONS = {
+            com.android.internal.R.drawable.ic_wifi_signal_0,
+            com.android.internal.R.drawable.ic_wifi_signal_1,
+            com.android.internal.R.drawable.ic_wifi_signal_2,
+            com.android.internal.R.drawable.ic_wifi_signal_3,
+            com.android.internal.R.drawable.ic_wifi_signal_4
+    };
+
     public static final int[][] QS_WIFI_SIGNAL_STRENGTH = {
             { R.drawable.ic_qs_wifi_0,
               R.drawable.ic_qs_wifi_1,
               R.drawable.ic_qs_wifi_2,
               R.drawable.ic_qs_wifi_3,
               R.drawable.ic_qs_wifi_4 },
-            { R.drawable.ic_qs_wifi_full_0,
-              R.drawable.ic_qs_wifi_full_1,
-              R.drawable.ic_qs_wifi_full_2,
-              R.drawable.ic_qs_wifi_full_3,
-              R.drawable.ic_qs_wifi_full_4 }
+            WIFI_FULL_ICONS
         };
 
+    public static final int QS_WIFI_DISABLED = com.android.internal.R.drawable.ic_wifi_signal_0;
     static final int QS_WIFI_NO_NETWORK = R.drawable.ic_qs_wifi_no_network;
     static final int WIFI_NO_NETWORK = R.drawable.stat_sys_wifi_signal_null;
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java b/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
index 0dd8937..88cbbb5 100644
--- a/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
+++ b/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
@@ -76,8 +76,9 @@
     }
 
     @Override
-    protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, int delayUs,
-            Handler handler, int maxReportLatencyUs, int reservedFlags) {
+    protected boolean registerListenerImpl(SensorEventListener listener,
+            Sensor sensor, int delayUs, Handler handler, int maxReportLatencyUs,
+            int reservedFlags) {
         mHandler.post(() -> {
             if (!mInner.registerListener(listener, sensor, delayUs, maxReportLatencyUs, handler)) {
                 Log.e(TAG, "Registering " + listener + " for " + sensor + " failed.");
@@ -146,23 +147,28 @@
      * @param sensor
      * @param listener
      */
-    public void requestPluginTriggerSensor(SensorManagerPlugin.Sensor sensor,
-            SensorManagerPlugin.TriggerEventListener listener) {
+    public void registerPluginListener(SensorManagerPlugin.Sensor sensor,
+            SensorManagerPlugin.SensorEventListener listener) {
         if (mPlugins.isEmpty()) {
             Log.w(TAG, "No plugins registered");
         }
         mHandler.post(() -> {
             for (int i = 0; i < mPlugins.size(); i++) {
-                mPlugins.get(i).registerTriggerEvent(sensor, listener);
+                mPlugins.get(i).registerListener(sensor, listener);
             }
         });
     }
 
-    public void cancelPluginTriggerSensor(SensorManagerPlugin.Sensor sensor,
-            SensorManagerPlugin.TriggerEventListener listener) {
+    /**
+     * Unregisters all sensors that match the give type for all plugins.
+     * @param sensor
+     * @param listener
+     */
+    public void unregisterPluginListener(SensorManagerPlugin.Sensor sensor,
+            SensorManagerPlugin.SensorEventListener listener) {
         mHandler.post(() -> {
             for (int i = 0; i < mPlugins.size(); i++) {
-                mPlugins.get(i).unregisterTriggerEvent(sensor, listener);
+                mPlugins.get(i).unregisterListener(sensor, listener);
             }
         });
     }
@@ -185,7 +191,8 @@
     }
 
     @Override
-    protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
+    protected void unregisterListenerImpl(SensorEventListener listener,
+            Sensor sensor) {
         mHandler.post(() -> {
             if (sensor == null) {
                 mInner.unregisterListener(listener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/LockScreenWakeUpControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/LockScreenWakeUpControllerTest.java
new file mode 100644
index 0000000..8963b59
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/LockScreenWakeUpControllerTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.systemui.doze;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.os.PowerManager;
+import android.support.test.filters.SmallTest;
+
+import com.android.internal.hardware.AmbientDisplayConfiguration;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.SensorManagerPlugin;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.util.AsyncSensorManager;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(JUnit4.class)
+@SmallTest
+public class LockScreenWakeUpControllerTest extends SysuiTestCase {
+
+    @Mock
+    private AsyncSensorManager mAsyncSensorManager;
+    @Mock
+    private SensorManagerPlugin.Sensor mSensor;
+    @Mock
+    private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
+    @Mock
+    private PowerManager mPowerManager;
+    @Mock
+    private DozeHost mDozeHost;
+    @Mock
+    private StatusBarStateController mStatusBarStateController;
+    @Mock
+    private Handler mHandler;
+
+    private LockScreenWakeUpController mLockScreenWakeUpController;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        doAnswer(invocation -> {
+            ((Runnable) invocation.getArgument(0)).run();
+            return null;
+        }).when(mHandler).post(any());
+
+        mLockScreenWakeUpController = new LockScreenWakeUpController(mAsyncSensorManager, mSensor,
+                mAmbientDisplayConfiguration, mPowerManager, mDozeHost, mStatusBarStateController,
+                mHandler);
+    }
+
+    @Test
+    public void testOnStateChanged_registersUnregistersListener() {
+        when(mAmbientDisplayConfiguration.wakeLockScreenGestureEnabled(anyInt())).thenReturn(true);
+        mLockScreenWakeUpController.onStateChanged(StatusBarState.KEYGUARD);
+        mLockScreenWakeUpController.onStateChanged(StatusBarState.SHADE);
+
+        verify(mAsyncSensorManager, times(1)).registerPluginListener(eq(mSensor),
+                eq(mLockScreenWakeUpController));
+
+        mLockScreenWakeUpController.onStateChanged(StatusBarState.SHADE);
+        verify(mAsyncSensorManager).unregisterPluginListener(eq(mSensor),
+                eq(mLockScreenWakeUpController));
+    }
+
+    @Test
+    public void testOnStateChanged_disabledSensor() {
+        when(mAmbientDisplayConfiguration.wakeLockScreenGestureEnabled(anyInt()))
+                .thenReturn(false);
+        mLockScreenWakeUpController.onStateChanged(StatusBarState.KEYGUARD);
+        mLockScreenWakeUpController.onStateChanged(StatusBarState.SHADE);
+
+        verify(mAsyncSensorManager, never()).registerPluginListener(eq(mSensor),
+                eq(mLockScreenWakeUpController));
+    }
+
+    @Test
+    public void testOnSensorChanged_postsToMainThread() {
+        SensorManagerPlugin.SensorEvent event = new SensorManagerPlugin.SensorEvent(mSensor, 0);
+        mLockScreenWakeUpController.onSensorChanged(event);
+
+        verify(mHandler).post(any());
+    }
+
+    @Test
+    public void testOnSensorChanged_wakeUpWhenDozing() {
+        SensorManagerPlugin.SensorEvent event =
+                new SensorManagerPlugin.SensorEvent(mSensor, 0, new float[] {1});
+        mLockScreenWakeUpController.onSensorChanged(event);
+        verify(mPowerManager, never()).wakeUp(anyLong(), any());
+
+        mLockScreenWakeUpController.onDozingChanged(true);
+        mLockScreenWakeUpController.onSensorChanged(event);
+        verify(mPowerManager).wakeUp(anyLong(), any());
+    }
+
+    @Test
+    public void testOnSensorChanged_sleepsWhenAwake() {
+        boolean[] goToSleep = new boolean[] {false};
+        doAnswer(invocation -> goToSleep[0] = true)
+                .when(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
+        SensorManagerPlugin.SensorEvent event =
+                new SensorManagerPlugin.SensorEvent(mSensor, 0, new float[] {0});
+        mLockScreenWakeUpController.onDozingChanged(true);
+        mLockScreenWakeUpController.onSensorChanged(event);
+        Assert.assertFalse("goToSleep should have never been called.", goToSleep[0]);
+
+        mLockScreenWakeUpController.onDozingChanged(false);
+        mLockScreenWakeUpController.onSensorChanged(event);
+        Assert.assertTrue("goToSleep should have been called.", goToSleep[0]);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 35f0dba..fdbf090 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -212,6 +212,11 @@
             NetworkCapabilities.TRANSPORT_CELLULAR, true, true);
     }
 
+    public void setupDefaultNr5GIconConfiguration() {
+        NetworkControllerImpl.Config.add5GIconMapping("connected_mmwave:5g_plus", mConfig);
+        NetworkControllerImpl.Config.add5GIconMapping("connected:5g", mConfig);
+    }
+
     public void setConnectivityViaBroadcast(
         int networkType, boolean validated, boolean isConnected) {
         setConnectivityCommon(networkType, validated, isConnected);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index d42940a..2baea1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -1,11 +1,14 @@
 package com.android.systemui.statusbar.policy;
 
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import android.net.NetworkCapabilities;
 import android.os.Looper;
+import android.telephony.NetworkRegistrationState;
+import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -16,6 +19,7 @@
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mockito;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -141,6 +145,47 @@
     }
 
     @Test
+    public void testNr5GIcon_NrConnectedWithoutMMWave_show5GIcon() {
+        setupDefaultNr5GIconConfiguration();
+        setupDefaultSignal();
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+                TelephonyManager.NETWORK_TYPE_LTE);
+        ServiceState ss = Mockito.mock(ServiceState.class);
+        doReturn(NetworkRegistrationState.NR_STATUS_CONNECTED).when(ss).getNrStatus();
+        doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange();
+        mPhoneStateListener.onServiceStateChanged(ss);
+
+        verifyDataIndicators(TelephonyIcons.ICON_5G);
+    }
+
+    @Test
+    public void testNr5GIcon_NrConnectedWithMMWave_show5GPlusIcon() {
+        setupDefaultNr5GIconConfiguration();
+        setupDefaultSignal();
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+                TelephonyManager.NETWORK_TYPE_LTE);
+        ServiceState ss = Mockito.mock(ServiceState.class);
+        doReturn(NetworkRegistrationState.NR_STATUS_CONNECTED).when(ss).getNrStatus();
+        doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(ss).getNrFrequencyRange();
+        mPhoneStateListener.onServiceStateChanged(ss);
+
+        verifyDataIndicators(TelephonyIcons.ICON_5G_PLUS);
+    }
+
+    @Test
+    public void testNr5GIcon_NrRestricted_showLteIcon() {
+        setupDefaultNr5GIconConfiguration();
+        setupDefaultSignal();
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
+                TelephonyManager.NETWORK_TYPE_LTE);
+        ServiceState ss = Mockito.mock(ServiceState.class);
+        doReturn(NetworkRegistrationState.NR_STATUS_RESTRICTED).when(ss).getNrStatus();
+        mPhoneStateListener.onServiceStateChanged(mServiceState);
+
+        verifyDataIndicators(TelephonyIcons.ICON_LTE);
+    }
+
+    @Test
     public void testDataDisabledIcon_UserNotSetup() {
         setupNetworkController();
         when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
@@ -222,5 +267,4 @@
                 true, DEFAULT_QS_SIGNAL_STRENGTH, dataIcon, false,
                 false);
     }
-
 }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index a917ced..2cbab49 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -477,6 +477,7 @@
      * requires on-screen confirmation by the user.
      */
     public void adbBackup(
+            @UserIdInt int userId,
             ParcelFileDescriptor fd,
             boolean includeApks,
             boolean includeObbs,
@@ -487,6 +488,8 @@
             boolean doCompress,
             boolean doKeyValue,
             String[] packageNames) {
+        enforceCallingPermissionOnUserId(userId, "adbBackup");
+
         mUserBackupManagerService.adbBackup(
                 fd,
                 includeApks,
@@ -505,7 +508,9 @@
      * is synchronous and does not return to the caller until the restore has been completed. It
      * requires on-screen confirmation by the user.
      */
-    public void adbRestore(ParcelFileDescriptor fd) {
+    public void adbRestore(@UserIdInt int userId, ParcelFileDescriptor fd) {
+        enforceCallingPermissionOnUserId(userId, "setBackupEnabled");
+
         mUserBackupManagerService.adbRestore(fd);
     }
 
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index ed6ff9b..4acd5c4 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -389,14 +389,13 @@
         backupNowForUser(binderGetCallingUserId());
     }
 
-    @Override
-    public void adbBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
-            boolean includeShared, boolean doWidgets, boolean allApps,
-            boolean allIncludesSystem, boolean doCompress, boolean doKeyValue, String[] packageNames)
-                    throws RemoteException {
+    public void adbBackup(@UserIdInt int userId, ParcelFileDescriptor fd,
+            boolean includeApks, boolean includeObbs, boolean includeShared, boolean doWidgets,
+            boolean allApps, boolean allIncludesSystem, boolean doCompress, boolean doKeyValue,
+            String[] packageNames) throws RemoteException {
         BackupManagerService svc = mService;
         if (svc != null) {
-            svc.adbBackup(fd, includeApks, includeObbs, includeShared, doWidgets,
+            svc.adbBackup(userId, fd, includeApks, includeObbs, includeShared, doWidgets,
                     allApps, allIncludesSystem, doCompress, doKeyValue, packageNames);
         }
     }
@@ -410,10 +409,10 @@
     }
 
     @Override
-    public void adbRestore(ParcelFileDescriptor fd) throws RemoteException {
+    public void adbRestore(@UserIdInt int userId, ParcelFileDescriptor fd) throws RemoteException {
         BackupManagerService svc = mService;
         if (svc != null) {
-            svc.adbRestore(fd);
+            svc.adbRestore(userId, fd);
         }
     }
 
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 5220a59..796ef40 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -37,6 +37,7 @@
 import static com.android.server.backup.internal.BackupHandler.MSG_SCHEDULE_BACKUP_PACKAGE;
 
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.AppGlobals;
@@ -2423,9 +2424,9 @@
      * return to the caller until the backup has been completed. It requires on-screen confirmation
      * by the user.
      */
-    public void adbBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,
-            boolean includeShared, boolean doWidgets, boolean doAllApps, boolean includeSystem,
-            boolean compress, boolean doKeyValue, String[] pkgList) {
+    public void adbBackup(ParcelFileDescriptor fd, boolean includeApks,
+            boolean includeObbs, boolean includeShared, boolean doWidgets, boolean doAllApps,
+            boolean includeSystem, boolean compress, boolean doKeyValue, String[] pkgList) {
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "adbBackup");
 
         final int callingUserHandle = UserHandle.getCallingUserId();
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index b6c4921..1ef3e94 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1684,7 +1684,9 @@
         }
 
         synchronized (mRecords) {
-            mEmergencyNumberList = TelephonyManager.getDefault().getCurrentEmergencyNumberList();
+            TelephonyManager tm = (TelephonyManager) mContext.getSystemService(
+                    Context.TELEPHONY_SERVICE);
+            mEmergencyNumberList = tm.getCurrentEmergencyNumberList();
 
             for (Record r : mRecords) {
                 if (r.matchPhoneStateListenerEvent(
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index ab9ba08..a376e7a 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -724,6 +724,8 @@
         synchronized (mStats) {
             mStats.noteWifiOnLocked();
         }
+        StatsLog.write(StatsLog.WIFI_ENABLED_STATE_CHANGED,
+                StatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__ON);
     }
 
     public void noteWifiOff() {
@@ -731,6 +733,8 @@
         synchronized (mStats) {
             mStats.noteWifiOffLocked();
         }
+        StatsLog.write(StatsLog.WIFI_ENABLED_STATE_CHANGED,
+                StatsLog.WIFI_ENABLED_STATE_CHANGED__STATE__OFF);
     }
 
     public void noteStartAudio(int uid) {
@@ -865,6 +869,9 @@
         synchronized (mStats) {
             mStats.noteWifiRunningLocked(ws);
         }
+        // TODO: Log WIFI_RUNNING_STATE_CHANGED in a better spot to include Hotspot too.
+        StatsLog.write(StatsLog.WIFI_RUNNING_STATE_CHANGED,
+                ws, StatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
     }
 
     public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) {
@@ -872,6 +879,10 @@
         synchronized (mStats) {
             mStats.noteWifiRunningChangedLocked(oldWs, newWs);
         }
+        StatsLog.write(StatsLog.WIFI_RUNNING_STATE_CHANGED,
+                newWs, StatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__ON);
+        StatsLog.write(StatsLog.WIFI_RUNNING_STATE_CHANGED,
+                oldWs, StatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
     }
 
     public void noteWifiStopped(WorkSource ws) {
@@ -879,6 +890,8 @@
         synchronized (mStats) {
             mStats.noteWifiStoppedLocked(ws);
         }
+        StatsLog.write(StatsLog.WIFI_RUNNING_STATE_CHANGED,
+                ws, StatsLog.WIFI_RUNNING_STATE_CHANGED__STATE__OFF);
     }
 
     public void noteWifiState(int wifiState, String accessPoint) {
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index 90fe30c..a584914 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -123,9 +123,8 @@
      * if the file is not available.
      */
     public static String readCmdlineFromProcfs(int pid) {
-        String path = String.format(Locale.US, PROC_CMDLINE_FILE_FMT, pid);
-        String cmdline = readFileContents(path);
-        return cmdline != null ? cmdline : "";
+        final String path = String.format(Locale.US, PROC_CMDLINE_FILE_FMT, pid);
+        return parseCmdlineFromProcfs(readFileContents(path));
     }
 
     private static String readFileContents(String path) {
@@ -210,6 +209,24 @@
         return m.find() ? Long.parseLong(m.group(1)) * BYTES_IN_KILOBYTE : 0;
     }
 
+
+    /**
+     * Parses cmdline out of the contents of the /proc/pid/cmdline file in procfs.
+     *
+     * Parsing is required to strip anything after first null byte.
+     */
+    @VisibleForTesting
+    static String parseCmdlineFromProcfs(String cmdline) {
+        if (cmdline == null) {
+            return "";
+        }
+        int firstNullByte = cmdline.indexOf("\0");
+        if (firstNullByte == -1) {
+            return cmdline;
+        }
+        return cmdline.substring(0, firstNullByte);
+    }
+
     /**
      * Returns whether per-app memcg is available on device.
      */
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3d87634..bad259b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3131,7 +3131,11 @@
                 throws RemoteException {
             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
-            Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
+            if (automaticZenRule.getOwner() == null
+                    && automaticZenRule.getConfigurationActivity() == null) {
+                throw new NullPointerException(
+                        "Rule must have a conditionproviderservice and/or configuration activity");
+            }
             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
 
@@ -3144,7 +3148,11 @@
                 throws RemoteException {
             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
-            Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
+            if (automaticZenRule.getOwner() == null
+                    && automaticZenRule.getConfigurationActivity() == null) {
+                throw new NullPointerException(
+                        "Rule must have a conditionproviderservice and/or configuration activity");
+            }
             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
 
@@ -3178,6 +3186,16 @@
         }
 
         @Override
+        public void setAutomaticZenRuleState(String id, Condition condition) {
+            Preconditions.checkNotNull(id, "id is null");
+            Preconditions.checkNotNull(condition, "Condition is null");
+
+            enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
+
+            mZenModeHelper.setAutomaticZenRuleState(id, condition);
+        }
+
+        @Override
         public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
             enforcePolicyAccess(pkg, "setInterruptionFilter");
             final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index b080a73..571f799 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -29,8 +29,11 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
-import java.util.Objects;
 
+/**
+ * Helper class for managing active rules from
+ * {@link android.service.notification.ConditionProviderService CPSes}.
+ */
 public class ZenModeConditions implements ConditionProviders.Callback {
     private static final String TAG = ZenModeHelper.TAG;
     private static final boolean DEBUG = ZenModeHelper.DEBUG;
@@ -41,8 +44,6 @@
     @VisibleForTesting
     protected final ArrayMap<Uri, ComponentName> mSubscriptions = new ArrayMap<>();
 
-    private boolean mFirstEvaluation = true;
-
     public ZenModeConditions(ZenModeHelper helper, ConditionProviders conditionProviders) {
         mHelper = helper;
         mConditionProviders = conditionProviders;
@@ -73,8 +74,10 @@
         final ArraySet<Uri> current = new ArraySet<>();
         evaluateRule(config.manualRule, current, null, processSubscriptions);
         for (ZenRule automaticRule : config.automaticRules.values()) {
-            evaluateRule(automaticRule, current, trigger, processSubscriptions);
-            updateSnoozing(automaticRule);
+            if (automaticRule.component != null) {
+                evaluateRule(automaticRule, current, trigger, processSubscriptions);
+                updateSnoozing(automaticRule);
+            }
         }
 
         synchronized (mSubscriptions) {
@@ -90,7 +93,6 @@
                 }
             }
         }
-        mFirstEvaluation = false;
     }
 
     @Override
@@ -114,23 +116,14 @@
         if (DEBUG) Log.d(TAG, "onConditionChanged " + id + " " + condition);
         ZenModeConfig config = mHelper.getConfig();
         if (config == null) return;
-        ComponentName trigger = null;
-        boolean updated = updateCondition(id, condition, config.manualRule);
-        for (ZenRule automaticRule : config.automaticRules.values()) {
-            updated |= updateCondition(id, condition, automaticRule);
-            updated |= updateSnoozing(automaticRule);
-            if (updated) {
-                trigger = automaticRule.component;
-            }
-        }
-        if (updated) {
-            mHelper.setConfig(config, trigger, "conditionChanged");
-        }
+        mHelper.setAutomaticZenRuleState(id, condition);
     }
 
+    // Only valid for CPS backed rules
     private void evaluateRule(ZenRule rule, ArraySet<Uri> current, ComponentName trigger,
             boolean processSubscriptions) {
         if (rule == null || rule.conditionId == null) return;
+        if (rule.configurationActivity != null) return;
         final Uri id = rule.conditionId;
         boolean isSystemCondition = false;
         for (SystemConditionProviderService sp : mConditionProviders.getSystemProviders()) {
@@ -140,6 +133,7 @@
                 isSystemCondition = true;
             }
         }
+        // ensure that we have a record of the rule if it's backed by an currently alive CPS
         if (!isSystemCondition) {
             final IConditionProvider cp = mConditionProviders.findConditionProvider(rule.component);
             if (DEBUG) Log.d(TAG, "Ensure external rule exists: " + (cp != null) + " for " + id);
@@ -147,7 +141,8 @@
                 mConditionProviders.ensureRecordExists(rule.component, id, cp);
             }
         }
-        if (rule.component == null) {
+        // empty rule? disable and bail early
+        if (rule.component == null && rule.enabler == null) {
             Log.w(TAG, "No component found for automatic rule: " + rule.conditionId);
             rule.enabled = false;
             return;
@@ -155,6 +150,8 @@
         if (current != null) {
             current.add(id);
         }
+
+        // If the rule is bound by a CPS and the CPS is alive, tell them about the rule
         if (processSubscriptions && ((trigger != null && trigger.equals(rule.component))
                 || isSystemCondition)) {
             if (DEBUG) Log.d(TAG, "Subscribing to " + rule.component);
@@ -167,40 +164,20 @@
                 if (DEBUG) Log.d(TAG, "zmc failed to subscribe");
             }
         }
-        if (rule.condition == null) {
+        // backfill the rule state from CPS backed components if it's missing
+        if (rule.component != null && rule.condition == null) {
             rule.condition = mConditionProviders.findCondition(rule.component, rule.conditionId);
             if (rule.condition != null && DEBUG) Log.d(TAG, "Found existing condition for: "
                     + rule.conditionId);
         }
     }
 
-    private boolean isAutomaticActive(ComponentName component) {
-        if (component == null) return false;
-        final ZenModeConfig config = mHelper.getConfig();
-        if (config == null) return false;
-        for (ZenRule rule : config.automaticRules.values()) {
-            if (component.equals(rule.component) && rule.isAutomaticActive()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     private boolean updateSnoozing(ZenRule rule) {
-        if (rule != null && rule.snoozing && (mFirstEvaluation || !rule.isTrueOrUnknown())) {
+        if (rule != null && rule.snoozing && !rule.isTrueOrUnknown()) {
             rule.snoozing = false;
             if (DEBUG) Log.d(TAG, "Snoozing reset for " + rule.conditionId);
             return true;
         }
         return false;
     }
-
-    private boolean updateCondition(Uri id, Condition condition, ZenRule rule) {
-        if (id == null || rule == null || rule.conditionId == null) return false;
-        if (!rule.conditionId.equals(id)) return false;
-        if (Objects.equals(condition, rule.condition)) return false;
-        rule.condition = condition;
-        return true;
-    }
-
 }
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 94d276c..f01d343 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -26,6 +26,8 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -282,20 +284,25 @@
 
     public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
         if (!isSystemRule(automaticZenRule)) {
-            ServiceInfo owner = getServiceInfo(automaticZenRule.getOwner());
-            if (owner == null) {
-                throw new IllegalArgumentException("Owner is not a condition provider service");
+            PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner());
+            if (component == null) {
+                component = getActivityInfo(automaticZenRule.getConfigurationActivity());
             }
-
+            if (component == null) {
+                throw new IllegalArgumentException("Lacking enabled CPS or config activity");
+            }
             int ruleInstanceLimit = -1;
-            if (owner.metaData != null) {
-                ruleInstanceLimit = owner.metaData.getInt(
+            if (component.metaData != null) {
+                ruleInstanceLimit = component.metaData.getInt(
                         ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
             }
-            if (ruleInstanceLimit > 0 && ruleInstanceLimit
-                    < (getCurrentInstanceCount(automaticZenRule.getOwner()) + 1)) {
+            int newRuleInstanceCount = getCurrentInstanceCount(automaticZenRule.getOwner())
+                    + getCurrentInstanceCount(automaticZenRule.getConfigurationActivity())
+                    + 1;
+            if (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount) {
                 throw new IllegalArgumentException("Rule instance limit exceeded");
             }
+
         }
 
         ZenModeConfig newConfig;
@@ -377,11 +384,73 @@
         }
     }
 
-    public int getCurrentInstanceCount(ComponentName owner) {
+    public void setAutomaticZenRuleState(String id, Condition condition) {
+        ZenModeConfig newConfig;
+        synchronized (mConfig) {
+            if (mConfig == null) return;
+
+            newConfig = mConfig.copy();
+        }
+        setAutomaticZenRuleState(newConfig, newConfig.automaticRules.get(id), condition);
+    }
+
+    public void setAutomaticZenRuleState(Uri ruleDefinition, Condition condition) {
+        ZenModeConfig newConfig;
+        synchronized (mConfig) {
+            if (mConfig == null) return;
+            newConfig = mConfig.copy();
+        }
+
+        setAutomaticZenRuleState(newConfig,
+                findMatchingRule(newConfig, ruleDefinition, condition),
+                condition);
+    }
+
+    private void setAutomaticZenRuleState(ZenModeConfig config, ZenRule rule, Condition condition) {
+        if (rule == null) return;
+
+        rule.condition = condition;
+        updateSnoozing(rule);
+        setConfigLocked(config, rule.component, "conditionChanged");
+    }
+
+    private ZenRule findMatchingRule(ZenModeConfig config, Uri id, Condition condition) {
+        if (ruleMatches(id, condition, config.manualRule)) {
+            return config.manualRule;
+        } else {
+            for (ZenRule automaticRule : config.automaticRules.values()) {
+                if (ruleMatches(id, condition, automaticRule)) {
+                    return automaticRule;
+                }
+            }
+        }
+        return null;
+    }
+
+    private boolean ruleMatches(Uri id, Condition condition, ZenRule rule) {
+        if (id == null || rule == null || rule.conditionId == null) return false;
+        if (!rule.conditionId.equals(id)) return false;
+        if (Objects.equals(condition, rule.condition)) return false;
+        return true;
+    }
+
+    private boolean updateSnoozing(ZenRule rule) {
+        if (rule != null && rule.snoozing && !rule.isTrueOrUnknown()) {
+            rule.snoozing = false;
+            if (DEBUG) Log.d(TAG, "Snoozing reset for " + rule.conditionId);
+            return true;
+        }
+        return false;
+    }
+
+    public int getCurrentInstanceCount(ComponentName cn) {
+        if (cn == null) {
+            return 0;
+        }
         int count = 0;
         synchronized (mConfig) {
             for (ZenRule rule : mConfig.automaticRules.values()) {
-                if (rule.component != null && rule.component.equals(owner)) {
+                if (cn.equals(rule.component) || cn.equals(rule.configurationActivity)) {
                     count++;
                 }
             }
@@ -401,7 +470,7 @@
             if (packages != null) {
                 final int packageCount = packages.length;
                 for (int i = 0; i < packageCount; i++) {
-                    if (packages[i].equals(rule.component.getPackageName())) {
+                    if (packages[i].equals(rule.pkg)) {
                         return true;
                     }
                 }
@@ -410,18 +479,6 @@
         }
     }
 
-    // Checks zen rule properties are the same (doesn't check creation time, name nor enabled)
-    // used to check if default rules were customized or not
-    private boolean ruleValuesEqual(AutomaticZenRule rule, ZenRule defaultRule) {
-        if (rule == null || defaultRule == null) {
-            return false;
-        }
-        return rule.getInterruptionFilter() ==
-                NotificationManager.zenModeToInterruptionFilter(defaultRule.zenMode)
-                && rule.getConditionId().equals(defaultRule.conditionId)
-                && rule.getOwner().equals(defaultRule.component);
-    }
-
     protected void updateDefaultZenRules() {
         updateDefaultAutomaticRuleNames();
         for (ZenRule defaultRule : mDefaultConfig.automaticRules.values()) {
@@ -443,7 +500,8 @@
     }
 
     private boolean isSystemRule(AutomaticZenRule rule) {
-        return ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
+        return rule.getOwner() != null
+                && ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
     }
 
     private ServiceInfo getServiceInfo(ComponentName owner) {
@@ -465,11 +523,31 @@
         return null;
     }
 
+    private ActivityInfo getActivityInfo(ComponentName configActivity) {
+        Intent queryIntent = new Intent();
+        queryIntent.setComponent(configActivity);
+        List<ResolveInfo> installedComponents = mPm.queryIntentActivitiesAsUser(
+                queryIntent,
+                PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA,
+                UserHandle.getCallingUserId());
+        if (installedComponents != null) {
+            for (int i = 0, count = installedComponents.size(); i < count; i++) {
+                ResolveInfo resolveInfo = installedComponents.get(i);
+                return resolveInfo.activityInfo;
+            }
+        }
+        return null;
+    }
+
     private void populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew) {
         if (isNew) {
             rule.id = ZenModeConfig.newRuleId();
             rule.creationTime = System.currentTimeMillis();
             rule.component = automaticZenRule.getOwner();
+            rule.configurationActivity = automaticZenRule.getConfigurationActivity();
+            rule.pkg = (rule.component != null)
+                    ? rule.component.getPackageName()
+                    : rule.configurationActivity.getPackageName();
         }
 
         if (rule.enabled != automaticZenRule.isEnabled()) {
@@ -488,14 +566,10 @@
     }
 
     protected AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
-        if (rule.zenPolicy != null) {
-            return new AutomaticZenRule(rule.name, rule.component, rule.conditionId, rule.zenPolicy,
-                    rule.enabled, rule.creationTime);
-        } else {
-            return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
-                    NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
-                    rule.creationTime);
-        }
+        return new AutomaticZenRule(rule.name, rule.component, rule.configurationActivity,
+                rule.conditionId, rule.zenPolicy,
+                NotificationManager.zenModeToInterruptionFilter(rule.zenMode),
+                rule.enabled, rule.creationTime);
     }
 
     public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
@@ -697,8 +771,9 @@
                     ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
                     if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
                         try {
-                            mPm.getPackageInfo(rule.component.getPackageName(),
-                                    PackageManager.MATCH_ANY_USER);
+                            if (rule.pkg != null) {
+                                mPm.getPackageInfo(rule.pkg, PackageManager.MATCH_ANY_USER);
+                            }
                         } catch (PackageManager.NameNotFoundException e) {
                             newConfig.automaticRules.removeAt(i);
                         }
@@ -753,11 +828,14 @@
                 if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
                 return true;
             }
-            // may modify config
+            // handle CPS backed conditions - danger! may modify config
             mConditions.evaluateConfig(config, null, false /*processSubscriptions*/);
+
             mConfigs.put(config.user, config);
             if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
             ZenLog.traceConfig(reason, mConfig, config);
+
+            // send some broadcasts
             final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
                     getNotificationPolicy(config));
             if (!config.equals(mConfig)) {
diff --git a/services/core/java/com/android/server/pm/ModuleInfoProvider.java b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
new file mode 100644
index 0000000..886cfb2
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ModuleInfoProvider.java
@@ -0,0 +1,178 @@
+/*
+ * 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.server.pm;
+
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.content.pm.ModuleInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.os.Process;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provides data to back {@code ModuleInfo} related APIs in the package manager. The data is stored
+ * as an XML resource in a configurable "module metadata" package.
+ */
+@VisibleForTesting
+public class ModuleInfoProvider {
+    private static final String TAG = "PackageManager.ModuleInfoProvider";
+
+    /**
+     * The key in the package's application level metadata bundle that provides a resource reference
+     * to the module metadata.
+     */
+    private static final String MODULE_METADATA_KEY = "android.content.pm.MODULE_METADATA";
+
+
+    private final Context mContext;
+    private final IPackageManager mPackageManager;
+    private final Map<String, ModuleInfo> mModuleInfo;
+
+    // TODO: Move this to an earlier boot phase if anybody requires it then.
+    private volatile boolean mMetadataLoaded;
+
+    ModuleInfoProvider(Context context, IPackageManager packageManager) {
+        mContext = context;
+        mPackageManager = packageManager;
+        mModuleInfo = new ArrayMap<>();
+    }
+
+    @VisibleForTesting
+    public ModuleInfoProvider(XmlResourceParser metadata, Resources resources) {
+        mContext = null;
+        mPackageManager = null;
+        mModuleInfo = new ArrayMap<>();
+        loadModuleMetadata(metadata, resources);
+    }
+
+    /** Called by the {@code PackageManager} when it has completed its boot sequence */
+    public void systemReady() {
+        final String packageName = mContext.getResources().getString(
+                R.string.config_defaultModuleMetadataProvider);
+        if (TextUtils.isEmpty(packageName)) {
+            Slog.w(TAG, "No configured module metadata provider.");
+            return;
+        }
+
+        final Resources packageResources;
+        final PackageInfo pi;
+        try {
+            pi = mPackageManager.getPackageInfo(packageName,
+                PackageManager.GET_META_DATA, Process.SYSTEM_UID);
+
+            Context packageContext = mContext.createPackageContext(packageName, 0);
+            packageResources = packageContext.getResources();
+        } catch (RemoteException | NameNotFoundException e) {
+            Slog.w(TAG, "Unable to discover metadata package: " + packageName, e);
+            return;
+        }
+
+        XmlResourceParser parser = packageResources.getXml(
+                pi.applicationInfo.metaData.getInt(MODULE_METADATA_KEY));
+        loadModuleMetadata(parser, packageResources);
+    }
+
+    private void loadModuleMetadata(XmlResourceParser parser, Resources packageResources) {
+        try {
+            // The format for the module metadata is straightforward :
+            //
+            // The following attributes on <module> are currently defined :
+            // -- name : A resource reference to a User visible package name, maps to
+            //           ModuleInfo#getName
+            // -- packageName : The package name of the module, see ModuleInfo#getPackageName
+            // -- isHidden : Whether the module is hidden, see ModuleInfo#isHidden
+            //
+            // <module-metadata>
+            //   <module name="@string/resource" packageName="package_name" isHidden="false|true" />
+            //   <module .... />
+            // </module-metadata>
+
+            XmlUtils.beginDocument(parser, "module-metadata");
+            while (true) {
+                XmlUtils.nextElement(parser);
+                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
+                    break;
+                }
+
+                if (!"module".equals(parser.getName())) {
+                    Slog.w(TAG, "Unexpected metadata element: " + parser.getName());
+                    mModuleInfo.clear();
+                    break;
+                }
+
+                // TODO: The module name here is fetched using the resource configuration applied
+                // at the time of parsing this information. This is probably not the best approach
+                // to dealing with this as we'll now have to listen to all config changes and
+                // regenerate the data if required. Also, is this the right way to parse a resource
+                // reference out of an XML file ?
+                final String moduleName = packageResources.getString(
+                        Integer.parseInt(parser.getAttributeValue(null, "name").substring(1)));
+                final String modulePackageName = XmlUtils.readStringAttribute(parser,
+                        "packageName");
+                final boolean isHidden = XmlUtils.readBooleanAttribute(parser, "isHidden");
+
+                ModuleInfo mi = new ModuleInfo();
+                mi.setHidden(isHidden);
+                mi.setPackageName(modulePackageName);
+                mi.setName(moduleName);
+
+                mModuleInfo.put(modulePackageName, mi);
+            }
+        } catch (XmlPullParserException | IOException e) {
+            Slog.w(TAG, "Error parsing module metadata", e);
+            mModuleInfo.clear();
+        } finally {
+            parser.close();
+            mMetadataLoaded = true;
+        }
+    }
+
+    List<ModuleInfo> getInstalledModules(int flags) {
+        if (!mMetadataLoaded) {
+            throw new IllegalStateException("Call to getInstalledModules before metadata loaded");
+        }
+
+        return new ArrayList<>(mModuleInfo.values());
+    }
+
+    ModuleInfo getModuleInfo(String packageName, int flags) {
+        if (!mMetadataLoaded) {
+            throw new IllegalStateException("Call to getModuleInfo before metadata loaded");
+        }
+
+        return mModuleInfo.get(packageName);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2826e7b..28fb01d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -162,12 +162,14 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
+import android.content.pm.ModuleInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageList;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
+import android.content.pm.PackageManager.ModuleInfoFlags;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManagerInternal.CheckPermissionDelegate;
 import android.content.pm.PackageManagerInternal.PackageListObserver;
@@ -718,6 +720,8 @@
 
     private PackageManager mPackageManager;
 
+    private final ModuleInfoProvider mModuleInfoProvider;
+
     class PackageParserCallback implements PackageParser.Callback {
         @Override public final boolean hasFeature(String feature) {
             return PackageManagerService.this.hasSystemFeature(feature, 0);
@@ -3030,6 +3034,8 @@
         } // synchronized (mPackages)
         } // synchronized (mInstallLock)
 
+        mModuleInfoProvider = new ModuleInfoProvider(mContext, this);
+
         // Now after opening every single application zip, make sure they
         // are all flushed.  Not really needed, but keeps things nice and
         // tidy.
@@ -4969,6 +4975,16 @@
     }
 
     @Override
+    public ModuleInfo getModuleInfo(String packageName, @ModuleInfoFlags int flags) {
+        return mModuleInfoProvider.getModuleInfo(packageName, flags);
+    }
+
+    @Override
+    public List<ModuleInfo> getInstalledModules(int flags) {
+        return mModuleInfoProvider.getInstalledModules(flags);
+    }
+
+    @Override
     public String[] getSystemSharedLibraryNames() {
         // allow instant applications
         synchronized (mPackages) {
@@ -20242,6 +20258,8 @@
                 }
             }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
         }
+
+        mModuleInfoProvider.systemReady();
     }
 
     public void waitForAppDataPrepared() {
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 35013de..f37ca12 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -503,6 +503,18 @@
             return userState.removeRoleHolder(roleName, packageName);
         }
 
+        @Override
+        public List<String> getHeldRolesFromController(@NonNull String packageName) {
+            Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+            getContext().enforceCallingOrSelfPermission(
+                    RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
+                    "getRolesHeldFromController");
+
+            int userId = UserHandle.getCallingUserId();
+            RoleUserState userState = getOrCreateUserState(userId);
+            return userState.getHeldRoles(packageName);
+        }
+
         @CheckResult
         private int handleIncomingUser(@UserIdInt int userId, @NonNull String name) {
             return ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
diff --git a/services/core/java/com/android/server/role/RoleManagerShellCommand.java b/services/core/java/com/android/server/role/RoleManagerShellCommand.java
index 336b311..b245e98 100644
--- a/services/core/java/com/android/server/role/RoleManagerShellCommand.java
+++ b/services/core/java/com/android/server/role/RoleManagerShellCommand.java
@@ -23,6 +23,7 @@
 import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.os.UserHandle;
+import android.util.Log;
 
 import java.io.PrintWriter;
 import java.util.concurrent.CompletableFuture;
@@ -47,7 +48,8 @@
                 mResult.get(5, TimeUnit.SECONDS);
                 return 0;
             } catch (Exception e) {
-                getErrPrintWriter().println("Error: " + e.toString());
+                getErrPrintWriter().println("Error: see logcat for details.\n"
+                        + Log.getStackTraceString(e));
                 return -1;
             }
         }
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index d55e261..630a39c 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -47,6 +47,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
@@ -315,6 +316,21 @@
     }
 
     /**
+     * @see android.app.role.RoleManager#getHeldRolesFromController
+     */
+    @NonNull
+    public List<String> getHeldRoles(@NonNull String packageName) {
+        ArrayList<String> result = new ArrayList<>();
+        int size = mRoles.size();
+        for (int i = 0; i < size; i++) {
+            if (mRoles.valueAt(i).contains(packageName)) {
+                result.add(mRoles.keyAt(i));
+            }
+        }
+        return result;
+    }
+
+    /**
      * Schedule writing the state to file.
      */
     @GuardedBy("mLock")
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index 6f10ed5..0c9c85a 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -27,6 +27,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     bmgrlib \
+    bu \
     services.backup \
     services.core \
     services.net
diff --git a/services/robotests/src/com/android/commands/bu/AdbBackupTest.java b/services/robotests/src/com/android/commands/bu/AdbBackupTest.java
new file mode 100644
index 0000000..6869f56
--- /dev/null
+++ b/services/robotests/src/com/android/commands/bu/AdbBackupTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.commands.bu;
+
+import static org.mockito.Mockito.verify;
+
+import android.app.backup.IBackupManager;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowParcelFileDescriptor;
+
+/** Unit tests for {@link com.android.commands.bu.Backup}. */
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowParcelFileDescriptor.class})
+@Presubmit
+public class AdbBackupTest {
+    @Mock private IBackupManager mBackupManager;
+    private Backup mBackup;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mBackup = new Backup(mBackupManager);
+    }
+
+    @Test
+    public void testRun_whenUserNotSpecified_callsAdbBackupAsSystemUser() throws Exception {
+        mBackup.run(new String[] {"backup", "-all"});
+
+        verify(mBackupManager).isBackupServiceActive(UserHandle.USER_SYSTEM);
+    }
+
+    @Test
+    public void testRun_whenUserSpecified_callsBackupManagerAsSpecifiedUser() throws Exception {
+        mBackup.run(new String[] {"backup", "-user", "10", "-all"});
+
+        verify(mBackupManager).isBackupServiceActive(10);
+    }
+}
diff --git a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
index 96ef0ce..58bce1c 100644
--- a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -65,6 +65,8 @@
     private static final String TEST_PACKAGE = "package";
     private static final String TEST_TRANSPORT = "transport";
 
+    private static final String[] ADB_TEST_PACKAGES = {TEST_PACKAGE};
+
     private static final int NON_USER_SYSTEM = UserHandle.USER_SYSTEM + 1;
 
     private ShadowContextWrapper mShadowContext;
@@ -555,16 +557,47 @@
         verify(mUserBackupManagerService).hasBackupPassword();
     }
 
-    /** Test that the backup service routes methods correctly to the user that requests it. */
+    /**
+     * Test verifying that {@link BackupManagerService#adbBackup(ParcelFileDescriptor, int, boolean,
+     * boolean, boolean, boolean, boolean, boolean, boolean, boolean, String[])} throws a
+     * {@link SecurityException} if the caller does not have INTERACT_ACROSS_USERS_FULL permission.
+     */
     @Test
-    public void testAdbBackup_callsAdbBackupForUser() throws Exception {
-        File testFile = new File(mContext.getFilesDir(), "test");
-        testFile.createNewFile();
-        ParcelFileDescriptor parcelFileDescriptor =
-                ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE);
-        String[] packages = {TEST_PACKAGE};
+    public void testAdbBackup_withoutPermission_throwsSecurityException() {
+        mShadowContext.denyPermissions(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+
+        expectThrows(SecurityException.class,
+                () ->
+                        mBackupManagerService.adbBackup(
+                                /* userId */ mUserId,
+                                /* parcelFileDescriptor*/ null,
+                                /* includeApks */ true,
+                                /* includeObbs */ true,
+                                /* includeShared */ true,
+                                /* doWidgets */ true,
+                                /* doAllApps */ true,
+                                /* includeSystem */ true,
+                                /* doCompress */ true,
+                                /* doKeyValue */ true,
+                                null));
+
+    }
+
+    /**
+     * Test verifying that {@link BackupManagerService#adbBackup(ParcelFileDescriptor, int, boolean,
+     * boolean, boolean, boolean, boolean, boolean, boolean, boolean, String[])} does not require
+     * the caller to have INTERACT_ACROSS_USERS_FULL permission when the calling user id is the
+     * same as the target user id.
+     */
+    @Test
+    public void testAdbBackup_whenCallingUserIsTargetUser_doesntNeedPermission() throws Exception {
+        ShadowBinder.setCallingUserHandle(UserHandle.of(mUserId));
+        mShadowContext.denyPermissions(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+
+        ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
 
         mBackupManagerService.adbBackup(
+                /* userId */ mUserId,
                 parcelFileDescriptor,
                 /* includeApks */ true,
                 /* includeObbs */ true,
@@ -574,7 +607,7 @@
                 /* includeSystem */ true,
                 /* doCompress */ true,
                 /* doKeyValue */ true,
-                packages);
+                ADB_TEST_PACKAGES);
 
         verify(mUserBackupManagerService)
                 .adbBackup(
@@ -587,18 +620,82 @@
                         /* includeSystem */ true,
                         /* doCompress */ true,
                         /* doKeyValue */ true,
-                        packages);
+                        ADB_TEST_PACKAGES);
+    }
+
+    /** Test that the backup service routes methods correctly to the user that requests it. */
+    @Test
+    public void testAdbBackup_callsAdbBackupForUser() throws Exception {
+        mShadowContext.grantPermissions(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+
+        ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
+
+        mBackupManagerService.adbBackup(
+                /* userId */ mUserId,
+                parcelFileDescriptor,
+                /* includeApks */ true,
+                /* includeObbs */ true,
+                /* includeShared */ true,
+                /* doWidgets */ true,
+                /* doAllApps */ true,
+                /* includeSystem */ true,
+                /* doCompress */ true,
+                /* doKeyValue */ true,
+                ADB_TEST_PACKAGES);
+
+        verify(mUserBackupManagerService)
+                .adbBackup(
+                        parcelFileDescriptor,
+                        /* includeApks */ true,
+                        /* includeObbs */ true,
+                        /* includeShared */ true,
+                        /* doWidgets */ true,
+                        /* doAllApps */ true,
+                        /* includeSystem */ true,
+                        /* doCompress */ true,
+                        /* doKeyValue */ true,
+                        ADB_TEST_PACKAGES);
+    }
+
+    /**
+     * Test verifying that {@link BackupManagerService#adbRestore(ParcelFileDescriptor, int)} throws
+     * a {@link SecurityException} if the caller does not have INTERACT_ACROSS_USERS_FULL
+     * permission.
+     */
+    @Test
+    public void testAdbRestore_withoutPermission_throwsSecurityException() {
+        mShadowContext.denyPermissions(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+
+        expectThrows(SecurityException.class,
+                () -> mBackupManagerService.adbRestore(mUserId, null));
+
+    }
+
+    /**
+     * Test verifying that {@link BackupManagerService#adbRestore(ParcelFileDescriptor, int)} does
+     * not require the caller to have INTERACT_ACROSS_USERS_FULL permission when the calling user id
+     * is the same as the target user id.
+     */
+    @Test
+    public void testAdbRestore_whenCallingUserIsTargetUser_doesntNeedPermission() throws Exception {
+        ShadowBinder.setCallingUserHandle(UserHandle.of(mUserId));
+        mShadowContext.denyPermissions(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+
+        ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
+
+        mBackupManagerService.adbRestore(mUserId, parcelFileDescriptor);
+
+        verify(mUserBackupManagerService).adbRestore(parcelFileDescriptor);
     }
 
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
     public void testAdbRestore_callsAdbRestoreForUser() throws Exception {
-        File testFile = new File(mContext.getFilesDir(), "test");
-        testFile.createNewFile();
-        ParcelFileDescriptor parcelFileDescriptor =
-                ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE);
+        mShadowContext.grantPermissions(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
 
-        mBackupManagerService.adbRestore(parcelFileDescriptor);
+        ParcelFileDescriptor parcelFileDescriptor = getFileDescriptorForAdbTest();
+
+        mBackupManagerService.adbRestore(mUserId, parcelFileDescriptor);
 
         verify(mUserBackupManagerService).adbRestore(parcelFileDescriptor);
     }
@@ -638,4 +735,10 @@
 
         verify(mUserBackupManagerService).dump(fileDescriptor, printWriter, args);
     }
+
+    private ParcelFileDescriptor getFileDescriptorForAdbTest() throws Exception {
+        File testFile = new File(mContext.getFilesDir(), "test");
+        testFile.createNewFile();
+        return ParcelFileDescriptor.open(testFile, ParcelFileDescriptor.MODE_READ_WRITE);
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index 04a8408..cff0521 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -203,6 +203,8 @@
                 .strictness(Strictness.LENIENT)
                 .mockStatic(LocalServices.class)
                 .startMocking();
+        spyOn(getContext());
+        doReturn(null).when(getContext()).registerReceiver(any(), any());
         doReturn(mock(ActivityManagerInternal.class))
                 .when(() -> LocalServices.getService(ActivityManagerInternal.class));
         doReturn(mock(ActivityTaskManagerInternal.class))
diff --git a/services/tests/servicestests/res/values/strings.xml b/services/tests/servicestests/res/values/strings.xml
index 57da0af..50ccd1f 100644
--- a/services/tests/servicestests/res/values/strings.xml
+++ b/services/tests/servicestests/res/values/strings.xml
@@ -32,4 +32,6 @@
     <string name="config_batterySaverDeviceSpecificConfig_1"></string>
     <string name="config_batterySaverDeviceSpecificConfig_2">cpufreq-n=1:123/2:456</string>
     <string name="config_batterySaverDeviceSpecificConfig_3">cpufreq-n=2:222,cpufreq-i=3:333/4:444</string>
+    <string name="module_1_name" translatable="false">module_1_name</string>
+    <string name="module_2_name" translatable="false">module_2_name</string>
 </resources>
diff --git a/services/tests/servicestests/res/xml/unparseable_metadata1.xml b/services/tests/servicestests/res/xml/unparseable_metadata1.xml
new file mode 100644
index 0000000..73967f1
--- /dev/null
+++ b/services/tests/servicestests/res/xml/unparseable_metadata1.xml
@@ -0,0 +1,4 @@
+<not-module-metadata>
+  <module name="@string/module_1_name" packageName="com.android.module1" isHidden="false"/>
+  <module name="@string/module_2_name" packageName="com.android.module2" isHidden="true"/>
+</not-module-metadata>
diff --git a/services/tests/servicestests/res/xml/unparseable_metadata2.xml b/services/tests/servicestests/res/xml/unparseable_metadata2.xml
new file mode 100644
index 0000000..bb5a1b2
--- /dev/null
+++ b/services/tests/servicestests/res/xml/unparseable_metadata2.xml
@@ -0,0 +1,4 @@
+<module-metadata>
+  <module name="@string/module_1_name" packageName="com.android.module1" isHidden="false"/>
+  <not-module name="@string/module_2_name" packageName="com.android.module2" isHidden="true"/>
+</module-metadata>
diff --git a/services/tests/servicestests/res/xml/well_formed_metadata.xml b/services/tests/servicestests/res/xml/well_formed_metadata.xml
new file mode 100644
index 0000000..17cc369
--- /dev/null
+++ b/services/tests/servicestests/res/xml/well_formed_metadata.xml
@@ -0,0 +1,4 @@
+<module-metadata>
+  <module name="@string/module_1_name" packageName="com.android.module1" isHidden="false"/>
+  <module name="@string/module_2_name" packageName="com.android.module2" isHidden="true"/>
+</module-metadata>
diff --git a/services/tests/servicestests/res/xml/well_formed_metadata2.xml b/services/tests/servicestests/res/xml/well_formed_metadata2.xml
new file mode 100644
index 0000000..47279e6
--- /dev/null
+++ b/services/tests/servicestests/res/xml/well_formed_metadata2.xml
@@ -0,0 +1,5 @@
+<module-metadata>
+  <module name="@string/module_1_name" packageName="com.android.module1" isHidden="false"
+    attribute1="attribute1" attribute2="attribute2" />
+  <module name="@string/module_2_name" packageName="com.android.module2" isHidden="true"/>
+</module-metadata>
diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
index 89c7b71..93cac08 100644
--- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
@@ -20,6 +20,7 @@
 import static com.android.server.am.MemoryStatUtil.JIFFY_NANOS;
 import static com.android.server.am.MemoryStatUtil.MemoryStat;
 import static com.android.server.am.MemoryStatUtil.PAGE_SIZE;
+import static com.android.server.am.MemoryStatUtil.parseCmdlineFromProcfs;
 import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg;
 import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromProcfs;
 import static com.android.server.am.MemoryStatUtil.parseVmHWMFromProcfs;
@@ -31,6 +32,7 @@
 
 import org.junit.Test;
 
+import java.io.ByteArrayOutputStream;
 import java.util.Collections;
 
 /**
@@ -232,4 +234,41 @@
 
         assertEquals(0, parseVmHWMFromProcfs(null));
     }
+
+    @Test
+    public void testParseCmdlineFromProcfs_invalidValue() {
+        byte[] nothing = new byte[] {0x00, 0x74, 0x65, 0x73, 0x74}; // \0test
+
+        assertEquals("", parseCmdlineFromProcfs(bytesToString(nothing)));
+    }
+
+    @Test
+    public void testParseCmdlineFromProcfs_correctValue_noNullBytes() {
+        assertEquals("com.google.app", parseCmdlineFromProcfs("com.google.app"));
+    }
+
+    @Test
+    public void testParseCmdlineFromProcfs_correctValue_withNullBytes() {
+        byte[] trailing = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00}; // test\0\0\0
+
+        assertEquals("test", parseCmdlineFromProcfs(bytesToString(trailing)));
+
+        // test\0\0test
+        byte[] inside = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74};
+
+        assertEquals("test", parseCmdlineFromProcfs(bytesToString(trailing)));
+    }
+
+    @Test
+    public void testParseCmdlineFromProcfs_emptyContents() {
+        assertEquals("", parseCmdlineFromProcfs(""));
+
+        assertEquals("", parseCmdlineFromProcfs(null));
+    }
+
+    private static String bytesToString(byte[] bytes) {
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        output.write(bytes, 0, bytes.length);
+        return output.toString();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index 751ed9b..d7a398e 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -487,8 +487,8 @@
 
     @Test
     public void adbBackup_calledBeforeInitialize_ignored() throws RemoteException {
-        mTrampoline.adbBackup(mParcelFileDescriptorMock, true, true, true, true, true, true, true,
-                true,
+        mTrampoline.adbBackup(mUserId, mParcelFileDescriptorMock, true, true,
+                true, true, true, true, true, true,
                 PACKAGE_NAMES);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
@@ -496,12 +496,11 @@
     @Test
     public void adbBackup_forwarded() throws RemoteException {
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
-        mTrampoline.adbBackup(mParcelFileDescriptorMock, true, true, true, true, true, true, true,
-                true,
+        mTrampoline.adbBackup(mUserId, mParcelFileDescriptorMock, true, true,
+                true, true, true, true, true, true,
                 PACKAGE_NAMES);
-        verify(mBackupManagerServiceMock).adbBackup(mParcelFileDescriptorMock, true, true, true,
-                true,
-                true, true, true, true, PACKAGE_NAMES);
+        verify(mBackupManagerServiceMock).adbBackup(mUserId, mParcelFileDescriptorMock, true,
+                true, true, true, true, true, true, true, PACKAGE_NAMES);
     }
 
     @Test
@@ -519,15 +518,15 @@
 
     @Test
     public void adbRestore_calledBeforeInitialize_ignored() throws RemoteException {
-        mTrampoline.adbRestore(mParcelFileDescriptorMock);
+        mTrampoline.adbRestore(mUserId, mParcelFileDescriptorMock);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
     public void adbRestore_forwarded() throws RemoteException {
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
-        mTrampoline.adbRestore(mParcelFileDescriptorMock);
-        verify(mBackupManagerServiceMock).adbRestore(mParcelFileDescriptorMock);
+        mTrampoline.adbRestore(mUserId, mParcelFileDescriptorMock);
+        verify(mBackupManagerServiceMock).adbRestore(mUserId, mParcelFileDescriptorMock);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java
new file mode 100644
index 0000000..bd3d9ab
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.server.pm;
+
+import android.content.Context;
+import android.content.pm.ModuleInfo;
+import android.test.InstrumentationTestCase;
+
+import com.android.frameworks.servicestests.R;
+
+import java.util.Collections;
+import java.util.List;
+
+public class ModuleInfoProviderTest extends InstrumentationTestCase {
+    public void testSuccessfulParse() {
+        ModuleInfoProvider provider = getProvider(R.xml.well_formed_metadata);
+
+        List<ModuleInfo> mi = provider.getInstalledModules(0);
+        assertEquals(2, mi.size());
+
+        Collections.sort(mi, (ModuleInfo m1, ModuleInfo m2) ->
+                m1.getPackageName().compareTo(m1.getPackageName()));
+        assertEquals("com.android.module1", mi.get(0).getPackageName());
+        assertEquals("com.android.module2", mi.get(1).getPackageName());
+
+        ModuleInfo mi1 = provider.getModuleInfo("com.android.module1", 0);
+        assertEquals("com.android.module1", mi1.getPackageName());
+        assertEquals("module_1_name", mi1.getName());
+        assertEquals(false, mi1.isHidden());
+
+        ModuleInfo mi2 = provider.getModuleInfo("com.android.module2", 0);
+        assertEquals("com.android.module2", mi2.getPackageName());
+        assertEquals("module_2_name", mi2.getName());
+        assertEquals(true, mi2.isHidden());
+    }
+
+    public void testParseFailure_incorrectTopLevelElement() {
+        ModuleInfoProvider provider = getProvider(R.xml.unparseable_metadata1);
+        assertEquals(0, provider.getInstalledModules(0).size());
+    }
+
+    public void testParseFailure_incorrectModuleElement() {
+        ModuleInfoProvider provider = getProvider(R.xml.unparseable_metadata2);
+        assertEquals(0, provider.getInstalledModules(0).size());
+    }
+
+    public void testParse_unknownAttributesIgnored() {
+        ModuleInfoProvider provider = getProvider(R.xml.well_formed_metadata);
+
+        List<ModuleInfo> mi = provider.getInstalledModules(0);
+        assertEquals(2, mi.size());
+
+        ModuleInfo mi1 = provider.getModuleInfo("com.android.module1", 0);
+        assertEquals("com.android.module1", mi1.getPackageName());
+        assertEquals("module_1_name", mi1.getName());
+        assertEquals(false, mi1.isHidden());
+    }
+
+    /**
+     * Constructs an {@code ModuleInfoProvider} using the test package resources.
+     */
+    private ModuleInfoProvider getProvider(int resourceId) {
+        final Context ctx = getInstrumentation().getContext();
+        return new ModuleInfoProvider(ctx.getResources().getXml(resourceId), ctx.getResources());
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 9bd3f26..68d3e4c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -17,20 +17,33 @@
 package com.android.server.notification;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNull;
 
 import android.app.NotificationManager.Policy;
+import android.content.ComponentName;
 import android.net.Uri;
+import android.provider.Settings;
+import android.service.notification.Condition;
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenModeConfig.EventInfo;
 import android.service.notification.ZenPolicy;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Xml;
 
+import com.android.internal.util.FastXmlSerializer;
 import com.android.server.UiServiceTestCase;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -138,6 +151,54 @@
         assertEquals(event, eventParsed);
     }
 
+    @Test
+    public void testRuleXml() throws Exception {
+        String tag = "tag";
+
+        ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
+        rule.configurationActivity = new ComponentName("a", "a");
+        rule.component = new ComponentName("a", "b");
+        rule.conditionId = new Uri.Builder().scheme("hello").build();
+        rule.condition = new Condition(rule.conditionId, "", Condition.STATE_TRUE);
+        rule.enabled = true;
+        rule.creationTime = 123;
+        rule.id = "id";
+        rule.zenMode = Settings.Global.ZEN_MODE_ALARMS;
+        rule.modified = true;
+        rule.name = "name";
+        rule.snoozing = true;
+
+        XmlSerializer out = new FastXmlSerializer();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        out.setOutput(new BufferedOutputStream(baos), "utf-8");
+        out.startDocument(null, true);
+        out.startTag(null, tag);
+        ZenModeConfig.writeRuleXml(rule, out);
+        out.endTag(null, tag);
+        out.endDocument();
+
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(baos.toByteArray())), null);
+        parser.nextTag();
+        ZenModeConfig.ZenRule fromXml = ZenModeConfig.readRuleXml(parser);
+        // read from backing component
+        assertEquals("a", fromXml.pkg);
+        // always resets on reboot
+        assertFalse(fromXml.snoozing);
+        //should all match original
+        assertEquals(rule.component, fromXml.component);
+        assertEquals(rule.configurationActivity, fromXml.configurationActivity);
+        assertNull(fromXml.enabler);
+        assertEquals(rule.condition, fromXml.condition);
+        assertEquals(rule.enabled, fromXml.enabled);
+        assertEquals(rule.creationTime, fromXml.creationTime);
+        assertEquals(rule.modified, fromXml.modified);
+        assertEquals(rule.conditionId, fromXml.conditionId);
+        assertEquals(rule.name, fromXml.name);
+        assertEquals(rule.zenMode, fromXml.zenMode);
+    }
+
     private ZenModeConfig getMutedNotificationsConfig() {
         ZenModeConfig config = new ZenModeConfig();
         // Allow alarms, media, and system
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 6c7ede3..dc3287e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -633,8 +633,8 @@
         mZenModeHelperSpy.mConfig.manualRule.zenMode =
                 Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a");
+        mZenModeHelperSpy.mConfig.manualRule.pkg = "a";
         mZenModeHelperSpy.mConfig.manualRule.enabled = true;
-        mZenModeHelperSpy.mConfig.manualRule.snoozing = true;
 
         ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
 
@@ -645,7 +645,8 @@
         parser.nextTag();
         mZenModeHelperSpy.readXml(parser, false);
 
-        assertEquals(expected, mZenModeHelperSpy.mConfig);
+        assertEquals("Config mismatch: current vs expected: "
+                + mZenModeHelperSpy.mConfig.diff(expected), expected, mZenModeHelperSpy.mConfig);
     }
 
     @Test
@@ -662,7 +663,9 @@
         customRule.name = "Custom Rule";
         customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
-        customRule.component = new ComponentName("android", "ScheduleConditionProvider");
+        customRule.configurationActivity
+                = new ComponentName("android", "ScheduleConditionProvider");
+        customRule.pkg = customRule.configurationActivity.getPackageName();
         automaticRules.put("customRule", customRule);
         mZenModeHelperSpy.mConfig.automaticRules = automaticRules;
 
@@ -674,7 +677,8 @@
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
         mZenModeHelperSpy.readXml(parser, true);
-        assertEquals(original, mZenModeHelperSpy.mConfig);
+        assertEquals("Config mismatch: current vs original: "
+                + mZenModeHelperSpy.mConfig.diff(original), original, mZenModeHelperSpy.mConfig);
         assertEquals(original.hashCode(), mZenModeHelperSpy.mConfig.hashCode());
     }
 
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index de40e0d..91cec554 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -24,6 +24,9 @@
         "libdexfile",
         "slicer",
     ],
+    static_libs: [
+        "libtinyxml2",
+    ],
 }
 
 cc_library_host_static {
@@ -32,7 +35,9 @@
     srcs: [
         "dex_builder.cc",
         "java_lang_builder.cc",
+        "tinyxml_layout_parser.cc",
         "util.cc",
+        "layout_validation.cc",
     ],
 }
 
@@ -43,7 +48,6 @@
         "main.cc",
     ],
     static_libs: [
-        "libtinyxml2",
         "libgflags",
         "libviewcompiler",
     ],
@@ -54,6 +58,7 @@
     defaults: ["viewcompiler_defaults"],
     srcs: [
         "dex_builder_test.cc",
+        "layout_validation_test.cc",
         "util_test.cc",
     ],
     static_libs: [
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc
index 906d64c..94879d0 100644
--- a/startop/view_compiler/dex_builder.cc
+++ b/startop/view_compiler/dex_builder.cc
@@ -61,18 +61,46 @@
     case Instruction::Op::kInvokeDirect:
       out << "kInvokeDirect";
       return out;
+    case Instruction::Op::kInvokeStatic:
+      out << "kInvokeStatic";
+      return out;
+    case Instruction::Op::kInvokeInterface:
+      out << "kInvokeInterface";
+      return out;
     case Instruction::Op::kBindLabel:
       out << "kBindLabel";
       return out;
     case Instruction::Op::kBranchEqz:
       out << "kBranchEqz";
       return out;
+    case Instruction::Op::kBranchNEqz:
+      out << "kBranchNEqz";
+      return out;
     case Instruction::Op::kNew:
       out << "kNew";
       return out;
   }
 }
 
+std::ostream& operator<<(std::ostream& out, const Value& value) {
+  if (value.is_register()) {
+    out << "Register(" << value.value() << ")";
+  } else if (value.is_parameter()) {
+    out << "Parameter(" << value.value() << ")";
+  } else if (value.is_immediate()) {
+    out << "Immediate(" << value.value() << ")";
+  } else if (value.is_string()) {
+    out << "String(" << value.value() << ")";
+  } else if (value.is_label()) {
+    out << "Label(" << value.value() << ")";
+  } else if (value.is_type()) {
+    out << "Type(" << value.value() << ")";
+  } else {
+    out << "UnknownValue";
+  }
+  return out;
+}
+
 void* TrackingAllocator::Allocate(size_t size) {
   std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(size);
   void* raw_buffer = buffer.get();
@@ -289,10 +317,16 @@
       return EncodeInvoke(instruction, art::Instruction::INVOKE_VIRTUAL);
     case Instruction::Op::kInvokeDirect:
       return EncodeInvoke(instruction, art::Instruction::INVOKE_DIRECT);
+    case Instruction::Op::kInvokeStatic:
+      return EncodeInvoke(instruction, art::Instruction::INVOKE_STATIC);
+    case Instruction::Op::kInvokeInterface:
+      return EncodeInvoke(instruction, art::Instruction::INVOKE_INTERFACE);
     case Instruction::Op::kBindLabel:
       return BindLabel(instruction.args()[0]);
     case Instruction::Op::kBranchEqz:
       return EncodeBranch(art::Instruction::IF_EQZ, instruction);
+    case Instruction::Op::kBranchNEqz:
+      return EncodeBranch(art::Instruction::IF_NEZ, instruction);
     case Instruction::Op::kNew:
       return EncodeNew(instruction);
   }
@@ -353,7 +387,9 @@
 
   // If there is a return value, add a move-result instruction
   if (instruction.dest().has_value()) {
-    Encode11x(art::Instruction::MOVE_RESULT, RegisterValue(*instruction.dest()));
+    Encode11x(instruction.result_is_object() ? art::Instruction::MOVE_RESULT_OBJECT
+                                             : art::Instruction::MOVE_RESULT,
+              RegisterValue(*instruction.dest()));
   }
 
   max_args_ = std::max(max_args_, instruction.args().size());
@@ -447,7 +483,7 @@
     auto& ir_node = dex_file_->methods_map[new_index];
     SLICER_CHECK(ir_node == nullptr);
     ir_node = decl;
-    decl->orig_index = new_index;
+    decl->orig_index = decl->index = new_index;
 
     entry = {id, decl};
   }
diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h
index adf82bf..45596ac 100644
--- a/startop/view_compiler/dex_builder.h
+++ b/startop/view_compiler/dex_builder.h
@@ -147,8 +147,11 @@
     kMove,
     kInvokeVirtual,
     kInvokeDirect,
+    kInvokeStatic,
+    kInvokeInterface,
     kBindLabel,
     kBranchEqz,
+    kBranchNEqz,
     kNew
   };
 
@@ -163,19 +166,53 @@
   // For most instructions, which take some number of arguments and have an optional return value.
   template <typename... T>
   static inline Instruction OpWithArgs(Op opcode, std::optional<const Value> dest, T... args) {
-    return Instruction{opcode, /*method_id*/ 0, dest, args...};
+    return Instruction{opcode, /*method_id=*/0, /*result_is_object=*/false, dest, args...};
   }
   // For method calls.
   template <typename... T>
   static inline Instruction InvokeVirtual(size_t method_id, std::optional<const Value> dest,
                                           Value this_arg, T... args) {
-    return Instruction{Op::kInvokeVirtual, method_id, dest, this_arg, args...};
+    return Instruction{
+        Op::kInvokeVirtual, method_id, /*result_is_object=*/false, dest, this_arg, args...};
+  }
+  // Returns an object
+  template <typename... T>
+  static inline Instruction InvokeVirtualObject(size_t method_id, std::optional<const Value> dest,
+                                                Value this_arg, T... args) {
+    return Instruction{
+        Op::kInvokeVirtual, method_id, /*result_is_object=*/true, dest, this_arg, args...};
   }
   // For direct calls (basically, constructors).
   template <typename... T>
   static inline Instruction InvokeDirect(size_t method_id, std::optional<const Value> dest,
                                          Value this_arg, T... args) {
-    return Instruction{Op::kInvokeDirect, method_id, dest, this_arg, args...};
+    return Instruction{
+        Op::kInvokeDirect, method_id, /*result_is_object=*/false, dest, this_arg, args...};
+  }
+  // Returns an object
+  template <typename... T>
+  static inline Instruction InvokeDirectObject(size_t method_id, std::optional<const Value> dest,
+                                               Value this_arg, T... args) {
+    return Instruction{
+        Op::kInvokeDirect, method_id, /*result_is_object=*/true, dest, this_arg, args...};
+  }
+  // For static calls.
+  template <typename... T>
+  static inline Instruction InvokeStatic(size_t method_id, std::optional<const Value> dest,
+                                         T... args) {
+    return Instruction{Op::kInvokeStatic, method_id, /*result_is_object=*/false, dest, args...};
+  }
+  // Returns an object
+  template <typename... T>
+  static inline Instruction InvokeStaticObject(size_t method_id, std::optional<const Value> dest,
+                                               T... args) {
+    return Instruction{Op::kInvokeStatic, method_id, /*result_is_object=*/true, dest, args...};
+  }
+  // For static calls.
+  template <typename... T>
+  static inline Instruction InvokeInterface(size_t method_id, std::optional<const Value> dest,
+                                            T... args) {
+    return Instruction{Op::kInvokeInterface, method_id, /*result_is_object=*/false, dest, args...};
   }
 
   ///////////////
@@ -184,21 +221,27 @@
 
   Op opcode() const { return opcode_; }
   size_t method_id() const { return method_id_; }
+  bool result_is_object() const { return result_is_object_; }
   const std::optional<const Value>& dest() const { return dest_; }
   const std::vector<const Value>& args() const { return args_; }
 
  private:
   inline Instruction(Op opcode, size_t method_id, std::optional<const Value> dest)
-      : opcode_{opcode}, method_id_{method_id}, dest_{dest}, args_{} {}
+      : opcode_{opcode}, method_id_{method_id}, result_is_object_{false}, dest_{dest}, args_{} {}
 
   template <typename... T>
-  inline constexpr Instruction(Op opcode, size_t method_id, std::optional<const Value> dest,
-                               T... args)
-      : opcode_{opcode}, method_id_{method_id}, dest_{dest}, args_{args...} {}
+  inline constexpr Instruction(Op opcode, size_t method_id, bool result_is_object,
+                               std::optional<const Value> dest, T... args)
+      : opcode_{opcode},
+        method_id_{method_id},
+        result_is_object_{result_is_object},
+        dest_{dest},
+        args_{args...} {}
 
   const Op opcode_;
   // The index of the method to invoke, for kInvokeVirtual and similar opcodes.
   const size_t method_id_{0};
+  const bool result_is_object_;
   const std::optional<const Value> dest_;
   const std::vector<const Value> args_;
 };
@@ -244,6 +287,8 @@
 
   // TODO: add builders for more instructions
 
+  DexBuilder* dex_file() const { return dex_; }
+
  private:
   void EncodeInstructions();
   void EncodeInstruction(const Instruction& instruction);
diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
index e20f3a9..1508ad9e 100644
--- a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
+++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
@@ -84,6 +84,15 @@
   }
 
   @Test
+  public void returnIfNotZero() throws Exception {
+    ClassLoader loader = loadDexFile("simple.dex");
+    Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+    Method method = clazz.getMethod("returnIfNotZero", int.class);
+    Assert.assertEquals(3, method.invoke(null, 0));
+    Assert.assertEquals(5, method.invoke(null, 17));
+  }
+
+  @Test
   public void backwardsBranch() throws Exception {
     ClassLoader loader = loadDexFile("simple.dex");
     Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
@@ -124,4 +133,22 @@
     Assert.assertEquals("b", method.invoke(null, 0));
     Assert.assertEquals("a", method.invoke(null, 1));
   }
+
+  @Test
+  public void invokeStaticReturnObject() throws Exception {
+    ClassLoader loader = loadDexFile("simple.dex");
+    Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+    Method method = clazz.getMethod("invokeStaticReturnObject", int.class, int.class);
+    Assert.assertEquals("10", method.invoke(null, 10, 10));
+    Assert.assertEquals("a", method.invoke(null, 10, 16));
+    Assert.assertEquals("5", method.invoke(null, 5, 16));
+  }
+
+  @Test
+  public void invokeVirtualReturnObject() throws Exception {
+    ClassLoader loader = loadDexFile("simple.dex");
+    Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+    Method method = clazz.getMethod("invokeVirtualReturnObject", String.class, int.class);
+    Assert.assertEquals("bc", method.invoke(null, "abc", 1));
+  }
 }
diff --git a/startop/view_compiler/dex_testcase_generator.cc b/startop/view_compiler/dex_testcase_generator.cc
index e2bf43bc..2781aa5 100644
--- a/startop/view_compiler/dex_testcase_generator.cc
+++ b/startop/view_compiler/dex_testcase_generator.cc
@@ -108,6 +108,27 @@
   }
   returnIfZero.Encode();
 
+  // int returnIfNotZero(int x) { if (x != 0) { return 5; } else { return 3; } }
+  MethodBuilder returnIfNotZero{cbuilder.CreateMethod(
+      "returnIfNotZero", Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})};
+  {
+    Value resultIfNotZero{returnIfNotZero.MakeRegister()};
+    Value else_target{returnIfNotZero.MakeLabel()};
+    returnIfNotZero.AddInstruction(Instruction::OpWithArgs(
+        Instruction::Op::kBranchNEqz, /*dest=*/{}, Value::Parameter(0), else_target));
+    // else branch
+    returnIfNotZero.BuildConst4(resultIfNotZero, 3);
+    returnIfNotZero.AddInstruction(
+        Instruction::OpWithArgs(Instruction::Op::kReturn, /*dest=*/{}, resultIfNotZero));
+    // then branch
+    returnIfNotZero.AddInstruction(
+        Instruction::OpWithArgs(Instruction::Op::kBindLabel, /*dest=*/{}, else_target));
+    returnIfNotZero.BuildConst4(resultIfNotZero, 5);
+    returnIfNotZero.AddInstruction(
+        Instruction::OpWithArgs(Instruction::Op::kReturn, /*dest=*/{}, resultIfNotZero));
+  }
+  returnIfNotZero.Encode();
+
   // Make sure backwards branches work too.
   //
   // Pseudo code for test:
@@ -216,6 +237,38 @@
     method.Encode();
   }(returnStringIfZeroBA);
 
+  // Make sure we can invoke static methods that return an object
+  // String invokeStaticReturnObject(int n, int radix) { return java.lang.Integer.toString(n,
+  // radix); }
+  MethodBuilder invokeStaticReturnObject{
+      cbuilder.CreateMethod("invokeStaticReturnObject",
+                            Prototype{string_type, TypeDescriptor::Int(), TypeDescriptor::Int()})};
+  [&](MethodBuilder& method) {
+    Value result{method.MakeRegister()};
+    MethodDeclData to_string{dex_file.GetOrDeclareMethod(
+        TypeDescriptor::FromClassname("java.lang.Integer"),
+        "toString",
+        Prototype{string_type, TypeDescriptor::Int(), TypeDescriptor::Int()})};
+    method.AddInstruction(Instruction::InvokeStaticObject(
+        to_string.id, result, Value::Parameter(0), Value::Parameter(1)));
+    method.BuildReturn(result, /*is_object=*/true);
+    method.Encode();
+  }(invokeStaticReturnObject);
+
+  // Make sure we can invoke virtual methods that return an object
+  // String invokeVirtualReturnObject(String s, int n) { return s.substring(n); }
+  MethodBuilder invokeVirtualReturnObject{cbuilder.CreateMethod(
+      "invokeVirtualReturnObject", Prototype{string_type, string_type, TypeDescriptor::Int()})};
+  [&](MethodBuilder& method) {
+    Value result{method.MakeRegister()};
+    MethodDeclData substring{dex_file.GetOrDeclareMethod(
+        string_type, "substring", Prototype{string_type, TypeDescriptor::Int()})};
+    method.AddInstruction(Instruction::InvokeVirtualObject(
+        substring.id, result, Value::Parameter(0), Value::Parameter(1)));
+    method.BuildReturn(result, /*is_object=*/true);
+    method.Encode();
+  }(invokeVirtualReturnObject);
+
   slicer::MemView image{dex_file.CreateImage()};
   std::ofstream out_file(outdir + "/simple.dex");
   out_file.write(image.ptr<const char>(), image.size());
diff --git a/startop/view_compiler/layout_validation.cc b/startop/view_compiler/layout_validation.cc
new file mode 100644
index 0000000..8c77377
--- /dev/null
+++ b/startop/view_compiler/layout_validation.cc
@@ -0,0 +1,42 @@
+/*
+ * 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 "layout_validation.h"
+
+#include "android-base/stringprintf.h"
+
+namespace startop {
+
+void LayoutValidationVisitor::VisitStartTag(const std::u16string& name) {
+  if (0 == name.compare(u"merge")) {
+    message_ = "Merge tags are not supported";
+    can_compile_ = false;
+  }
+  if (0 == name.compare(u"include")) {
+    message_ = "Include tags are not supported";
+    can_compile_ = false;
+  }
+  if (0 == name.compare(u"view")) {
+    message_ = "View tags are not supported";
+    can_compile_ = false;
+  }
+  if (0 == name.compare(u"fragment")) {
+    message_ = "Fragment tags are not supported";
+    can_compile_ = false;
+  }
+}
+
+}  // namespace startop
\ No newline at end of file
diff --git a/startop/view_compiler/layout_validation.h b/startop/view_compiler/layout_validation.h
new file mode 100644
index 0000000..bed34bb
--- /dev/null
+++ b/startop/view_compiler/layout_validation.h
@@ -0,0 +1,46 @@
+/*
+ * 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 LAYOUT_VALIDATION_H_
+#define LAYOUT_VALIDATION_H_
+
+#include "dex_builder.h"
+
+#include <string>
+
+namespace startop {
+
+// This visitor determines whether a layout can be compiled. Since we do not currently support all
+// features, such as includes and merges, we need to pre-validate the layout before we start
+// compiling.
+class LayoutValidationVisitor {
+ public:
+  void VisitStartDocument() const {}
+  void VisitEndDocument() const {}
+  void VisitStartTag(const std::u16string& name);
+  void VisitEndTag() const {}
+
+  const std::string& message() const { return message_; }
+  bool can_compile() const { return can_compile_; }
+
+ private:
+  std::string message_{"Okay"};
+  bool can_compile_{true};
+};
+
+}  // namespace startop
+
+#endif  // LAYOUT_VALIDATION_H_
diff --git a/startop/view_compiler/layout_validation_test.cc b/startop/view_compiler/layout_validation_test.cc
new file mode 100644
index 0000000..b74cdae
--- /dev/null
+++ b/startop/view_compiler/layout_validation_test.cc
@@ -0,0 +1,163 @@
+/*
+ * 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 "tinyxml_layout_parser.h"
+
+#include "gtest/gtest.h"
+
+using startop::CanCompileLayout;
+using std::string;
+
+namespace {
+void ValidateXmlText(const string& xml, bool expected) {
+  tinyxml2::XMLDocument doc;
+  doc.Parse(xml.c_str());
+  EXPECT_EQ(CanCompileLayout(doc), expected);
+}
+}  // namespace
+
+TEST(LayoutValidationTest, SingleButtonLayout) {
+  const string xml = R"(<?xml version="1.0" encoding="utf-8"?>
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:text="Hello, World!">
+
+</Button>)";
+  ValidateXmlText(xml, /*expected=*/true);
+}
+
+TEST(LayoutValidationTest, SmallConstraintLayout) {
+  const string xml = R"(<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <Button
+        android:id="@+id/button6"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="16dp"
+        android:layout_marginBottom="16dp"
+        android:text="Button"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent" />
+
+    <Button
+        android:id="@+id/button7"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="8dp"
+        android:layout_marginBottom="16dp"
+        android:text="Button2"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/button6" />
+
+    <Button
+        android:id="@+id/button8"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="8dp"
+        android:layout_marginBottom="16dp"
+        android:text="Button1"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@+id/button7" />
+</android.support.constraint.ConstraintLayout>)";
+  ValidateXmlText(xml, /*expected=*/true);
+}
+
+TEST(LayoutValidationTest, MergeNode) {
+  const string xml = R"(<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <TextView
+        android:id="@+id/textView3"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="TextView" />
+
+    <Button
+        android:id="@+id/button9"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Button" />
+</merge>)";
+  ValidateXmlText(xml, /*expected=*/false);
+}
+
+TEST(LayoutValidationTest, IncludeLayout) {
+  const string xml = R"(<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <include
+        layout="@layout/single_button_layout"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+</android.support.constraint.ConstraintLayout>)";
+  ValidateXmlText(xml, /*expected=*/false);
+}
+
+TEST(LayoutValidationTest, ViewNode) {
+  const string xml = R"(<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <view
+        class="android.support.design.button.MaterialButton"
+        id="@+id/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+</android.support.constraint.ConstraintLayout>)";
+  ValidateXmlText(xml, /*expected=*/false);
+}
+
+TEST(LayoutValidationTest, FragmentNode) {
+  // This test case is from https://developer.android.com/guide/components/fragments
+  const string xml = R"(<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <fragment android:name="com.example.news.ArticleListFragment"
+            android:id="@+id/list"
+            android:layout_weight="1"
+            android:layout_width="0dp"
+            android:layout_height="match_parent" />
+    <fragment android:name="com.example.news.ArticleReaderFragment"
+            android:id="@+id/viewer"
+            android:layout_weight="2"
+            android:layout_width="0dp"
+            android:layout_height="match_parent" />
+</LinearLayout>)";
+  ValidateXmlText(xml, /*expected=*/false);
+}
diff --git a/startop/view_compiler/main.cc b/startop/view_compiler/main.cc
index 7d791c2..9351dc3 100644
--- a/startop/view_compiler/main.cc
+++ b/startop/view_compiler/main.cc
@@ -18,6 +18,7 @@
 
 #include "dex_builder.h"
 #include "java_lang_builder.h"
+#include "tinyxml_layout_parser.h"
 #include "util.h"
 
 #include "tinyxml2.h"
@@ -100,6 +101,12 @@
   XMLDocument xml;
   xml.LoadFile(filename);
 
+  string message{};
+  if (!startop::CanCompileLayout(xml, &message)) {
+    LOG(ERROR) << "Layout not supported: " << message;
+    return 1;
+  }
+
   std::ofstream outfile;
   if (FLAGS_out != kStdoutFilename) {
     outfile.open(FLAGS_out);
diff --git a/startop/view_compiler/tinyxml_layout_parser.cc b/startop/view_compiler/tinyxml_layout_parser.cc
new file mode 100644
index 0000000..1b3a81f
--- /dev/null
+++ b/startop/view_compiler/tinyxml_layout_parser.cc
@@ -0,0 +1,34 @@
+/*
+ * 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 "tinyxml_layout_parser.h"
+
+#include "layout_validation.h"
+
+namespace startop {
+
+bool CanCompileLayout(const tinyxml2::XMLDocument& xml, std::string* message) {
+  LayoutValidationVisitor validator;
+  TinyXmlVisitorAdapter adapter{&validator};
+  xml.Accept(&adapter);
+
+  if (message != nullptr) {
+    *message = validator.message();
+  }
+
+  return validator.can_compile();
+}
+
+}  // namespace startop
diff --git a/startop/view_compiler/tinyxml_layout_parser.h b/startop/view_compiler/tinyxml_layout_parser.h
new file mode 100644
index 0000000..8f714a2
--- /dev/null
+++ b/startop/view_compiler/tinyxml_layout_parser.h
@@ -0,0 +1,65 @@
+/*
+ * 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 TINYXML_LAYOUT_PARSER_H_
+#define TINYXML_LAYOUT_PARSER_H_
+
+#include "tinyxml2.h"
+
+#include <codecvt>
+#include <locale>
+#include <string>
+
+namespace startop {
+
+template <typename Visitor>
+class TinyXmlVisitorAdapter : public tinyxml2::XMLVisitor {
+ public:
+  explicit TinyXmlVisitorAdapter(Visitor* visitor) : visitor_{visitor} {}
+
+  bool VisitEnter(const tinyxml2::XMLDocument& /*doc*/) override {
+    visitor_->VisitStartDocument();
+    return true;
+  }
+
+  bool VisitExit(const tinyxml2::XMLDocument& /*doc*/) override {
+    visitor_->VisitEndDocument();
+    return true;
+  }
+
+  bool VisitEnter(const tinyxml2::XMLElement& element,
+                  const tinyxml2::XMLAttribute* /*firstAttribute*/) override {
+    visitor_->VisitStartTag(
+        std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(
+            element.Name()));
+    return true;
+  }
+
+  bool VisitExit(const tinyxml2::XMLElement& /*element*/) override {
+    visitor_->VisitEndTag();
+    return true;
+  }
+
+ private:
+  Visitor* visitor_;
+};
+
+// Returns whether a layout resource represented by a TinyXML document is supported by the layout
+// compiler.
+bool CanCompileLayout(const tinyxml2::XMLDocument& xml, std::string* message = nullptr);
+
+}  // namespace startop
+
+#endif  // TINYXML_LAYOUT_PARSER_H_
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index bbac8eb..7b23061 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -369,16 +369,13 @@
         }
 
         /**
-         * Create a call camera capabilities instance that optionally
-         * supports zoom.
+         * Create a call camera capabilities instance that optionally supports zoom.
          *
          * @param width The width of the camera video (in pixels).
          * @param height The height of the camera video (in pixels).
          * @param zoomSupported True when camera supports zoom.
          * @param maxZoom Maximum zoom supported by camera.
-         * @hide
          */
-        @UnsupportedAppUsage
         public CameraCapabilities(int width, int height, boolean zoomSupported, float maxZoom) {
             mWidth = width;
             mHeight = height;
@@ -455,16 +452,14 @@
         }
 
         /**
-         * Whether the camera supports zoom.
-         * @hide
+         * Returns {@code true} is zoom is supported, {@code false} otherwise.
          */
         public boolean isZoomSupported() {
             return mZoomSupported;
         }
 
         /**
-         * The maximum zoom supported by the camera.
-         * @hide
+         * Returns the maximum zoom supported by the camera.
          */
         public float getMaxZoom() {
             return mMaxZoom;
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 9587704..c91134c 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -78,7 +78,7 @@
 
 static uint32_t ParseFormatAttribute(const StringPiece& str) {
   uint32_t mask = 0;
-  for (StringPiece part : util::Tokenize(str, '|')) {
+  for (const StringPiece& part : util::Tokenize(str, '|')) {
     StringPiece trimmed_part = util::TrimWhitespace(part);
     uint32_t type = ParseFormatType(trimmed_part);
     if (type == 0) {
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index da22e88..c6f9152 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -362,7 +362,7 @@
     return util::make_unique<BinaryPrimitive>(flags);
   }
 
-  for (StringPiece part : util::Tokenize(str, '|')) {
+  for (const StringPiece& part : util::Tokenize(str, '|')) {
     StringPiece trimmed_part = util::TrimWhitespace(part);
 
     bool flag_set = false;
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index fc9514a..f63a074 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -433,7 +433,7 @@
     }
 
     Printer r_txt_printer(&fout_text);
-    for (const auto res : xmlres->file.exported_symbols) {
+    for (const auto& res : xmlres->file.exported_symbols) {
       r_txt_printer.Print("default int id ");
       r_txt_printer.Println(res.name.entry);
     }
diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp
index 8d91b00..a4610b2 100644
--- a/tools/aapt2/java/AnnotationProcessor.cpp
+++ b/tools/aapt2/java/AnnotationProcessor.cpp
@@ -113,7 +113,7 @@
 void AnnotationProcessor::Print(Printer* printer) const {
   if (has_comments_) {
     std::string result = comment_.str();
-    for (StringPiece line : util::Tokenize(result, '\n')) {
+    for (const StringPiece& line : util::Tokenize(result, '\n')) {
       printer->Println(line);
     }
     printer->Println(" */");
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 73105e16..5cfbbf2 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -182,7 +182,7 @@
 
 std::string PackageToPath(const StringPiece& package) {
   std::string out_path;
-  for (StringPiece part : util::Tokenize(package, '.')) {
+  for (const StringPiece& part : util::Tokenize(package, '.')) {
     AppendPath(&out_path, part);
   }
   return out_path;
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 21d6b94..a8e82b3 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -66,6 +66,8 @@
 
     List<OsuProvider> getMatchingOsuProviders(in List<ScanResult> scanResult);
 
+    Map getMatchingPasspointConfigsForOsuProviders(in List<OsuProvider> osuProviders);
+
     int addOrUpdateNetwork(in WifiConfiguration config, String packageName);
 
     boolean addOrUpdatePasspointConfiguration(in PasspointConfiguration config, String packageName);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 57c97ea..8cb2063 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -57,8 +57,11 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.net.InetAddress;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 
 /**
@@ -1230,6 +1233,30 @@
     }
 
     /**
+     * Returns the matching Passpoint R2 configurations for given OSU (Online Sign-Up) providers.
+     *
+     * Given a list of OSU providers, this only returns OSU providers that already have Passpoint R2
+     * configurations in the device.
+     * An empty map will be returned when there is no matching Passpoint R2 configuration for the
+     * given OsuProviders.
+     *
+     * @param osuProviders a set of {@link OsuProvider}
+     * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}.
+     * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+    public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
+            @NonNull Set<OsuProvider> osuProviders) {
+        try {
+            return mService.getMatchingPasspointConfigsForOsuProviders(
+                    new ArrayList<>(osuProviders));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Add a new network description to the set of configured networks.
      * The {@code networkId} field of the supplied configuration object
      * is ignored.
diff --git a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
index 893b19c..6d82ca1 100644
--- a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
+++ b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
@@ -19,13 +19,16 @@
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.net.wifi.WifiSsid;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 
 import java.util.ArrayList;
-import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -52,9 +55,9 @@
     private WifiSsid mOsuSsid;
 
     /**
-     * Friendly name of the OSU provider.
+     * Map of friendly names expressed as different language for the OSU provider.
      */
-    private final String mFriendlyName;
+    private final Map<String, String> mFriendlyNames;
 
     /**
      * Description of the OSU provider.
@@ -81,10 +84,11 @@
      */
     private final Icon mIcon;
 
-    public OsuProvider(WifiSsid osuSsid, String friendlyName, String serviceDescription,
-            Uri serverUri, String nai, List<Integer> methodList, Icon icon) {
+    public OsuProvider(WifiSsid osuSsid, Map<String, String> friendlyNames,
+            String serviceDescription, Uri serverUri, String nai, List<Integer> methodList,
+            Icon icon) {
         mOsuSsid = osuSsid;
-        mFriendlyName = friendlyName;
+        mFriendlyNames = friendlyNames;
         mServiceDescription = serviceDescription;
         mServerUri = serverUri;
         mNetworkAccessIdentifier = nai;
@@ -104,7 +108,7 @@
     public OsuProvider(OsuProvider source) {
         if (source == null) {
             mOsuSsid = null;
-            mFriendlyName = null;
+            mFriendlyNames = null;
             mServiceDescription = null;
             mServerUri = null;
             mNetworkAccessIdentifier = null;
@@ -114,7 +118,7 @@
         }
 
         mOsuSsid = source.mOsuSsid;
-        mFriendlyName = source.mFriendlyName;
+        mFriendlyNames = source.mFriendlyNames;
         mServiceDescription = source.mServiceDescription;
         mServerUri = source.mServerUri;
         mNetworkAccessIdentifier = source.mNetworkAccessIdentifier;
@@ -134,8 +138,32 @@
         mOsuSsid = osuSsid;
     }
 
+    /**
+     * Return the friendly Name for current language from the list of friendly names of OSU
+     * provider.
+     *
+     * The string matching the default locale will be returned if it is found, otherwise the string
+     * in english or the first string in the list will be returned if english is not found.
+     * A null will be returned if the list is empty.
+     *
+     * @return String matching the default locale, null otherwise
+     */
     public String getFriendlyName() {
-        return mFriendlyName;
+        if (mFriendlyNames == null || mFriendlyNames.isEmpty()) return null;
+        String lang = Locale.getDefault().getLanguage();
+        String friendlyName = mFriendlyNames.get(lang);
+        if (friendlyName != null) {
+            return friendlyName;
+        }
+        friendlyName = mFriendlyNames.get("en");
+        if (friendlyName != null) {
+            return friendlyName;
+        }
+        return mFriendlyNames.get(mFriendlyNames.keySet().stream().findFirst().get());
+    }
+
+    public Map<String, String> getFriendlyNameList() {
+        return mFriendlyNames;
     }
 
     public String getServiceDescription() {
@@ -151,7 +179,7 @@
     }
 
     public List<Integer> getMethodList() {
-        return Collections.unmodifiableList(mMethodList);
+        return mMethodList;
     }
 
     public Icon getIcon() {
@@ -166,12 +194,14 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeParcelable(mOsuSsid, flags);
-        dest.writeString(mFriendlyName);
         dest.writeString(mServiceDescription);
         dest.writeParcelable(mServerUri, flags);
         dest.writeString(mNetworkAccessIdentifier);
         dest.writeList(mMethodList);
         dest.writeParcelable(mIcon, flags);
+        Bundle bundle = new Bundle();
+        bundle.putSerializable("friendlyNameMap", (HashMap<String, String>) mFriendlyNames);
+        dest.writeBundle(bundle);
     }
 
     @Override
@@ -184,7 +214,8 @@
         }
         OsuProvider that = (OsuProvider) thatObject;
         return (mOsuSsid == null ? that.mOsuSsid == null : mOsuSsid.equals(that.mOsuSsid))
-                && TextUtils.equals(mFriendlyName, that.mFriendlyName)
+                && (mFriendlyNames == null) ? that.mFriendlyNames == null
+                            : mFriendlyNames.equals(that.mFriendlyNames)
                 && TextUtils.equals(mServiceDescription, that.mServiceDescription)
                 && (mServerUri == null ? that.mServerUri == null
                             : mServerUri.equals(that.mServerUri))
@@ -196,14 +227,15 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mOsuSsid, mFriendlyName, mServiceDescription, mServerUri,
-                mNetworkAccessIdentifier, mMethodList, mIcon);
+        // mIcon is not hashable, skip the variable.
+        return Objects.hash(mOsuSsid, mServiceDescription, mFriendlyNames,
+                mServerUri, mNetworkAccessIdentifier, mMethodList);
     }
 
     @Override
     public String toString() {
         return "OsuProvider{mOsuSsid=" + mOsuSsid
-                + " mFriendlyName=" + mFriendlyName
+                + " mFriendlyNames=" + mFriendlyNames
                 + " mServiceDescription=" + mServiceDescription
                 + " mServerUri=" + mServerUri
                 + " mNetworkAccessIdentifier=" + mNetworkAccessIdentifier
@@ -212,20 +244,22 @@
     }
 
     public static final Creator<OsuProvider> CREATOR =
-        new Creator<OsuProvider>() {
-            @Override
-            public OsuProvider createFromParcel(Parcel in) {
-                WifiSsid osuSsid = (WifiSsid) in.readParcelable(null);
-                String friendlyName = in.readString();
-                String serviceDescription = in.readString();
-                Uri serverUri = (Uri) in.readParcelable(null);
-                String nai = in.readString();
-                List<Integer> methodList = new ArrayList<>();
-                in.readList(methodList, null);
-                Icon icon = (Icon) in.readParcelable(null);
-                return new OsuProvider(osuSsid, friendlyName, serviceDescription, serverUri,
-                        nai, methodList, icon);
-            }
+            new Creator<OsuProvider>() {
+                @Override
+                public OsuProvider createFromParcel(Parcel in) {
+                    WifiSsid osuSsid = in.readParcelable(null);
+                    String serviceDescription = in.readString();
+                    Uri serverUri = in.readParcelable(null);
+                    String nai = in.readString();
+                    List<Integer> methodList = new ArrayList<>();
+                    in.readList(methodList, null);
+                    Icon icon = in.readParcelable(null);
+                    Bundle bundle = in.readBundle();
+                    Map<String, String> friendlyNamesMap = (HashMap) bundle.getSerializable(
+                            "friendlyNameMap");
+                    return new OsuProvider(osuSsid, friendlyNamesMap, serviceDescription,
+                            serverUri, nai, methodList, icon);
+                }
 
             @Override
             public OsuProvider[] newArray(int size) {
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 26bdb18..f09d864 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -20,6 +20,7 @@
 import android.net.wifi.hotspot2.pps.HomeSp;
 import android.net.wifi.hotspot2.pps.Policy;
 import android.net.wifi.hotspot2.pps.UpdateParameter;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -30,6 +31,7 @@
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 
@@ -324,6 +326,50 @@
     }
 
     /**
+     * The map of OSU service provider names whose each element is presented in different
+     * languages for the service provider, which is used for finding a matching
+     * PasspointConfiguration with a given service provider name.
+     */
+    private Map<String, String> mServiceFriendlyNames = null;
+
+    /**
+     * @hide
+     */
+    public void setServiceFriendlyNames(Map<String, String> serviceFriendlyNames) {
+        mServiceFriendlyNames = serviceFriendlyNames;
+    }
+
+    /**
+     * @hide
+     */
+    public Map<String, String> getServiceFriendlyNames() {
+        return mServiceFriendlyNames;
+    }
+
+    /**
+     * Return the friendly Name for current language from the list of friendly names of OSU
+     * provider.
+     * The string matching the default locale will be returned if it is found, otherwise the
+     * first string in the list will be returned.  A null will be returned if the list is empty.
+     *
+     * @return String matching the default locale, null otherwise
+     * @hide
+     */
+    public String getServiceFriendlyName() {
+        if (mServiceFriendlyNames == null || mServiceFriendlyNames.isEmpty()) return null;
+        String lang = Locale.getDefault().getLanguage();
+        String friendlyName = mServiceFriendlyNames.get(lang);
+        if (friendlyName != null) {
+            return friendlyName;
+        }
+        friendlyName = mServiceFriendlyNames.get("en");
+        if (friendlyName != null) {
+            return friendlyName;
+        }
+        return mServiceFriendlyNames.get(mServiceFriendlyNames.keySet().stream().findFirst().get());
+    }
+
+    /**
      * Constructor for creating PasspointConfiguration with default values.
      */
     public PasspointConfiguration() {}
@@ -362,6 +408,7 @@
         mUsageLimitStartTimeInMillis = source.mUsageLimitStartTimeInMillis;
         mUsageLimitTimeLimitInMinutes = source.mUsageLimitTimeLimitInMinutes;
         mUsageLimitUsageTimePeriodInMinutes = source.mUsageLimitUsageTimePeriodInMinutes;
+        mServiceFriendlyNames = source.mServiceFriendlyNames;
     }
 
     @Override
@@ -385,6 +432,10 @@
         dest.writeLong(mUsageLimitStartTimeInMillis);
         dest.writeLong(mUsageLimitDataLimit);
         dest.writeLong(mUsageLimitTimeLimitInMinutes);
+        Bundle bundle = new Bundle();
+        bundle.putSerializable("serviceFriendlyNames",
+                (HashMap<String, String>) mServiceFriendlyNames);
+        dest.writeBundle(bundle);
     }
 
     @Override
@@ -398,10 +449,10 @@
         PasspointConfiguration that = (PasspointConfiguration) thatObject;
         return (mHomeSp == null ? that.mHomeSp == null : mHomeSp.equals(that.mHomeSp))
                 && (mCredential == null ? that.mCredential == null
-                        : mCredential.equals(that.mCredential))
+                : mCredential.equals(that.mCredential))
                 && (mPolicy == null ? that.mPolicy == null : mPolicy.equals(that.mPolicy))
                 && (mSubscriptionUpdate == null ? that.mSubscriptionUpdate == null
-                        : mSubscriptionUpdate.equals(that.mSubscriptionUpdate))
+                : mSubscriptionUpdate.equals(that.mSubscriptionUpdate))
                 && isTrustRootCertListEquals(mTrustRootCertList, that.mTrustRootCertList)
                 && mUpdateIdentifier == that.mUpdateIdentifier
                 && mCredentialPriority == that.mCredentialPriority
@@ -411,7 +462,9 @@
                 && mUsageLimitUsageTimePeriodInMinutes == that.mUsageLimitUsageTimePeriodInMinutes
                 && mUsageLimitStartTimeInMillis == that.mUsageLimitStartTimeInMillis
                 && mUsageLimitDataLimit == that.mUsageLimitDataLimit
-                && mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes;
+                && mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes
+                && (mServiceFriendlyNames == null ? that.mServiceFriendlyNames == null
+                : mServiceFriendlyNames.equals(that.mServiceFriendlyNames));
     }
 
     @Override
@@ -419,7 +472,8 @@
         return Objects.hash(mHomeSp, mCredential, mPolicy, mSubscriptionUpdate, mTrustRootCertList,
                 mUpdateIdentifier, mCredentialPriority, mSubscriptionCreationTimeInMillis,
                 mSubscriptionExpirationTimeInMillis, mUsageLimitUsageTimePeriodInMinutes,
-                mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes);
+                mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes,
+                mServiceFriendlyNames);
     }
 
     @Override
@@ -463,6 +517,9 @@
             builder.append("TrustRootCertServers: ").append(mTrustRootCertList.keySet())
                     .append("\n");
         }
+        if (mServiceFriendlyNames != null) {
+            builder.append("ServiceFriendlyNames: ").append(mServiceFriendlyNames);
+        }
         return builder.toString();
     }
 
@@ -562,6 +619,10 @@
                 config.setUsageLimitStartTimeInMillis(in.readLong());
                 config.setUsageLimitDataLimit(in.readLong());
                 config.setUsageLimitTimeLimitInMinutes(in.readLong());
+                Bundle bundle = in.readBundle();
+                Map<String, String> friendlyNamesMap = (HashMap) bundle.getSerializable(
+                        "serviceFriendlyNames");
+                config.setServiceFriendlyNames(friendlyNamesMap);
                 return config;
             }
 
diff --git a/wifi/java/com/android/server/wifi/AbstractWifiService.java b/wifi/java/com/android/server/wifi/AbstractWifiService.java
index 36f66aa..e94b9e6 100644
--- a/wifi/java/com/android/server/wifi/AbstractWifiService.java
+++ b/wifi/java/com/android/server/wifi/AbstractWifiService.java
@@ -39,6 +39,7 @@
 import android.os.WorkSource;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * Abstract class implementing IWifiManager with stub methods throwing runtime exceptions.
@@ -127,6 +128,12 @@
     }
 
     @Override
+    public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
+            List<OsuProvider> osuProviders) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public int addOrUpdateNetwork(WifiConfiguration config, String packageName) {
         throw new UnsupportedOperationException();
     }
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
index d3f91f0..89ecd0f 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
@@ -28,9 +28,10 @@
 import org.junit.Test;
 
 import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Unit tests for {@link android.net.wifi.hotspot2.OsuProvider}.
@@ -40,6 +41,15 @@
     private static final WifiSsid TEST_SSID =
             WifiSsid.createFromByteArray("TEST SSID".getBytes(StandardCharsets.UTF_8));
     private static final String TEST_FRIENDLY_NAME = "Friendly Name";
+    private static final Map<String, String> TEST_FRIENDLY_NAMES =
+            new HashMap<String, String>() {
+                {
+                    put("en", TEST_FRIENDLY_NAME);
+                    put("kr", TEST_FRIENDLY_NAME + 2);
+                    put("jp", TEST_FRIENDLY_NAME + 3);
+                }
+            };
+
     private static final String TEST_SERVICE_DESCRIPTION = "Dummy Service";
     private static final Uri TEST_SERVER_URI = Uri.parse("https://test.com");
     private static final String TEST_NAI = "test.access.com";
@@ -59,7 +69,9 @@
 
         parcel.setDataPosition(0);    // Rewind data position back to the beginning for read.
         OsuProvider readInfo = OsuProvider.CREATOR.createFromParcel(parcel);
+
         assertEquals(writeInfo, readInfo);
+        assertEquals(writeInfo.hashCode(), readInfo.hashCode());
     }
 
     /**
@@ -79,8 +91,8 @@
      */
     @Test
     public void verifyParcelWithFullProviderInfo() throws Exception {
-        verifyParcel(new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAME, TEST_SERVICE_DESCRIPTION,
-                TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON));
+        verifyParcel(new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
+                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON));
     }
 
     /**
@@ -100,8 +112,8 @@
      */
     @Test
     public void verifyCopyConstructorWithValidSource() throws Exception {
-        OsuProvider source = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAME, TEST_SERVICE_DESCRIPTION,
-                TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON);
+        OsuProvider source = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
+                TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON);
         assertEquals(source, new OsuProvider(source));
     }
 
@@ -112,10 +124,12 @@
      */
     @Test
     public void verifyGetters() throws Exception {
-        OsuProvider provider = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAME,
+        OsuProvider provider = new OsuProvider(TEST_SSID, TEST_FRIENDLY_NAMES,
                 TEST_SERVICE_DESCRIPTION, TEST_SERVER_URI, TEST_NAI, TEST_METHOD_LIST, TEST_ICON);
+
         assertTrue(TEST_SSID.equals(provider.getOsuSsid()));
         assertTrue(TEST_FRIENDLY_NAME.equals(provider.getFriendlyName()));
+        assertTrue(TEST_FRIENDLY_NAMES.equals(provider.getFriendlyNameList()));
         assertTrue(TEST_SERVICE_DESCRIPTION.equals(provider.getServiceDescription()));
         assertTrue(TEST_SERVER_URI.equals(provider.getServerUri()));
         assertTrue(TEST_NAI.equals(provider.getNetworkAccessIdentifier()));
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index 775ce21..ee5a75e 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -166,6 +166,10 @@
         config.setUsageLimitStartTimeInMillis(124214213);
         config.setUsageLimitDataLimit(14121);
         config.setUsageLimitTimeLimitInMinutes(78912);
+        Map<String, String> friendlyNames = new HashMap<>();
+        friendlyNames.put("en", "ServiceName1");
+        friendlyNames.put("kr", "ServiceName2");
+        config.setServiceFriendlyNames(friendlyNames);
         return config;
     }
 
@@ -206,6 +210,18 @@
     }
 
     /**
+     * Verify parcel read/write for a configuration that doesn't contain a list of service names.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void verifyParcelWithoutServiceNames() throws Exception {
+        PasspointConfiguration config = createConfig();
+        config.setServiceFriendlyNames(null);
+        verifyParcel(config);
+    }
+
+    /**
      * Verify parcel read/write for a configuration that doesn't contain HomeSP.
      *
      * @throws Exception