Merge "Cancel all pending anims when tearing down."
diff --git a/Android.bp b/Android.bp
index dc9c4d4..4e7a7b4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -521,6 +521,8 @@
         "telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl",
         "telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl",
         "telecomm/java/com/android/internal/telecom/IInCallService.aidl",
+        "telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionCallback.aidl",
+        "telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionService.aidl",
         "telecomm/java/com/android/internal/telecom/ITelecomService.aidl",
         "telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl",
         "telephony/java/android/telephony/data/IDataService.aidl",
diff --git a/api/current.txt b/api/current.txt
index 2b34f4f..31ec76e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5730,7 +5730,6 @@
 
   public final class NotificationChannelGroup implements android.os.Parcelable {
     ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence);
-    method public boolean canOverlayApps();
     method public android.app.NotificationChannelGroup clone();
     method public int describeContents();
     method public java.util.List<android.app.NotificationChannel> getChannels();
@@ -5738,7 +5737,6 @@
     method public java.lang.String getId();
     method public java.lang.CharSequence getName();
     method public boolean isBlocked();
-    method public void setAllowAppOverlay(boolean);
     method public void setDescription(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
@@ -5746,6 +5744,7 @@
 
   public class NotificationManager {
     method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
+    method public boolean areAppOverlaysAllowed();
     method public boolean areNotificationsEnabled();
     method public boolean canNotifyAsPackage(java.lang.String);
     method public void cancel(int);
@@ -10268,6 +10267,7 @@
     field public static final java.lang.String CATEGORY_OPENABLE = "android.intent.category.OPENABLE";
     field public static final java.lang.String CATEGORY_PREFERENCE = "android.intent.category.PREFERENCE";
     field public static final java.lang.String CATEGORY_SAMPLE_CODE = "android.intent.category.SAMPLE_CODE";
+    field public static final java.lang.String CATEGORY_SECONDARY_HOME = "android.intent.category.SECONDARY_HOME";
     field public static final java.lang.String CATEGORY_SELECTED_ALTERNATIVE = "android.intent.category.SELECTED_ALTERNATIVE";
     field public static final java.lang.String CATEGORY_TAB = "android.intent.category.TAB";
     field public static final java.lang.String CATEGORY_TEST = "android.intent.category.TEST";
@@ -11366,13 +11366,20 @@
     method public android.net.Uri getReferrerUri();
     method public int getSessionId();
     method public long getSize();
+    method public int getStagedSessionErrorCode();
     method public boolean isActive();
     method public boolean isMultiPackage();
     method public boolean isSealed();
+    method public boolean isSessionApplied();
+    method public boolean isSessionFailed();
+    method public boolean isSessionReady();
     method public boolean isStaged();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ACTIVATION_FAILED = 2; // 0x2
     field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR;
     field public static final int INVALID_ID = -1; // 0xffffffff
+    field public static final int NO_ERROR = 0; // 0x0
+    field public static final int VERIFICATION_FAILED = 1; // 0x1
   }
 
   public static class PackageInstaller.SessionParams implements android.os.Parcelable {
@@ -35140,6 +35147,7 @@
 
   public final class StorageVolume implements android.os.Parcelable {
     method public deprecated android.content.Intent createAccessIntent(java.lang.String);
+    method public android.content.Intent createOpenDocumentTreeIntent();
     method public int describeContents();
     method public java.lang.String getDescription(android.content.Context);
     method public java.lang.String getState();
@@ -43638,6 +43646,10 @@
     field public static final java.lang.String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int";
     field public static final java.lang.String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array";
     field public static final java.lang.String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
+    field public static final java.lang.String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT = "opportunistic_network_entry_threshold_rsrp_int";
+    field public static final java.lang.String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT = "opportunistic_network_entry_threshold_rssnr_int";
+    field public static final java.lang.String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int";
+    field public static final java.lang.String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int";
     field public static final java.lang.String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
     field public static final java.lang.String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array";
     field public static final java.lang.String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string";
@@ -52219,13 +52231,13 @@
     method public void setContentCaptureEnabled(boolean);
   }
 
-  public final class ContentCaptureSession implements java.lang.AutoCloseable {
+  public abstract class ContentCaptureSession implements java.lang.AutoCloseable {
     method public void close();
-    method public void destroy();
-    method public android.view.contentcapture.ContentCaptureSessionId getContentCaptureSessionId();
-    method public void notifyViewAppeared(android.view.ViewStructure);
-    method public void notifyViewDisappeared(android.view.autofill.AutofillId);
-    method public void notifyViewTextChanged(android.view.autofill.AutofillId, java.lang.CharSequence, int);
+    method public final void destroy();
+    method public final android.view.contentcapture.ContentCaptureSessionId getContentCaptureSessionId();
+    method public final void notifyViewAppeared(android.view.ViewStructure);
+    method public final void notifyViewDisappeared(android.view.autofill.AutofillId);
+    method public final void notifyViewTextChanged(android.view.autofill.AutofillId, java.lang.CharSequence, int);
     field public static final int FLAG_USER_INPUT = 1; // 0x1
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index 4278003..751ef34 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -27,6 +27,7 @@
     field public static final java.lang.String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
     field public static final java.lang.String BIND_NETWORK_RECOMMENDATION_SERVICE = "android.permission.BIND_NETWORK_RECOMMENDATION_SERVICE";
     field public static final java.lang.String BIND_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE";
+    field public static final java.lang.String BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE = "android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE";
     field public static final java.lang.String BIND_PRINT_RECOMMENDATION_SERVICE = "android.permission.BIND_PRINT_RECOMMENDATION_SERVICE";
     field public static final java.lang.String BIND_RESOLVER_RANKER_SERVICE = "android.permission.BIND_RESOLVER_RANKER_SERVICE";
     field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
@@ -5049,7 +5050,7 @@
 
 package android.service.contentcapture {
 
-  public final class ContentCaptureEventsRequest implements android.os.Parcelable {
+  public final deprecated class ContentCaptureEventsRequest implements android.os.Parcelable {
     method public int describeContents();
     method public java.util.List<android.view.contentcapture.ContentCaptureEvent> getEvents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -5061,7 +5062,8 @@
     method public final java.util.Set<android.content.ComponentName> getContentCaptureDisabledActivities();
     method public final java.util.Set<java.lang.String> getContentCaptureDisabledPackages();
     method public void onActivitySnapshot(android.view.contentcapture.ContentCaptureSessionId, android.service.contentcapture.SnapshotData);
-    method public void onContentCaptureEventsRequest(android.view.contentcapture.ContentCaptureSessionId, android.service.contentcapture.ContentCaptureEventsRequest);
+    method public void onContentCaptureEvent(android.view.contentcapture.ContentCaptureSessionId, android.view.contentcapture.ContentCaptureEvent);
+    method public deprecated void onContentCaptureEventsRequest(android.view.contentcapture.ContentCaptureSessionId, android.service.contentcapture.ContentCaptureEventsRequest);
     method public void onCreateContentCaptureSession(android.view.contentcapture.ContentCaptureContext, android.view.contentcapture.ContentCaptureSessionId);
     method public void onDestroyContentCaptureSession(android.view.contentcapture.ContentCaptureSessionId);
     method public final void setActivityContentCaptureEnabled(android.content.ComponentName, boolean);
@@ -5649,6 +5651,14 @@
     ctor public PhoneAccountSuggestion(android.telecom.PhoneAccountHandle, int, boolean);
   }
 
+  public class PhoneAccountSuggestionService extends android.app.Service {
+    ctor public PhoneAccountSuggestionService();
+    method public void onAccountSuggestionRequest(java.lang.String);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public final void suggestPhoneAccounts(java.lang.String, java.util.List<android.telecom.PhoneAccountSuggestion>);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService";
+  }
+
   public final class RemoteConference {
     method public deprecated void setAudioState(android.telecom.AudioState);
   }
@@ -6141,6 +6151,7 @@
     method public boolean getEmergencyCallbackMode();
     method public java.lang.String getIsimDomain();
     method public int getPreferredNetworkType(int);
+    method public int getPreferredNetworkTypeBitmap();
     method public int getRadioPowerState();
     method public int getSimApplicationState();
     method public int getSimCardState();
@@ -6169,6 +6180,7 @@
     method public void setDataActivationState(int);
     method public deprecated void setDataEnabled(int, boolean);
     method public void setDataRoamingEnabled(boolean);
+    method public boolean setPreferredNetworkTypeBitmap(int);
     method public boolean setRadio(boolean);
     method public boolean setRadioPower(boolean);
     method public void setSimPowerState(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 46e7683..1e15792 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -182,7 +182,6 @@
     method public int getUserLockedFields();
     method public void lockFields(int);
     method public void setBlocked(boolean);
-    field public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 2; // 0x2
   }
 
   public class NotificationManager {
@@ -1282,6 +1281,14 @@
     ctor public PhoneAccountSuggestion(android.telecom.PhoneAccountHandle, int, boolean);
   }
 
+  public class PhoneAccountSuggestionService extends android.app.Service {
+    ctor public PhoneAccountSuggestionService();
+    method public void onAccountSuggestionRequest(java.lang.String);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public final void suggestPhoneAccounts(java.lang.String, java.util.List<android.telecom.PhoneAccountSuggestion>);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService";
+  }
+
 }
 
 package android.telephony {
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index a981997..69cb264 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -293,7 +293,7 @@
 
     // Then, check stats-data directory to see there's any file containing
     // ConfigMetricsReport from previous shutdowns to concatenate to reports.
-    StorageManager::appendConfigMetricsReport(key, proto);
+    StorageManager::appendConfigMetricsReport(key, proto, erase_data);
 
     auto it = mMetricsManagers.find(key);
     if (it != mMetricsManagers.end()) {
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 51a7316..50b64b9 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -296,6 +296,7 @@
                                  ADB_DUMP, &proto);
         proto.end(reportsListToken);
         proto.flush(out);
+        proto.clear();
     }
 }
 
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 0c05be1..fd62843 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -172,6 +172,7 @@
         WifiEnabledStateChanged wifi_enabled_state_changed = 113;
         WifiRunningStateChanged wifi_running_state_changed = 114;
         AppCompacted app_compacted = 115;
+        NetworkDnsEventReported network_dns_event_Reported = 116;
     }
 
     // Pulled events will start at field 10000.
@@ -3670,7 +3671,7 @@
     SOME = 1;
     FULL = 2;
   }
-  optional Action action = 3 [default = UNKNOWN];
+  optional Action action = 3;
 
   // Total RSS in kilobytes consumed by the process prior to compaction.
   optional int64 before_rss_total_kilobytes = 4;
@@ -3702,13 +3703,61 @@
   // The last compaction action performed for this app.
   optional Action last_action = 13;
 
-  // The last time that compaction was attempted on this process in seconds
-  // since boot.
-  optional int64 last_compact_timestamp = 14;
+  // The last time that compaction was attempted on this process in milliseconds
+  // since boot, not including sleep (see SystemClock.uptimeMillis()).
+  optional int64 last_compact_timestamp_ms_since_boot = 14;
 
-  // The oom_adj at the time of compaction.
-  optional int32 oom_adj = 15;
+  // The oom_score_adj at the time of compaction.
+  optional int32 oom_score_adj = 15;
 
   // The process state at the time of compaction.
   optional android.app.ProcessStateEnum process_state = 16 [default = PROCESS_STATE_UNKNOWN];
 }
+
+/**
+ * Logs the latency period(in microseconds) and the return code of
+ * the DNS(Domain Name System) lookups.
+ * These 4 methods(GETADDRINFO,GETHOSTBYNAME,GETHOSTBYADDR,RES_NSEND)
+ * to get info(address or hostname) from DNS server(or DNS cache).
+ * Logged from:
+ *   /system/netd/server/DnsProxyListener.cpp
+ */
+message NetworkDnsEventReported {
+    // The types of the DNS lookups, as defined in
+    //system/netd/server/binder/android/net/metrics/INetdEventListener.aidl
+    enum EventType {
+        EVENT_UNKNOWN = 0;
+        EVENT_GETADDRINFO = 1;
+        EVENT_GETHOSTBYNAME = 2;
+        EVENT_GETHOSTBYADDR = 3;
+        EVENT_RES_NSEND = 4;
+    }
+    optional EventType event_type = 1;
+
+    // The return value of the DNS resolver for each DNS lookups.
+    //bionic/libc/include/netdb.h
+    //system/netd/resolv/include/netd_resolv/resolv.h
+    enum ReturnCode {
+        EAI_NOERR = 0;
+        EAI_ADDRFAMILY = 1;
+        EAI_AGAIN = 2;
+        EAI_BADFLAGS = 3;
+        EAI_FAIL = 4;
+        EAI_FAMILY = 5;
+        EAI_MEMORY = 6;
+        EAI_NODATA = 7;
+        EAI_NONAME = 8;
+        EAI_SERVICE = 9;
+        EAI_SOCKTYPE = 10;
+        EAI_SYSTEM = 11;
+        EAI_BADHINTS = 12;
+        EAI_PROTOCOL = 13;
+        EAI_OVERFLOW = 14;
+        RESOLV_TIMEOUT = 255;
+        EAI_MAX = 256;
+    }
+    optional ReturnCode return_code = 2;
+
+    // The latency period(in microseconds) it took for this DNS lookup to complete.
+    optional int32 latency_micros = 3;
+}
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 2f19a02..90f641a 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -188,7 +188,9 @@
     return false;
 }
 
-void StorageManager::appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto) {
+void StorageManager::appendConfigMetricsReport(const ConfigKey& key,
+                                               ProtoOutputStream* proto,
+                                               bool erasa_data) {
     unique_ptr<DIR, decltype(&closedir)> dir(opendir(STATS_DATA_DIR), closedir);
     if (dir == NULL) {
         VLOG("Path %s does not exist", STATS_DATA_DIR);
@@ -224,8 +226,9 @@
                 close(fd);
             }
 
-            // Remove file from disk after reading.
-            remove(file_name.c_str());
+            if (erasa_data) {
+                remove(file_name.c_str());
+            }
         }
     }
 }
diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h
index 8fbc89e..dcf3bb6 100644
--- a/cmds/statsd/src/storage/StorageManager.h
+++ b/cmds/statsd/src/storage/StorageManager.h
@@ -68,10 +68,12 @@
     static bool hasConfigMetricsReport(const ConfigKey& key);
 
     /**
-     * Appends ConfigMetricsReport found on disk to the specific proto and
-     * delete it.
+     * Appends the ConfigMetricsReport found on disk to the specifid proto
+     * and, if erase_data, deletes it from disk.
      */
-    static void appendConfigMetricsReport(const ConfigKey& key, ProtoOutputStream* proto);
+    static void appendConfigMetricsReport(const ConfigKey& key,
+                                          ProtoOutputStream* proto,
+                                          bool erase_data);
 
     /**
      * Call to load the saved configs from disk.
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index a39f5e3..4174ad7 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -51,6 +51,8 @@
     private static final String COMMAND_ADD_OR_REMOVE_CALL_COMPANION_APP =
             "add-or-remove-call-companion-app";
     private static final String COMMAND_SET_TEST_AUTO_MODE_APP = "set-test-auto-mode-app";
+    private static final String COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT =
+            "set-phone-acct-suggestion-component";
     private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account";
     private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
     private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
@@ -64,36 +66,37 @@
 
     @Override
     public void onShowUsage(PrintStream out) {
-        out.println(
-                "usage: telecom [subcommand] [options]\n" +
-                "usage: telecom set-phone-account-enabled <COMPONENT> <ID> <USER_SN>\n" +
-                "usage: telecom set-phone-account-disabled <COMPONENT> <ID> <USER_SN>\n" +
-                "usage: telecom register-phone-account <COMPONENT> <ID> <USER_SN> <LABEL>\n" +
-                "usage: telecom set-test-call-redirection-app <PACKAGE>\n" +
-                "usage: telecom set-test-call-screening-app <PACKAGE>\n" +
-                "usage: telecom set-test-auto-mode-app <PACKAGE>\n" +
-                "usage: telecom add-or-remove-call-companion-app <PACKAGE> <1/0>\n" +
-                "usage: telecom register-sim-phone-account <COMPONENT> <ID> <USER_SN> <LABEL> <ADDRESS>\n" +
-                "usage: telecom unregister-phone-account <COMPONENT> <ID> <USER_SN>\n" +
-                "usage: telecom set-default-dialer <PACKAGE>\n" +
-                "usage: telecom get-default-dialer\n" +
-                "usage: telecom get-system-dialer\n" +
-                "usage: telecom wait-on-handlers\n" +
-                "\n" +
-                "telecom set-phone-account-enabled: Enables the given phone account, if it has \n" +
-                " already been registered with Telecom.\n" +
-                "\n" +
-                "telecom set-phone-account-disabled: Disables the given phone account, if it \n" +
-                " has already been registered with telecom.\n" +
-                "\n" +
-                "telecom set-default-dialer: Sets the default dialer to the given component. \n" +
-                "\n" +
-                "telecom get-default-dialer: Displays the current default dialer. \n" +
-                "\n" +
-                "telecom get-system-dialer: Displays the current system dialer. \n" +
-                "\n" +
-                "telecom wait-on-handlers: Wait until all handlers finish their work. \n"
-                );
+        out.println("usage: telecom [subcommand] [options]\n"
+                + "usage: telecom set-phone-account-enabled <COMPONENT> <ID> <USER_SN>\n"
+                + "usage: telecom set-phone-account-disabled <COMPONENT> <ID> <USER_SN>\n"
+                + "usage: telecom register-phone-account <COMPONENT> <ID> <USER_SN> <LABEL>\n"
+                + "usage: telecom set-test-call-redirection-app <PACKAGE>\n"
+                + "usage: telecom set-test-call-screening-app <PACKAGE>\n"
+                + "usage: telecom set-test-auto-mode-app <PACKAGE>\n"
+                + "usage: telecom set-phone-acct-suggestion-component <COMPONENT>\n"
+                + "usage: telecom add-or-remove-call-companion-app <PACKAGE> <1/0>\n"
+                + "usage: telecom register-sim-phone-account <COMPONENT> <ID> <USER_SN>"
+                + " <LABEL> <ADDRESS>\n"
+                + "usage: telecom unregister-phone-account <COMPONENT> <ID> <USER_SN>\n"
+                + "usage: telecom set-default-dialer <PACKAGE>\n"
+                + "usage: telecom get-default-dialer\n"
+                + "usage: telecom get-system-dialer\n"
+                + "usage: telecom wait-on-handlers\n"
+                + "\n"
+                + "telecom set-phone-account-enabled: Enables the given phone account, if it has \n"
+                + " already been registered with Telecom.\n"
+                + "\n"
+                + "telecom set-phone-account-disabled: Disables the given phone account, if it \n"
+                + " has already been registered with telecom.\n"
+                + "\n"
+                + "telecom set-default-dialer: Sets the default dialer to the given component. \n"
+                + "\n"
+                + "telecom get-default-dialer: Displays the current default dialer. \n"
+                + "\n"
+                + "telecom get-system-dialer: Displays the current system dialer. \n"
+                + "\n"
+                + "telecom wait-on-handlers: Wait until all handlers finish their work. \n"
+        );
     }
 
     @Override
@@ -134,6 +137,9 @@
             case COMMAND_SET_TEST_AUTO_MODE_APP:
                 runSetTestAutoModeApp();
                 break;
+            case COMMAND_SET_PHONE_ACCOUNT_SUGGESTION_COMPONENT:
+                runSetTestPhoneAcctSuggestionComponent();
+                break;
             case COMMAND_REGISTER_SIM_PHONE_ACCOUNT:
                 runRegisterSimPhoneAccount();
                 break;
@@ -216,6 +222,11 @@
         mTelecomService.setTestAutoModeApp(packageName);
     }
 
+    private void runSetTestPhoneAcctSuggestionComponent() throws RemoteException {
+        final String componentName = nextArg();
+        mTelecomService.setTestPhoneAcctSuggestionComponent(componentName);
+    }
+
     private void runUnregisterPhoneAccount() throws RemoteException {
         final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
         mTelecomService.unregisterPhoneAccount(handle);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index a278423..791f3da 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -3078,7 +3078,7 @@
      */
     public int unsafeCheckOpRaw(String op, int uid, String packageName) {
         try {
-            return mService.checkOperation(strOpToOp(op), uid, packageName);
+            return mService.checkOperationRaw(strOpToOp(op), uid, packageName);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index 7fe21b2..139a39f 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -37,10 +37,11 @@
          * @param uid The UID for which to check.
          * @param packageName The package for which to check.
          * @param superImpl The super implementation.
+         * @param raw Whether to check the raw op i.e. not interpret the mode based on UID state.
          * @return The app op check result.
          */
-        int checkOperation(int code, int uid, String packageName,
-                TriFunction<Integer, Integer, String, Integer> superImpl);
+        int checkOperation(int code, int uid, String packageName, boolean raw,
+                QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl);
 
         /**
          * Allows overriding check audio operation behavior.
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 00567523..163be8e 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -65,6 +65,10 @@
     boolean areNotificationsEnabled(String pkg);
     int getPackageImportance(String pkg);
 
+    void setAppOverlaysAllowed(String pkg, int uid, boolean allowed);
+    boolean areAppOverlaysAllowed(String pkg);
+    boolean areAppOverlaysAllowedForPackage(String pkg, int uid);
+
     void createNotificationChannelGroups(String pkg, in ParceledListSlice channelGroupList);
     void createNotificationChannels(String pkg, in ParceledListSlice channelsList);
     void createNotificationChannelsForPackage(String pkg, int uid, in ParceledListSlice channelsList);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b9d5907..e066f06 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3130,6 +3130,10 @@
         return mAppOverlayIntent;
     }
 
+    /**
+     * Returns whether the platform is allowed (by the app developer) to generate contextual actions
+     * for this notification.
+     */
     public boolean getAllowSystemGeneratedContextualActions() {
         return mAllowSystemGeneratedContextualActions;
     }
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 2322a42..34cd9f0 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -50,20 +50,12 @@
     private static final String ATT_DESC = "desc";
     private static final String ATT_ID = "id";
     private static final String ATT_BLOCKED = "blocked";
-    private static final String ATT_ALLOW_APP_OVERLAY = "app_overlay";
     private static final String ATT_USER_LOCKED = "locked";
 
-    private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true;
-
     /**
      * @hide
      */
     public static final int USER_LOCKED_BLOCKED_STATE = 0x00000001;
-    /**
-     * @hide
-     */
-    @TestApi
-    public static final int USER_LOCKED_ALLOW_APP_OVERLAY = 0x00000002;
 
     /**
      * @see #getId()
@@ -74,7 +66,6 @@
     private String mDescription;
     private boolean mBlocked;
     private List<NotificationChannel> mChannels = new ArrayList<>();
-    private boolean mAllowAppOverlay = DEFAULT_ALLOW_APP_OVERLAY;
     // Bitwise representation of fields that have been changed by the user
     private int mUserLockedFields;
 
@@ -110,7 +101,6 @@
         }
         in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader());
         mBlocked = in.readBoolean();
-        mAllowAppOverlay = in.readBoolean();
         mUserLockedFields = in.readInt();
     }
 
@@ -138,7 +128,6 @@
         }
         dest.writeParcelableList(mChannels, flags);
         dest.writeBoolean(mBlocked);
-        dest.writeBoolean(mAllowAppOverlay);
         dest.writeInt(mUserLockedFields);
     }
 
@@ -181,15 +170,6 @@
     }
 
     /**
-     * Returns whether notifications posted to this channel group can display outside of the
-     * notification shade, in a floating window on top of other apps. These may additionally be
-     * blocked at the notification channel level, see {@link NotificationChannel#canOverlayApps()}.
-     */
-    public boolean canOverlayApps() {
-        return mAllowAppOverlay;
-    }
-
-    /**
      * Sets the user visible description of this group.
      *
      * <p>The recommended maximum length is 300 characters; the value may be truncated if it is too
@@ -200,21 +180,6 @@
     }
 
     /**
-     * Sets whether notifications posted to this channel group can appear outside of the
-     * notification shade, floating over other apps' content.
-     *
-     * <p>This value will be ignored for notifications that are posted to channels that do not
-     * allow app overlays ({@link NotificationChannel#canOverlayApps()}.
-     *
-     * <p>Only modifiable before the channel is submitted to
-     * {@link NotificationManager#createNotificationChannelGroup(NotificationChannelGroup)}.</p>
-     * @see Notification#getAppOverlayIntent()
-     */
-    public void setAllowAppOverlay(boolean allowAppOverlay) {
-        mAllowAppOverlay = allowAppOverlay;
-    }
-
-    /**
      * @hide
      */
     @TestApi
@@ -266,7 +231,6 @@
         // Name, id, and importance are set in the constructor.
         setDescription(parser.getAttributeValue(null, ATT_DESC));
         setBlocked(safeBool(parser, ATT_BLOCKED, false));
-        setAllowAppOverlay(safeBool(parser, ATT_ALLOW_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY));
     }
 
     private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
@@ -289,9 +253,6 @@
             out.attribute(null, ATT_DESC, getDescription().toString());
         }
         out.attribute(null, ATT_BLOCKED, Boolean.toString(isBlocked()));
-        if (canOverlayApps() != DEFAULT_ALLOW_APP_OVERLAY) {
-            out.attribute(null, ATT_ALLOW_APP_OVERLAY, Boolean.toString(canOverlayApps()));
-        }
         out.attribute(null, ATT_USER_LOCKED, Integer.toString(mUserLockedFields));
 
         out.endTag(null, TAG_GROUP);
@@ -307,7 +268,6 @@
         record.put(ATT_NAME, getName());
         record.put(ATT_DESC, getDescription());
         record.put(ATT_BLOCKED, isBlocked());
-        record.put(ATT_ALLOW_APP_OVERLAY, canOverlayApps());
         record.put(ATT_USER_LOCKED, mUserLockedFields);
         return record;
     }
@@ -336,7 +296,6 @@
         if (o == null || getClass() != o.getClass()) return false;
         NotificationChannelGroup that = (NotificationChannelGroup) o;
         return isBlocked() == that.isBlocked() &&
-                mAllowAppOverlay == that.mAllowAppOverlay &&
                 mUserLockedFields == that.mUserLockedFields &&
                 Objects.equals(getId(), that.getId()) &&
                 Objects.equals(getName(), that.getName()) &&
@@ -347,7 +306,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(getId(), getName(), getDescription(), isBlocked(), getChannels(),
-                mAllowAppOverlay, mUserLockedFields);
+                mUserLockedFields);
     }
 
     @Override
@@ -356,7 +315,6 @@
         cloned.setDescription(getDescription());
         cloned.setBlocked(isBlocked());
         cloned.setChannels(getChannels());
-        cloned.setAllowAppOverlay(canOverlayApps());
         cloned.lockFields(mUserLockedFields);
         return cloned;
     }
@@ -369,7 +327,6 @@
                 + ", mDescription=" + (!TextUtils.isEmpty(mDescription) ? "hasDescription " : "")
                 + ", mBlocked=" + mBlocked
                 + ", mChannels=" + mChannels
-                + ", mAllowAppOverlay=" + mAllowAppOverlay
                 + ", mUserLockedFields=" + mUserLockedFields
                 + '}';
     }
@@ -385,7 +342,6 @@
         for (NotificationChannel channel : mChannels) {
             channel.writeToProto(proto, NotificationChannelGroupProto.CHANNELS);
         }
-        proto.write(NotificationChannelGroupProto.ALLOW_APP_OVERLAY, mAllowAppOverlay);
         proto.end(token);
     }
 }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 606b00b..a782ced 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1074,6 +1074,25 @@
         }
     }
 
+
+    /**
+     * Sets whether notifications posted by this app can appear outside of the
+     * notification shade, floating over other apps' content.
+     *
+     * <p>This value will be ignored for notifications that are posted to channels that do not
+     * allow app overlays ({@link NotificationChannel#canOverlayApps()}.
+     *
+     * @see Notification#getAppOverlayIntent()
+     */
+    public boolean areAppOverlaysAllowed() {
+        INotificationManager service = getService();
+        try {
+            return service.areAppOverlaysAllowed(mContext.getPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /**
      * Checks the ability to modify notification do not disturb policy for the calling package.
      *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2f0618c..d5c6c63 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4222,6 +4222,11 @@
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_HOME_MAIN = "android.intent.category.HOME_MAIN";
     /**
+     * The home activity shown on secondary displays that support showing home activities.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_SECONDARY_HOME = "android.intent.category.SECONDARY_HOME";
+    /**
      * This is the setup wizard activity, that is the first activity that is displayed
      * when the user sets up the device for the first time.
      * @hide
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index f81eb76..623bdda 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -17,6 +17,7 @@
 package android.content.pm;
 
 import android.Manifest;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -54,6 +55,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.security.MessageDigest;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -1594,6 +1597,29 @@
         public static final int INVALID_ID = -1;
         /** {@hide} */
         private static final int[] NO_SESSIONS = {};
+
+        /** @hide */
+        @IntDef(value = {NO_ERROR, VERIFICATION_FAILED, ACTIVATION_FAILED})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface StagedSessionErrorCode{}
+        /**
+         * Constant indicating that no error occurred during the preparation or the activation of
+         * this staged session.
+         */
+        public static final int NO_ERROR = 0;
+
+        /**
+         * Constant indicating that an error occurred during the verification phase (pre-reboot) of
+         * this staged session.
+         */
+        public static final int VERIFICATION_FAILED = 1;
+
+        /**
+         * Constant indicating that an error occurred during the activation phase (post-reboot) of
+         * this staged session.
+         */
+        public static final int ACTIVATION_FAILED = 2;
+
         /** {@hide} */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
         public int sessionId;
@@ -1653,6 +1679,14 @@
         public int[] childSessionIds = NO_SESSIONS;
 
         /** {@hide} */
+        public boolean isSessionApplied;
+        /** {@hide} */
+        public boolean isSessionReady;
+        /** {@hide} */
+        public boolean isSessionFailed;
+        private int mStagedSessionErrorCode;
+
+        /** {@hide} */
         @UnsupportedAppUsage
         public SessionInfo() {
         }
@@ -1686,6 +1720,10 @@
             if (childSessionIds == null) {
                 childSessionIds = NO_SESSIONS;
             }
+            isSessionApplied = source.readBoolean();
+            isSessionReady = source.readBoolean();
+            isSessionFailed = source.readBoolean();
+            mStagedSessionErrorCode = source.readInt();
         }
 
         /**
@@ -1970,6 +2008,44 @@
             return childSessionIds;
         }
 
+        /**
+         * Whether the staged session has been applied successfully, meaning that all of its
+         * packages have been activated and no further action is required.
+         * Only meaningful if {@code isStaged} is true.
+         */
+        public boolean isSessionApplied() {
+            return isSessionApplied;
+        }
+
+        /**
+         * Whether the staged session is ready to be applied at next reboot. Only meaningful if
+         * {@code isStaged} is true.
+         */
+        public boolean isSessionReady() {
+            return isSessionReady;
+        }
+
+        /**
+         * Whether something went wrong and the staged session is declared as failed, meaning that
+         * it will be ignored at next reboot. Only meaningful if {@code isStaged} is true.
+         */
+        public boolean isSessionFailed() {
+            return isSessionFailed;
+        }
+
+        /**
+         * If something went wrong with a staged session, clients can check this error code to
+         * understand which kind of failure happened. Only meaningful if {@code isStaged} is true.
+         */
+        public int getStagedSessionErrorCode() {
+            return mStagedSessionErrorCode;
+        }
+
+        /** {@hide} */
+        public void setStagedSessionErrorCode(@StagedSessionErrorCode int errorCode) {
+            mStagedSessionErrorCode = errorCode;
+        }
+
         @Override
         public int describeContents() {
             return 0;
@@ -2001,6 +2077,10 @@
             dest.writeBoolean(isStaged);
             dest.writeInt(parentSessionId);
             dest.writeIntArray(childSessionIds);
+            dest.writeBoolean(isSessionApplied);
+            dest.writeBoolean(isSessionReady);
+            dest.writeBoolean(isSessionFailed);
+            dest.writeInt(mStagedSessionErrorCode);
         }
 
         public static final Parcelable.Creator<SessionInfo>
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 8a03e9e..df1a713 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -16,6 +16,7 @@
 
 package android.os.storage;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -348,6 +349,32 @@
         return intent;
     }
 
+    /**
+     * Builds an {@link Intent#ACTION_OPEN_DOCUMENT_TREE} to allow the user to grant access to any
+     * directory subtree (or entire volume) from the {@link android.provider.DocumentsProvider}s
+     * available on the device. The initial location of the document navigation will be the root of
+     * this {@link StorageVolume}.
+     *
+     * Note that the returned {@link Intent} simply suggests that the user picks this {@link
+     * StorageVolume} by default, but the user may select a different location. Callers must respect
+     * the user's chosen location, even if it is different from the originally requested location.
+     *
+     * @return intent to {@link Intent#ACTION_OPEN_DOCUMENT_TREE} initially showing the contents
+     *         of this {@link StorageVolume}
+     * @see Intent#ACTION_OPEN_DOCUMENT_TREE
+     */
+    @NonNull public Intent createOpenDocumentTreeIntent() {
+        final String rootId = isEmulated()
+                ? DocumentsContract.EXTERNAL_STORAGE_PRIMARY_EMULATED_ROOT_ID
+                : mFsUuid;
+        final Uri rootUri = DocumentsContract.buildRootUri(
+                DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY, rootId);
+        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
+                .putExtra(DocumentsContract.EXTRA_INITIAL_URI, rootUri)
+                .putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, true);
+        return intent;
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (obj instanceof StorageVolume && mPath != null) {
diff --git a/core/java/android/permission/RuntimePermissionPresenter.java b/core/java/android/permission/RuntimePermissionPresenter.java
index 3ce3c9d..c607e3f 100644
--- a/core/java/android/permission/RuntimePermissionPresenter.java
+++ b/core/java/android/permission/RuntimePermissionPresenter.java
@@ -16,27 +16,28 @@
 
 package android.permission;
 
+import static android.permission.RuntimePermissionPresenterService.SERVICE_INTERFACE;
+
 import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
 import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.ServiceConnection;
+import android.content.pm.ResolveInfo;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Message;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
+import com.android.internal.infra.AbstractRemoteService;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -80,7 +81,7 @@
      */
     public interface OnCountPermissionAppsResultCallback {
         /**
-         * The result for {@link #countPermissionApps(List, boolean,
+         * The result for {@link #countPermissionApps(List, boolean, boolean,
          * OnCountPermissionAppsResultCallback, Handler)}.
          *
          * @param numApps The number of apps that have one of the permissions
@@ -110,8 +111,13 @@
         }
     }
 
-    private RuntimePermissionPresenter(Context context) {
-        mRemoteService = new RemoteService(context);
+    private RuntimePermissionPresenter(@NonNull Context context) {
+        Intent intent = new Intent(SERVICE_INTERFACE);
+        intent.setPackage(context.getPackageManager().getPermissionControllerPackageName());
+        ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0);
+
+        mRemoteService = new RemoteService(context,
+                serviceInfo.getComponentInfo().getComponentName());
     }
 
     /**
@@ -126,8 +132,8 @@
         checkNotNull(packageName);
         checkNotNull(callback);
 
-        mRemoteService.processMessage(obtainMessage(RemoteService::getAppPermissions,
-                mRemoteService, packageName, callback, handler));
+        mRemoteService.scheduleRequest(new PendingGetAppPermissionRequest(mRemoteService,
+                packageName, callback, handler == null ? mRemoteService.getHandler() : handler));
     }
 
     /**
@@ -141,8 +147,8 @@
         checkNotNull(packageName);
         checkNotNull(permissionName);
 
-        mRemoteService.processMessage(obtainMessage(RemoteService::revokeAppPermissions,
-                mRemoteService, packageName, permissionName));
+        mRemoteService.scheduleAsyncRequest(new PendingRevokeAppPermissionRequest(packageName,
+                permissionName));
     }
 
     /**
@@ -160,183 +166,192 @@
         checkCollectionElementsNotNull(permissionNames, "permissionNames");
         checkNotNull(callback);
 
-        mRemoteService.processMessage(obtainMessage(RemoteService::countPermissionApps,
-                mRemoteService, permissionNames, countOnlyGranted, countSystem, callback, handler));
+        mRemoteService.scheduleRequest(new PendingCountPermissionAppsRequest(mRemoteService,
+                permissionNames, countOnlyGranted, countSystem, callback,
+                handler == null ? mRemoteService.getHandler() : handler));
     }
 
-    private static final class RemoteService
-            extends Handler implements ServiceConnection {
+    /**
+     * A connection to the remote service
+     */
+    static final class RemoteService extends
+            AbstractMultiplePendingRequestsRemoteService<RemoteService,
+                    IRuntimePermissionPresenter>  {
         private static final long UNBIND_TIMEOUT_MILLIS = 10000;
+        private static final long MESSAGE_TIMEOUT_MILLIS = 30000;
 
-        public static final int MSG_UNBIND = 0;
-
-        private final Object mLock = new Object();
-
-        private final Context mContext;
-
-        @GuardedBy("mLock")
-        private final List<Message> mPendingWork = new ArrayList<>();
-
-        @GuardedBy("mLock")
-        private IRuntimePermissionPresenter mRemoteInstance;
-
-        @GuardedBy("mLock")
-        private boolean mBound;
-
-        RemoteService(Context context) {
-            super(context.getMainLooper(), null, false);
-            mContext = context;
+        /**
+         * Create a connection to the remote service
+         *
+         * @param context A context to use
+         * @param componentName The component of the service to connect to
+         */
+        RemoteService(@NonNull Context context, @NonNull ComponentName componentName) {
+            super(context, SERVICE_INTERFACE, componentName, UserHandle.myUserId(),
+                    service -> Log.e(TAG, "RuntimePermPresenterService " + service + " died"),
+                    false, false, 1);
         }
 
-        public void processMessage(Message message) {
-            synchronized (mLock) {
-                if (!mBound) {
-                    Intent intent = new Intent(
-                            RuntimePermissionPresenterService.SERVICE_INTERFACE);
-                    intent.setPackage(mContext.getPackageManager()
-                            .getPermissionControllerPackageName());
-                    mBound = mContext.bindService(intent, this,
-                            Context.BIND_AUTO_CREATE);
+        /**
+         * @return The default handler used by this service.
+         */
+        Handler getHandler() {
+            return mHandler;
+        }
+
+        @Override
+        protected @NonNull IRuntimePermissionPresenter getServiceInterface(
+                @NonNull IBinder binder) {
+            return IRuntimePermissionPresenter.Stub.asInterface(binder);
+        }
+
+        @Override
+        protected long getTimeoutIdleBindMillis() {
+            return UNBIND_TIMEOUT_MILLIS;
+        }
+
+        @Override
+        protected long getRemoteRequestMillis() {
+            return MESSAGE_TIMEOUT_MILLIS;
+        }
+
+        @Override
+        public void scheduleRequest(@NonNull PendingRequest<RemoteService,
+                IRuntimePermissionPresenter> pendingRequest) {
+            super.scheduleRequest(pendingRequest);
+        }
+
+        @Override
+        public void scheduleAsyncRequest(
+                @NonNull AsyncRequest<IRuntimePermissionPresenter> request) {
+            super.scheduleAsyncRequest(request);
+        }
+    }
+
+    /**
+     * Request for {@link #getAppPermissions}
+     */
+    private static final class PendingGetAppPermissionRequest extends
+            AbstractRemoteService.PendingRequest<RemoteService, IRuntimePermissionPresenter> {
+        private final @NonNull String mPackageName;
+        private final @NonNull OnGetAppPermissionResultCallback mCallback;
+
+        private final @NonNull RemoteCallback mRemoteCallback;
+
+        private PendingGetAppPermissionRequest(@NonNull RemoteService service,
+                @NonNull String packageName, @NonNull OnGetAppPermissionResultCallback callback,
+                @NonNull Handler handler) {
+            super(service);
+
+            mPackageName = packageName;
+            mCallback = callback;
+
+            mRemoteCallback = new RemoteCallback(result -> {
+                final List<RuntimePermissionPresentationInfo> reportedPermissions;
+                List<RuntimePermissionPresentationInfo> permissions = null;
+                if (result != null) {
+                    permissions = result.getParcelableArrayList(KEY_RESULT);
                 }
-                mPendingWork.add(message);
-                scheduleNextMessageIfNeededLocked();
-            }
+                if (permissions == null) {
+                    permissions = Collections.emptyList();
+                }
+                reportedPermissions = permissions;
+
+                callback.onGetAppPermissions(reportedPermissions);
+
+                finish();
+            }, handler);
         }
 
         @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            synchronized (mLock) {
-                mRemoteInstance = IRuntimePermissionPresenter.Stub.asInterface(service);
-                scheduleNextMessageIfNeededLocked();
-            }
+        protected void onTimeout(RemoteService remoteService) {
+            mCallback.onGetAppPermissions(Collections.emptyList());
         }
 
         @Override
-        public void onServiceDisconnected(ComponentName name) {
-            synchronized (mLock) {
-                mRemoteInstance = null;
-            }
-        }
-
-        private void getAppPermissions(@NonNull String packageName,
-                @NonNull OnGetAppPermissionResultCallback callback, @Nullable Handler handler) {
-            final IRuntimePermissionPresenter remoteInstance;
-            synchronized (mLock) {
-                remoteInstance = mRemoteInstance;
-            }
-            if (remoteInstance == null) {
-                return;
-            }
+        public void run() {
             try {
-                remoteInstance.getAppPermissions(packageName,
-                        new RemoteCallback(result -> {
-                            final List<RuntimePermissionPresentationInfo> reportedPermissions;
-                            List<RuntimePermissionPresentationInfo> permissions = null;
-                            if (result != null) {
-                                permissions = result.getParcelableArrayList(KEY_RESULT);
-                            }
-                            if (permissions == null) {
-                                permissions = Collections.emptyList();
-                            }
-                            reportedPermissions = permissions;
-                            if (handler != null) {
-                                handler.post(
-                                        () -> callback.onGetAppPermissions(reportedPermissions));
-                            } else {
-                                callback.onGetAppPermissions(reportedPermissions);
-                            }
-                        }, this));
-            } catch (RemoteException re) {
-                Log.e(TAG, "Error getting app permissions", re);
-            }
-            scheduleUnbind();
-
-            synchronized (mLock) {
-                scheduleNextMessageIfNeededLocked();
+                getService().getServiceInterface().getAppPermissions(mPackageName, mRemoteCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error getting app permission", e);
             }
         }
+    }
 
-        private void revokeAppPermissions(@NonNull String packageName,
+    /**
+     * Request for {@link #revokeRuntimePermission}
+     */
+    private static final class PendingRevokeAppPermissionRequest
+            implements AbstractRemoteService.AsyncRequest<IRuntimePermissionPresenter> {
+        private final @NonNull String mPackageName;
+        private final @NonNull String mPermissionName;
+
+        private PendingRevokeAppPermissionRequest(@NonNull String packageName,
                 @NonNull String permissionName) {
-            final IRuntimePermissionPresenter remoteInstance;
-            synchronized (mLock) {
-                remoteInstance = mRemoteInstance;
-            }
-            if (remoteInstance == null) {
-                return;
-            }
-            try {
-                remoteInstance.revokeRuntimePermission(packageName, permissionName);
-            } catch (RemoteException re) {
-                Log.e(TAG, "Error getting app permissions", re);
-            }
-
-            synchronized (mLock) {
-                scheduleNextMessageIfNeededLocked();
-            }
+            mPackageName = packageName;
+            mPermissionName = permissionName;
         }
 
-        private void countPermissionApps(@NonNull List<String> permissionNames,
-                boolean countOnlyGranted, boolean countSystem,
-                @NonNull OnCountPermissionAppsResultCallback callback, @Nullable Handler handler) {
-            final IRuntimePermissionPresenter remoteInstance;
-
-            synchronized (mLock) {
-                remoteInstance = mRemoteInstance;
-            }
-            if (remoteInstance == null) {
-                return;
-            }
-
+        @Override
+        public void run(IRuntimePermissionPresenter remoteInterface) {
             try {
-                remoteInstance.countPermissionApps(permissionNames, countOnlyGranted, countSystem,
-                        new RemoteCallback(result -> {
-                            final int numApps;
-                            if (result != null) {
-                                numApps = result.getInt(KEY_RESULT);
-                            } else {
-                                numApps = 0;
-                            }
-
-                            if (handler != null) {
-                                handler.post(() -> callback.onCountPermissionApps(numApps));
-                            } else {
-                                callback.onCountPermissionApps(numApps);
-                            }
-                        }, this));
-            } catch (RemoteException re) {
-                Log.e(TAG, "Error counting permission apps", re);
-            }
-
-            scheduleUnbind();
-
-            synchronized (mLock) {
-                scheduleNextMessageIfNeededLocked();
+                remoteInterface.revokeRuntimePermission(mPackageName, mPermissionName);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error revoking app permission", e);
             }
         }
+    }
 
-        private void unbind() {
-            synchronized (mLock) {
-                if (mBound) {
-                    mContext.unbindService(this);
-                    mBound = false;
+    /**
+     * Request for {@link #countPermissionApps}
+     */
+    private static final class PendingCountPermissionAppsRequest extends
+            AbstractRemoteService.PendingRequest<RemoteService, IRuntimePermissionPresenter> {
+        private final @NonNull List<String> mPermissionNames;
+        private final @NonNull OnCountPermissionAppsResultCallback mCallback;
+        private final boolean mCountOnlyGranted;
+        private final boolean mCountSystem;
+
+        private final @NonNull RemoteCallback mRemoteCallback;
+
+        private PendingCountPermissionAppsRequest(@NonNull RemoteService service,
+                @NonNull List<String> permissionNames, boolean countOnlyGranted,
+                boolean countSystem, @NonNull OnCountPermissionAppsResultCallback callback,
+                @NonNull Handler handler) {
+            super(service);
+
+            mPermissionNames = permissionNames;
+            mCountOnlyGranted = countOnlyGranted;
+            mCountSystem = countSystem;
+            mCallback = callback;
+
+            mRemoteCallback = new RemoteCallback(result -> {
+                final int numApps;
+                if (result != null) {
+                    numApps = result.getInt(KEY_RESULT);
+                } else {
+                    numApps = 0;
                 }
-                mRemoteInstance = null;
-            }
+
+                callback.onCountPermissionApps(numApps);
+
+                finish();
+            }, handler);
         }
 
-        @GuardedBy("mLock")
-        private void scheduleNextMessageIfNeededLocked() {
-            if (mBound && mRemoteInstance != null && !mPendingWork.isEmpty()) {
-                Message nextMessage = mPendingWork.remove(0);
-                sendMessage(nextMessage);
-            }
+        @Override
+        protected void onTimeout(RemoteService remoteService) {
+            mCallback.onCountPermissionApps(0);
         }
 
-        private void scheduleUnbind() {
-            removeMessages(MSG_UNBIND);
-            sendMessageDelayed(PooledLambda.obtainMessage(RemoteService::unbind, this)
-                    .setWhat(MSG_UNBIND), UNBIND_TIMEOUT_MILLIS);
+        @Override
+        public void run() {
+            try {
+                getService().getServiceInterface().countPermissionApps(mPermissionNames,
+                        mCountOnlyGranted, mCountSystem, mRemoteCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error counting permission apps", e);
+            }
         }
     }
 }
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index cd991cc..a323ed1 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -238,6 +238,9 @@
             "com.android.externalstorage.documents";
 
     /** {@hide} */
+    public static final String EXTERNAL_STORAGE_PRIMARY_EMULATED_ROOT_ID = "primary";
+
+    /** {@hide} */
     public static final String PACKAGE_DOCUMENTS_UI = "com.android.documentsui";
 
     /**
@@ -857,16 +860,6 @@
     }
 
     /**
-     * Builds URI for user home directory on external (local) storage.
-     * {@hide}
-     */
-    public static Uri buildHomeUri() {
-        // TODO: Avoid this type of interpackage copying. Added here to avoid
-        // direct coupling, but not ideal.
-        return DocumentsContract.buildRootUri(EXTERNAL_STORAGE_PROVIDER_AUTHORITY, "home");
-    }
-
-    /**
      * Build URI representing the recently modified documents of a specific root
      * in a document provider. When queried, a provider will return zero or more
      * rows with columns defined by {@link Document}.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 40f1946..d93985c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12820,6 +12820,17 @@
                 "privileged_device_identifier_3p_check_relaxed";
 
         /**
+         * If set to 1, the device identifier check will be relaxed to the previous READ_PHONE_STATE
+         * permission check for preloaded non-privileged apps.
+         *
+         * STOPSHIP: Remove this once we ship with the new device identifier check enabled.
+         *
+         * @hide
+         */
+        public static final String PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED =
+                "privileged_device_identifier_non_priv_check_relaxed";
+
+        /**
          * If set to 1, SettingsProvider's restoreAnyVersion="true" attribute will be ignored
          * and restoring to lower version of platform API will be skipped.
          *
@@ -12949,14 +12960,20 @@
 
         /**
          * Property used by {@code com.android.server.SystemServer} on start to decide whether
-         * the Content Capture service should be created or not
+         * the Content Capture service should be created or not.
          *
-         * <p>By default it should *NOT* be set (in which case the decision is based on whether
-         * the OEM provides an implementation for the service), but it can be overridden to:
+         * <p>Possible values are:
          *
          * <ul>
-         *   <li>Provide a "kill switch" so OEMs can disable it remotely in case of emergency.
-         *   <li>Enable the CTS tests to be run on AOSP builds
+         *   <li>If set to {@code default}, it will only be set if the OEM provides and defines the
+         *   service name by overlaying {@code config_defaultContentCaptureService} (this is the
+         *   "default" mode)
+         *   <li>If set to {@code always}, it will always be enabled, even when the resource is not
+         *   overlaid (this is useful during development and to run the CTS tests on AOSP builds).
+         *   <li>Otherwise, it's explicitly disabled (this could work as a "kill switch" so OEMs
+         *   can disable it remotely in case of emergency by setting to something else (like
+         *   {@code "false"}); notice that it's also disabled if the OEM doesn't explicitly set one
+         *   of the values above).
          * </ul>
          *
          * @hide
diff --git a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
index 028180d..784e719 100644
--- a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
+++ b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
@@ -17,26 +17,30 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
-import android.content.pm.ParceledListSlice;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.view.contentcapture.ContentCaptureEvent;
 
+import java.util.Arrays;
 import java.util.List;
 
 /**
- * Batch of content capture events.
+ * Not needed anymore...
+ *
+ * @deprecated
  *
  * @hide
  */
 @SystemApi
+@Deprecated
 public final class ContentCaptureEventsRequest implements Parcelable {
+// TODO(b/121033016): remove .java and .aidl once service implementation doesn't use it anymore
 
-    private final ParceledListSlice<ContentCaptureEvent> mEvents;
+    private final ContentCaptureEvent mEvent;
 
     /** @hide */
-    public ContentCaptureEventsRequest(@NonNull ParceledListSlice<ContentCaptureEvent> events) {
-        mEvents = events;
+    public ContentCaptureEventsRequest(@NonNull ContentCaptureEvent event) {
+        mEvent = event;
     }
 
     /**
@@ -44,7 +48,7 @@
      */
     @NonNull
     public List<ContentCaptureEvent> getEvents() {
-        return mEvents.getList();
+        return Arrays.asList(mEvent);
     }
 
     @Override
@@ -54,7 +58,7 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeParcelable(mEvents, flags);
+        parcel.writeParcelable(mEvent, flags);
     }
 
     public static final Parcelable.Creator<ContentCaptureEventsRequest> CREATOR =
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 953ccf1..c5e62f1 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -34,6 +34,7 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
+import android.view.contentcapture.ActivityContentCaptureSession;
 import android.view.contentcapture.ContentCaptureContext;
 import android.view.contentcapture.ContentCaptureEvent;
 import android.view.contentcapture.ContentCaptureManager;
@@ -108,10 +109,9 @@
             new IContentCaptureDirectManager.Stub() {
 
         @Override
-        public void sendEvents(String sessionId,
-                @SuppressWarnings("rawtypes") ParceledListSlice events) {
+        public void sendEvents(@SuppressWarnings("rawtypes") ParceledListSlice events) {
             mHandler.sendMessage(obtainMessage(ContentCaptureService::handleSendEvents,
-                            ContentCaptureService.this, sessionId, Binder.getCallingUid(), events));
+                            ContentCaptureService.this, Binder.getCallingUid(), events));
         }
     };
 
@@ -217,18 +217,29 @@
     }
 
     /**
-     * Notifies the service of {@link ContentCaptureEvent events} associated with a content capture
-     * session.
      *
-     * @param sessionId the session's Id
-     * @param request the events
+     * @deprecated use {@link #onContentCaptureEvent(ContentCaptureSessionId, ContentCaptureEvent)}
+     * instead.
      */
+    @Deprecated
     public void onContentCaptureEventsRequest(@NonNull ContentCaptureSessionId sessionId,
             @NonNull ContentCaptureEventsRequest request) {
         if (VERBOSE) Log.v(TAG, "onContentCaptureEventsRequest(id=" + sessionId + ")");
     }
 
     /**
+     * Notifies the service of {@link ContentCaptureEvent events} associated with a content capture
+     * session.
+     *
+     * @param sessionId the session's Id
+     * @param event the event
+     */
+    public void onContentCaptureEvent(@NonNull ContentCaptureSessionId sessionId,
+            @NonNull ContentCaptureEvent event) {
+        if (VERBOSE) Log.v(TAG, "onContentCaptureEventsRequest(id=" + sessionId + ")");
+        onContentCaptureEventsRequest(sessionId, new ContentCaptureEventsRequest(event));
+    }
+    /**
      * Notifies the service of {@link SnapshotData snapshot data} associated with a session.
      *
      * @param sessionId the session's Id
@@ -271,11 +282,24 @@
                 mClientInterface.asBinder());
     }
 
-    private void handleSendEvents(@NonNull String sessionId, int uid,
-            @NonNull ParceledListSlice<ContentCaptureEvent> events) {
-        if (handleIsRightCallerFor(sessionId, uid)) {
-            onContentCaptureEventsRequest(new ContentCaptureSessionId(sessionId),
-                    new ContentCaptureEventsRequest(events));
+    private void handleSendEvents(int uid,
+            @NonNull ParceledListSlice<ContentCaptureEvent> parceledEvents) {
+
+        // Most events belong to the same session, so we can keep a reference to the last one
+        // to avoid creating too many ContentCaptureSessionId objects
+        String lastSessionId = null;
+        ContentCaptureSessionId sessionId = null;
+
+        final List<ContentCaptureEvent> events = parceledEvents.getList();
+        for (int i = 0; i < events.size(); i++) {
+            final ContentCaptureEvent event = events.get(i);
+            String sessionIdString = event.getSessionId();
+            if (!sessionIdString.equals(lastSessionId)) {
+                if (!handleIsRightCallerFor(sessionIdString, uid)) continue;
+                sessionId = new ContentCaptureSessionId(sessionIdString);
+                lastSessionId = sessionIdString;
+            }
+            onContentCaptureEvent(sessionId, event);
         }
     }
 
@@ -323,7 +347,7 @@
             final Bundle extras;
             if (binder != null) {
                 extras = new Bundle();
-                extras.putBinder(ContentCaptureSession.EXTRA_BINDER, binder);
+                extras.putBinder(ActivityContentCaptureSession.EXTRA_BINDER, binder);
             } else {
                 extras = null;
             }
diff --git a/core/java/android/view/contentcapture/ActivityContentCaptureSession.java b/core/java/android/view/contentcapture/ActivityContentCaptureSession.java
new file mode 100644
index 0000000..a8f3e0b
--- /dev/null
+++ b/core/java/android/view/contentcapture/ActivityContentCaptureSession.java
@@ -0,0 +1,471 @@
+/*
+ * 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 android.view.contentcapture;
+
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED;
+import static android.view.contentcapture.ContentCaptureManager.DEBUG;
+import static android.view.contentcapture.ContentCaptureManager.VERBOSE;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.TimeUtils;
+import android.view.autofill.AutofillId;
+import android.view.contentcapture.ViewNode.ViewStructureImpl;
+
+import com.android.internal.os.IResultReceiver;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Main session associated with a context.
+ *
+ * <p>This session is created when the activity starts and finished when it stops; clients can use
+ * it to create children activities.
+ *
+ * <p><b>NOTE: all methods in this class should return right away, or do the real work in a handler
+ * thread. Hence, the only field that must be thread-safe is {@code mEnabled}, which is called at
+ * the beginning of every method.
+ *
+ * @hide
+ */
+public final class ActivityContentCaptureSession extends ContentCaptureSession {
+
+    /**
+     * Handler message used to flush the buffer.
+     */
+    private static final int MSG_FLUSH = 1;
+
+    /**
+     * Maximum number of events that are buffered before sent to the app.
+     */
+    // TODO(b/121044064): use settings
+    private static final int MAX_BUFFER_SIZE = 100;
+
+    /**
+     * Frequency the buffer is flushed if stale.
+     */
+    // TODO(b/121044064): use settings
+    private static final int FLUSHING_FREQUENCY_MS = 5_000;
+
+    /**
+     * Name of the {@link IResultReceiver} extra used to pass the binder interface to the service.
+     * @hide
+     */
+    public static final String EXTRA_BINDER = "binder";
+
+    @NonNull
+    private final AtomicBoolean mDisabled;
+
+    @NonNull
+    private final Context mContext;
+
+    @NonNull
+    private final Handler mHandler;
+
+    /**
+     * Interface to the system_server binder object - it's only used to start the session (and
+     * notify when the session is finished).
+     */
+    @Nullable
+    private final IContentCaptureManager mSystemServerInterface;
+
+    /**
+     * Direct interface to the service binder object - it's used to send the events, including the
+     * last ones (when the session is finished)
+     */
+    @Nullable
+    private IContentCaptureDirectManager mDirectServiceInterface;
+    @Nullable
+    private DeathRecipient mDirectServiceVulture;
+
+    private int mState = STATE_UNKNOWN;
+
+    @Nullable
+    private IBinder mApplicationToken;
+
+    @Nullable
+    private ComponentName mComponentName;
+
+    /**
+     * List of events held to be sent as a batch.
+     */
+    @Nullable
+    private ArrayList<ContentCaptureEvent> mEvents;
+
+    // Used just for debugging purposes (on dump)
+    private long mNextFlush;
+
+    // Lazily created on demand.
+    private ContentCaptureSessionId mContentCaptureSessionId;
+
+    /**
+     * @hide */
+    protected ActivityContentCaptureSession(@NonNull Context context, @NonNull Handler handler,
+            @Nullable IContentCaptureManager systemServerInterface, @NonNull AtomicBoolean disabled,
+            @Nullable ContentCaptureContext clientContext) {
+        super(clientContext);
+        mContext = context;
+        mHandler = handler;
+        mSystemServerInterface = systemServerInterface;
+        mDisabled = disabled;
+    }
+
+    /**
+     * Starts this session.
+     *
+     * @hide
+     */
+    void start(@NonNull IBinder applicationToken, @NonNull ComponentName activityComponent) {
+        if (!isContentCaptureEnabled()) return;
+
+        if (VERBOSE) {
+            Log.v(mTag, "start(): token=" + applicationToken + ", comp="
+                    + ComponentName.flattenToShortString(activityComponent));
+        }
+
+        mHandler.sendMessage(obtainMessage(ActivityContentCaptureSession::handleStartSession, this,
+                applicationToken, activityComponent));
+    }
+
+    @Override
+    void flush() {
+        mHandler.sendMessage(obtainMessage(ActivityContentCaptureSession::handleForceFlush, this));
+    }
+
+    @Override
+    void onDestroy() {
+        mHandler.sendMessage(
+                obtainMessage(ActivityContentCaptureSession::handleDestroySession, this));
+    }
+
+    private void handleStartSession(@NonNull IBinder token, @NonNull ComponentName componentName) {
+        if (mState != STATE_UNKNOWN) {
+            // TODO(b/111276913): revisit this scenario
+            Log.w(mTag, "ignoring handleStartSession(" + token + ") while on state "
+                    + getStateAsString(mState));
+            return;
+        }
+        mState = STATE_WAITING_FOR_SERVER;
+        mApplicationToken = token;
+        mComponentName = componentName;
+
+        if (VERBOSE) {
+            Log.v(mTag, "handleStartSession(): token=" + token + ", act="
+                    + getActivityDebugName() + ", id=" + mId);
+        }
+        final int flags = 0; // TODO(b/111276913): get proper flags
+
+        try {
+            mSystemServerInterface.startSession(mContext.getUserId(), mApplicationToken,
+                    componentName, mId, mClientContext, flags, new IResultReceiver.Stub() {
+                        @Override
+                        public void send(int resultCode, Bundle resultData) {
+                            IBinder binder = null;
+                            if (resultData != null) {
+                                binder = resultData.getBinder(EXTRA_BINDER);
+                                if (binder == null) {
+                                    Log.wtf(mTag, "No " + EXTRA_BINDER + " extra result");
+                                    handleResetState();
+                                    return;
+                                }
+                            }
+                            handleSessionStarted(resultCode, binder);
+                        }
+                    });
+        } catch (RemoteException e) {
+            Log.w(mTag, "Error starting session for " + componentName.flattenToShortString() + ": "
+                    + e);
+        }
+    }
+
+    /**
+     * Callback from {@code system_server} after call to
+     * {@link IContentCaptureManager#startSession(int, IBinder, ComponentName, String,
+     * ContentCaptureContext, int, IResultReceiver)}.
+     *
+     * @param resultCode session state
+     * @param binder handle to {@code IContentCaptureDirectManager}
+     */
+    private void handleSessionStarted(int resultCode, @Nullable IBinder binder) {
+        mState = resultCode;
+        if (binder != null) {
+            mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder);
+            mDirectServiceVulture = () -> {
+                Log.w(mTag, "Destroying session " + mId + " because service died");
+                destroy();
+            };
+            try {
+                binder.linkToDeath(mDirectServiceVulture, 0);
+            } catch (RemoteException e) {
+                Log.w(mTag, "Failed to link to death on " + binder + ": " + e);
+            }
+        }
+        if (resultCode == STATE_DISABLED || resultCode == STATE_DISABLED_DUPLICATED_ID) {
+            mDisabled.set(true);
+            handleResetSession(/* resetState= */ false);
+        } else {
+            mDisabled.set(false);
+        }
+        if (VERBOSE) {
+            Log.v(mTag, "handleSessionStarted() result: code=" + resultCode + ", id=" + mId
+                    + ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get()
+                    + ", binder=" + binder);
+        }
+    }
+
+    private void handleSendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
+        if (mEvents == null) {
+            if (VERBOSE) {
+                Log.v(mTag, "Creating buffer for " + MAX_BUFFER_SIZE + " events");
+            }
+            mEvents = new ArrayList<>(MAX_BUFFER_SIZE);
+        }
+        mEvents.add(event);
+
+        final int numberEvents = mEvents.size();
+
+        // TODO(b/120784831): need to optimize it so we buffer changes until a number of X are
+        // buffered (either total or per autofillid). For
+        // example, if the user typed "a", "b", "c" and the threshold is 3, we should buffer
+        // "a" and "b" then send "abc".
+        final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE;
+
+        if (bufferEvent && !forceFlush) {
+            handleScheduleFlush(/* checkExisting= */ true);
+            return;
+        }
+
+        if (mState != STATE_ACTIVE) {
+            // Callback from startSession hasn't been called yet - typically happens on system
+            // apps that are started before the system service
+            // TODO(b/111276913): try to ignore session while system is not ready / boot
+            // not complete instead. Similarly, the manager service should return right away
+            // when the user does not have a service set
+            if (VERBOSE) {
+                Log.v(mTag, "Closing session for " + getActivityDebugName()
+                        + " after " + numberEvents + " delayed events and state "
+                        + getStateAsString(mState));
+            }
+            handleResetState();
+            // TODO(b/111276913): blacklist activity / use special flag to indicate that
+            // when it's launched again
+            return;
+        }
+
+        handleForceFlush();
+    }
+
+    private void handleScheduleFlush(boolean checkExisting) {
+        if (checkExisting && mHandler.hasMessages(MSG_FLUSH)) {
+            // "Renew" the flush message by removing the previous one
+            mHandler.removeMessages(MSG_FLUSH);
+        }
+        mNextFlush = SystemClock.elapsedRealtime() + FLUSHING_FREQUENCY_MS;
+        if (VERBOSE) {
+            Log.v(mTag, "Scheduled to flush in " + FLUSHING_FREQUENCY_MS + "ms: " + mNextFlush);
+        }
+        mHandler.sendMessageDelayed(
+                obtainMessage(ActivityContentCaptureSession::handleFlushIfNeeded, this)
+                .setWhat(MSG_FLUSH), FLUSHING_FREQUENCY_MS);
+    }
+
+    private void handleFlushIfNeeded() {
+        if (mEvents.isEmpty()) {
+            if (VERBOSE) Log.v(mTag, "Nothing to flush");
+            return;
+        }
+        handleForceFlush();
+    }
+
+    private void handleForceFlush() {
+        if (mEvents == null) return;
+
+        if (mDirectServiceInterface == null) {
+            Log.w(mTag, "handleForceFlush(): client not available yet");
+            if (!mHandler.hasMessages(MSG_FLUSH)) {
+                handleScheduleFlush(/* checkExisting= */ false);
+            }
+            return;
+        }
+
+        final int numberEvents = mEvents.size();
+        try {
+            if (DEBUG) {
+                Log.d(mTag, "Flushing " + numberEvents + " event(s) for " + getActivityDebugName());
+            }
+            mHandler.removeMessages(MSG_FLUSH);
+
+            final ParceledListSlice<ContentCaptureEvent> events = handleClearEvents();
+            mDirectServiceInterface.sendEvents(events);
+        } catch (RemoteException e) {
+            Log.w(mTag, "Error sending " + numberEvents + " for " + getActivityDebugName()
+                    + ": " + e);
+        }
+    }
+
+    /**
+     * Resets the buffer and return a {@link ParceledListSlice} with the previous events.
+     */
+    @NonNull
+    private ParceledListSlice<ContentCaptureEvent> handleClearEvents() {
+        // NOTE: we must save a reference to the current mEvents and then set it to to null,
+        // otherwise clearing it would clear it in the receiving side if the service is also local.
+        final List<ContentCaptureEvent> events = mEvents == null
+                ? Collections.emptyList()
+                : mEvents;
+        mEvents = null;
+        return new ParceledListSlice<>(events);
+    }
+
+    private void handleDestroySession() {
+        if (DEBUG) {
+            Log.d(mTag, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
+                    + (mEvents == null ? 0 : mEvents.size()) + " event(s) for "
+                    + getActivityDebugName());
+        }
+
+        try {
+            mSystemServerInterface.finishSession(mContext.getUserId(), mId);
+        } catch (RemoteException e) {
+            Log.e(mTag, "Error destroying system-service session " + mId + " for "
+                    + getActivityDebugName() + ": " + e);
+        }
+    }
+
+    private void handleResetState() {
+        handleResetSession(/* resetState= */ true);
+    }
+
+    // TODO(b/121042846): once we support multiple sessions, we might need to move some of these
+    // clearings out.
+    private void handleResetSession(boolean resetState) {
+        if (resetState) {
+            mState = STATE_UNKNOWN;
+        }
+        mContentCaptureSessionId = null;
+        mApplicationToken = null;
+        mComponentName = null;
+        mEvents = null;
+        if (mDirectServiceInterface != null) {
+            mDirectServiceInterface.asBinder().unlinkToDeath(mDirectServiceVulture, 0);
+        }
+        mDirectServiceInterface = null;
+        mHandler.removeMessages(MSG_FLUSH);
+    }
+
+    @Override
+    void internalNotifyViewAppeared(@NonNull ViewStructureImpl node) {
+        mHandler.sendMessage(obtainMessage(ActivityContentCaptureSession::handleSendEvent, this,
+                new ContentCaptureEvent(mId, TYPE_VIEW_APPEARED)
+                        .setViewNode(node.mNode), /* forceFlush= */ false));
+    }
+
+    @Override
+    void internalNotifyViewDisappeared(@NonNull AutofillId id) {
+        mHandler.sendMessage(obtainMessage(ActivityContentCaptureSession::handleSendEvent, this,
+                new ContentCaptureEvent(mId, TYPE_VIEW_DISAPPEARED).setAutofillId(id),
+                        /* forceFlush= */ false));
+    }
+
+    @Override
+    void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
+            int flags) {
+        mHandler.sendMessage(obtainMessage(ActivityContentCaptureSession::handleSendEvent, this,
+                new ContentCaptureEvent(mId, TYPE_VIEW_TEXT_CHANGED, flags).setAutofillId(id)
+                        .setText(text), /* forceFlush= */ false));
+    }
+
+    @Override
+    boolean isContentCaptureEnabled() {
+        return mSystemServerInterface != null && !mDisabled.get();
+    }
+
+    @Override
+    void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+        pw.print(prefix); pw.print("id: "); pw.println(mId);
+        pw.print(prefix); pw.print("mContext: "); pw.println(mContext);
+        pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId());
+        if (mSystemServerInterface != null) {
+            pw.print(prefix); pw.print("mSystemServerInterface: ");
+            pw.println(mSystemServerInterface);
+        }
+        if (mDirectServiceInterface != null) {
+            pw.print(prefix); pw.print("mDirectServiceInterface: ");
+            pw.println(mDirectServiceInterface);
+        }
+        if (mClientContext != null) {
+            // NOTE: we don't dump clientContent because it could have PII
+            pw.print(prefix); pw.println("hasClientContext");
+
+        }
+        pw.print(prefix); pw.print("mDisabled: "); pw.println(mDisabled.get());
+        pw.print(prefix); pw.print("isEnabled(): "); pw.println(isContentCaptureEnabled());
+        if (mContentCaptureSessionId != null) {
+            pw.print(prefix); pw.print("public id: "); pw.println(mContentCaptureSessionId);
+        }
+        pw.print(prefix); pw.print("state: "); pw.print(mState); pw.print(" (");
+        pw.print(getStateAsString(mState)); pw.println(")");
+        if (mApplicationToken != null) {
+            pw.print(prefix); pw.print("app token: "); pw.println(mApplicationToken);
+        }
+        if (mComponentName != null) {
+            pw.print(prefix); pw.print("component name: ");
+            pw.println(mComponentName.flattenToShortString());
+        }
+        if (mEvents != null && !mEvents.isEmpty()) {
+            final int numberEvents = mEvents.size();
+            pw.print(prefix); pw.print("buffered events: "); pw.print(numberEvents);
+            pw.print('/'); pw.println(MAX_BUFFER_SIZE);
+            if (VERBOSE && numberEvents > 0) {
+                final String prefix3 = prefix + "  ";
+                for (int i = 0; i < numberEvents; i++) {
+                    final ContentCaptureEvent event = mEvents.get(i);
+                    pw.print(prefix3); pw.print(i); pw.print(": "); event.dump(pw);
+                    pw.println();
+                }
+            }
+            pw.print(prefix); pw.print("flush frequency: "); pw.println(FLUSHING_FREQUENCY_MS);
+            pw.print(prefix); pw.print("next flush: ");
+            TimeUtils.formatDuration(mNextFlush - SystemClock.elapsedRealtime(), pw); pw.println();
+        }
+    }
+
+    /**
+     * Gets a string that can be used to identify the activity on logging statements.
+     */
+    private String getActivityDebugName() {
+        return mComponentName == null ? mContext.getPackageName()
+                : mComponentName.flattenToShortString();
+    }
+}
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index 5d8fe5f..43c9699 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -29,7 +29,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
-// TODO(b/111276913): add javadocs / implement Parcelable / implement
 /** @hide */
 @SystemApi
 public final class ContentCaptureEvent implements Parcelable {
@@ -72,6 +71,7 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventType{}
 
+    private final @NonNull String mSessionId;
     private final int mType;
     private final long mEventTime;
     private final int mFlags;
@@ -80,21 +80,21 @@
     private @Nullable CharSequence mText;
 
     /** @hide */
-    public ContentCaptureEvent(int type, long eventTime, int flags) {
+    public ContentCaptureEvent(@NonNull String sessionId, int type, long eventTime, int flags) {
+        mSessionId = sessionId;
         mType = type;
         mEventTime = eventTime;
         mFlags = flags;
     }
 
-
     /** @hide */
-    public ContentCaptureEvent(int type, int flags) {
-        this(type, System.currentTimeMillis(), flags);
+    public ContentCaptureEvent(@NonNull String sessionId, int type, int flags) {
+        this(sessionId, type, System.currentTimeMillis(), flags);
     }
 
     /** @hide */
-    public ContentCaptureEvent(int type) {
-        this(type, /* flags= */ 0);
+    public ContentCaptureEvent(@NonNull String sessionId, int type) {
+        this(sessionId, type, /* flags= */ 0);
     }
 
     /** @hide */
@@ -104,12 +104,20 @@
     }
 
     /** @hide */
+    @NonNull
+    public String getSessionId() {
+        return mSessionId;
+    }
+
+    /** @hide */
+    @NonNull
     public ContentCaptureEvent setViewNode(@NonNull ViewNode node) {
         mNode = Preconditions.checkNotNull(node);
         return this;
     }
 
     /** @hide */
+    @NonNull
     public ContentCaptureEvent setText(@Nullable CharSequence text) {
         mText = text;
         return this;
@@ -214,6 +222,7 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeString(mSessionId);
         parcel.writeInt(mType);
         parcel.writeLong(mEventTime);
         parcel.writeInt(mFlags);
@@ -227,10 +236,12 @@
 
         @Override
         public ContentCaptureEvent createFromParcel(Parcel parcel) {
+            final String sessionId = parcel.readString();
             final int type = parcel.readInt();
             final long eventTime  = parcel.readLong();
             final int flags = parcel.readInt();
-            final ContentCaptureEvent event = new ContentCaptureEvent(type, eventTime, flags);
+            final ContentCaptureEvent event =
+                    new ContentCaptureEvent(sessionId, type, eventTime, flags);
             final AutofillId id = parcel.readParcelable(null);
             if (id != null) {
                 event.setAutofillId(id);
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 7fbbfb7..fca2857 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -66,7 +66,7 @@
     @NonNull
     private final Handler mHandler;
 
-    private ContentCaptureSession mMainSession;
+    private ActivityContentCaptureSession mMainSession;
 
     /** @hide */
     public ContentCaptureManager(@NonNull Context context,
@@ -110,7 +110,7 @@
         // 4.Close (and delete) these sessions when onActivityStopped() is called.
         // 5.Figure out whether each session will have its own mDisabled AtomicBoolean.
         if (mMainSession == null) {
-            mMainSession = new ContentCaptureSession(mContext, mHandler, mService,
+            mMainSession = new ActivityContentCaptureSession(mContext, mHandler, mService,
                     mDisabled, Preconditions.checkNotNull(context));
         } else {
             throw new IllegalStateException("Manager already has a session: " + mMainSession);
@@ -127,12 +127,12 @@
      * @hide
      */
     @NonNull
-    public ContentCaptureSession getMainContentCaptureSession() {
+    public ActivityContentCaptureSession getMainContentCaptureSession() {
         // TODO(b/121033016): figure out how to manage the "default" session when it support
         // multiple sessions (can't just be the first one, as it could be closed).
         if (mMainSession == null) {
-            mMainSession = new ContentCaptureSession(mContext, mHandler, mService, mDisabled,
-                    /* contentCaptureContext=  */ null);
+            mMainSession = new ActivityContentCaptureSession(mContext, mHandler, mService,
+                    mDisabled, /* clientContext= */ null);
             if (VERBOSE) {
                 Log.v(TAG, "getDefaultContentCaptureSession(): created " + mMainSession);
             }
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index f411cf7..aedb7a9 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -15,62 +15,32 @@
  */
 package android.view.contentcapture;
 
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
-import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED;
-import static android.view.contentcapture.ContentCaptureManager.DEBUG;
 import static android.view.contentcapture.ContentCaptureManager.VERBOSE;
 
-import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ParceledListSlice;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.IBinder.DeathRecipient;
-import android.os.RemoteException;
-import android.os.SystemClock;
 import android.util.Log;
-import android.util.TimeUtils;
 import android.view.View;
 import android.view.ViewStructure;
 import android.view.autofill.AutofillId;
+import android.view.contentcapture.ViewNode.ViewStructureImpl;
 
-import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.Preconditions;
 
 import dalvik.system.CloseGuard;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
 import java.util.UUID;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Session used to notify a system-provided Content Capture service about events associated with
  * views.
  */
-public final class ContentCaptureSession implements AutoCloseable {
-
-    /*
-     * IMPLEMENTATION NOTICE:
-     *
-     * All methods in this class should return right away, or do the real work in a handler thread.
-     *
-     * Hence, the only field that must be thread-safe is mEnabled, which is called at the
-     * beginning of every method.
-     */
-
-    private static final String TAG = ContentCaptureSession.class.getSimpleName();
+public abstract class ContentCaptureSession implements AutoCloseable {
 
     /**
      * Used on {@link #notifyViewTextChanged(AutofillId, CharSequence, int)} to indicate that the
+     *
      * thext change was caused by user input (for example, through IME).
      */
     public static final int FLAG_USER_INPUT = 0x1;
@@ -110,79 +80,17 @@
      */
     public static final int STATE_DISABLED_DUPLICATED_ID = 4;
 
-    /**
-     * Handler message used to flush the buffer.
-     */
-    private static final int MSG_FLUSH = 1;
-
-    /**
-     * Maximum number of events that are buffered before sent to the app.
-     */
-    // TODO(b/121044064): use settings
-    private static final int MAX_BUFFER_SIZE = 100;
-
-    /**
-     * Frequency the buffer is flushed if stale.
-     */
-    // TODO(b/121044064): use settings
-    private static final int FLUSHING_FREQUENCY_MS = 5_000;
-
-
-    /**
-     * Name of the {@link IResultReceiver} extra used to pass the binder interface to the service.
-     * @hide
-     */
-    public static final String EXTRA_BINDER = "binder";
+    /** @hide */
+    protected final String mTag = getClass().getSimpleName();
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
-    @NonNull
-    private final AtomicBoolean mDisabled;
-
-    @NonNull
-    private final Context mContext;
-
-    @NonNull
-    private final Handler mHandler;
-
-    /**
-     * Interface to the system_server binder object - it's only used to start the session (and
-     * notify when the session is finished).
-     */
+    /** @hide */
     @Nullable
-    private final IContentCaptureManager mSystemServerInterface;
-
-    /**
-     * Direct interface to the service binder object - it's used to send the events, including the
-     * last ones (when the session is finished)
-     */
-    @Nullable
-    private IContentCaptureDirectManager mDirectServiceInterface;
-    @Nullable
-    private DeathRecipient mDirectServiceVulture;
-
-    @Nullable
-    private final String mId = UUID.randomUUID().toString();
+    protected final String mId = UUID.randomUUID().toString();
 
     private int mState = STATE_UNKNOWN;
 
-    @Nullable
-    private IBinder mApplicationToken;
-
-    @Nullable
-    private ComponentName mComponentName;
-
-    /**
-     * List of events held to be sent as a batch.
-     */
-    // TODO(b/111276913): once we support multiple sessions, we need to move the buffer of events
-    // to its own class so it's shared by all sessions
-    @Nullable
-    private ArrayList<ContentCaptureEvent> mEvents;
-
-    // Used just for debugging purposes (on dump)
-    private long mNextFlush;
-
     // Lazily created on demand.
     private ContentCaptureSessionId mContentCaptureSessionId;
 
@@ -190,18 +98,15 @@
      * {@link ContentCaptureContext} set by client, or {@code null} when it's the
      * {@link ContentCaptureManager#getMainContentCaptureSession() default session} for the
      * context.
+     *
+     * @hide
      */
     @Nullable
-    private final ContentCaptureContext mClientContext;
+    // TODO(b/121042846): move to ChildContentCaptureSession.java
+    protected final ContentCaptureContext mClientContext;
 
     /** @hide */
-    protected ContentCaptureSession(@NonNull Context context, @NonNull Handler handler,
-            @Nullable IContentCaptureManager systemServerInterface, @NonNull AtomicBoolean disabled,
-            @Nullable ContentCaptureContext clientContext) {
-        mContext = context;
-        mHandler = handler;
-        mSystemServerInterface = systemServerInterface;
-        mDisabled = disabled;
+    protected ContentCaptureSession(@Nullable ContentCaptureContext clientContext) {
         mClientContext = clientContext;
         mCloseGuard.open("destroy");
     }
@@ -209,7 +114,7 @@
     /**
      * Gets the id used to identify this session.
      */
-    public ContentCaptureSessionId getContentCaptureSessionId() {
+    public final ContentCaptureSessionId getContentCaptureSessionId() {
         if (mContentCaptureSessionId == null) {
             mContentCaptureSessionId = new ContentCaptureSessionId(mId);
         }
@@ -217,37 +122,16 @@
     }
 
     /**
-     * Starts this session.
-     *
-     * @hide
-     */
-    void start(@NonNull IBinder applicationToken, @NonNull ComponentName activityComponent) {
-        if (!isContentCaptureEnabled()) return;
-
-        if (VERBOSE) {
-            Log.v(TAG, "start(): token=" + applicationToken + ", comp="
-                    + ComponentName.flattenToShortString(activityComponent));
-        }
-
-        mHandler.sendMessage(obtainMessage(ContentCaptureSession::handleStartSession, this,
-                applicationToken, activityComponent));
-    }
-
-    /**
      * Flushes the buffered events to the service.
-     *
-     * @hide
      */
-    void flush() {
-        mHandler.sendMessage(obtainMessage(ContentCaptureSession::handleForceFlush, this));
-    }
+    abstract void flush();
 
     /**
      * Destroys this session, flushing out all pending notifications to the service.
      *
      * <p>Once destroyed, any new notification will be dropped.
      */
-    public void destroy() {
+    public final void destroy() {
         //TODO(b/111276913): mark it as destroyed so other methods are ignored (and test on CTS)
 
         if (!isContentCaptureEnabled()) return;
@@ -255,15 +139,19 @@
         //TODO(b/111276913): check state (for example, how to handle if it's waiting for remote
         // id) and send it to the cache of batched commands
         if (VERBOSE) {
-            Log.v(TAG, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId);
+            Log.v(mTag, "destroy(): state=" + getStateAsString(mState) + ", mId=" + mId);
         }
 
         flush();
 
-        mHandler.sendMessage(obtainMessage(ContentCaptureSession::handleDestroySession, this));
+        onDestroy();
+
         mCloseGuard.close();
     }
 
+    abstract void onDestroy();
+
+
     /** @hide */
     @Override
     public void close() {
@@ -282,225 +170,6 @@
         }
     }
 
-    private void handleStartSession(@NonNull IBinder token, @NonNull ComponentName componentName) {
-        if (mState != STATE_UNKNOWN) {
-            // TODO(b/111276913): revisit this scenario
-            Log.w(TAG, "ignoring handleStartSession(" + token + ") while on state "
-                    + getStateAsString(mState));
-            return;
-        }
-        mState = STATE_WAITING_FOR_SERVER;
-        mApplicationToken = token;
-        mComponentName = componentName;
-
-        if (VERBOSE) {
-            Log.v(TAG, "handleStartSession(): token=" + token + ", act="
-                    + getActivityDebugName() + ", id=" + mId);
-        }
-        final int flags = 0; // TODO(b/111276913): get proper flags
-
-        try {
-            mSystemServerInterface.startSession(mContext.getUserId(), mApplicationToken,
-                    componentName, mId, mClientContext, flags, new IResultReceiver.Stub() {
-                        @Override
-                        public void send(int resultCode, Bundle resultData) {
-                            IBinder binder = null;
-                            if (resultData != null) {
-                                binder = resultData.getBinder(EXTRA_BINDER);
-                                if (binder == null) {
-                                    Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result");
-                                    handleResetState();
-                                    return;
-                                }
-                            }
-                            handleSessionStarted(resultCode, binder);
-                        }
-                    });
-        } catch (RemoteException e) {
-            Log.w(TAG, "Error starting session for " + componentName.flattenToShortString() + ": "
-                    + e);
-        }
-    }
-
-    /**
-     * Callback from {@code system_server} after call to
-     * {@link IContentCaptureManager#startSession(int, IBinder, ComponentName, String,
-     * ContentCaptureContext, int, IResultReceiver)}.
-     *
-     * @param resultCode session state
-     * @param binder handle to {@link IContentCaptureDirectManager}
-     */
-    private void handleSessionStarted(int resultCode, @Nullable IBinder binder) {
-        mState = resultCode;
-        if (binder != null) {
-            mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder);
-            mDirectServiceVulture = () -> {
-                Log.w(TAG, "Destroying session " + mId + " because service died");
-                destroy();
-            };
-            try {
-                binder.linkToDeath(mDirectServiceVulture, 0);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed to link to death on " + binder + ": " + e);
-            }
-        }
-        if (resultCode == STATE_DISABLED || resultCode == STATE_DISABLED_DUPLICATED_ID) {
-            mDisabled.set(true);
-            handleResetSession(/* resetState= */ false);
-        } else {
-            mDisabled.set(false);
-        }
-        if (VERBOSE) {
-            Log.v(TAG, "handleSessionStarted() result: code=" + resultCode + ", id=" + mId
-                    + ", state=" + getStateAsString(mState) + ", disabled=" + mDisabled.get()
-                    + ", binder=" + binder);
-        }
-    }
-
-    private void handleSendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
-        if (mEvents == null) {
-            if (VERBOSE) {
-                Log.v(TAG, "Creating buffer for " + MAX_BUFFER_SIZE + " events");
-            }
-            mEvents = new ArrayList<>(MAX_BUFFER_SIZE);
-        }
-        mEvents.add(event);
-
-        final int numberEvents = mEvents.size();
-
-        // TODO(b/120784831): need to optimize it so we buffer changes until a number of X are
-        // buffered (either total or per autofillid). For
-        // example, if the user typed "a", "b", "c" and the threshold is 3, we should buffer
-        // "a" and "b" then send "abc".
-        final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE;
-
-        if (bufferEvent && !forceFlush) {
-            handleScheduleFlush(/* checkExisting= */ true);
-            return;
-        }
-
-        if (mState != STATE_ACTIVE) {
-            // Callback from startSession hasn't been called yet - typically happens on system
-            // apps that are started before the system service
-            // TODO(b/111276913): try to ignore session while system is not ready / boot
-            // not complete instead. Similarly, the manager service should return right away
-            // when the user does not have a service set
-            if (VERBOSE) {
-                Log.v(TAG, "Closing session for " + getActivityDebugName()
-                        + " after " + numberEvents + " delayed events and state "
-                        + getStateAsString(mState));
-            }
-            handleResetState();
-            // TODO(b/111276913): blacklist activity / use special flag to indicate that
-            // when it's launched again
-            return;
-        }
-
-        handleForceFlush();
-    }
-
-    private void handleScheduleFlush(boolean checkExisting) {
-        if (checkExisting && mHandler.hasMessages(MSG_FLUSH)) {
-            // "Renew" the flush message by removing the previous one
-            mHandler.removeMessages(MSG_FLUSH);
-        }
-        mNextFlush = SystemClock.elapsedRealtime() + FLUSHING_FREQUENCY_MS;
-        if (VERBOSE) {
-            Log.v(TAG, "Scheduled to flush in " + FLUSHING_FREQUENCY_MS + "ms: " + mNextFlush);
-        }
-        mHandler.sendMessageDelayed(
-                obtainMessage(ContentCaptureSession::handleFlushIfNeeded, this).setWhat(MSG_FLUSH),
-                FLUSHING_FREQUENCY_MS);
-    }
-
-    private void handleFlushIfNeeded() {
-        if (mEvents.isEmpty()) {
-            if (VERBOSE) Log.v(TAG, "Nothing to flush");
-            return;
-        }
-        handleForceFlush();
-    }
-
-    private void handleForceFlush() {
-        if (mEvents == null) return;
-
-        if (mDirectServiceInterface == null) {
-            Log.w(TAG, "handleForceFlush(): client not available yet");
-            if (!mHandler.hasMessages(MSG_FLUSH)) {
-                handleScheduleFlush(/* checkExisting= */ false);
-            }
-            return;
-        }
-
-        final int numberEvents = mEvents.size();
-        try {
-            if (DEBUG) {
-                Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getActivityDebugName());
-            }
-            mHandler.removeMessages(MSG_FLUSH);
-
-            final ParceledListSlice<ContentCaptureEvent> events = handleClearEvents();
-            mDirectServiceInterface.sendEvents(mId, events);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Error sending " + numberEvents + " for " + getActivityDebugName()
-                    + ": " + e);
-        }
-    }
-
-    /**
-     * Resets the buffer and return a {@link ParceledListSlice} with the previous events.
-     */
-    @NonNull
-    private ParceledListSlice<ContentCaptureEvent> handleClearEvents() {
-        // NOTE: we must save a reference to the current mEvents and then set it to to null,
-        // otherwise clearing it would clear it in the receiving side if the service is also local.
-        final List<ContentCaptureEvent> events = mEvents == null
-                ? Collections.emptyList()
-                : mEvents;
-        mEvents = null;
-        return new ParceledListSlice<>(events);
-    }
-
-    private void handleDestroySession() {
-        //TODO(b/111276913): right now both the ContentEvents and lifecycle sessions are sent
-        // to system_server, so it's ok to call both in sequence here. But once we split
-        // them so the events are sent directly to the service, we need to make sure they're
-        // sent in order.
-        if (DEBUG) {
-            Log.d(TAG, "Destroying session (ctx=" + mContext + ", id=" + mId + ") with "
-                    + (mEvents == null ? 0 : mEvents.size()) + " event(s) for "
-                    + getActivityDebugName());
-        }
-
-        try {
-            mSystemServerInterface.finishSession(mContext.getUserId(), mId);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error destroying system-service session " + mId + " for "
-                    + getActivityDebugName() + ": " + e);
-        }
-    }
-
-    private void handleResetState() {
-        handleResetSession(/* resetState= */ true);
-    }
-
-    // TODO(b/111276913): once we support multiple sessions, we might need to move some of these
-    // clearings out.
-    private void handleResetSession(boolean resetState) {
-        if (resetState) {
-            mState = STATE_UNKNOWN;
-        }
-        mContentCaptureSessionId = null;
-        mApplicationToken = null;
-        mComponentName = null;
-        mEvents = null;
-        if (mDirectServiceInterface != null) {
-            mDirectServiceInterface.asBinder().unlinkToDeath(mDirectServiceVulture, 0);
-        }
-        mDirectServiceInterface = null;
-        mHandler.removeMessages(MSG_FLUSH);
-    }
-
     /**
      * Notifies the Content Capture Service that a node has been added to the view structure.
      *
@@ -510,7 +179,7 @@
      *
      * @param node node that has been added.
      */
-    public void notifyViewAppeared(@NonNull ViewStructure node) {
+    public final void notifyViewAppeared(@NonNull ViewStructure node) {
         Preconditions.checkNotNull(node);
         if (!isContentCaptureEnabled()) return;
 
@@ -518,12 +187,11 @@
             throw new IllegalArgumentException("Invalid node class: " + node.getClass());
         }
 
-        mHandler.sendMessage(obtainMessage(ContentCaptureSession::handleSendEvent, this,
-                new ContentCaptureEvent(TYPE_VIEW_APPEARED)
-                        .setViewNode(((ViewNode.ViewStructureImpl) node).mNode),
-                        /* forceFlush= */ false));
+        internalNotifyViewAppeared((ViewStructureImpl) node);
     }
 
+    abstract void internalNotifyViewAppeared(@NonNull ViewNode.ViewStructureImpl node);
+
     /**
      * Notifies the Content Capture Service that a node has been removed from the view structure.
      *
@@ -532,15 +200,15 @@
      *
      * @param id id of the node that has been removed.
      */
-    public void notifyViewDisappeared(@NonNull AutofillId id) {
+    public final void notifyViewDisappeared(@NonNull AutofillId id) {
         Preconditions.checkNotNull(id);
         if (!isContentCaptureEnabled()) return;
 
-        mHandler.sendMessage(obtainMessage(ContentCaptureSession::handleSendEvent, this,
-                new ContentCaptureEvent(TYPE_VIEW_DISAPPEARED).setAutofillId(id),
-                        /* forceFlush= */ false));
+        internalNotifyViewDisappeared(id);
     }
 
+    abstract void internalNotifyViewDisappeared(@NonNull AutofillId id);
+
     /**
      * Notifies the Intelligence Service that the value of a text node has been changed.
      *
@@ -549,24 +217,25 @@
      * @param flags either {@code 0} or {@link #FLAG_USER_INPUT} when the value was explicitly
      * changed by the user (for example, through the keyboard).
      */
-    public void notifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
+    public final void notifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
             int flags) {
         Preconditions.checkNotNull(id);
 
         if (!isContentCaptureEnabled()) return;
 
-        mHandler.sendMessage(obtainMessage(ContentCaptureSession::handleSendEvent, this,
-                new ContentCaptureEvent(TYPE_VIEW_TEXT_CHANGED, flags).setAutofillId(id)
-                        .setText(text), /* forceFlush= */ false));
+        internalNotifyViewTextChanged(id, text, flags);
     }
 
+    abstract void internalNotifyViewTextChanged(@NonNull AutofillId id, @Nullable CharSequence text,
+            int flags);
+
     /**
      * Creates a {@link ViewStructure} for a "standard" view.
      *
      * @hide
      */
     @NonNull
-    public ViewStructure newViewStructure(@NonNull View view) {
+    public final ViewStructure newViewStructure(@NonNull View view) {
         return new ViewNode.ViewStructureImpl(view);
     }
 
@@ -583,78 +252,25 @@
      * @hide
      */
     @NonNull
-    public ViewStructure newVirtualViewStructure(@NonNull AutofillId parentId, int virtualId) {
+    public final ViewStructure newVirtualViewStructure(@NonNull AutofillId parentId,
+            int virtualId) {
         return new ViewNode.ViewStructureImpl(parentId, virtualId);
     }
 
-    private boolean isContentCaptureEnabled() {
-        return mSystemServerInterface != null && !mDisabled.get();
-    }
+    abstract boolean isContentCaptureEnabled();
 
-    void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
-        pw.print(prefix); pw.print("id: "); pw.println(mId);
-        pw.print(prefix); pw.print("mContext: "); pw.println(mContext);
-        pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId());
-        if (mSystemServerInterface != null) {
-            pw.print(prefix); pw.print("mSystemServerInterface: ");
-            pw.println(mSystemServerInterface);
-        }
-        if (mDirectServiceInterface != null) {
-            pw.print(prefix); pw.print("mDirectServiceInterface: ");
-            pw.println(mDirectServiceInterface);
-        }
-        if (mClientContext != null) {
-            // NOTE: we don't dump clientContent because it could have PII
-            pw.print(prefix); pw.println("hasClientContext");
-
-        }
-        pw.print(prefix); pw.print("mDisabled: "); pw.println(mDisabled.get());
-        pw.print(prefix); pw.print("isEnabled(): "); pw.println(isContentCaptureEnabled());
-        if (mContentCaptureSessionId != null) {
-            pw.print(prefix); pw.print("public id: "); pw.println(mContentCaptureSessionId);
-        }
-        pw.print(prefix); pw.print("state: "); pw.print(mState); pw.print(" (");
-        pw.print(getStateAsString(mState)); pw.println(")");
-        if (mApplicationToken != null) {
-            pw.print(prefix); pw.print("app token: "); pw.println(mApplicationToken);
-        }
-        if (mComponentName != null) {
-            pw.print(prefix); pw.print("component name: ");
-            pw.println(mComponentName.flattenToShortString());
-        }
-        if (mEvents != null && !mEvents.isEmpty()) {
-            final int numberEvents = mEvents.size();
-            pw.print(prefix); pw.print("buffered events: "); pw.print(numberEvents);
-            pw.print('/'); pw.println(MAX_BUFFER_SIZE);
-            if (VERBOSE && numberEvents > 0) {
-                final String prefix3 = prefix + "  ";
-                for (int i = 0; i < numberEvents; i++) {
-                    final ContentCaptureEvent event = mEvents.get(i);
-                    pw.print(prefix3); pw.print(i); pw.print(": "); event.dump(pw);
-                    pw.println();
-                }
-            }
-            pw.print(prefix); pw.print("flush frequency: "); pw.println(FLUSHING_FREQUENCY_MS);
-            pw.print(prefix); pw.print("next flush: ");
-            TimeUtils.formatDuration(mNextFlush - SystemClock.elapsedRealtime(), pw); pw.println();
-        }
-    }
-
-    /**
-     * Gets a string that can be used to identify the activity on logging statements.
-     */
-    private String getActivityDebugName() {
-        return mComponentName == null ? mContext.getPackageName()
-                : mComponentName.flattenToShortString();
-    }
+    abstract void dump(@NonNull String prefix, @NonNull PrintWriter pw);
 
     @Override
     public String toString() {
         return mId;
     }
 
+    /**
+     * @hide
+     */
     @NonNull
-    private static String getStateAsString(int state) {
+    protected static String getStateAsString(int state) {
         switch (state) {
             case STATE_UNKNOWN:
                 return "UNKNOWN";
diff --git a/core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl b/core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl
index 145fc16..8d8117b 100644
--- a/core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureDirectManager.aidl
@@ -26,5 +26,5 @@
   * @hide
   */
 oneway interface IContentCaptureDirectManager {
-    void sendEvents(in String sessionId, in ParceledListSlice events);
+    void sendEvents(in ParceledListSlice events);
 }
diff --git a/core/java/android/webkit/WebSyncManager.java b/core/java/android/webkit/WebSyncManager.java
index 3fa1b01..e44d6eb 100644
--- a/core/java/android/webkit/WebSyncManager.java
+++ b/core/java/android/webkit/WebSyncManager.java
@@ -26,6 +26,7 @@
 abstract class WebSyncManager implements Runnable {
     protected static final java.lang.String LOGTAG = "websync";
     protected android.webkit.WebViewDatabase mDataBase;
+    @UnsupportedAppUsage
     protected android.os.Handler mHandler;
 
     protected WebSyncManager(Context context, String name) {
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index e571656..e59bee4 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -65,4 +65,6 @@
 
     void startWatchingNoted(in int[] ops, IAppOpsNotedCallback callback);
     void stopWatchingNoted(IAppOpsNotedCallback callback);
+
+    int checkOperationRaw(int code, int uid, String packageName);
 }
diff --git a/services/core/java/com/android/server/infra/AbstractMultiplePendingRequestsRemoteService.java b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
similarity index 98%
rename from services/core/java/com/android/server/infra/AbstractMultiplePendingRequestsRemoteService.java
rename to core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
index aaea45e..26cf180 100644
--- a/services/core/java/com/android/server/infra/AbstractMultiplePendingRequestsRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.infra;
+package com.android.internal.infra;
 
 import android.annotation.NonNull;
 import android.content.ComponentName;
diff --git a/services/core/java/com/android/server/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
similarity index 97%
rename from services/core/java/com/android/server/infra/AbstractRemoteService.java
rename to core/java/com/android/internal/infra/AbstractRemoteService.java
index 41dcf89..3391840 100644
--- a/services/core/java/com/android/server/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.server.infra;
+package com.android.internal.infra;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -27,13 +28,13 @@
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
 import android.os.IInterface;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.server.FgThread;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -109,7 +110,7 @@
         mComponentName = componentName;
         mIntent = new Intent(serviceInterface).setComponent(mComponentName);
         mUserId = userId;
-        mHandler = new Handler(FgThread.getHandler().getLooper());
+        mHandler = new Handler(Looper.getMainLooper());
         mBindInstantServiceAllowed = bindInstantServiceAllowed;
     }
 
@@ -164,6 +165,15 @@
      */
     protected abstract long getRemoteRequestMillis();
 
+    /**
+     * Gets the currently registered service interface or {@code null} if the service is not
+     * connected.
+     */
+    @Nullable
+    public final I getServiceInterface() {
+        return mService;
+    }
+
     private void handleDestroy() {
         if (checkIfDestroyed()) return;
         handleOnDestroy();
diff --git a/services/core/java/com/android/server/infra/AbstractSinglePendingRequestRemoteService.java b/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java
similarity index 98%
rename from services/core/java/com/android/server/infra/AbstractSinglePendingRequestRemoteService.java
rename to core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java
index d32f13b..f0c2233 100644
--- a/services/core/java/com/android/server/infra/AbstractSinglePendingRequestRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractSinglePendingRequestRemoteService.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.infra;
+package com.android.internal.infra;
 
 import android.annotation.NonNull;
 import android.content.ComponentName;
diff --git a/core/java/com/android/internal/widget/NumericTextView.java b/core/java/com/android/internal/widget/NumericTextView.java
index 27c5834..d215670 100644
--- a/core/java/com/android/internal/widget/NumericTextView.java
+++ b/core/java/com/android/internal/widget/NumericTextView.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.widget;
 
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
@@ -53,6 +54,7 @@
 
     private OnValueChangedListener mListener;
 
+    @UnsupportedAppUsage
     public NumericTextView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 21fa75e..dc6a73a 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -271,7 +271,7 @@
         "libhardware",
         "libhardware_legacy",
         "libselinux",
-        "libicuuc",
+        "libandroidicu",
         "libmedia",
         "libmediametrics",
         "libmeminfo",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cc8927f..8b6f33f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2003,6 +2003,15 @@
     <permission android:name="android.permission.BIND_SCREENING_SERVICE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Must be required by a {@link android.telecom.PhoneAccountSuggestionService},
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature|privileged
+         @SystemApi
+         @hide
+    -->
+    <permission android:name="android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Must be required by a {@link android.telecom.CallRedirectionService},
          to ensure that only the system can bind to it.
          <p>Protection level: signature|privileged
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7688c8d..9f5eab5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3647,4 +3647,11 @@
 
     <!-- Component name for the default module metadata provider on this device -->
     <string name="config_defaultModuleMetadataProvider">com.android.modulemetadata</string>
+
+    <!-- This is the default launcher component to use on secondary displays that support system
+         decorations.
+         This launcher activity must support multiple instances and have corresponding launch mode
+         set in AndroidManifest.
+         {@see android.view.Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS} -->
+    <string name="config_secondaryHomeComponent" translatable="false">com.android.launcher3/com.android.launcher3.SecondaryDisplayLauncher</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c3d5f63..4ed0501 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3521,4 +3521,7 @@
   <java-symbol type="dimen" name="rounded_corner_radius_bottom" />
 
   <java-symbol type="string" name="config_defaultModuleMetadataProvider" />
+
+  <!-- For Secondary Launcher -->
+  <java-symbol type="string" name="config_secondaryHomeComponent" />
 </resources>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 6d1aae1..f8bd4e3 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -384,6 +384,7 @@
                     Settings.Global.PRIV_APP_OOB_LIST,
                     Settings.Global.PRIVATE_DNS_DEFAULT_MODE,
                     Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED,
+                    Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED,
                     Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED,
                     Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED,
                     Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index c84c035..f7541e0 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -365,7 +365,7 @@
         <font weight="400" style="normal">NotoSansCarian-Regular.ttf</font>
     </family>
     <family lang="und-Cakm">
-        <font weight="400" style="normal">NotoSansChakma-Regular.ttf</font>
+        <font weight="400" style="normal">NotoSansChakma-Regular.otf</font>
     </family>
     <family lang="und-Cher">
         <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
index aec31ee..30429ed 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
@@ -16,7 +16,11 @@
 
 package com.android.systemui.statusbar.car.hvac;
 
+import static android.car.VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
+import static android.car.VehiclePropertyIds.HVAC_TEMPERATURE_DISPLAY_UNITS;
+
 import android.car.Car;
+import android.car.VehicleUnit;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.hvac.CarHvacManager;
 import android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback;
@@ -167,7 +171,17 @@
     private void initComponent(TemperatureView view) {
         int id = view.getPropertyId();
         int zone = view.getAreaId();
+
         try {
+            if (mHvacManager != null
+                    && mHvacManager.isPropertyAvailable(HVAC_TEMPERATURE_DISPLAY_UNITS,
+                            VEHICLE_AREA_TYPE_GLOBAL)) {
+                if (mHvacManager.getIntProperty(HVAC_TEMPERATURE_DISPLAY_UNITS,
+                        VEHICLE_AREA_TYPE_GLOBAL) == VehicleUnit.FAHRENHEIT) {
+                    view.setDisplayInFahrenheit(true);
+                }
+
+            }
             if (mHvacManager == null || !mHvacManager.isPropertyAvailable(id, zone)) {
                 view.setTemp(Float.NaN);
                 return;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java
index 507c60f..17ef3c0 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureTextView.java
@@ -36,6 +36,7 @@
     private final int mAreaId;
     private final int mPropertyId;
     private final String mTempFormat;
+    private boolean mDisplayFahrenheit = false;
 
     public TemperatureTextView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -57,9 +58,17 @@
             setText("--");
             return;
         }
+        if (mDisplayFahrenheit) {
+            temp = convertToFahrenheit(temp);
+        }
         setText(String.format(mTempFormat, temp));
     }
 
+    @Override
+    public void setDisplayInFahrenheit(boolean displayFahrenheit) {
+        mDisplayFahrenheit = displayFahrenheit;
+    }
+
     /**
      * @return propertiyId  Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
      */
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java
index 7651356..c17da18 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java
@@ -23,10 +23,26 @@
     /**
      * Formats the float for display
      *
-     * @param temp - The current temp or NaN
+     * @param temp - The current temp in Celsius or NaN
      */
     void setTemp(float temp);
 
+    /**
+     * Render the displayed temperature in Fahrenheit
+     *
+     * @param displayFahrenheit - True if temperature should be displayed in Fahrenheit
+     */
+    void setDisplayInFahrenheit(boolean displayFahrenheit);
+
+    /**
+     * Convert the given temperature in Celsius into Fahrenheit
+     *
+     * @param realTemp - The temperature in Celsius
+     * @return Temperature in Fahrenheit.
+     */
+    default float convertToFahrenheit(float realTemp) {
+        return (realTemp * 9f / 5f) + 32;
+    }
 
     /**
      * @return propertiyId  Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
index 0467bff..76126fc 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
@@ -99,6 +99,7 @@
     private final TemperatureColorStore mColorStore = new TemperatureColorStore();
     private final TemperatureBackgroundAnimator mBackgroundAnimator;
     private final TemperatureTextAnimator mTextAnimator;
+    boolean mDisplayInFahrenheit = false;
 
     public AnimatedTemperatureView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -193,6 +194,9 @@
      */
     @Override
     public void setTemp(float temp) {
+        if (mDisplayInFahrenheit) {
+            temp = convertToFahrenheit(temp);
+        }
         mTextAnimator.setTemp(temp);
         if (Float.isNaN(temp)) {
             mBackgroundAnimator.hideCircle();
@@ -219,6 +223,11 @@
         mBackgroundAnimator.animateOpen();
     }
 
+    @Override
+    public void setDisplayInFahrenheit(boolean displayInFahrenheit) {
+        mDisplayInFahrenheit = displayInFahrenheit;
+    }
+
     boolean isMinValue(float temp) {
         return !Float.isNaN(mMinValue) && isApproxEqual(temp, mMinValue);
     }
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 1eb4b74..8d04702 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -67,7 +67,7 @@
 
     private static final boolean DEBUG = false;
 
-    public static final String AUTHORITY = "com.android.externalstorage.documents";
+    public static final String AUTHORITY = DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY;
 
     private static final Uri BASE_URI =
             new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY).build();
@@ -96,7 +96,8 @@
         public boolean reportAvailableBytes = true;
     }
 
-    private static final String ROOT_ID_PRIMARY_EMULATED = "primary";
+    private static final String ROOT_ID_PRIMARY_EMULATED =
+            DocumentsContract.EXTERNAL_STORAGE_PRIMARY_EMULATED_ROOT_ID;
     private static final String ROOT_ID_HOME = "home";
 
     private StorageManager mStorageManager;
diff --git a/packages/MtpDocumentsProvider/perf_tests/Android.mk b/packages/MtpDocumentsProvider/perf_tests/Android.mk
index e873157..d2f1c7a 100644
--- a/packages/MtpDocumentsProvider/perf_tests/Android.mk
+++ b/packages/MtpDocumentsProvider/perf_tests/Android.mk
@@ -3,7 +3,7 @@
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
 LOCAL_PACKAGE_NAME := MtpDocumentsProviderPerfTests
 LOCAL_PRIVATE_PLATFORM_APIS := true
 LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider
diff --git a/packages/MtpDocumentsProvider/perf_tests/AndroidManifest.xml b/packages/MtpDocumentsProvider/perf_tests/AndroidManifest.xml
index 26e109d..4367652 100644
--- a/packages/MtpDocumentsProvider/perf_tests/AndroidManifest.xml
+++ b/packages/MtpDocumentsProvider/perf_tests/AndroidManifest.xml
@@ -7,7 +7,7 @@
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.mtp"
         android:label="Performance tests for MtpDocumentsProvider." />
 </manifest>
diff --git a/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java b/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java
index 36f6fe9..58b9c67 100644
--- a/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java
+++ b/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java
@@ -23,17 +23,15 @@
 import android.os.ProxyFileDescriptorCallback;
 import android.os.storage.StorageManager;
 import android.system.ErrnoException;
-import android.system.Os;
-import android.support.test.filters.LargeTest;
-import android.support.test.InstrumentationRegistry;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Arrays;
-import libcore.io.IoUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+
+import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.junit.Test;
+
+import java.io.IOException;
 
 @RunWith(JUnit4.class)
 public class AppFusePerfTest {
diff --git a/packages/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml
index 1e0ff50..a05a219 100644
--- a/packages/PackageInstaller/res/values/strings.xml
+++ b/packages/PackageInstaller/res/values/strings.xml
@@ -121,7 +121,7 @@
     <string name="uninstall_update_text_multiuser">Replace this app with the factory version? All data will be removed. This affects all users of this device, including those with work profiles.</string>
     <!-- Label of a checkbox that allows to remove the files contributed by app during uninstall [CHAR LIMIT=none] -->
     <string name="uninstall_remove_contributed_files">Also remove <xliff:g id="size" example="1.5MB">%1$s</xliff:g> of associated media files.</string>
-    <!-- Label of a checkbox that allows to remove the files contributed by app during uninstall [CHAR LIMIT=none] -->
+    <!-- Label of a checkbox that allows to keep the data (e.g. files, settings) of the app on uninstall [CHAR LIMIT=none] -->
     <string name="uninstall_keep_data">Keep <xliff:g id="size" example="1.5MB">%1$s</xliff:g> of app data.</string>
 
     <!-- Label for the notification channel containing notifications for current uninstall operations [CHAR LIMIT=40] -->
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.bp b/packages/PrintSpooler/tests/outofprocess/Android.bp
index e88074e..c6dc263 100644
--- a/packages/PrintSpooler/tests/outofprocess/Android.bp
+++ b/packages/PrintSpooler/tests/outofprocess/Android.bp
@@ -19,7 +19,7 @@
 
     libs: ["android.test.runner.stubs"],
     static_libs: [
-        "android-support-test",
+        "androidx.test.rules",
         "ub-uiautomator",
         "mockito-target-minus-junit4",
         "print-test-util-lib",
diff --git a/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml b/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml
index 307cc93..fdcaa52 100644
--- a/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml
+++ b/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml
@@ -54,7 +54,7 @@
     </application>
 
     <!-- This runs in its own process, hence it instruments itself -->
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
             android:targetPackage="com.android.printspooler.outofprocess.tests"
             android:label="PrintSpooler Out of Process Test Cases">
     </instrumentation>
diff --git a/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml b/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml
index d21a2e4..b649e82 100644
--- a/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml
+++ b/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml
@@ -24,7 +24,7 @@
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.printspooler.outofprocess.tests" />
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
 </configuration>
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java
index 7ebf93d..61c2f54 100644
--- a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java
+++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java
@@ -35,7 +35,6 @@
 import android.print.test.services.FirstPrintService;
 import android.print.test.services.PrinterDiscoverySessionCallbacks;
 import android.print.test.services.StubbablePrinterDiscoverySession;
-import android.support.test.filters.LargeTest;
 import android.support.test.uiautomator.By;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiObjectNotFoundException;
@@ -43,6 +42,8 @@
 import android.support.test.uiautomator.Until;
 import android.util.Log;
 
+import androidx.test.filters.LargeTest;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
index 89ebf4d..d400159 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarChartPreference.java
@@ -31,7 +31,7 @@
 import java.util.Arrays;
 
 /**
- * This BarChartPreference shows four bar views in this preference at most.
+ * This BarChartPreference shows up to four bar views in this preference at most.
  *
  * <p>The following code sample shows a typical use, with an XML layout and code to initialize the
  * contents of the BarChartPreference:
@@ -74,71 +74,28 @@
     };
 
     private int mMaxBarHeight;
-    private @StringRes int mTitleId;
-    private @StringRes int mDetailsId;
+    @StringRes
+    private int mTitleId;
+    @StringRes
+    private int mDetailsId;
     private BarViewInfo[] mBarViewsInfo;
     private View.OnClickListener mDetailsOnClickListener;
 
-    /**
-     * Constructs a new BarChartPreference with the given context's theme.
-     * It sets a layout with settings bar chart style
-     *
-     * @param context The Context the view is running in, through which it can
-     *                access the current theme, resources, etc.
-     */
     public BarChartPreference(Context context) {
         super(context);
         init();
     }
 
-    /**
-     * Constructs a new BarChartPreference with the given context's theme and the supplied
-     * attribute set.
-     * It sets a layout with settings bar chart style
-     *
-     * @param context the Context the view is running in
-     * @param attrs the attributes of the XML tag that is inflating the view.
-     */
     public BarChartPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
         init();
     }
 
-    /**
-     * Constructs a new BarChartPreference with the given context's theme, the supplied
-     * attribute set, and default style attribute.
-     * It sets a layout with settings bar chart style
-     *
-     * @param context The Context the view is running in, through which it can
-     *                access the current theme, resources, etc.
-     * @param attrs The attributes of the XML tag that is inflating the view.
-     * @param defStyleAttr An attribute in the current theme that contains a
-     *                     reference to a style resource that supplies default
-     *                     values for the view. Can be 0 to not look for
-     *                     defaults.
-     */
     public BarChartPreference(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         init();
     }
 
-    /**
-     * Constructs a new BarChartPreference with the given context's theme, the supplied
-     * attribute set, and default styles.
-     * It sets a layout with settings bar chart style
-     *
-     * @param context The Context the view is running in, through which it can
-     *                access the current theme, resources, etc.
-     * @param attrs The attributes of the XML tag that is inflating the view.
-     * @param defStyleAttr An attribute in the current theme that contains a
-     *                     reference to a style resource that supplies default
-     *                     values for the view. Can be 0 to not look for
-     *                     defaults.
-     * @param defStyleRes  A resource identifier of a style resource that
-     *                     supplies default values for the view, used only if
-     *                     defStyleAttr is 0 or can not be found in the theme.
-     *                     Can be 0 to not look for defaults.
-     */
     public BarChartPreference(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
@@ -172,8 +129,6 @@
     /**
      * Set all bar view information which you'd like to show in preference.
      *
-     * <p>This method helps you do a sort by {@linkBarViewInfo#mBarNumber} in descending order.
-     *
      * @param barViewsInfo the barViewsInfo contain at least one {@link BarViewInfo}.
      */
     public void setAllBarViewsInfo(@NonNull BarViewInfo[] barViewsInfo) {
@@ -181,7 +136,7 @@
         // Do a sort in descending order, the first element would have max {@link
         // BarViewInfo#mBarNumber}
         Arrays.sort(mBarViewsInfo);
-        caculateAllBarViewsHeight();
+        calculateAllBarViewHeights();
         notifyChanged();
     }
 
@@ -224,19 +179,19 @@
                 continue;
             }
             barView.setVisibility(View.VISIBLE);
-            barView.updateBarViewUI(mBarViewsInfo[index]);
+            barView.updateView(mBarViewsInfo[index]);
         }
     }
 
-    private void caculateAllBarViewsHeight() {
+    private void calculateAllBarViewHeights() {
         // Since we sorted this array in advance, the first element must have the max {@link
-        // BarViewInfo#mBarNumber}.
-        final int maxBarViewNumber = mBarViewsInfo[0].getBarNumber();
-        // If the max number of bar view is zero, then we don't caculate the unit for bar height.
-        final int unit = maxBarViewNumber == 0 ? 0 : mMaxBarHeight / maxBarViewNumber;
+        // BarViewInfo#mHeight}.
+        final int maxBarHeight = mBarViewsInfo[0].getHeight();
+        // If the max number of bar view is zero, then we don't calculate the unit for bar height.
+        final int unit = maxBarHeight == 0 ? 0 : mMaxBarHeight / maxBarHeight;
 
         for (BarViewInfo barView : mBarViewsInfo) {
-            barView.setBarHeight(barView.getBarNumber() * unit);
+            barView.setNormalizedHeight(barView.getHeight() * unit);
         }
     }
 }
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
index 6243a2d..6bf61ae 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
@@ -30,7 +30,7 @@
 import androidx.annotation.VisibleForTesting;
 
 /**
- * A extension view for bar chart.
+ * {@link View} for a single vertical bar with icon and summary.
  */
 public class BarView extends LinearLayout {
 
@@ -41,24 +41,11 @@
     private TextView mBarTitle;
     private TextView mBarSummary;
 
-    /**
-     * Constructs a new BarView with the given context's theme.
-     *
-     * @param context The Context the view is running in, through which it can
-     *                access the current theme, resources, etc.
-     */
     public BarView(Context context) {
         super(context);
         init();
     }
 
-    /**
-     * Constructs a new BarView with the given context's theme and the supplied
-     * attribute set.
-     *
-     * @param context the Context the view is running in
-     * @param attrs the attributes of the XML tag that is inflating the view.
-     */
     public BarView(Context context, AttributeSet attrs) {
         super(context, attrs);
         init();
@@ -77,17 +64,16 @@
     }
 
     /**
-     * This helps update the bar view UI with a {@link BarViewInfo}.
-     *
-     * @param barViewInfo A {@link BarViewInfo} saves bar view status.
+     * Updates the view with a {@link BarViewInfo}.
      */
-    public void updateBarViewUI(BarViewInfo barViewInfo) {
+    void updateView(BarViewInfo barViewInfo) {
+        setOnClickListener(barViewInfo.getClickListener());
         //Set height of bar view
-        mBarView.getLayoutParams().height = barViewInfo.getBarHeight();
+        mBarView.getLayoutParams().height = barViewInfo.getNormalizedHeight();
         mIcon.setImageDrawable(barViewInfo.getIcon());
         // For now, we use the bar number as title.
-        mBarTitle.setText(Integer.toString(barViewInfo.getBarNumber()));
-        mBarSummary.setText(barViewInfo.getSummaryRes());
+        mBarTitle.setText(Integer.toString(barViewInfo.getHeight()));
+        mBarSummary.setText(barViewInfo.getSummary());
     }
 
     @VisibleForTesting
@@ -106,9 +92,9 @@
         setGravity(Gravity.CENTER);
 
         mBarView = findViewById(R.id.bar_view);
-        mIcon = (ImageView) findViewById(R.id.icon_view);
-        mBarTitle = (TextView) findViewById(R.id.bar_title);
-        mBarSummary = (TextView) findViewById(R.id.bar_summary);
+        mIcon = findViewById(R.id.icon_view);
+        mBarTitle = findViewById(R.id.bar_title);
+        mBarSummary = findViewById(R.id.bar_summary);
     }
 
     private void setOnClickListner(View.OnClickListener listener) {
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java
index aa83ce9..409f9ea 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java
@@ -31,116 +31,71 @@
 public class BarViewInfo implements Comparable<BarViewInfo> {
 
     private final Drawable mIcon;
-    private View.OnClickListener mListener;
-    private @StringRes int mSummaryRes;
+    private View.OnClickListener mClickListener;
+    @StringRes
+    private int mSummary;
     // A number indicates this bar's height. The larger number shows a higher bar view.
-    private int mBarNumber;
+    private int mHeight;
     // A real height of bar view.
-    private int mBarHeight;
+    private int mNormalizedHeight;
 
     /**
      * Construct a BarViewInfo instance.
      *
-     * @param icon the icon of bar view.
-     * @param barNumber the number of bar view. The larger number show a more height of bar view.
-     * @param summaryRes the resource identifier of the string resource to be displayed
-     * @return BarViewInfo object.
+     * @param icon      The icon of bar view.
+     * @param barHeight The height of bar view. Larger number shows a higher bar view.
+     * @param summary   The string resource id for summary.
      */
-    public BarViewInfo(Drawable icon, @IntRange(from = 0) int barNumber,
-            @StringRes int summaryRes) {
+    public BarViewInfo(Drawable icon, @IntRange(from = 0) int barHeight, @StringRes int summary) {
         mIcon = icon;
-        mBarNumber = barNumber;
-        mSummaryRes = summaryRes;
+        mHeight = barHeight;
+        mSummary = summary;
     }
 
     /**
-     * Set number for bar view.
-     *
-     * @param barNumber the number of bar view. The larger number shows a higher bar view.
-     */
-    public void setBarNumber(@IntRange(from = 0) int barNumber) {
-        mBarNumber = barNumber;
-    }
-
-    /**
-     * Set summary resource for bar view
-     *
-     * @param resId the resource identifier of the string resource to be displayed
-     */
-    public void setSummary(@StringRes int resId) {
-        mSummaryRes = resId;
-    }
-
-    /**
-     * Set a click listner for bar view.
-     *
-     * @param listener the click listner is attached on bar view.
+     * Set a click listener for bar view.
      */
     public void setClickListener(@Nullable View.OnClickListener listener) {
-        mListener = listener;
-    }
-
-    /**
-     * Get the icon of bar view.
-     *
-     * @return Drawable the icon of bar view.
-     */
-    public Drawable getIcon() {
-        return mIcon;
-    }
-
-    /**
-     * Get the OnClickListener of bar view.
-     *
-     * @return View.OnClickListener the click listner of bar view.
-     */
-    public View.OnClickListener getListener() {
-        return mListener;
-    }
-
-    /**
-     * Get the real height of bar view.
-     *
-     * @return the real height of bar view.
-     */
-    public int getBarHeight() {
-        return mBarHeight;
-    }
-
-    /**
-     * Get summary resource of bar view.
-     *
-     * @return summary resource of bar view.
-     */
-    public int getSummaryRes() {
-        return mSummaryRes;
-    }
-
-    /**
-     * Get the number of app uses this permisssion.
-     *
-     * @return the number of app uses this permission.
-     */
-    public int getBarNumber() {
-        return mBarNumber;
+        mClickListener = listener;
     }
 
     @Override
     public int compareTo(BarViewInfo other) {
         // Descending order
-        return Comparator.comparingInt((BarViewInfo barViewInfo) -> barViewInfo.mBarNumber)
+        return Comparator.comparingInt((BarViewInfo barViewInfo) -> barViewInfo.mHeight)
                 .compare(other, this);
     }
 
-    /**
-     * Set a real height for bar view.
-     *
-     * <p>This method should not be called by outside. It usually should be called by
-     * {@link BarChartPreference#caculateAllBarViewsHeight}
-     *
-     * @param barHeight the real bar height for bar view.
-     */
-    void setBarHeight(@IntRange(from = 0) int barHeight) {
-        mBarHeight = barHeight;
+    void setHeight(@IntRange(from = 0) int height) {
+        mHeight = height;
+    }
+
+    void setSummary(@StringRes int resId) {
+        mSummary = resId;
+    }
+
+    Drawable getIcon() {
+        return mIcon;
+    }
+
+    int getHeight() {
+        return mHeight;
+    }
+
+    View.OnClickListener getClickListener() {
+        return mClickListener;
+    }
+
+    @StringRes
+    int getSummary() {
+        return mSummary;
+    }
+
+    void setNormalizedHeight(@IntRange(from = 0) int barHeight) {
+        mNormalizedHeight = barHeight;
+    }
+
+    int getNormalizedHeight() {
+        return mNormalizedHeight;
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 2b7babd0..7914a0b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -321,6 +321,11 @@
                 // Dispatch device add callback to show bonded but
                 // not connected devices in discovery mode
                 dispatchDeviceAdded(cachedDevice);
+                Log.d(TAG, "DeviceFoundHandler found bonded and not connected device:"
+                        + cachedDevice);
+            } else {
+                Log.d(TAG, "DeviceFoundHandler found existing CachedBluetoothDevice:"
+                        + cachedDevice);
             }
             cachedDevice.setRssi(rssi);
             cachedDevice.setJustDiscovered(true);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 1bffff7..e28c894 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -116,8 +116,8 @@
 
     void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) {
         if (BluetoothUtils.D) {
-            Log.d(TAG, "onProfileStateChanged: profile " + profile +
-                    " newProfileState " + newProfileState);
+            Log.d(TAG, "onProfileStateChanged: profile " + profile + ", device=" + mDevice
+                    + ", newProfileState " + newProfileState);
         }
         if (mLocalAdapter.getState() == BluetoothAdapter.STATE_TURNING_OFF)
         {
@@ -570,7 +570,7 @@
         }
 
         if (BluetoothUtils.D) {
-            Log.e(TAG, "updating profiles for " + mDevice.getAliasName());
+            Log.e(TAG, "updating profiles for " + mDevice.getAliasName() + ", " + mDevice);
             BluetoothClass bluetoothClass = mDevice.getBluetoothClass();
 
             if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString());
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
index 9572fb3..20fe495 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
@@ -1,6 +1,8 @@
 package com.android.settingslib.core;
 
 import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.preference.Preference;
 import androidx.preference.PreferenceGroup;
@@ -11,6 +13,8 @@
  */
 public abstract class AbstractPreferenceController {
 
+    private static final String TAG = "AbstractPrefController";
+
     protected final Context mContext;
 
     public AbstractPreferenceController(Context context) {
@@ -22,6 +26,10 @@
      */
     public void displayPreference(PreferenceScreen screen) {
         final String prefKey = getPreferenceKey();
+        if (TextUtils.isEmpty(prefKey)) {
+            Log.w(TAG, "Skipping displayPreference because key is empty:" + getClass().getName());
+            return;
+        }
         if (isAvailable()) {
             setVisible(screen, prefKey, true /* visible */);
             if (this instanceof Preference.OnPreferenceChangeListener) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
index 28de191..f695e0c3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
@@ -35,6 +35,8 @@
 @RunWith(RobolectricTestRunner.class)
 public class AbstractPreferenceControllerTest {
 
+    private static final String KEY_PREF = "test_pref";
+
     @Mock
     private PreferenceScreen mScreen;
 
@@ -47,9 +49,9 @@
         MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
         mPreference = new Preference(mContext);
-        mPreference.setKey(TestPrefController.KEY_PREF);
-        when(mScreen.findPreference(TestPrefController.KEY_PREF)).thenReturn(mPreference);
-        mTestPrefController = new TestPrefController(mContext);
+        mPreference.setKey(KEY_PREF);
+        when(mScreen.findPreference(KEY_PREF)).thenReturn(mPreference);
+        mTestPrefController = new TestPrefController(mContext, KEY_PREF);
     }
 
     @Test
@@ -62,15 +64,24 @@
     }
 
     @Test
+    public void displayPref_noKey_shouldDoNothing() {
+        mTestPrefController.isAvailable = true;
+
+        mTestPrefController.displayPreference(mScreen);
+
+        assertThat(mPreference.isVisible()).isTrue();
+    }
+
+    @Test
     public void setVisible_prefIsVisible_shouldSetToVisible() {
-        mTestPrefController.setVisible(mScreen, TestPrefController.KEY_PREF, true /* visible */);
+        mTestPrefController.setVisible(mScreen, KEY_PREF, true /* visible */);
 
         assertThat(mPreference.isVisible()).isTrue();
     }
 
     @Test
     public void setVisible_prefNotVisible_shouldSetToInvisible() {
-        mTestPrefController.setVisible(mScreen, TestPrefController.KEY_PREF, false /* visible */);
+        mTestPrefController.setVisible(mScreen, KEY_PREF, false /* visible */);
 
         assertThat(mPreference.isVisible()).isFalse();
     }
@@ -92,13 +103,14 @@
     }
 
     private static class TestPrefController extends AbstractPreferenceController {
-        private static final String KEY_PREF = "test_pref";
         private static final CharSequence TEST_SUMMARY = "Test";
 
         public boolean isAvailable;
+        private final String mPrefKey;
 
-        public TestPrefController(Context context) {
+        TestPrefController(Context context, String key) {
             super(context);
+            mPrefKey = key;
         }
 
         @Override
@@ -113,7 +125,7 @@
 
         @Override
         public String getPreferenceKey() {
-            return KEY_PREF;
+            return mPrefKey;
         }
 
         @Override
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
index 371c3d4..d4e7481 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
@@ -208,4 +208,18 @@
         assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
         assertThat(mBarView1.getSummary()).isEqualTo(mContext.getText(R.string.debug_app));
     }
+
+    @Test
+    public void setAllBarViewsInfo_setClickListenerForBarView_barViewAttachClickListener() {
+        final BarViewInfo viewInfo = new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app);
+        viewInfo.setClickListener(v -> {
+        });
+        final BarViewInfo[] barViewsInfo = new BarViewInfo[]{viewInfo};
+
+        mPreference.setAllBarViewsInfo(barViewsInfo);
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView1.hasOnClickListeners()).isTrue();
+    }
 }
diff --git a/packages/SystemUI/docs/dagger.md b/packages/SystemUI/docs/dagger.md
index 565d765f..8bfa1c2 100644
--- a/packages/SystemUI/docs/dagger.md
+++ b/packages/SystemUI/docs/dagger.md
@@ -125,6 +125,28 @@
 }
 ```
 
+### Using injection with Fragments
+
+Fragments are created as part of the FragmentManager, so they need to be
+setup so the manager knows how to create them. To do that, add a method
+to com.android.systemui.fragments.FragmentService$FragmentCreator that
+returns your fragment class. Thats all thats required, once the method
+exists, FragmentService will automatically pick it up and use injection
+whenever your fragment needs to be created.
+
+```java
+public interface FragmentCreator {
++   NavigationBarFragment createNavigationBar();
+}
+```
+
+If you need to create your fragment (i.e. for the add or replace transaction),
+then the FragmentHostManager can do this for you.
+
+```java
+FragmentHostManager.get(view).create(NavigationBarFragment.class);
+```
+
 ## TODO List
 
  - Eliminate usages of Depndency#get
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index cc6848f..d57fe8a 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -28,4 +28,7 @@
 -keep class com.android.systemui.plugins.** {
     *;
 }
+-keep class com.android.systemui.fragments.FragmentService$FragmentCreator {
+    *;
+}
 -keep class androidx.core.app.CoreComponentFactory
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index e051317..583dac7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -28,6 +28,7 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Display;
+import android.view.DisplayInfo;
 import android.view.View;
 import android.view.WindowManager;
 
@@ -45,6 +46,7 @@
     private final Context mContext;
 
     private boolean mShowing;
+    private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
 
     private final SparseArray<Presentation> mPresentations = new SparseArray<>();
 
@@ -86,6 +88,22 @@
         mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
     }
 
+    private boolean isKeyguardShowable(Display display) {
+        if (display == null) {
+            if (DEBUG) Log.i(TAG, "Cannot show Keyguard on null display");
+            return false;
+        }
+        if (display.getDisplayId() == DEFAULT_DISPLAY) {
+            if (DEBUG) Log.i(TAG, "Do not show KeyguardPresentation on the default display");
+            return false;
+        }
+        display.getDisplayInfo(mTmpDisplayInfo);
+        if ((mTmpDisplayInfo.flags & Display.FLAG_PRIVATE) != 0) {
+            if (DEBUG) Log.i(TAG, "Do not show KeyguardPresentation on a private display");
+            return false;
+        }
+        return true;
+    }
     /**
      * @param display The display to show the presentation on.
      * @return {@code true} if a presentation was added.
@@ -93,7 +111,7 @@
      *         was already there.
      */
     private boolean showPresentation(Display display) {
-        if (display == null || display.getDisplayId() == DEFAULT_DISPLAY) return false;
+        if (!isKeyguardShowable(display)) return false;
         if (DEBUG) Log.i(TAG, "Keyguard enabled on display: " + display);
         final int displayId = display.getDisplayId();
         Presentation presentation = mPresentations.get(displayId);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index c41ef0e..5766604 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -24,6 +24,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.annotation.ColorInt;
+import android.annotation.StyleRes;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.graphics.Color;
@@ -444,9 +445,11 @@
     static class KeyguardSliceButton extends Button implements
             ConfigurationController.ConfigurationListener {
 
+        @StyleRes
+        private static int sStyleId = R.style.TextAppearance_Keyguard_Secondary;
+
         public KeyguardSliceButton(Context context) {
-            super(context, null /* attrs */, 0 /* styleAttr */,
-                    com.android.keyguard.R.style.TextAppearance_Keyguard_Secondary);
+            super(context, null /* attrs */, 0 /* styleAttr */, sStyleId);
             onDensityOrFontScaleChanged();
             setEllipsize(TruncateAt.END);
         }
@@ -469,6 +472,11 @@
         }
 
         @Override
+        public void onOverlayChanged() {
+            setTextAppearance(sStyleId);
+        }
+
+        @Override
         public void setText(CharSequence text, BufferType type) {
             super.setText(text, type);
             updatePadding();
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 38dadd4..874cdcc 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -325,6 +325,17 @@
                 .inflate(R.layout.battery_percentage_view, null);
     }
 
+    /**
+     * Updates percent view by removing old one and reinflating if necessary
+     */
+    public void updatePercentView() {
+        if (mBatteryPercentView != null) {
+            removeView(mBatteryPercentView);
+            mBatteryPercentView = null;
+        }
+        updateShowPercent();
+    }
+
     private void updatePercentText() {
         if (mBatteryPercentView != null) {
             mBatteryPercentView.setText(
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 4e5af15..445d156 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -56,6 +56,7 @@
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.NotificationData.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -254,6 +255,7 @@
     @Inject Lazy<NotificationListener> mNotificationListener;
     @Inject Lazy<NotificationLogger> mNotificationLogger;
     @Inject Lazy<NotificationViewHierarchyManager> mNotificationViewHierarchyManager;
+    @Inject Lazy<NotificationRowBinder> mNotificationRowBinder;
     @Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil;
     @Inject Lazy<SmartReplyController> mSmartReplyController;
     @Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler;
@@ -422,6 +424,7 @@
         mProviders.put(NotificationLogger.class, mNotificationLogger::get);
         mProviders.put(NotificationViewHierarchyManager.class,
                 mNotificationViewHierarchyManager::get);
+        mProviders.put(NotificationRowBinder.class, mNotificationRowBinder::get);
         mProviders.put(KeyguardDismissUtil.class, mKeyguardDismissUtil::get);
         mProviders.put(SmartReplyController.class, mSmartReplyController::get);
         mProviders.put(RemoteInputQuickSettingsDisabler.class,
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
index e828b23..76336bb 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
@@ -44,7 +44,6 @@
 import com.android.systemui.appops.AppOpsController;
 import com.android.systemui.appops.AppOpsControllerImpl;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.ActivityStarter;
@@ -405,12 +404,6 @@
 
     @Singleton
     @Provides
-    public FragmentService provideFragmentService() {
-        return new FragmentService();
-    }
-
-    @Singleton
-    @Provides
     public ExtensionController provideExtensionController(Context context) {
         return new ExtensionControllerImpl(context);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 9bc91ee..1a2473e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -30,6 +30,7 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.EnhancedEstimatesImpl;
@@ -41,6 +42,7 @@
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationRowBinder;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
@@ -215,5 +217,11 @@
     public interface SystemUIRootComponent {
         @Singleton
         Dependency.DependencyInjector createDependency();
+
+        /**
+         * FragmentCreator generates all Fragments that need injection.
+         */
+        @Singleton
+        FragmentService.FragmentCreator createFragmentCreator();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 906a210..52d1260 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -39,25 +39,39 @@
  * NotificationPresenter to be displayed to the user.
  */
 public class AppOpsControllerImpl implements AppOpsController,
-        AppOpsManager.OnOpActiveChangedListener {
+        AppOpsManager.OnOpActiveChangedListener,
+        AppOpsManager.OnOpNotedListener {
 
-    private static final long LOCATION_TIME_DELAY_MS = 5000;
+    private static final long NOTED_OP_TIME_DELAY_MS = 5000;
     private static final String TAG = "AppOpsControllerImpl";
     private static final boolean DEBUG = false;
     private final Context mContext;
 
-    protected final AppOpsManager mAppOps;
-    private final H mBGHandler;
+    private final AppOpsManager mAppOps;
+    private H mBGHandler;
     private final List<AppOpsController.Callback> mCallbacks = new ArrayList<>();
     private final ArrayMap<Integer, Set<Callback>> mCallbacksByCode = new ArrayMap<>();
+
     @GuardedBy("mActiveItems")
     private final List<AppOpItem> mActiveItems = new ArrayList<>();
+    @GuardedBy("mNotedItems")
+    private final List<AppOpItem> mNotedItems = new ArrayList<>();
 
-    protected static final int[] OPS = new int[] {AppOpsManager.OP_CAMERA,
-            AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
-            AppOpsManager.OP_RECORD_AUDIO,
-            AppOpsManager.OP_COARSE_LOCATION,
-            AppOpsManager.OP_FINE_LOCATION};
+    protected static final int[] OPS;
+    protected static final String[] OPS_STRING = new String[] {
+            AppOpsManager.OPSTR_CAMERA,
+            AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW,
+            AppOpsManager.OPSTR_RECORD_AUDIO,
+            AppOpsManager.OPSTR_COARSE_LOCATION,
+            AppOpsManager.OPSTR_FINE_LOCATION};
+
+    static {
+        int numOps = OPS_STRING.length;
+        OPS = new int[numOps];
+        for (int i = 0; i < numOps; i++) {
+            OPS[i] = AppOpsManager.strOpToOp(OPS_STRING[i]);
+        }
+    }
 
     public AppOpsControllerImpl(Context context, Looper bgLooper) {
         mContext = context;
@@ -70,11 +84,18 @@
     }
 
     @VisibleForTesting
+    protected void setBGHandler(H handler) {
+        mBGHandler = handler;
+    }
+
+    @VisibleForTesting
     protected void setListening(boolean listening) {
         if (listening) {
             mAppOps.startWatchingActive(OPS, this);
+            mAppOps.startWatchingNoted(OPS_STRING, this);
         } else {
             mAppOps.stopWatchingActive(this);
+            mAppOps.stopWatchingNoted(this);
         }
     }
 
@@ -124,10 +145,11 @@
         if (mCallbacks.isEmpty()) setListening(false);
     }
 
-    private AppOpItem getAppOpItem(int code, int uid, String packageName) {
-        final int itemsQ = mActiveItems.size();
+    private AppOpItem getAppOpItem(List<AppOpItem> appOpList, int code, int uid,
+            String packageName) {
+        final int itemsQ = appOpList.size();
         for (int i = 0; i < itemsQ; i++) {
-            AppOpItem item = mActiveItems.get(i);
+            AppOpItem item = appOpList.get(i);
             if (item.getCode() == code && item.getUid() == uid
                     && item.getPackageName().equals(packageName)) {
                 return item;
@@ -138,39 +160,59 @@
 
     private boolean updateActives(int code, int uid, String packageName, boolean active) {
         synchronized (mActiveItems) {
-            AppOpItem item = getAppOpItem(code, uid, packageName);
+            AppOpItem item = getAppOpItem(mActiveItems, code, uid, packageName);
             if (item == null && active) {
                 item = new AppOpItem(code, uid, packageName, System.currentTimeMillis());
                 mActiveItems.add(item);
-                if (code == AppOpsManager.OP_COARSE_LOCATION
-                        || code == AppOpsManager.OP_FINE_LOCATION) {
-                    mBGHandler.scheduleRemoval(item, LOCATION_TIME_DELAY_MS);
-                }
                 if (DEBUG) Log.w(TAG, "Added item: " + item.toString());
                 return true;
             } else if (item != null && !active) {
                 mActiveItems.remove(item);
                 if (DEBUG) Log.w(TAG, "Removed item: " + item.toString());
                 return true;
-            } else if (item != null && active
-                    && (code == AppOpsManager.OP_COARSE_LOCATION
-                            || code == AppOpsManager.OP_FINE_LOCATION)) {
-                mBGHandler.scheduleRemoval(item, LOCATION_TIME_DELAY_MS);
-                return true;
             }
             return false;
         }
     }
 
+    private void removeNoted(int code, int uid, String packageName) {
+        AppOpItem item;
+        synchronized (mNotedItems) {
+            item = getAppOpItem(mNotedItems, code, uid, packageName);
+            if (item == null) return;
+            mNotedItems.remove(item);
+            if (DEBUG) Log.w(TAG, "Removed item: " + item.toString());
+        }
+        notifySuscribers(code, uid, packageName, false);
+    }
+
+    private void addNoted(int code, int uid, String packageName) {
+        AppOpItem item;
+        synchronized (mNotedItems) {
+            item = getAppOpItem(mNotedItems, code, uid, packageName);
+            if (item == null) {
+                item = new AppOpItem(code, uid, packageName, System.currentTimeMillis());
+                mNotedItems.add(item);
+                if (DEBUG) Log.w(TAG, "Added item: " + item.toString());
+            }
+        }
+        mBGHandler.scheduleRemoval(item, NOTED_OP_TIME_DELAY_MS);
+    }
+
     /**
      * Returns a copy of the list containing all the active AppOps that the controller tracks.
      *
      * @return List of active AppOps information
      */
     public List<AppOpItem> getActiveAppOps() {
+        ArrayList<AppOpItem> active;
         synchronized (mActiveItems) {
-            return new ArrayList<>(mActiveItems);
+            active = new ArrayList<>(mActiveItems);
         }
+        synchronized (mNotedItems) {
+            active.addAll(mNotedItems);
+        }
+        return active;
     }
 
     /**
@@ -192,19 +234,45 @@
                 }
             }
         }
+        synchronized (mNotedItems) {
+            final int numNotedItems = mNotedItems.size();
+            for (int i = 0; i < numNotedItems; i++) {
+                AppOpItem item = mNotedItems.get(i);
+                if (UserHandle.getUserId(item.getUid()) == userId) {
+                    list.add(item);
+                }
+            }
+        }
         return list;
     }
 
     @Override
     public void onOpActiveChanged(int code, int uid, String packageName, boolean active) {
         if (updateActives(code, uid, packageName, active)) {
+            notifySuscribers(code, uid, packageName, active);
+        }
+    }
+
+    @Override
+    public void onOpNoted(String code, int uid, String packageName, int result) {
+        if (DEBUG) {
+            Log.w(TAG, "Op: " + code + " with result " + AppOpsManager.MODE_NAMES[result]);
+        }
+        if (result != AppOpsManager.MODE_ALLOWED) return;
+        int op_code = AppOpsManager.strOpToOp(code);
+        addNoted(op_code, uid, packageName);
+        notifySuscribers(op_code, uid, packageName, true);
+    }
+
+    private void notifySuscribers(int code, int uid, String packageName, boolean active) {
+        if (mCallbacksByCode.containsKey(code)) {
             for (Callback cb: mCallbacksByCode.get(code)) {
                 cb.onActiveStateChanged(code, uid, packageName, active);
             }
         }
     }
 
-    private final class H extends Handler {
+    protected final class H extends Handler {
         H(Looper looper) {
             super(looper);
         }
@@ -214,8 +282,7 @@
             postDelayed(new Runnable() {
                 @Override
                 public void run() {
-                    onOpActiveChanged(item.getCode(), item.getUid(),
-                            item.getPackageName(), false);
+                    removeNoted(item.getCode(), item.getUid(), item.getPackageName());
                 }
             }, item, timeToRemoval);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 60e39b2..30f6e1a 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -41,6 +41,8 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.HashMap;
 
@@ -186,6 +188,13 @@
         mFragments.dispatchDestroy();
     }
 
+    /**
+     * Creates a fragment that requires injection.
+     */
+    public <T> T create(Class<T> fragmentCls) {
+        return (T) mPlugins.instantiate(mContext, fragmentCls.getName(), null);
+    }
+
     public interface FragmentListener {
         void onFragmentViewCreated(String tag, Fragment fragment);
 
@@ -294,13 +303,36 @@
         Fragment instantiate(Context context, String className, Bundle arguments) {
             Context extensionContext = mExtensionLookup.get(className);
             if (extensionContext != null) {
-                Fragment f = Fragment.instantiate(extensionContext, className, arguments);
+                Fragment f = instantiateWithInjections(extensionContext, className, arguments);
                 if (f instanceof Plugin) {
                     ((Plugin) f).onCreate(mContext, extensionContext);
                 }
                 return f;
             }
-            return Fragment.instantiate(context, className, arguments);
+            return instantiateWithInjections(context, className, arguments);
+        }
+
+        private Fragment instantiateWithInjections(Context context, String className,
+                Bundle args) {
+            Method method = mManager.getInjectionMap().get(className);
+            if (method != null) {
+                try {
+                    Fragment f = (Fragment) method.invoke(mManager.getFragmentCreator());
+                    // Setup the args, taken from Fragment#instantiate.
+                    if (args != null) {
+                        args.setClassLoader(f.getClass().getClassLoader());
+                        f.setArguments(args);
+                    }
+                    return f;
+                } catch (IllegalAccessException e) {
+                    throw new Fragment.InstantiationException("Unable to instantiate " + className,
+                            e);
+                } catch (InvocationTargetException e) {
+                    throw new Fragment.InstantiationException("Unable to instantiate " + className,
+                            e);
+                }
+            }
+            return Fragment.instantiate(context, className, args);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
index bf7d629..8dbaf0f 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
@@ -14,6 +14,7 @@
 
 package com.android.systemui.fragments;
 
+import android.app.Fragment;
 import android.content.res.Configuration;
 import android.os.Handler;
 import android.util.ArrayMap;
@@ -21,20 +22,56 @@
 
 import com.android.systemui.ConfigurationChangedReceiver;
 import com.android.systemui.Dumpable;
+import com.android.systemui.SystemUIFactory;
+import com.android.systemui.qs.QSFragment;
+import com.android.systemui.statusbar.phone.NavigationBarFragment;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import dagger.Subcomponent;
 
 /**
  * Holds a map of root views to FragmentHostStates and generates them as needed.
  * Also dispatches the configuration changes to all current FragmentHostStates.
  */
+@Singleton
 public class FragmentService implements ConfigurationChangedReceiver, Dumpable {
 
     private static final String TAG = "FragmentService";
 
     private final ArrayMap<View, FragmentHostState> mHosts = new ArrayMap<>();
+    private final ArrayMap<String, Method> mInjectionMap = new ArrayMap<>();
     private final Handler mHandler = new Handler();
+    private final FragmentCreator mFragmentCreator;
+
+    @Inject
+    public FragmentService(SystemUIFactory.SystemUIRootComponent rootComponent) {
+        mFragmentCreator = rootComponent.createFragmentCreator();
+        initInjectionMap();
+    }
+
+    ArrayMap<String, Method> getInjectionMap() {
+        return mInjectionMap;
+    }
+
+    FragmentCreator getFragmentCreator() {
+        return mFragmentCreator;
+    }
+
+    private void initInjectionMap() {
+        for (Method method : FragmentCreator.class.getDeclaredMethods()) {
+            if (Fragment.class.isAssignableFrom(method.getReturnType())
+                    && (method.getModifiers() & Modifier.PUBLIC) != 0) {
+                mInjectionMap.put(method.getReturnType().getName(), method);
+            }
+        }
+    }
 
     public FragmentHostManager getFragmentHostManager(View view) {
         View root = view.getRootView();
@@ -74,6 +111,21 @@
         }
     }
 
+    /**
+     * The subcomponent of dagger that holds all fragments that need injection.
+     */
+    @Subcomponent
+    public interface FragmentCreator {
+        /**
+         * Inject a NavigationBarFragment.
+         */
+        NavigationBarFragment createNavigationBarFragment();
+        /**
+         * Inject a QSFragment.
+         */
+        QSFragment createQSFragment();
+    }
+
     private class FragmentHostState {
         private final View mView;
 
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index 268462e..a87d634 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -115,7 +115,7 @@
 
     private fun updatePrivacyList() {
         privacyList = currentUserIds.flatMap { appOpsController.getActiveAppOpsForUser(it) }
-                .mapNotNull { toPrivacyItem(it) }
+                .mapNotNull { toPrivacyItem(it) }.distinct()
     }
 
     private fun toPrivacyItem(appOpItem: AppOpItem): PrivacyItem? {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 2acbea4..fa775c0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -35,7 +35,6 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.R.id;
@@ -47,6 +46,8 @@
 import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 
+import javax.inject.Inject;
+
 public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks {
     private static final String TAG = "QS";
     private static final boolean DEBUG = false;
@@ -74,8 +75,12 @@
     private float mLastQSExpansion = -1;
     private boolean mQsDisabled;
 
-    private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler =
-            Dependency.get(RemoteInputQuickSettingsDisabler.class);
+    private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
+
+    @Inject
+    public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler) {
+        mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
+    }
 
     @Override
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 9d2be39..4dcacd4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -87,6 +87,8 @@
         if (current != null) {
             // The setting QS_TILES is not populated immediately upon Factory Reset
             possibleTiles.addAll(Arrays.asList(current.split(",")));
+        } else {
+            current = "";
         }
         String[] stockSplit =  stock.split(",");
         for (String spec : stockSplit) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
index a5c0a2d..ee0d1a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationPresenter.java
@@ -16,6 +16,7 @@
 package com.android.systemui.statusbar;
 
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 
@@ -28,7 +29,8 @@
  */
 public interface NotificationPresenter extends ExpandableNotificationRow.OnExpandClickListener,
         ActivatableNotificationView.OnActivatedListener,
-        NotificationEntryManager.Callback {
+        NotificationEntryManager.Callback,
+        NotificationRowBinder.BindRowCallback {
     /**
      * Returns true if the presenter is not visible. For example, it may not be necessary to do
      * animations if this returns true.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
index ae9f323..ef7e0fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationData.java
@@ -105,6 +105,7 @@
         public NotificationChannel channel;
         public long lastAudiblyAlertedMs;
         public boolean noisy;
+        public boolean ambient;
         public int importance;
         public StatusBarIconView icon;
         public StatusBarIconView expandedIcon;
@@ -174,6 +175,7 @@
             channel = ranking.getChannel();
             lastAudiblyAlertedMs = ranking.getLastAudiblyAlertedMillis();
             importance = ranking.getImportance();
+            ambient = ranking.isAmbient();
             snoozeCriteria = ranking.getSnoozeCriteria();
             userSentiment = ranking.getUserSentiment();
             systemGeneratedSmartActions = ranking.getSmartActions() == null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index d2a5864..535ea62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -15,9 +15,7 @@
  */
 package com.android.systemui.statusbar.notification;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.systemui.bubbles.BubbleController.DEBUG_DEMOTE_TO_NOTIF;
-import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
 import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
@@ -28,10 +26,7 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
 import android.database.ContentObserver;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PowerManager;
@@ -49,25 +44,21 @@
 import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.Log;
-import android.view.ViewGroup;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
-import com.android.internal.util.NotificationMessagingUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.ForegroundServiceController;
-import com.android.systemui.R;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
 import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -79,11 +70,9 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationInflater;
 import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag;
-import com.android.systemui.statusbar.notification.row.RowInflaterTask;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.leak.LeakDetector;
@@ -100,9 +89,12 @@
  * It also handles tasks such as their inflation and their interaction with other
  * Notification.*Manager objects.
  */
-public class NotificationEntryManager implements Dumpable, NotificationInflater.InflationCallback,
-        ExpandableNotificationRow.ExpansionLogger, NotificationUpdateHandler,
-        VisualStabilityManager.Callback, BubbleController.BubbleDismissListener {
+public class NotificationEntryManager implements
+        Dumpable,
+        NotificationInflater.InflationCallback,
+        NotificationUpdateHandler,
+        VisualStabilityManager.Callback,
+        BubbleController.BubbleDismissListener {
     private static final String TAG = "NotificationEntryMgr";
     protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private static final boolean ENABLE_HEADS_UP = true;
@@ -110,7 +102,6 @@
 
     public static final long RECENTLY_ALERTED_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
 
-    private final NotificationMessagingUtil mMessagingUtil;
     protected final Context mContext;
     protected final HashMap<String, NotificationData.Entry> mPendingNotifications = new HashMap<>();
 
@@ -123,7 +114,6 @@
             Dependency.get(DeviceProvisionedController.class);
     private final VisualStabilityManager mVisualStabilityManager =
             Dependency.get(VisualStabilityManager.class);
-    private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
     private final ForegroundServiceController mForegroundServiceController =
             Dependency.get(ForegroundServiceController.class);
     private final AmbientPulseManager mAmbientPulseManager =
@@ -135,6 +125,7 @@
     private NotificationMediaManager mMediaManager;
     private NotificationListener mNotificationListener;
     private ShadeController mShadeController;
+    private NotificationRowBinder mNotificationRowBinder;
 
     private final Handler mDeferredNotificationViewUpdateHandler;
     private Runnable mUpdateNotificationViewsCallback;
@@ -154,10 +145,8 @@
     @VisibleForTesting
     final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders
             = new ArrayList<>();
-    private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
     private NotificationViewHierarchyManager.StatusBarStateListener mStatusBarStateListener;
     @Nullable private AlertTransferListener mAlertTransferListener;
-    @Nullable private NotificationClicker mNotificationClicker;
 
     private final DeviceProvisionedController.DeviceProvisionedListener
             mDeviceProvisionedListener =
@@ -199,7 +188,6 @@
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
         mDreamManager = IDreamManager.Stub.asInterface(
                 ServiceManager.checkService(DreamService.DREAM_SERVICE));
-        mMessagingUtil = new NotificationMessagingUtil(context);
         mBubbleController.setDismissListener(this /* bubbleEventListener */);
         mNotificationData = new NotificationData();
         mDeferredNotificationViewUpdateHandler = new Handler();
@@ -209,10 +197,6 @@
         mAlertTransferListener = listener;
     }
 
-    public void setNotificationClicker(NotificationClicker clicker) {
-        mNotificationClicker = clicker;
-    }
-
     /**
      * Our dependencies can have cyclic references, so some need to be lazy
      */
@@ -244,6 +228,13 @@
         return mShadeController;
     }
 
+    private NotificationRowBinder getRowBinder() {
+        if (mNotificationRowBinder == null) {
+            mNotificationRowBinder = Dependency.get(NotificationRowBinder.class);
+        }
+        return mNotificationRowBinder;
+    }
+
     public void setUpWithPresenter(NotificationPresenter presenter,
             NotificationListContainer listContainer, Callback callback,
             HeadsUpManager headsUpManager) {
@@ -296,7 +287,18 @@
         mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
 
         mHeadsUpObserver.onChange(true); // set up
-        mOnAppOpsClickListener = mGutsManager::openGuts;
+
+        getRowBinder().setInterruptionStateProvider(new InterruptionStateProvider() {
+            @Override
+            public boolean shouldHeadsUp(NotificationData.Entry entry) {
+                return NotificationEntryManager.this.shouldHeadsUp(entry);
+            }
+
+            @Override
+            public boolean shouldPulse(NotificationData.Entry entry) {
+                return NotificationEntryManager.this.shouldPulse(entry);
+            }
+        });
     }
 
     public NotificationData getNotificationData() {
@@ -312,18 +314,7 @@
     }
 
     public ExpandableNotificationRow.LongPressListener getNotificationLongClicker() {
-        return mGutsManager::openGuts;
-    }
-
-    @Override
-    public void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
-        mUiOffloadThread.submit(() -> {
-            try {
-                mBarService.onNotificationExpansionChanged(key, userAction, expanded);
-            } catch (RemoteException e) {
-                // Ignore.
-            }
-        });
+        return getRowBinder().getNotificationLongClicker();
     }
 
     @Override
@@ -339,64 +330,6 @@
         return mNotificationData.shouldSuppressFullScreenIntent(entry);
     }
 
-    private void inflateViews(NotificationData.Entry entry, ViewGroup parent) {
-        PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext,
-                entry.notification.getUser().getIdentifier());
-
-        final StatusBarNotification sbn = entry.notification;
-        if (entry.rowExists()) {
-            entry.reset();
-            updateNotification(entry, pmUser, sbn, entry.getRow());
-        } else {
-            new RowInflaterTask().inflate(mContext, parent, entry,
-                    row -> {
-                        bindRow(entry, pmUser, sbn, row);
-                        updateNotification(entry, pmUser, sbn, row);
-                    });
-        }
-    }
-
-    private void bindRow(NotificationData.Entry entry, PackageManager pmUser,
-            StatusBarNotification sbn, ExpandableNotificationRow row) {
-        row.setExpansionLogger(this, entry.notification.getKey());
-        row.setGroupManager(mGroupManager);
-        row.setHeadsUpManager(mHeadsUpManager);
-        row.setOnExpandClickListener(mPresenter);
-        row.setInflationCallback(this);
-        row.setLongPressListener(getNotificationLongClicker());
-        mListContainer.bindRow(row);
-        getRemoteInputManager().bindRow(row);
-
-        // Get the app name.
-        // Note that Notification.Builder#bindHeaderAppName has similar logic
-        // but since this field is used in the guts, it must be accurate.
-        // Therefore we will only show the application label, or, failing that, the
-        // package name. No substitutions.
-        final String pkg = sbn.getPackageName();
-        String appname = pkg;
-        try {
-            final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
-                    PackageManager.MATCH_UNINSTALLED_PACKAGES
-                            | PackageManager.MATCH_DISABLED_COMPONENTS);
-            if (info != null) {
-                appname = String.valueOf(pmUser.getApplicationLabel(info));
-            }
-        } catch (PackageManager.NameNotFoundException e) {
-            // Do nothing
-        }
-        row.setAppName(appname);
-        row.setOnDismissRunnable(() ->
-                performRemoveNotification(row.getStatusBarNotification()));
-        row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-        if (ENABLE_REMOTE_INPUT) {
-            row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
-        }
-
-        row.setAppOpsOnClickListener(mOnAppOpsClickListener);
-
-        mCallback.onBindRow(entry, pmUser, sbn, row);
-    }
-
     public void performRemoveNotification(StatusBarNotification n) {
         final int rank = mNotificationData.getRank(n.getKey());
         final int count = mNotificationData.getActiveNotifications().size();
@@ -687,56 +620,11 @@
         }
     }
 
-    //TODO: This method associates a row with an entry, but eventually needs to not do that
-    protected void updateNotification(NotificationData.Entry entry, PackageManager pmUser,
-            StatusBarNotification sbn, ExpandableNotificationRow row) {
-        boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
-        boolean isUpdate = mNotificationData.get(entry.key) != null;
-        boolean wasLowPriority = row.isLowPriority();
-        row.setIsLowPriority(isLowPriority);
-        row.setLowPriorityStateUpdated(isUpdate && (wasLowPriority != isLowPriority));
-        // bind the click event to the content area
-        checkNotNull(mNotificationClicker).register(row, sbn);
-
-        // Extract target SDK version.
-        try {
-            ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
-            entry.targetSdk = info.targetSdkVersion;
-        } catch (PackageManager.NameNotFoundException ex) {
-            Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
-        }
-        row.setLegacy(entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
-                && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
-        entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
-        entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
-
-        entry.setRow(row);
-        row.setOnActivatedListener(mPresenter);
-
-        boolean useIncreasedCollapsedHeight = mMessagingUtil.isImportantMessaging(sbn,
-                mNotificationData.getImportance(sbn.getKey()));
-        boolean useIncreasedHeadsUp = useIncreasedCollapsedHeight
-                && !mPresenter.isPresenterFullyCollapsed();
-        row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
-        row.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
-        row.setEntry(entry);
-
-        if (shouldHeadsUp(entry)) {
-            row.updateInflationFlag(FLAG_CONTENT_VIEW_HEADS_UP, true /* shouldInflate */);
-        }
-        if (shouldPulse(entry)) {
-            row.updateInflationFlag(FLAG_CONTENT_VIEW_AMBIENT, true /* shouldInflate */);
-        }
-        row.setNeedsRedaction(
-                Dependency.get(NotificationLockscreenUserManager.class).needsRedaction(entry));
-        row.inflateViews();
-    }
-
-    private NotificationData.Entry createNotificationViews(
+    private NotificationData.Entry createNotificationEntry(
             StatusBarNotification sbn, NotificationListenerService.Ranking ranking)
             throws InflationException {
         if (DEBUG) {
-            Log.d(TAG, "createNotificationViews(notification=" + sbn + " " + ranking);
+            Log.d(TAG, "createNotificationEntry(notification=" + sbn + " " + ranking);
         }
 
         NotificationData.Entry entry = new NotificationData.Entry(sbn, ranking);
@@ -747,7 +635,8 @@
         Dependency.get(LeakDetector.class).trackInstance(entry);
         entry.createIcons(mContext, sbn);
         // Construct the expanded view.
-        inflateViews(entry, mListContainer.getViewParentForNotification(entry));
+        getRowBinder().inflateViews(entry, () -> performRemoveNotification(sbn),
+                mNotificationData.get(entry.key) != null);
         return entry;
     }
 
@@ -761,7 +650,7 @@
         mNotificationData.updateRanking(rankingMap);
         NotificationListenerService.Ranking ranking = new NotificationListenerService.Ranking();
         rankingMap.getRanking(key, ranking);
-        NotificationData.Entry shadeEntry = createNotificationViews(notification, ranking);
+        NotificationData.Entry shadeEntry = createNotificationEntry(notification, ranking);
         boolean isHeadsUped = shouldHeadsUp(shadeEntry);
         if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
             if (shouldSuppressFullScreenIntent(shadeEntry)) {
@@ -870,7 +759,8 @@
         mGroupManager.onEntryUpdated(entry, oldNotification);
 
         entry.updateIcons(mContext, notification);
-        inflateViews(entry, mListContainer.getViewParentForNotification(entry));
+        getRowBinder().inflateViews(entry, () -> performRemoveNotification(notification),
+                mNotificationData.get(entry.key) != null);
 
         mForegroundServiceController.updateNotification(notification,
                 mNotificationData.getImportance(key));
@@ -938,26 +828,12 @@
 
         // By comparing the old and new UI adjustments, reinflate the view accordingly.
         for (NotificationData.Entry entry : entries) {
-            NotificationUiAdjustment newAdjustment =
-                    NotificationUiAdjustment.extractFromNotificationEntry(entry);
-
-            if (NotificationUiAdjustment.needReinflate(
-                    oldAdjustments.get(entry.key), newAdjustment)) {
-                if (entry.rowExists()) {
-                    entry.reset();
-                    PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext,
-                            entry.notification.getUser().getIdentifier());
-                    updateNotification(entry, pmUser, entry.notification, entry.getRow());
-                } else {
-                    // Once the RowInflaterTask is done, it will pick up the updated entry, so
-                    // no-op here.
-                }
-            } else if (oldImportances.containsKey(entry.key)
-                    && entry.importance != oldImportances.get(entry.key)) {
-                if (entry.rowExists()) {
-                    entry.getRow().onNotificationRankingUpdated();
-                }
-            }
+            mNotificationRowBinder.onNotificationRankingUpdated(
+                    entry,
+                    oldImportances.get(entry.key),
+                    oldAdjustments.get(entry.key),
+                    NotificationUiAdjustment.extractFromNotificationEntry(entry),
+                    mNotificationData.get(entry.key) != null);
         }
 
         updateNotifications();
@@ -1202,6 +1078,22 @@
     }
 
     /**
+     * Interface for retrieving heads-up and pulsing state for an entry.
+     */
+    public interface InterruptionStateProvider {
+        /**
+         * Whether the provided entry should be marked as heads-up when inflated.
+         */
+        boolean shouldHeadsUp(NotificationData.Entry entry);
+
+        /**
+         * Whether the provided entry should be marked as pulsing (displayed in ambient) when
+         * inflated.
+         */
+        boolean shouldPulse(NotificationData.Entry entry);
+    }
+
+    /**
      * Callback for NotificationEntryManager.
      */
     public interface Callback {
@@ -1229,17 +1121,6 @@
         void onNotificationRemoved(String key, StatusBarNotification old);
 
         /**
-         * Called when a new notification and row is created.
-         *
-         * @param entry entry for the notification
-         * @param pmUser package manager for user
-         * @param sbn notification
-         * @param row row for the notification
-         */
-        void onBindRow(NotificationData.Entry entry, PackageManager pmUser,
-                StatusBarNotification sbn, ExpandableNotificationRow row);
-
-        /**
          * Removes a notification immediately.
          *
          * @param statusBarNotification notification that is being removed
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
new file mode 100644
index 0000000..824bd81
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationRowBinder.java
@@ -0,0 +1,294 @@
+/*
+ * 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.statusbar.notification;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_AMBIENT;
+import static com.android.systemui.statusbar.notification.row.NotificationInflater.FLAG_CONTENT_VIEW_HEADS_UP;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import android.view.ViewGroup;
+
+import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.util.NotificationMessagingUtil;
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+import com.android.systemui.UiOffloadThread;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationUiAdjustment;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.NotificationInflater;
+import com.android.systemui.statusbar.notification.row.RowInflaterTask;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** Handles inflating and updating views for notifications. */
+@Singleton
+public class NotificationRowBinder {
+
+    private static final String TAG = "NotificationViewManager";
+
+    private final NotificationGroupManager mGroupManager =
+            Dependency.get(NotificationGroupManager.class);
+    private final NotificationGutsManager mGutsManager =
+            Dependency.get(NotificationGutsManager.class);
+    private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
+
+    private final Context mContext;
+    private final IStatusBarService mBarService;
+    private final NotificationMessagingUtil mMessagingUtil;
+    private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
+            this::logNotificationExpansion;
+
+    private NotificationRemoteInputManager mRemoteInputManager;
+    private NotificationPresenter mPresenter;
+    private NotificationListContainer mListContainer;
+    private HeadsUpManager mHeadsUpManager;
+    private NotificationInflater.InflationCallback mInflationCallback;
+    private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
+    private BindRowCallback mBindRowCallback;
+    private NotificationClicker mNotificationClicker;
+    private NotificationEntryManager.InterruptionStateProvider mInterruptionStateProvider;
+
+    @Inject
+    public NotificationRowBinder(Context context) {
+        mContext = context;
+        mMessagingUtil = new NotificationMessagingUtil(context);
+        mBarService = IStatusBarService.Stub.asInterface(
+                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+    }
+
+    private NotificationRemoteInputManager getRemoteInputManager() {
+        if (mRemoteInputManager == null) {
+            mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
+        }
+        return mRemoteInputManager;
+    }
+
+    /**
+     * Sets up late-bound dependencies for this component.
+     */
+    public void setUpWithPresenter(NotificationPresenter presenter,
+            NotificationListContainer listContainer,
+            HeadsUpManager headsUpManager,
+            NotificationInflater.InflationCallback inflationCallback,
+            BindRowCallback bindRowCallback) {
+        mPresenter = presenter;
+        mListContainer = listContainer;
+        mHeadsUpManager = headsUpManager;
+        mInflationCallback = inflationCallback;
+        mBindRowCallback = bindRowCallback;
+        mOnAppOpsClickListener = mGutsManager::openGuts;
+    }
+
+    public void setNotificationClicker(NotificationClicker clicker) {
+        mNotificationClicker = clicker;
+    }
+
+    public void setInterruptionStateProvider(
+            NotificationEntryManager.InterruptionStateProvider interruptionStateProvider) {
+        mInterruptionStateProvider = interruptionStateProvider;
+    }
+
+    /**
+     * Inflates the views for the given entry (possibly asynchronously).
+     */
+    public void inflateViews(NotificationData.Entry entry, Runnable onDismissRunnable,
+            boolean isUpdate) {
+        ViewGroup parent = mListContainer.getViewParentForNotification(entry);
+        PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext,
+                entry.notification.getUser().getIdentifier());
+
+        final StatusBarNotification sbn = entry.notification;
+        if (entry.rowExists()) {
+            entry.reset();
+            updateNotification(entry, pmUser, sbn, entry.getRow(), isUpdate);
+        } else {
+            new RowInflaterTask().inflate(mContext, parent, entry,
+                    row -> {
+                        bindRow(entry, pmUser, sbn, row, onDismissRunnable);
+                        updateNotification(entry, pmUser, sbn, row, isUpdate);
+                    });
+        }
+    }
+
+    private void bindRow(NotificationData.Entry entry, PackageManager pmUser,
+            StatusBarNotification sbn, ExpandableNotificationRow row,
+            Runnable onDismissRunnable) {
+        row.setExpansionLogger(mExpansionLogger, entry.notification.getKey());
+        row.setGroupManager(mGroupManager);
+        row.setHeadsUpManager(mHeadsUpManager);
+        row.setOnExpandClickListener(mPresenter);
+        row.setInflationCallback(mInflationCallback);
+        row.setLongPressListener(getNotificationLongClicker());
+        mListContainer.bindRow(row);
+        getRemoteInputManager().bindRow(row);
+
+        // Get the app name.
+        // Note that Notification.Builder#bindHeaderAppName has similar logic
+        // but since this field is used in the guts, it must be accurate.
+        // Therefore we will only show the application label, or, failing that, the
+        // package name. No substitutions.
+        final String pkg = sbn.getPackageName();
+        String appname = pkg;
+        try {
+            final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES
+                            | PackageManager.MATCH_DISABLED_COMPONENTS);
+            if (info != null) {
+                appname = String.valueOf(pmUser.getApplicationLabel(info));
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            // Do nothing
+        }
+        row.setAppName(appname);
+        row.setOnDismissRunnable(onDismissRunnable);
+        row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        if (ENABLE_REMOTE_INPUT) {
+            row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+        }
+
+        row.setAppOpsOnClickListener(mOnAppOpsClickListener);
+
+        mBindRowCallback.onBindRow(entry, pmUser, sbn, row);
+    }
+
+    /**
+     * Updates the views bound to an entry when the entry's ranking changes, either in-place or by
+     * reinflating them.
+     */
+    public void onNotificationRankingUpdated(
+            NotificationData.Entry entry,
+            @Nullable Integer oldImportance,
+            NotificationUiAdjustment oldAdjustment,
+            NotificationUiAdjustment newAdjustment,
+            boolean isUpdate) {
+        if (NotificationUiAdjustment.needReinflate(oldAdjustment, newAdjustment)) {
+            if (entry.rowExists()) {
+                entry.reset();
+                PackageManager pmUser = StatusBar.getPackageManagerForUser(
+                        mContext,
+                        entry.notification.getUser().getIdentifier());
+                updateNotification(entry, pmUser, entry.notification, entry.getRow(), isUpdate);
+            } else {
+                // Once the RowInflaterTask is done, it will pick up the updated entry, so
+                // no-op here.
+            }
+        } else {
+            if (oldImportance != null && entry.importance != oldImportance) {
+                if (entry.rowExists()) {
+                    entry.getRow().onNotificationRankingUpdated();
+                }
+            }
+        }
+    }
+
+    //TODO: This method associates a row with an entry, but eventually needs to not do that
+    private void updateNotification(
+            NotificationData.Entry entry,
+            PackageManager pmUser,
+            StatusBarNotification sbn,
+            ExpandableNotificationRow row,
+            boolean isUpdate) {
+        boolean isLowPriority = entry.ambient;
+        boolean wasLowPriority = row.isLowPriority();
+        row.setIsLowPriority(isLowPriority);
+        row.setLowPriorityStateUpdated(isUpdate && (wasLowPriority != isLowPriority));
+        // bind the click event to the content area
+        checkNotNull(mNotificationClicker).register(row, sbn);
+
+        // Extract target SDK version.
+        try {
+            ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
+            entry.targetSdk = info.targetSdkVersion;
+        } catch (PackageManager.NameNotFoundException ex) {
+            Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
+        }
+        row.setLegacy(entry.targetSdk >= Build.VERSION_CODES.GINGERBREAD
+                && entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
+
+        // TODO: should updates to the entry be happening somewhere else?
+        entry.setIconTag(R.id.icon_is_pre_L, entry.targetSdk < Build.VERSION_CODES.LOLLIPOP);
+        entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
+
+        entry.setRow(row);
+        row.setOnActivatedListener(mPresenter);
+
+        boolean useIncreasedCollapsedHeight =
+                mMessagingUtil.isImportantMessaging(sbn, entry.importance);
+        boolean useIncreasedHeadsUp = useIncreasedCollapsedHeight
+                && !mPresenter.isPresenterFullyCollapsed();
+        row.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
+        row.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
+        row.setEntry(entry);
+
+        if (mInterruptionStateProvider.shouldHeadsUp(entry)) {
+            row.updateInflationFlag(FLAG_CONTENT_VIEW_HEADS_UP, true /* shouldInflate */);
+        }
+        if (mInterruptionStateProvider.shouldPulse(entry)) {
+            row.updateInflationFlag(FLAG_CONTENT_VIEW_AMBIENT, true /* shouldInflate */);
+        }
+        row.setNeedsRedaction(
+                Dependency.get(NotificationLockscreenUserManager.class).needsRedaction(entry));
+        row.inflateViews();
+    }
+
+    ExpandableNotificationRow.LongPressListener getNotificationLongClicker() {
+        return mGutsManager::openGuts;
+    }
+
+    private void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
+        mUiOffloadThread.submit(() -> {
+            try {
+                mBarService.onNotificationExpansionChanged(key, userAction, expanded);
+            } catch (RemoteException e) {
+                // Ignore.
+            }
+        });
+    }
+
+    /** Callback for when a row is bound to an entry. */
+    public interface BindRowCallback {
+        /**
+         * Called when a new notification and row is created.
+         *
+         * @param entry  entry for the notification
+         * @param pmUser package manager for user
+         * @param sbn    notification
+         * @param row    row for the notification
+         */
+        void onBindRow(NotificationData.Entry entry, PackageManager pmUser,
+                StatusBarNotification sbn, ExpandableNotificationRow row);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 96b7536..5ba59b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -466,6 +466,14 @@
                 .onDensityOrFontScaleChanged();
     }
 
+    @Override
+    public void onOverlayChanged() {
+        mCarrierLabel.setTextAppearance(
+                Utils.getThemeAttr(mContext, com.android.internal.R.attr.textAppearanceSmall));
+        onThemeChanged();
+        mBatteryView.updatePercentView();
+    }
+
     private void updateIconsAndTextColors() {
         @ColorInt int textColor = Utils.getColorAttrDefaultColor(mContext,
                 R.attr.wallpaperTextColor);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 55655d5..2daff2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -72,7 +72,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.LatencyTracker;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.assist.AssistManager;
@@ -97,6 +96,8 @@
 import java.util.Locale;
 import java.util.function.Consumer;
 
+import javax.inject.Inject;
+
 /**
  * Fragment containing the NavigationBarFragment. Contains logic for what happens
  * on clicks and view states of the nav bar.
@@ -111,11 +112,12 @@
     /** Allow some time inbetween the long press for back and recents. */
     private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
 
-    private final DeviceProvisionedController mDeviceProvisionedController =
-            Dependency.get(DeviceProvisionedController.class);
+    private final AccessibilityManagerWrapper mAccessibilityManagerWrapper;
+    protected final AssistManager mAssistManager;
+    private final MetricsLogger mMetricsLogger;
+    private final DeviceProvisionedController mDeviceProvisionedController;
 
     protected NavigationBarView mNavigationBarView = null;
-    protected AssistManager mAssistManager;
 
     private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
 
@@ -124,7 +126,6 @@
     private AccessibilityManager mAccessibilityManager;
     private MagnificationContentObserver mMagnificationObserver;
     private ContentResolver mContentResolver;
-    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
     private int mDisabledFlags1;
     private int mDisabledFlags2;
@@ -193,6 +194,17 @@
         }
     };
 
+    @Inject
+    public NavigationBarFragment(AccessibilityManagerWrapper accessibilityManagerWrapper,
+            DeviceProvisionedController deviceProvisionedController, MetricsLogger metricsLogger,
+            AssistManager assistManager, OverviewProxyService overviewProxyService) {
+        mAccessibilityManagerWrapper = accessibilityManagerWrapper;
+        mDeviceProvisionedController = deviceProvisionedController;
+        mMetricsLogger = metricsLogger;
+        mAssistManager = assistManager;
+        mOverviewProxyService = overviewProxyService;
+    }
+
     // ----- Fragment Lifecycle Callbacks -----
 
     @Override
@@ -205,8 +217,6 @@
         mDivider = SysUiServiceProvider.getComponent(getContext(), Divider.class);
         mWindowManager = getContext().getSystemService(WindowManager.class);
         mAccessibilityManager = getContext().getSystemService(AccessibilityManager.class);
-        Dependency.get(AccessibilityManagerWrapper.class).addCallback(
-                mAccessibilityListener);
         mContentResolver = getContext().getContentResolver();
         mMagnificationObserver = new MagnificationContentObserver(
                 getContext().getMainThreadHandler());
@@ -218,15 +228,13 @@
             mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
             mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0);
         }
-        mAssistManager = Dependency.get(AssistManager.class);
-        mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+        mAccessibilityManagerWrapper.addCallback(mAccessibilityListener);
     }
 
     @Override
     public void onDestroy() {
         super.onDestroy();
-        Dependency.get(AccessibilityManagerWrapper.class).removeCallback(
-                mAccessibilityListener);
+        mAccessibilityManagerWrapper.removeCallback(mAccessibilityListener);
         mContentResolver.unregisterContentObserver(mMagnificationObserver);
     }
 
@@ -892,7 +900,8 @@
         if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView);
         if (navigationBarView == null) return null;
 
-        final NavigationBarFragment fragment = new NavigationBarFragment();
+        final NavigationBarFragment fragment = FragmentHostManager.get(navigationBarView)
+                .create(NavigationBarFragment.class);
         navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
             @Override
             public void onViewAttachedToWindow(View v) {
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 1e70912..1b43f8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -191,6 +191,7 @@
 import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationData.Entry;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -376,6 +377,7 @@
     private NotificationGutsManager mGutsManager;
     protected NotificationLogger mNotificationLogger;
     protected NotificationEntryManager mEntryManager;
+    private NotificationRowBinder mNotificationRowBinder;
     protected NotificationViewHierarchyManager mViewHierarchyManager;
     protected ForegroundServiceController mForegroundServiceController;
     protected AppOpsController mAppOpsController;
@@ -620,6 +622,7 @@
         mGutsManager = Dependency.get(NotificationGutsManager.class);
         mMediaManager = Dependency.get(NotificationMediaManager.class);
         mEntryManager = Dependency.get(NotificationEntryManager.class);
+        mNotificationRowBinder = Dependency.get(NotificationRowBinder.class);
         mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class);
         mForegroundServiceController = Dependency.get(ForegroundServiceController.class);
         mAppOpsController = Dependency.get(AppOpsController.class);
@@ -1014,7 +1017,7 @@
     }
 
     protected QS createDefaultQSFragment() {
-        return new QSFragment();
+        return FragmentHostManager.get(mStatusBarWindow).create(QSFragment.class);
     }
 
     private void setUpPresenter() {
@@ -1035,10 +1038,10 @@
         mNotificationActivityStarter = new StatusBarNotificationActivityStarter(
                 mContext, mNotificationPanel, mPresenter, mHeadsUpManager, mActivityLaunchAnimator);
         mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
+        mNotificationRowBinder.setNotificationClicker(new NotificationClicker(
+                this, Dependency.get(BubbleController.class), mNotificationActivityStarter));
 
         mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager);
-        mEntryManager.setNotificationClicker(new NotificationClicker(
-                this, Dependency.get(BubbleController.class), mNotificationActivityStarter));
     }
 
     /**
@@ -1164,6 +1167,10 @@
         if (mBrightnessMirrorController != null) {
             mBrightnessMirrorController.onOverlayChanged();
         }
+        // We need the new R.id.keyguard_indication_area before recreating
+        // mKeyguardIndicationController
+        mNotificationPanel.onThemeChanged();
+        onThemeChanged();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 261f117..c8c9ebe5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -58,6 +58,7 @@
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.NotificationData.Entry;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -88,6 +89,8 @@
             Dependency.get(StatusBarStateController.class);
     private final NotificationEntryManager mEntryManager =
             Dependency.get(NotificationEntryManager.class);
+    private final NotificationRowBinder mNotificationRowBinder =
+            Dependency.get(NotificationRowBinder.class);
     private final NotificationMediaManager mMediaManager =
             Dependency.get(NotificationMediaManager.class);
     protected AmbientPulseManager mAmbientPulseManager = Dependency.get(AmbientPulseManager.class);
@@ -168,6 +171,8 @@
         Dependency.get(InitController.class).addPostInitTask(() -> {
             mViewHierarchyManager.setUpWithPresenter(this, notifListContainer);
             mEntryManager.setUpWithPresenter(this, notifListContainer, this, mHeadsUpManager);
+            mNotificationRowBinder.setUpWithPresenter(this, notifListContainer, mHeadsUpManager,
+                    mEntryManager, this);
             mLockscreenUserManager.setUpWithPresenter(this);
             mMediaManager.setUpWithPresenter(this);
             Dependency.get(NotificationGutsManager.class).setUpWithPresenter(this,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index b699163..bb44548 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -17,8 +17,10 @@
 package com.android.systemui.appops;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
@@ -32,7 +34,6 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationPresenter;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -48,9 +49,12 @@
     private static final int TEST_UID = 0;
     private static final int TEST_UID_OTHER = 500000;
 
-    @Mock private NotificationPresenter mPresenter;
-    @Mock private AppOpsManager mAppOpsManager;
-    @Mock private AppOpsController.Callback mCallback;
+    @Mock
+    private AppOpsManager mAppOpsManager;
+    @Mock
+    private AppOpsController.Callback mCallback;
+    @Mock
+    private AppOpsControllerImpl.H mMockHandler;
 
     private AppOpsControllerImpl mController;
 
@@ -77,9 +81,13 @@
 
     @Test
     public void addCallback_includedCode() {
-        mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
+        mController.addCallback(
+                new int[]{AppOpsManager.OP_RECORD_AUDIO, AppOpsManager.OP_FINE_LOCATION},
+                mCallback);
         mController.onOpActiveChanged(
                 AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
+        mController.onOpNoted(AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
+                AppOpsManager.MODE_ALLOWED);
         verify(mCallback).onActiveStateChanged(AppOpsManager.OP_RECORD_AUDIO,
                 TEST_UID, TEST_PACKAGE_NAME, true);
     }
@@ -106,7 +114,7 @@
     @Test
     public void addCallback_notSameCode() {
         mController.addCallback(new int[]{AppOpsManager.OP_RECORD_AUDIO}, mCallback);
-        mController.removeCallback(new int[]{AppOpsManager.OP_FINE_LOCATION}, mCallback);
+        mController.removeCallback(new int[]{AppOpsManager.OP_CAMERA}, mCallback);
         mController.onOpActiveChanged(
                 AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true);
         verify(mCallback).onActiveStateChanged(AppOpsManager.OP_RECORD_AUDIO,
@@ -128,17 +136,30 @@
                 TEST_UID, TEST_PACKAGE_NAME, true);
         mController.onOpActiveChanged(AppOpsManager.OP_CAMERA,
                 TEST_UID, TEST_PACKAGE_NAME, true);
-        assertEquals(2, mController.getActiveAppOps().size());
+        mController.onOpNoted(AppOpsManager.OPSTR_FINE_LOCATION,
+                TEST_UID, TEST_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
+        assertEquals(3, mController.getActiveAppOps().size());
     }
 
-    @Test public void getActiveItemsForUser() {
+    @Test
+    public void getActiveItemsForUser() {
         mController.onOpActiveChanged(AppOpsManager.OP_RECORD_AUDIO,
                 TEST_UID, TEST_PACKAGE_NAME, true);
         mController.onOpActiveChanged(AppOpsManager.OP_CAMERA,
                 TEST_UID_OTHER, TEST_PACKAGE_NAME, true);
-        assertEquals(1,
+        mController.onOpNoted(AppOpsManager.OPSTR_FINE_LOCATION,
+                TEST_UID, TEST_PACKAGE_NAME, AppOpsManager.MODE_ALLOWED);
+        assertEquals(2,
                 mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID)).size());
         assertEquals(1,
-                mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID)).size());
+                mController.getActiveAppOpsForUser(UserHandle.getUserId(TEST_UID_OTHER)).size());
+    }
+
+    @Test
+    public void opNotedScheduledForRemoval() {
+        mController.setBGHandler(mMockHandler);
+        mController.onOpNoted(AppOpsManager.OPSTR_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME,
+                AppOpsManager.MODE_ALLOWED);
+        verify(mMockHandler).scheduleRemoval(any(AppOpItem.class), anyLong());
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
index 24bcca50..563599b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
@@ -19,6 +19,7 @@
 import android.app.ActivityManager
 import android.app.AppOpsManager
 import android.content.Intent
+import android.content.pm.UserInfo
 import android.os.Handler
 import android.os.UserHandle
 import android.os.UserManager
@@ -30,13 +31,16 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.appops.AppOpItem
 import com.android.systemui.appops.AppOpsController
+import org.junit.Assert.assertEquals
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.any
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.anyList
 import org.mockito.ArgumentMatchers.eq
+import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito.atLeastOnce
 import org.mockito.Mockito.doReturn
@@ -52,8 +56,8 @@
 
     companion object {
         val CURRENT_USER_ID = ActivityManager.getCurrentUser()
-        val OTHER_USER = UserHandle(CURRENT_USER_ID + 1)
         const val TAG = "PrivacyItemControllerTest"
+        fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
     }
 
     @Mock
@@ -62,6 +66,8 @@
     private lateinit var callback: PrivacyItemController.Callback
     @Mock
     private lateinit var userManager: UserManager
+    @Captor
+    private lateinit var argCaptor: ArgumentCaptor<List<PrivacyItem>>
 
     private lateinit var testableLooper: TestableLooper
     private lateinit var privacyItemController: PrivacyItemController
@@ -76,8 +82,11 @@
         mDependency.injectTestDependency(Dependency.MAIN_HANDLER, Handler(testableLooper.looper))
         mContext.addMockSystemService(UserManager::class.java, userManager)
 
-        doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, 0, "", 0)))
-                .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+        doReturn(listOf(object : UserInfo() {
+            init {
+                id = CURRENT_USER_ID
+            }
+        })).`when`(userManager).getProfiles(anyInt())
 
         privacyItemController = PrivacyItemController(mContext, callback)
     }
@@ -100,6 +109,18 @@
     }
 
     @Test
+    fun testDistinctItems() {
+        doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, CURRENT_USER_ID, "", 0),
+                AppOpItem(AppOpsManager.OP_CAMERA, CURRENT_USER_ID, "", 1)))
+                .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+
+        privacyItemController.setListening(true)
+        testableLooper.processAllMessages()
+        verify(callback).privacyChanged(capture(argCaptor))
+        assertEquals(1, argCaptor.value.size)
+    }
+
+    @Test
     fun testRegisterReceiver_allUsers() {
         val spiedContext = spy(mContext)
         val itemController = PrivacyItemController(spiedContext, callback)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index bc7d983..39afbac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -18,7 +18,9 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
+import android.app.Fragment;
 import android.content.Context;
+import android.os.Bundle;
 import android.os.Looper;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -35,6 +37,7 @@
 import com.android.systemui.SysuiBaseFragmentTest;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.Clock;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
 import org.junit.Before;
@@ -52,6 +55,7 @@
 
     public QSFragmentTest() {
         super(QSFragment.class);
+        injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
     }
 
     @Before
@@ -70,7 +74,6 @@
         mDependency.injectTestDependency(Dependency.BG_LOOPER,
                 TestableLooper.get(this).getLooper());
         mDependency.injectMockDependency(UserSwitcherController.class);
-        injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
     }
 
     @Test
@@ -116,4 +119,9 @@
         assertTrue(qs.isListening());
         assertTrue(qs.isExpanded());
     }
+
+    @Override
+    protected Fragment instantiate(Context context, String className, Bundle arguments) {
+        return new QSFragment(new RemoteInputQuickSettingsDisabler(context));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 26fa20d..c3a3e63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -218,4 +218,12 @@
         }
         assertFalse(specs.contains("other"));
     }
+
+    @Test
+    public void testQueryTiles_nullSetting() {
+        Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.QS_TILES, null);
+        mContext.getOrCreateTestableResources().addOverride(R.string.quick_settings_tiles_stock,
+                STOCK_TILES);
+        mTileQueryHelper.queryTiles(mQSTileHost);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 7f0e435..8fe91cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -104,6 +104,8 @@
     @Mock private ExpandableNotificationRow mRow;
     @Mock private NotificationListContainer mListContainer;
     @Mock private NotificationEntryManager.Callback mCallback;
+    @Mock
+    private NotificationRowBinder.BindRowCallback mBindCallback;
     @Mock private HeadsUpManager mHeadsUpManager;
     @Mock private NotificationListenerService.RankingMap mRankingMap;
     @Mock private RemoteInputController mRemoteInputController;
@@ -231,7 +233,11 @@
         mEntryManager = new TestableNotificationEntryManager(mContext, mBarService);
         Dependency.get(InitController.class).executePostInitTasks();
         mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mCallback, mHeadsUpManager);
-        mEntryManager.setNotificationClicker(mock(NotificationClicker.class));
+
+        NotificationRowBinder notificationRowBinder = Dependency.get(NotificationRowBinder.class);
+        notificationRowBinder.setUpWithPresenter(
+                mPresenter, mListContainer, mHeadsUpManager, mEntryManager, mBindCallback);
+        notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class));
 
         setUserSentiment(mEntry.key, NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL);
     }
@@ -244,7 +250,7 @@
         doAnswer(invocation -> {
             mCountDownLatch.countDown();
             return null;
-        }).when(mCallback).onBindRow(any(), any(), any(), any());
+        }).when(mBindCallback).onBindRow(any(), any(), any(), any());
 
         // Post on main thread, otherwise we will be stuck waiting here for the inflation finished
         // callback forever, since it won't execute until the tests ends.
@@ -261,7 +267,7 @@
         // Row inflation:
         ArgumentCaptor<NotificationData.Entry> entryCaptor = ArgumentCaptor.forClass(
                 NotificationData.Entry.class);
-        verify(mCallback).onBindRow(entryCaptor.capture(), any(), eq(mSbn), any());
+        verify(mBindCallback).onBindRow(entryCaptor.capture(), any(), eq(mSbn), any());
         NotificationData.Entry entry = entryCaptor.getValue();
         verify(mRemoteInputManager).bindRow(entry.getRow());
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index 9e2db91..728723b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -14,10 +14,13 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import android.app.Fragment;
 import android.content.Context;
+import android.os.Bundle;
 import android.os.Looper;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -27,13 +30,17 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.assist.AssistManager;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -44,6 +51,23 @@
 @SmallTest
 public class NavigationBarFragmentTest extends SysuiBaseFragmentTest {
 
+    private OverviewProxyService mOverviewProxyService =
+            mDependency.injectMockDependency(OverviewProxyService.class);
+    private AccessibilityManagerWrapper mAccessibilityWrapper =
+            new AccessibilityManagerWrapper(mContext) {
+                Tracker mTracker = mLeakCheck.getTracker("accessibility_manager");
+
+                @Override
+                public void addCallback(AccessibilityServicesStateChangeListener listener) {
+                    mTracker.getLeakInfo(listener).addAllocation(new Throwable());
+                }
+
+                @Override
+                public void removeCallback(AccessibilityServicesStateChangeListener listener) {
+                    mTracker.getLeakInfo(listener).clearAllocations();
+                }
+            };
+
     public NavigationBarFragmentTest() {
         super(NavigationBarFragment.class);
     }
@@ -54,32 +78,19 @@
 
     @Before
     public void setup() {
-        mDependency.injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper());
         mSysuiContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
         mSysuiContext.putComponent(StatusBar.class, mock(StatusBar.class));
         mSysuiContext.putComponent(Recents.class, mock(Recents.class));
         mSysuiContext.putComponent(Divider.class, mock(Divider.class));
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
-        mDependency.injectMockDependency(OverviewProxyService.class);
         WindowManager windowManager = mock(WindowManager.class);
         Display defaultDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
         when(windowManager.getDefaultDisplay()).thenReturn(
                 defaultDisplay);
         mContext.addMockSystemService(Context.WINDOW_SERVICE, windowManager);
 
-        Tracker tracker = mLeakCheck.getTracker("accessibility_manager");
-        AccessibilityManagerWrapper wrapper = new AccessibilityManagerWrapper(mContext) {
-            @Override
-            public void addCallback(AccessibilityServicesStateChangeListener listener) {
-                tracker.getLeakInfo(listener).addAllocation(new Throwable());
-            }
-
-            @Override
-            public void removeCallback(AccessibilityServicesStateChangeListener listener) {
-                tracker.getLeakInfo(listener).clearAllocations();
-            }
-        };
-        mDependency.injectTestDependency(AccessibilityManagerWrapper.class, wrapper);
+        mDependency.injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper());
+        mDependency.injectTestDependency(AccessibilityManagerWrapper.class, mAccessibilityWrapper);
     }
 
     @Test
@@ -91,4 +102,15 @@
         navigationBarFragment.onHomeLongClick(navigationBarFragment.getView());
     }
 
+    @Override
+    protected Fragment instantiate(Context context, String className, Bundle arguments) {
+        DeviceProvisionedController deviceProvisionedController =
+                new DeviceProvisionedControllerImpl(context);
+        assertNotNull(mAccessibilityWrapper);
+        return new NavigationBarFragment(mAccessibilityWrapper,
+                deviceProvisionedController,
+                new MetricsLogger(),
+                new AssistManager(deviceProvisionedController, mContext),
+                mOverviewProxyService);
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index fc7265d..681a994 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -38,8 +38,8 @@
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAutoFillManagerClient;
 
+import com.android.internal.infra.AbstractSinglePendingRequestRemoteService;
 import com.android.internal.os.IResultReceiver;
-import com.android.server.infra.AbstractSinglePendingRequestRemoteService;
 
 final class RemoteAugmentedAutofillService
         extends AbstractSinglePendingRequestRemoteService<RemoteAugmentedAutofillService,
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 417ea9c..e5529af 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -39,7 +39,7 @@
 import android.text.format.DateUtils;
 import android.util.Slog;
 
-import com.android.server.infra.AbstractSinglePendingRequestRemoteService;
+import com.android.internal.infra.AbstractSinglePendingRequestRemoteService;
 
 final class RemoteFillService
         extends AbstractSinglePendingRequestRemoteService<RemoteFillService, IAutoFillService> {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index fd20437..a9f4e46 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -117,7 +117,7 @@
      * @param userId User id on which the backup operation is being requested.
      * @param message A message to include in the exception if it is thrown.
      */
-    private void enforceCallingPermissionOnUserId(int userId, String message) {
+    private void enforceCallingPermissionOnUserId(@UserIdInt int userId, String message) {
         if (Binder.getCallingUserHandle().getIdentifier() != userId) {
             mContext.enforceCallingOrSelfPermission(
                     Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
@@ -170,9 +170,14 @@
      * @param userId The id of the user to retrieve its instance of {@link
      *     UserBackupManagerService}.
      * @param caller A {@link String} identifying the caller for logging purposes.
+     * @throws SecurityException if {@code userId} is different from the calling user id and the
+     * caller does NOT have the android.permission.INTERACT_ACROSS_USERS_FULL permission.
      */
     @Nullable
-    private UserBackupManagerService getServiceForUser(@UserIdInt int userId, String caller) {
+    @VisibleForTesting
+    UserBackupManagerService getServiceForUserIfCallerHasPermission(
+            @UserIdInt int userId, String caller) {
+        enforceCallingPermissionOnUserId(userId, caller);
         UserBackupManagerService userBackupManagerService = mServiceUsers.get(userId);
         if (userBackupManagerService == null) {
             Slog.w(TAG, "Called " + caller + " for unknown user: " + userId);
@@ -196,9 +201,9 @@
      * backup for their app {@code packageName}. Only used for apps participating in key-value
      * backup.
      */
-    public void dataChanged(String packageName) {
+    public void dataChanged(@UserIdInt int userId, String packageName) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "dataChanged()");
+                getServiceForUserIfCallerHasPermission(userId, "dataChanged()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.dataChanged(packageName);
@@ -209,9 +214,9 @@
      * Callback: a requested backup agent has been instantiated. This should only be called from the
      * {@link ActivityManager}.
      */
-    public void agentConnected(String packageName, IBinder agentBinder) {
+    public void agentConnected(@UserIdInt int userId, String packageName, IBinder agentBinder) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "agentConnected()");
+                getServiceForUserIfCallerHasPermission(userId, "agentConnected()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.agentConnected(packageName, agentBinder);
@@ -222,9 +227,9 @@
      * Callback: a backup agent has failed to come up, or has unexpectedly quit. This should only be
      * called from the {@link ActivityManager}.
      */
-    public void agentDisconnected(String packageName) {
+    public void agentDisconnected(@UserIdInt int userId, String packageName) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "agentDisconnected()");
+                getServiceForUserIfCallerHasPermission(userId, "agentDisconnected()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.agentDisconnected(packageName);
@@ -235,9 +240,9 @@
      * Used by a currently-active backup agent to notify the service that it has completed its given
      * outstanding asynchronous backup/restore operation.
      */
-    public void opComplete(int token, long result) {
+    public void opComplete(@UserIdInt int userId, int token, long result) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "opComplete()");
+                getServiceForUserIfCallerHasPermission(userId, "opComplete()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.opComplete(token, result);
@@ -249,9 +254,10 @@
     // ---------------------------------------------
 
     /** Run an initialize operation for the given transports {@code transportNames}. */
-    public void initializeTransports(String[] transportNames, IBackupObserver observer) {
+    public void initializeTransports(
+            @UserIdInt int userId, String[] transportNames, IBackupObserver observer) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "initializeTransports()");
+                getServiceForUserIfCallerHasPermission(userId, "initializeTransports()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.initializeTransports(transportNames, observer);
@@ -262,9 +268,9 @@
      * Clear the given package {@code packageName}'s backup data from the transport {@code
      * transportName}.
      */
-    public void clearBackupData(String transportName, String packageName) {
+    public void clearBackupData(@UserIdInt int userId, String transportName, String packageName) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "clearBackupData()");
+                getServiceForUserIfCallerHasPermission(userId, "clearBackupData()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.clearBackupData(transportName, packageName);
@@ -273,9 +279,9 @@
 
     /** Return the name of the currently active transport. */
     @Nullable
-    public String getCurrentTransport() {
+    public String getCurrentTransport(@UserIdInt int userId) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "getCurrentTransport()");
+                getServiceForUserIfCallerHasPermission(userId, "getCurrentTransport()");
 
         return userBackupManagerService == null
                 ? null
@@ -287,9 +293,9 @@
      * null} if no transport selected or if the transport selected is not registered.
      */
     @Nullable
-    public ComponentName getCurrentTransportComponent() {
+    public ComponentName getCurrentTransportComponent(@UserIdInt int userId) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "getCurrentTransportComponent()");
+                getServiceForUserIfCallerHasPermission(userId, "getCurrentTransportComponent()");
 
         return userBackupManagerService == null
                 ? null
@@ -298,9 +304,9 @@
 
     /** Report all known, available backup transports by name. */
     @Nullable
-    public String[] listAllTransports() {
+    public String[] listAllTransports(@UserIdInt int userId) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "listAllTransports()");
+                getServiceForUserIfCallerHasPermission(userId, "listAllTransports()");
 
         return userBackupManagerService == null
                 ? null
@@ -309,9 +315,9 @@
 
     /** Report all known, available backup transports by {@link ComponentName}. */
     @Nullable
-    public ComponentName[] listAllTransportComponents() {
+    public ComponentName[] listAllTransportComponents(@UserIdInt int userId) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "listAllTransportComponents()");
+                getServiceForUserIfCallerHasPermission(userId, "listAllTransportComponents()");
 
         return userBackupManagerService == null
                 ? null
@@ -321,12 +327,14 @@
     /** Report all system whitelisted transports. */
     @Nullable
     public String[] getTransportWhitelist() {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "getTransportWhitelist()");
-
-        return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.getTransportWhitelist();
+        // No permission check, intentionally.
+        String[] whitelistedTransports = new String[mTransportWhitelist.size()];
+        int i = 0;
+        for (ComponentName component : mTransportWhitelist) {
+            whitelistedTransports[i] = component.flattenToShortString();
+            i++;
+        }
+        return whitelistedTransports;
     }
 
     /**
@@ -353,6 +361,7 @@
      *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
      */
     public void updateTransportAttributes(
+            @UserIdInt int userId,
             ComponentName transportComponent,
             String name,
             @Nullable Intent configurationIntent,
@@ -360,7 +369,7 @@
             @Nullable Intent dataManagementIntent,
             String dataManagementLabel) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "updateTransportAttributes()");
+                getServiceForUserIfCallerHasPermission(userId, "updateTransportAttributes()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.updateTransportAttributes(
@@ -381,9 +390,9 @@
      */
     @Deprecated
     @Nullable
-    public String selectBackupTransport(String transportName) {
+    public String selectBackupTransport(@UserIdInt int userId, String transportName) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "selectBackupTransport()");
+                getServiceForUserIfCallerHasPermission(userId, "selectBackupTransport()");
 
         return userBackupManagerService == null
                 ? null
@@ -395,9 +404,11 @@
      * with the result upon completion.
      */
     public void selectBackupTransportAsync(
-            ComponentName transportComponent, ISelectBackupTransportCallback listener) {
+            @UserIdInt int userId,
+            ComponentName transportComponent,
+            ISelectBackupTransportCallback listener) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "selectBackupTransportAsync()");
+                getServiceForUserIfCallerHasPermission(userId, "selectBackupTransportAsync()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.selectBackupTransportAsync(transportComponent, listener);
@@ -410,9 +421,9 @@
      * returns {@code null}.
      */
     @Nullable
-    public Intent getConfigurationIntent(String transportName) {
+    public Intent getConfigurationIntent(@UserIdInt int userId, String transportName) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "getConfigurationIntent()");
+                getServiceForUserIfCallerHasPermission(userId, "getConfigurationIntent()");
 
         return userBackupManagerService == null
                 ? null
@@ -429,9 +440,9 @@
      * @return The current destination string or null if the transport is not registered.
      */
     @Nullable
-    public String getDestinationString(String transportName) {
+    public String getDestinationString(@UserIdInt int userId, String transportName) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "getDestinationString()");
+                getServiceForUserIfCallerHasPermission(userId, "getDestinationString()");
 
         return userBackupManagerService == null
                 ? null
@@ -440,9 +451,9 @@
 
     /** Supply the manage-data intent for the given transport. */
     @Nullable
-    public Intent getDataManagementIntent(String transportName) {
+    public Intent getDataManagementIntent(@UserIdInt int userId, String transportName) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "getDataManagementIntent()");
+                getServiceForUserIfCallerHasPermission(userId, "getDataManagementIntent()");
 
         return userBackupManagerService == null
                 ? null
@@ -454,9 +465,9 @@
      * transport.
      */
     @Nullable
-    public String getDataManagementLabel(String transportName) {
+    public String getDataManagementLabel(@UserIdInt int userId, String transportName) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "getDataManagementLabel()");
+                getServiceForUserIfCallerHasPermission(userId, "getDataManagementLabel()");
 
         return userBackupManagerService == null
                 ? null
@@ -469,9 +480,8 @@
 
     /** Enable/disable the backup service. This is user-configurable via backup settings. */
     public void setBackupEnabled(@UserIdInt int userId, boolean enable) {
-        enforceCallingPermissionOnUserId(userId, "setBackupEnabled");
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(userId, "setBackupEnabled()");
+                getServiceForUserIfCallerHasPermission(userId, "setBackupEnabled()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.setBackupEnabled(enable);
@@ -479,32 +489,21 @@
     }
 
     /** Enable/disable automatic restore of app data at install time. */
-    public void setAutoRestore(boolean autoRestore) {
+    public void setAutoRestore(@UserIdInt int userId, boolean autoRestore) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "setAutoRestore()");
+                getServiceForUserIfCallerHasPermission(userId, "setAutoRestore()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.setAutoRestore(autoRestore);
         }
     }
 
-    /** Mark the backup service as having been provisioned (device has gone through SUW). */
-    public void setBackupProvisioned(boolean provisioned) {
-        UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "setBackupProvisioned()");
-
-        if (userBackupManagerService != null) {
-            userBackupManagerService.setBackupProvisioned(provisioned);
-        }
-    }
-
     /**
      * Return {@code true} if the backup mechanism is currently enabled, else returns {@code false}.
      */
     public boolean isBackupEnabled(@UserIdInt int userId) {
-        enforceCallingPermissionOnUserId(userId, "isBackupEnabled");
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(userId, "isBackupEnabled()");
+                getServiceForUserIfCallerHasPermission(userId, "isBackupEnabled()");
 
         return userBackupManagerService != null && userBackupManagerService.isBackupEnabled();
     }
@@ -514,9 +513,9 @@
     // ---------------------------------------------
 
     /** Checks if the given package {@code packageName} is eligible for backup. */
-    public boolean isAppEligibleForBackup(String packageName) {
+    public boolean isAppEligibleForBackup(@UserIdInt int userId, String packageName) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "isAppEligibleForBackup()");
+                getServiceForUserIfCallerHasPermission(userId, "isAppEligibleForBackup()");
 
         return userBackupManagerService != null
                 && userBackupManagerService.isAppEligibleForBackup(packageName);
@@ -526,9 +525,9 @@
      * Returns from the inputted packages {@code packages}, the ones that are eligible for backup.
      */
     @Nullable
-    public String[] filterAppsEligibleForBackup(String[] packages) {
+    public String[] filterAppsEligibleForBackup(@UserIdInt int userId, String[] packages) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "filterAppsEligibleForBackup()");
+                getServiceForUserIfCallerHasPermission(userId, "filterAppsEligibleForBackup()");
 
         return userBackupManagerService == null
                 ? null
@@ -540,9 +539,8 @@
      * they have pending updates.
      */
     public void backupNow(@UserIdInt int userId) {
-        enforceCallingPermissionOnUserId(userId, "backupNow");
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(userId, "backupNow()");
+                getServiceForUserIfCallerHasPermission(userId, "backupNow()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.backupNow();
@@ -559,9 +557,8 @@
             IBackupObserver observer,
             IBackupManagerMonitor monitor,
             int flags) {
-        enforceCallingPermissionOnUserId(userId, "requestBackup");
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(userId, "requestBackup()");
+                getServiceForUserIfCallerHasPermission(userId, "requestBackup()");
 
         return userBackupManagerService == null
                 ? BackupManager.ERROR_BACKUP_NOT_ALLOWED
@@ -570,9 +567,8 @@
 
     /** Cancel all running backup operations. */
     public void cancelBackups(@UserIdInt int userId) {
-        enforceCallingPermissionOnUserId(userId, "cancelBackups");
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(userId, "cancelBackups()");
+                getServiceForUserIfCallerHasPermission(userId, "cancelBackups()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.cancelBackups();
@@ -589,7 +585,7 @@
      */
     public boolean beginFullBackup(FullBackupJob scheduledJob) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "beginFullBackup()");
+                getServiceForUserIfCallerHasPermission(UserHandle.USER_SYSTEM, "beginFullBackup()");
 
         return userBackupManagerService != null
                 && userBackupManagerService.beginFullBackup(scheduledJob);
@@ -601,7 +597,7 @@
      */
     public void endFullBackup() {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "endFullBackup()");
+                getServiceForUserIfCallerHasPermission(UserHandle.USER_SYSTEM, "endFullBackup()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.endFullBackup();
@@ -611,9 +607,9 @@
     /**
      * Run a full backup pass for the given packages {@code packageNames}. Used by 'adb shell bmgr'.
      */
-    public void fullTransportBackup(String[] packageNames) {
+    public void fullTransportBackup(@UserIdInt int userId, String[] packageNames) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "fullTransportBackup()");
+                getServiceForUserIfCallerHasPermission(userId, "fullTransportBackup()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.fullTransportBackup(packageNames);
@@ -628,9 +624,9 @@
      * Used to run a restore pass for an application that is being installed. This should only be
      * called from the {@link PackageManager}.
      */
-    public void restoreAtInstall(String packageName, int token) {
+    public void restoreAtInstall(@UserIdInt int userId, String packageName, int token) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "restoreAtInstall()");
+                getServiceForUserIfCallerHasPermission(userId, "restoreAtInstall()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.restoreAtInstall(packageName, token);
@@ -642,9 +638,10 @@
      * {@code transportName}.
      */
     @Nullable
-    public IRestoreSession beginRestoreSession(String packageName, String transportName) {
+    public IRestoreSession beginRestoreSession(
+            @UserIdInt int userId, String packageName, String transportName) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "beginRestoreSession()");
+                getServiceForUserIfCallerHasPermission(userId, "beginRestoreSession()");
 
         return userBackupManagerService == null
                 ? null
@@ -655,9 +652,9 @@
      * Get the restore-set token for the best-available restore set for this {@code packageName}:
      * the active set if possible, else the ancestral one. Returns zero if none available.
      */
-    public long getAvailableRestoreToken(String packageName) {
+    public long getAvailableRestoreToken(@UserIdInt int userId, String packageName) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "getAvailableRestoreToken()");
+                getServiceForUserIfCallerHasPermission(userId, "getAvailableRestoreToken()");
 
         return userBackupManagerService == null
                 ? 0
@@ -671,7 +668,8 @@
     /** Sets the backup password used when running adb backup. */
     public boolean setBackupPassword(String currentPassword, String newPassword) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "setBackupPassword()");
+                getServiceForUserIfCallerHasPermission(
+                        UserHandle.USER_SYSTEM, "setBackupPassword()");
 
         return userBackupManagerService != null
                 && userBackupManagerService.setBackupPassword(currentPassword, newPassword);
@@ -680,7 +678,8 @@
     /** Returns {@code true} if adb backup was run with a password, else returns {@code false}. */
     public boolean hasBackupPassword() {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "hasBackupPassword()");
+                getServiceForUserIfCallerHasPermission(
+                        UserHandle.USER_SYSTEM, "hasBackupPassword()");
 
         return userBackupManagerService != null && userBackupManagerService.hasBackupPassword();
     }
@@ -703,9 +702,8 @@
             boolean doCompress,
             boolean doKeyValue,
             String[] packageNames) {
-        enforceCallingPermissionOnUserId(userId, "adbBackup");
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(userId, "adbBackup()");
+                getServiceForUserIfCallerHasPermission(userId, "adbBackup()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.adbBackup(
@@ -728,9 +726,8 @@
      * requires on-screen confirmation by the user.
      */
     public void adbRestore(@UserIdInt int userId, ParcelFileDescriptor fd) {
-        enforceCallingPermissionOnUserId(userId, "setBackupEnabled");
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(userId, "adbRestore()");
+                getServiceForUserIfCallerHasPermission(userId, "adbRestore()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.adbRestore(fd);
@@ -742,13 +739,14 @@
      * to require a user-facing disclosure about the operation.
      */
     public void acknowledgeAdbBackupOrRestore(
+            @UserIdInt int userId,
             int token,
             boolean allow,
             String currentPassword,
             String encryptionPassword,
             IFullBackupRestoreObserver observer) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "acknowledgeAdbBackupOrRestore()");
+                getServiceForUserIfCallerHasPermission(userId, "acknowledgeAdbBackupOrRestore()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.acknowledgeAdbBackupOrRestore(
@@ -763,7 +761,7 @@
     /** Prints service state for 'dumpsys backup'. */
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         UserBackupManagerService userBackupManagerService =
-                getServiceForUser(UserHandle.USER_SYSTEM, "dump()");
+                getServiceForUserIfCallerHasPermission(UserHandle.USER_SYSTEM, "dump()");
 
         if (userBackupManagerService != null) {
             userBackupManagerService.dump(fd, pw, args);
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index eb10a04..d403680 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -287,7 +287,7 @@
     public void dataChangedForUser(int userId, String packageName) throws RemoteException {
         BackupManagerService svc = mService;
         if (svc != null) {
-            svc.dataChanged(packageName);
+            svc.dataChanged(userId, packageName);
         }
     }
 
@@ -301,7 +301,7 @@
             int userId, String[] transportNames, IBackupObserver observer) throws RemoteException {
         BackupManagerService svc = mService;
         if (svc != null) {
-            svc.initializeTransports(transportNames, observer);
+            svc.initializeTransports(userId, transportNames, observer);
         }
     }
 
@@ -310,7 +310,7 @@
             throws RemoteException {
         BackupManagerService svc = mService;
         if (svc != null) {
-            svc.clearBackupData(transportName, packageName);
+            svc.clearBackupData(userId, transportName, packageName);
         }
     }
 
@@ -325,7 +325,7 @@
             throws RemoteException {
         BackupManagerService svc = mService;
         if (svc != null) {
-            svc.agentConnected(packageName, agent);
+            svc.agentConnected(userId, packageName, agent);
         }
     }
 
@@ -338,7 +338,7 @@
     public void agentDisconnectedForUser(int userId, String packageName) throws RemoteException {
         BackupManagerService svc = mService;
         if (svc != null) {
-            svc.agentDisconnected(packageName);
+            svc.agentDisconnected(userId, packageName);
         }
     }
 
@@ -352,7 +352,7 @@
             throws RemoteException {
         BackupManagerService svc = mService;
         if (svc != null) {
-            svc.restoreAtInstall(packageName, token);
+            svc.restoreAtInstall(userId, packageName, token);
         }
     }
 
@@ -379,7 +379,7 @@
     public void setAutoRestoreForUser(int userId, boolean doAutoRestore) throws RemoteException {
         BackupManagerService svc = mService;
         if (svc != null) {
-            svc.setAutoRestore(doAutoRestore);
+            svc.setAutoRestore(userId, doAutoRestore);
         }
     }
 
@@ -390,10 +390,9 @@
 
     @Override
     public void setBackupProvisioned(boolean isProvisioned) throws RemoteException {
-        BackupManagerService svc = mService;
-        if (svc != null) {
-            svc.setBackupProvisioned(isProvisioned);
-        }
+        /*
+         * This is now a no-op; provisioning is simply the device's own setup state.
+         */
     }
 
     @Override
@@ -448,7 +447,7 @@
             throws RemoteException {
         BackupManagerService svc = mService;
         if (svc != null) {
-            svc.fullTransportBackup(packageNames);
+            svc.fullTransportBackup(userId, packageNames);
         }
     }
 
@@ -471,7 +470,7 @@
             throws RemoteException {
         BackupManagerService svc = mService;
         if (svc != null) {
-            svc.acknowledgeAdbBackupOrRestore(token, allow,
+            svc.acknowledgeAdbBackupOrRestore(userId, token, allow,
                     curPassword, encryptionPassword, observer);
         }
     }
@@ -489,7 +488,7 @@
     @Override
     public String getCurrentTransportForUser(int userId) throws RemoteException {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.getCurrentTransport() : null;
+        return (svc != null) ? svc.getCurrentTransport(userId) : null;
     }
 
     @Override
@@ -505,13 +504,13 @@
     @Nullable
     public ComponentName getCurrentTransportComponentForUser(int userId) {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.getCurrentTransportComponent() : null;
+        return (svc != null) ? svc.getCurrentTransportComponent(userId) : null;
     }
 
     @Override
     public String[] listAllTransportsForUser(int userId) throws RemoteException {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.listAllTransports() : null;
+        return (svc != null) ? svc.listAllTransports(userId) : null;
     }
 
     @Override
@@ -522,7 +521,7 @@
     @Override
     public ComponentName[] listAllTransportComponentsForUser(int userId) throws RemoteException {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.listAllTransportComponents() : null;
+        return (svc != null) ? svc.listAllTransportComponents(userId) : null;
     }
 
     @Override
@@ -543,6 +542,7 @@
         BackupManagerService svc = mService;
         if (svc != null) {
             svc.updateTransportAttributes(
+                    userId,
                     transportComponent,
                     name,
                     configurationIntent,
@@ -556,7 +556,7 @@
     public String selectBackupTransportForUser(int userId, String transport)
             throws RemoteException {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.selectBackupTransport(transport) : null;
+        return (svc != null) ? svc.selectBackupTransport(userId, transport) : null;
     }
 
     @Override
@@ -569,7 +569,7 @@
             ISelectBackupTransportCallback listener) throws RemoteException {
         BackupManagerService svc = mService;
         if (svc != null) {
-            svc.selectBackupTransportAsync(transport, listener);
+            svc.selectBackupTransportAsync(userId, transport, listener);
         } else {
             if (listener != null) {
                 try {
@@ -585,7 +585,7 @@
     public Intent getConfigurationIntentForUser(int userId, String transport)
             throws RemoteException {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.getConfigurationIntent(transport) : null;
+        return (svc != null) ? svc.getConfigurationIntent(userId, transport) : null;
     }
 
     @Override
@@ -597,7 +597,7 @@
     @Override
     public String getDestinationStringForUser(int userId, String transport) throws RemoteException {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.getDestinationString(transport) : null;
+        return (svc != null) ? svc.getDestinationString(userId, transport) : null;
     }
 
     @Override
@@ -609,7 +609,7 @@
     public Intent getDataManagementIntentForUser(int userId, String transport)
             throws RemoteException {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.getDataManagementIntent(transport) : null;
+        return (svc != null) ? svc.getDataManagementIntent(userId, transport) : null;
     }
 
     @Override
@@ -622,7 +622,7 @@
     public String getDataManagementLabelForUser(int userId, String transport)
             throws RemoteException {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.getDataManagementLabel(transport) : null;
+        return (svc != null) ? svc.getDataManagementLabel(userId, transport) : null;
     }
 
     @Override
@@ -635,33 +635,33 @@
     public IRestoreSession beginRestoreSessionForUser(
             int userId, String packageName, String transportID) throws RemoteException {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.beginRestoreSession(packageName, transportID) : null;
+        return (svc != null) ? svc.beginRestoreSession(userId, packageName, transportID) : null;
     }
 
     @Override
     public void opComplete(int token, long result) throws RemoteException {
         BackupManagerService svc = mService;
         if (svc != null) {
-            svc.opComplete(token, result);
+            svc.opComplete(binderGetCallingUserId(), token, result);
         }
     }
 
     @Override
     public long getAvailableRestoreTokenForUser(int userId, String packageName) {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.getAvailableRestoreToken(packageName) : 0;
+        return (svc != null) ? svc.getAvailableRestoreToken(userId, packageName) : 0;
     }
 
     @Override
     public boolean isAppEligibleForBackupForUser(int userId, String packageName) {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.isAppEligibleForBackup(packageName) : false;
+        return (svc != null) ? svc.isAppEligibleForBackup(userId, packageName) : false;
     }
 
     @Override
     public String[] filterAppsEligibleForBackupForUser(int userId, String[] packages) {
         BackupManagerService svc = mService;
-        return (svc != null) ? svc.filterAppsEligibleForBackup(packages) : null;
+        return (svc != null) ? svc.filterAppsEligibleForBackup(userId, packages) : null;
     }
 
     @Override
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index d357404..2e41443 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -2811,15 +2811,6 @@
         }
     }
 
-    /** Mark the backup service as having been provisioned. */
-    public void setBackupProvisioned(boolean available) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
-                "setBackupProvisioned");
-        /*
-         * This is now a no-op; provisioning is simply the device's own setup state.
-         */
-    }
-
     /** Report whether the backup mechanism is currently enabled. */
     public boolean isBackupEnabled() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
@@ -2869,19 +2860,6 @@
         return mTransportManager.getRegisteredTransportComponents();
     }
 
-    /** Report all system whitelisted transports. */
-    public String[] getTransportWhitelist() {
-        // No permission check, intentionally.
-        Set<ComponentName> whitelistedComponents = mTransportManager.getTransportWhitelist();
-        String[] whitelistedTransports = new String[whitelistedComponents.size()];
-        int i = 0;
-        for (ComponentName component : whitelistedComponents) {
-            whitelistedTransports[i] = component.flattenToShortString();
-            i++;
-        }
-        return whitelistedTransports;
-    }
-
     /**
      * Update the attributes of the transport identified by {@code transportComponent}. If the
      * specified transport has not been bound at least once (for registration), this call will be
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index b9b1943..942ee11 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -25,8 +25,8 @@
 import android.text.format.DateUtils;
 import android.view.contentcapture.ContentCaptureContext;
 
+import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
 import com.android.internal.os.IResultReceiver;
-import com.android.server.infra.AbstractMultiplePendingRequestsRemoteService;
 
 final class RemoteContentCaptureService
         extends AbstractMultiplePendingRequestsRemoteService<RemoteContentCaptureService,
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index f0ec69f..f027253 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -65,7 +65,6 @@
 import android.os.ShellCallback;
 import android.os.ShellCommand;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
@@ -1646,29 +1645,40 @@
     }
 
     @Override
+    public int checkOperationRaw(int code, int uid, String packageName) {
+        return checkOperationInternal(code, uid, packageName, true /*raw*/);
+    }
+
+    @Override
     public int checkOperation(int code, int uid, String packageName) {
+        return checkOperationInternal(code, uid, packageName, false /*raw*/);
+    }
+
+    private int checkOperationInternal(int code, int uid, String packageName, boolean raw) {
         final CheckOpsDelegate delegate;
         synchronized (this) {
             delegate = mCheckOpsDelegate;
         }
         if (delegate == null) {
-            return checkOperationImpl(code, uid, packageName);
+            return checkOperationImpl(code, uid, packageName, raw);
         }
-        return delegate.checkOperation(code, uid, packageName,
+        return delegate.checkOperation(code, uid, packageName, raw,
                     AppOpsService.this::checkOperationImpl);
     }
 
-    private int checkOperationImpl(int code, int uid, String packageName) {
+    private int checkOperationImpl(int code, int uid, String packageName,
+                boolean raw) {
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
         String resolvedPackageName = resolvePackageName(uid, packageName);
         if (resolvedPackageName == null) {
             return AppOpsManager.MODE_IGNORED;
         }
-        return checkOperationUnchecked(code, uid, resolvedPackageName);
+        return checkOperationUnchecked(code, uid, resolvedPackageName, raw);
     }
 
-    private int checkOperationUnchecked(int code, int uid, String packageName) {
+    private int checkOperationUnchecked(int code, int uid, String packageName,
+                boolean raw) {
         synchronized (this) {
             if (isOpRestrictedLocked(uid, code, packageName)) {
                 return AppOpsManager.MODE_IGNORED;
@@ -1677,7 +1687,8 @@
             UidState uidState = getUidStateLocked(uid, false);
             if (uidState != null && uidState.opModes != null
                     && uidState.opModes.indexOfKey(code) >= 0) {
-                return uidState.evalMode(uidState.opModes.get(code));
+                final int rawMode = uidState.opModes.get(code);
+                return raw ? rawMode : uidState.evalMode(rawMode);
             }
             Op op = getOpLocked(code, uid, packageName, false, true, false);
             if (op == null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3bfd363..983ec4b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -20117,18 +20117,18 @@
         }
 
         @Override
-        public int checkOperation(int code, int uid, String packageName,
-                TriFunction<Integer, Integer, String, Integer> superImpl) {
+        public int checkOperation(int code, int uid, String packageName, boolean raw,
+                QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl) {
             if (uid == mTargetUid && isTargetOp(code)) {
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     return superImpl.apply(code, Process.SHELL_UID,
-                            "com.android.shell");
+                            "com.android.shell", raw);
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
             }
-            return superImpl.apply(code, uid, packageName);
+            return superImpl.apply(code, uid, packageName, raw);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 1882be2..a381477 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -653,7 +653,7 @@
             }
 
             mHandler.post(() -> {
-                final Pair<Integer, Integer> result = checkAndGetBiometricModality(callingUserId);
+                final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId);
                 final int modality = result.first;
                 final int error = result.second;
 
@@ -950,7 +950,7 @@
      * {@link BiometricAuthenticator#TYPE_FACE}
      * and the error containing one of the {@link BiometricConstants} errors.
      */
-    private Pair<Integer, Integer> checkAndGetBiometricModality(int callingUid) {
+    private Pair<Integer, Integer> checkAndGetBiometricModality(int userId) {
         int modality = TYPE_NONE;
 
         // No biometric features, send error
@@ -979,7 +979,7 @@
                     // order.
                     firstHwAvailable = modality;
                 }
-                if (authenticator.hasEnrolledTemplates(callingUid)) {
+                if (authenticator.hasEnrolledTemplates(userId)) {
                     hasTemplatesEnrolled = true;
                     if (isEnabledForApp(modality)) {
                         // TODO(b/110907543): When face settings (and other settings) have both a
diff --git a/services/core/java/com/android/server/infra/ServiceNameResolver.java b/services/core/java/com/android/server/infra/ServiceNameResolver.java
index 205d40b..fd87e3d 100644
--- a/services/core/java/com/android/server/infra/ServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/ServiceNameResolver.java
@@ -18,6 +18,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
+import com.android.internal.infra.AbstractRemoteService;
+
 import java.io.PrintWriter;
 
 /**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3552e66..4a32f75 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3275,7 +3275,11 @@
                 final int packageNum = packageInfos.length;
                 for (int i = 0; i < packageNum; ++i) {
                     if (packageInfos[i].equals(imi.getPackageName())) {
-                        mFileManager.addInputMethodSubtypes(imi, subtypes);
+                        if (subtypes.length > 0) {
+                            mFileManager.addInputMethodSubtypes(imi, subtypes);
+                        } else {
+                            mFileManager.deleteAllInputMethodSubtypes(imi.getId());
+                        }
                         final long ident = Binder.clearCallingIdentity();
                         try {
                             buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
@@ -4301,14 +4305,8 @@
             }
             final File subtypeFile = new File(inputMethodDir, ADDITIONAL_SUBTYPES_FILE_NAME);
             mAdditionalInputMethodSubtypeFile = new AtomicFile(subtypeFile, "input-subtypes");
-            if (!subtypeFile.exists()) {
-                // If "subtypes.xml" doesn't exist, create a blank file.
-                writeAdditionalInputMethodSubtypes(
-                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile, methodMap);
-            } else {
-                readAdditionalInputMethodSubtypes(
-                        mAdditionalSubtypesMap, mAdditionalInputMethodSubtypeFile);
-            }
+            readAdditionalInputMethodSubtypes(mAdditionalSubtypesMap,
+                    mAdditionalInputMethodSubtypeFile);
         }
 
         private void deleteAllInputMethodSubtypes(String imiId) {
@@ -4348,6 +4346,13 @@
         private static void writeAdditionalInputMethodSubtypes(
                 ArrayMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile,
                 ArrayMap<String, InputMethodInfo> methodMap) {
+            if (allSubtypes.isEmpty()) {
+                if (subtypesFile.exists()) {
+                    subtypesFile.delete();
+                }
+                return;
+            }
+
             // Safety net for the case that this function is called before methodMap is set.
             final boolean isSetMethodMap = methodMap != null && methodMap.size() > 0;
             FileOutputStream fos = null;
@@ -4404,6 +4409,10 @@
                 ArrayMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile) {
             if (allSubtypes == null || subtypesFile == null) return;
             allSubtypes.clear();
+            if (!subtypesFile.exists()) {
+                // Not having the file means there is no additional subtype.
+                return;
+            }
             try (final FileInputStream fis = subtypesFile.openRead()) {
                 final XmlPullParser parser = Xml.newPullParser();
                 parser.setInput(fis, StandardCharsets.UTF_8.name());
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index b7bb2c6..93b6620 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -27,10 +27,8 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.media.AudioManager;
@@ -636,16 +634,11 @@
      * <p>The contents of this object is guarded by {@link #mLock}.
      */
     final class FullUserRecord implements MediaSessionStack.OnMediaButtonSessionChangedListener {
-        public static final int COMPONENT_TYPE_BROADCAST = 0;
-        public static final int COMPONENT_TYPE_ACTIVITY = 1;
-        public static final int COMPONENT_TYPE_SERVICE = 2;
         private static final String COMPONENT_NAME_USER_ID_DELIM = ",";
-
         private final int mFullUserId;
         private final MediaSessionStack mPriorityStack;
         private PendingIntent mLastMediaButtonReceiver;
         private ComponentName mRestoredMediaButtonReceiver;
-        private int mRestoredMediaButtonReceiverComponentType;
         private int mRestoredMediaButtonReceiverUserId;
 
         private IOnVolumeKeyLongPressListener mOnVolumeKeyLongPressListener;
@@ -662,23 +655,17 @@
             mFullUserId = fullUserId;
             mPriorityStack = new MediaSessionStack(mAudioPlayerStateMonitor, this);
             // Restore the remembered media button receiver before the boot.
-            String mediaButtonReceiverInfo = Settings.Secure.getStringForUser(mContentResolver,
+            String mediaButtonReceiver = Settings.Secure.getStringForUser(mContentResolver,
                     Settings.System.MEDIA_BUTTON_RECEIVER, mFullUserId);
-            if (mediaButtonReceiverInfo == null) {
+            if (mediaButtonReceiver == null) {
                 return;
             }
-            String[] tokens = mediaButtonReceiverInfo.split(COMPONENT_NAME_USER_ID_DELIM);
-            if (tokens == null || (tokens.length != 2 && tokens.length != 3)) {
+            String[] tokens = mediaButtonReceiver.split(COMPONENT_NAME_USER_ID_DELIM);
+            if (tokens == null || tokens.length != 2) {
                 return;
             }
             mRestoredMediaButtonReceiver = ComponentName.unflattenFromString(tokens[0]);
             mRestoredMediaButtonReceiverUserId = Integer.parseInt(tokens[1]);
-            if (tokens.length == 3) {
-                mRestoredMediaButtonReceiverComponentType = Integer.parseInt(tokens[2]);
-            } else {
-                mRestoredMediaButtonReceiverComponentType =
-                        getComponentType(mRestoredMediaButtonReceiver);
-            }
         }
 
         public void destroySessionsForUserLocked(int userId) {
@@ -709,8 +696,6 @@
             pw.println(indent + "Callback: " + mCallback);
             pw.println(indent + "Last MediaButtonReceiver: " + mLastMediaButtonReceiver);
             pw.println(indent + "Restored MediaButtonReceiver: " + mRestoredMediaButtonReceiver);
-            pw.println(indent + "Restored MediaButtonReceiverComponentType: "
-                    + mRestoredMediaButtonReceiverComponentType);
             mPriorityStack.dump(pw, indent);
         }
 
@@ -737,21 +722,17 @@
             PendingIntent receiver = record.getMediaButtonReceiver();
             mLastMediaButtonReceiver = receiver;
             mRestoredMediaButtonReceiver = null;
-
-            String mediaButtonReceiverInfo = "";
+            String componentName = "";
             if (receiver != null) {
                 ComponentName component = receiver.getIntent().getComponent();
                 if (component != null
                         && record.getPackageName().equals(component.getPackageName())) {
-                    String componentName = component.flattenToString();
-                    int componentType = getComponentType(component);
-                    mediaButtonReceiverInfo = String.join(COMPONENT_NAME_USER_ID_DELIM,
-                            componentName, String.valueOf(record.getUserId()),
-                            String.valueOf(componentType));
+                    componentName = component.flattenToString();
                 }
             }
             Settings.Secure.putStringForUser(mContentResolver,
-                    Settings.System.MEDIA_BUTTON_RECEIVER, mediaButtonReceiverInfo,
+                    Settings.System.MEDIA_BUTTON_RECEIVER,
+                    componentName + COMPONENT_NAME_USER_ID_DELIM + record.getUserId(),
                     mFullUserId);
         }
 
@@ -781,32 +762,6 @@
             return isGlobalPriorityActiveLocked()
                     ? mGlobalPrioritySession : mPriorityStack.getMediaButtonSession();
         }
-
-        private int getComponentType(ComponentName componentName) {
-            PackageManager pm = getContext().getPackageManager();
-            try {
-                ActivityInfo activityInfo = pm.getActivityInfo(componentName,
-                        PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                                | PackageManager.GET_ACTIVITIES);
-                if (activityInfo != null) {
-                    return COMPONENT_TYPE_ACTIVITY;
-                }
-            } catch (NameNotFoundException e) {
-            }
-            try {
-                ServiceInfo serviceInfo = pm.getServiceInfo(componentName,
-                        PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                                | PackageManager.GET_SERVICES);
-                if (serviceInfo != null) {
-                    return COMPONENT_TYPE_SERVICE;
-                }
-            } catch (NameNotFoundException e) {
-            }
-            // Pick legacy behavior for BroadcastReceiver or unknown.
-            return COMPONENT_TYPE_BROADCAST;
-        }
     }
 
     final class SessionsListenerRecord implements IBinder.DeathRecipient {
@@ -1625,32 +1580,14 @@
                     } else {
                         ComponentName receiver =
                                 mCurrentFullUserRecord.mRestoredMediaButtonReceiver;
-                        int componentType = mCurrentFullUserRecord
-                                .mRestoredMediaButtonReceiverComponentType;
-                        UserHandle userHandle = UserHandle.of(mCurrentFullUserRecord
-                                .mRestoredMediaButtonReceiverUserId);
                         if (DEBUG_KEY_EVENT) {
                             Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
-                                    + receiver + ", type=" + componentType);
+                                    + receiver);
                         }
                         mediaButtonIntent.setComponent(receiver);
-                        try {
-                            switch (componentType) {
-                                case FullUserRecord.COMPONENT_TYPE_ACTIVITY:
-                                    getContext().startActivityAsUser(mediaButtonIntent, userHandle);
-                                    break;
-                                case FullUserRecord.COMPONENT_TYPE_SERVICE:
-                                    getContext().startForegroundServiceAsUser(mediaButtonIntent,
-                                            userHandle);
-                                    break;
-                                default:
-                                    // Legacy behavior for other cases.
-                                    getContext().sendBroadcastAsUser(mediaButtonIntent, userHandle);
-                            }
-                        } catch (Exception e) {
-                            Log.w(TAG, "Error sending media button to the restored intent "
-                                    + receiver + ", type=" + componentType, e);
-                        }
+                        getContext().sendBroadcastAsUser(mediaButtonIntent,
+                                UserHandle.of(mCurrentFullUserRecord
+                                      .mRestoredMediaButtonReceiverUserId));
                         if (mCurrentFullUserRecord.mCallback != null) {
                             mCurrentFullUserRecord.mCallback
                                     .onMediaKeyEventDispatchedToMediaButtonReceiver(
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8fa3c46..2359c2a 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -842,25 +842,13 @@
                         // Report to usage stats that notification was made visible
                         if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
                         reportSeen(r);
-
-                        // If the newly visible notification has smart suggestions
-                        // then log that the user has seen them.
-                        if ((r.getNumSmartRepliesAdded() > 0 || r.getNumSmartActionsAdded() > 0)
-                                && !r.hasSeenSmartReplies()) {
-                            r.setSeenSmartReplies(true);
-                            LogMaker logMaker = r.getLogMaker()
-                                    .setCategory(MetricsEvent.SMART_REPLY_VISIBLE)
-                                    .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT,
-                                            r.getNumSmartRepliesAdded())
-                                    .addTaggedData(MetricsEvent.NOTIFICATION_SMART_ACTION_COUNT,
-                                            r.getNumSmartActionsAdded())
-                                    .addTaggedData(
-                                            MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
-                                            r.getSuggestionsGeneratedByAssistant());
-                            mMetricsLogger.write(logMaker);
-                        }
                     }
                     r.setVisibility(true, nv.rank, nv.count);
+                    // hasBeenVisiblyExpanded must be called after updating the expansion state of
+                    // the NotificationRecord to ensure the expansion state is up-to-date.
+                    if (r.hasBeenVisiblyExpanded()) {
+                        logSmartSuggestionsVisible(r);
+                    }
                     maybeRecordInterruptionLocked(r);
                     nv.recycle();
                 }
@@ -884,6 +872,11 @@
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r != null) {
                     r.stats.onExpansionChanged(userAction, expanded);
+                    // hasBeenVisiblyExpanded must be called after updating the expansion state of
+                    // the NotificationRecord to ensure the expansion state is up-to-date.
+                    if (r.hasBeenVisiblyExpanded()) {
+                        logSmartSuggestionsVisible(r);
+                    }
                     final long now = System.currentTimeMillis();
                     if (userAction) {
                         MetricsLogger.action(r.getItemLogMaker()
@@ -961,6 +954,26 @@
         }
     };
 
+    @VisibleForTesting
+    void logSmartSuggestionsVisible(NotificationRecord r) {
+        // If the newly visible notification has smart suggestions
+        // then log that the user has seen them.
+        if ((r.getNumSmartRepliesAdded() > 0 || r.getNumSmartActionsAdded() > 0)
+                && !r.hasSeenSmartReplies()) {
+            r.setSeenSmartReplies(true);
+            LogMaker logMaker = r.getLogMaker()
+                    .setCategory(MetricsEvent.SMART_REPLY_VISIBLE)
+                    .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT,
+                            r.getNumSmartRepliesAdded())
+                    .addTaggedData(MetricsEvent.NOTIFICATION_SMART_ACTION_COUNT,
+                            r.getNumSmartActionsAdded())
+                    .addTaggedData(
+                            MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
+                            r.getSuggestionsGeneratedByAssistant());
+            mMetricsLogger.write(logMaker);
+        }
+    }
+
     @GuardedBy("mNotificationLock")
     private void clearSoundLocked() {
         mSoundNotificationKey = null;
@@ -1939,9 +1952,11 @@
      */
     @GuardedBy("mNotificationLock")
     protected void reportSeen(NotificationRecord r) {
-        mAppUsageStats.reportEvent(r.sbn.getPackageName(),
-                getRealUserId(r.sbn.getUserId()),
-                UsageEvents.Event.NOTIFICATION_SEEN);
+        if (!r.isProxied()) {
+            mAppUsageStats.reportEvent(r.sbn.getPackageName(),
+                    getRealUserId(r.sbn.getUserId()),
+                    UsageEvents.Event.NOTIFICATION_SEEN);
+        }
     }
 
     protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
@@ -2279,6 +2294,26 @@
         }
 
         @Override
+        public boolean areAppOverlaysAllowed(String pkg) {
+            return areAppOverlaysAllowedForPackage(pkg, Binder.getCallingUid());
+        }
+
+        @Override
+        public boolean areAppOverlaysAllowedForPackage(String pkg, int uid) {
+            checkCallerIsSystemOrSameApp(pkg);
+
+            return mPreferencesHelper.areAppOverlaysAllowed(pkg, uid);
+        }
+
+        @Override
+        public void setAppOverlaysAllowed(String pkg, int uid, boolean allowed) {
+            checkCallerIsSystem();
+
+            mPreferencesHelper.setAppOverlaysAllowed(pkg, uid, allowed);
+            handleSavePolicyFile();
+        }
+
+        @Override
         public int getPackageImportance(String pkg) {
             checkCallerIsSystemOrSameApp(pkg);
             return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
@@ -4023,7 +4058,7 @@
                 final ArraySet<ComponentName> listeners =
                     mListenersDisablingEffects.valueAt(i);
                 for (int j = 0; j < listeners.size(); j++) {
-                    final ComponentName componentName = listeners.valueAt(i);
+                    final ComponentName componentName = listeners.valueAt(j);
                     componentName.writeToProto(proto,
                             ListenersDisablingEffectsProto.LISTENER_COMPONENTS);
                 }
@@ -4168,8 +4203,8 @@
                     final int listenerSize = listeners.size();
 
                     for (int j = 0; j < listenerSize; j++) {
-                        if (i > 0) pw.print(',');
-                        final ComponentName listener = listeners.valueAt(i);
+                        if (j > 0) pw.print(',');
+                        final ComponentName listener = listeners.valueAt(j);
                         if (listener != null) {
                             pw.print(listener);
                         }
@@ -4409,7 +4444,7 @@
             notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
         }
 
-        if (ai.targetSdkVersion >= Build.VERSION_CODES.Q) {
+        if (notification.fullScreenIntent != null && ai.targetSdkVersion >= Build.VERSION_CODES.Q) {
             int fullscreenIntentPermission = mPackageManagerClient.checkPermission(
                     android.Manifest.permission.USE_FULL_SCREEN_INTENT, pkg);
             if (fullscreenIntentPermission != PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 89ec38d..e2c64ca 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -151,7 +151,6 @@
 
     private int mSuppressedVisualEffects = 0;
     private String mUserExplanation;
-    private String mPeopleExplanation;
     private boolean mPreChannelsNotification = true;
     private Uri mSound;
     private long[] mVibration;
@@ -1166,6 +1165,13 @@
         mHasSeenSmartReplies = hasSeenSmartReplies;
     }
 
+    /**
+     * Returns whether this notification has been visible and expanded at the same time.
+     */
+    public boolean hasBeenVisiblyExpanded() {
+        return stats.hasBeenVisiblyExpanded();
+    }
+
     public void setSystemGeneratedSmartActions(
             ArrayList<Notification.Action> systemGeneratedSmartActions) {
         mSystemGeneratedSmartActions = systemGeneratedSmartActions;
@@ -1184,6 +1190,13 @@
     }
 
     /**
+     * Returns whether this notification was posted by a secondary app
+     */
+    public boolean isProxied() {
+        return !Objects.equals(sbn.getPackageName(), sbn.getOpPkg());
+    }
+
+    /**
      * @return all {@link Uri} that should have permission granted to whoever
      *         will be rendering it. This list has already been vetted to only
      *         include {@link Uri} that the enqueuing app can grant.
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index e40dad6..d630b9a 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -916,6 +916,13 @@
             updateVisiblyExpandedStats();
         }
 
+        /**
+         * Returns whether this notification has been visible and expanded at the same.
+         */
+        public boolean hasBeenVisiblyExpanded() {
+            return posttimeToFirstVisibleExpansionMs >= 0;
+        }
+
         private void updateVisiblyExpandedStats() {
             long elapsedNowMs = SystemClock.elapsedRealtime();
             if (isExpanded && isVisible) {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index eb46d53..7c0e0b0 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -80,6 +80,7 @@
     private static final String ATT_NAME = "name";
     private static final String ATT_UID = "uid";
     private static final String ATT_ID = "id";
+    private static final String ATT_APP_OVERLAY = "overlay";
     private static final String ATT_PRIORITY = "priority";
     private static final String ATT_VISIBILITY = "visibility";
     private static final String ATT_IMPORTANCE = "importance";
@@ -92,6 +93,7 @@
     private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
     private static final int DEFAULT_IMPORTANCE = NotificationManager.IMPORTANCE_UNSPECIFIED;
     private static final boolean DEFAULT_SHOW_BADGE = true;
+    private static final boolean DEFAULT_ALLOW_APP_OVERLAY = true;
     /**
      * Default value for what fields are user locked. See {@link LockableAppFields} for all lockable
      * fields.
@@ -104,6 +106,7 @@
     @IntDef({LockableAppFields.USER_LOCKED_IMPORTANCE})
     public @interface LockableAppFields {
         int USER_LOCKED_IMPORTANCE = 0x00000001;
+        int USER_LOCKED_APP_OVERLAY = 0x00000002;
     }
 
     // pkg|uid => PackagePreferences
@@ -169,7 +172,9 @@
                                     XmlUtils.readIntAttribute(
                                             parser, ATT_VISIBILITY, DEFAULT_VISIBILITY),
                                     XmlUtils.readBooleanAttribute(
-                                            parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE));
+                                            parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE),
+                                    XmlUtils.readBooleanAttribute(
+                                            parser, ATT_APP_OVERLAY, DEFAULT_ALLOW_APP_OVERLAY));
                             r.importance = XmlUtils.readIntAttribute(
                                     parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
                             r.priority = XmlUtils.readIntAttribute(
@@ -264,11 +269,12 @@
 
     private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid) {
         return getOrCreatePackagePreferences(pkg, uid,
-                DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE);
+                DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE,
+                DEFAULT_ALLOW_APP_OVERLAY);
     }
 
     private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid, int importance,
-            int priority, int visibility, boolean showBadge) {
+            int priority, int visibility, boolean showBadge, boolean allowAppOverlay) {
         final String key = packagePreferencesKey(pkg, uid);
         synchronized (mPackagePreferences) {
             PackagePreferences
@@ -282,6 +288,7 @@
                 r.priority = priority;
                 r.visibility = visibility;
                 r.showBadge = showBadge;
+                r.appOverlay = allowAppOverlay;
 
                 try {
                     createDefaultChannelIfNeeded(r);
@@ -382,7 +389,8 @@
                                 || r.lockedAppFields != DEFAULT_LOCKED_APP_FIELDS
                                 || r.channels.size() > 0
                                 || r.groups.size() > 0
-                                || r.delegate != null;
+                                || r.delegate != null
+                                || r.appOverlay != DEFAULT_ALLOW_APP_OVERLAY;
                 if (hasNonDefaultSettings) {
                     out.startTag(null, TAG_PACKAGE);
                     out.attribute(null, ATT_NAME, r.pkg);
@@ -395,6 +403,9 @@
                     if (r.visibility != DEFAULT_VISIBILITY) {
                         out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
                     }
+                    if (r.appOverlay != DEFAULT_ALLOW_APP_OVERLAY) {
+                        out.attribute(null, ATT_APP_OVERLAY, Boolean.toString(r.appOverlay));
+                    }
                     out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(r.showBadge));
                     out.attribute(null, ATT_APP_USER_LOCKED_FIELDS,
                             Integer.toString(r.lockedAppFields));
@@ -439,6 +450,20 @@
         out.endTag(null, TAG_RANKING);
     }
 
+    public void setAppOverlaysAllowed(String pkg, int uid, boolean allowed) {
+        PackagePreferences p = getOrCreatePackagePreferences(pkg, uid);
+        p.appOverlay = allowed;
+        p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_APP_OVERLAY;
+    }
+
+    public boolean areAppOverlaysAllowed(String pkg, int uid) {
+        return getOrCreatePackagePreferences(pkg, uid).appOverlay;
+    }
+
+    public int getAppLockedFields(String pkg, int uid) {
+        return getOrCreatePackagePreferences(pkg, uid).lockedAppFields;
+    }
+
     /**
      * Gets importance.
      */
@@ -512,7 +537,6 @@
             // apps can't update the blocked status or app overlay permission
             if (fromTargetApp) {
                 group.setBlocked(oldGroup.isBlocked());
-                group.setAllowAppOverlay(oldGroup.canOverlayApps());
                 group.unlockFields(group.getUserLockedFields());
                 group.lockFields(oldGroup.getUserLockedFields());
             } else {
@@ -521,9 +545,6 @@
                     group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE);
                     updateChannelsBypassingDnd(mContext.getUserId());
                 }
-                if (group.canOverlayApps() != oldGroup.canOverlayApps()) {
-                    group.lockFields(NotificationChannelGroup.USER_LOCKED_ALLOW_APP_OVERLAY);
-                }
             }
         }
         r.groups.put(group.getId(), group);
@@ -1581,6 +1602,7 @@
         int priority = DEFAULT_PRIORITY;
         int visibility = DEFAULT_VISIBILITY;
         boolean showBadge = DEFAULT_SHOW_BADGE;
+        boolean appOverlay = DEFAULT_ALLOW_APP_OVERLAY;
         int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
 
         Delegate delegate = null;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 093b85e..f9e31ae 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -402,12 +402,17 @@
                 + " dexoptFlags=" + printDexoptFlags(dexoptFlags)
                 + " target-filter=" + compilerFilter);
 
-        // TODO(calin): b/64530081 b/66984396. Use SKIP_SHARED_LIBRARY_CHECK for the context
-        // (instead of dexUseInfo.getClassLoaderContext()) in order to compile secondary dex files
-        // in isolation (and avoid to extract/verify the main apk if it's in the class path).
-        // Note this trades correctness for performance since the resulting slow down is
-        // unacceptable in some cases until b/64530081 is fixed.
-        String classLoaderContext = SKIP_SHARED_LIBRARY_CHECK;
+        String classLoaderContext;
+        if (dexUseInfo.isUnknownClassLoaderContext() || dexUseInfo.isVariableClassLoaderContext()) {
+            // If we have an unknown (not yet set), or a variable class loader chain, compile
+            // without a context and mark the oat file with SKIP_SHARED_LIBRARY_CHECK. Note that
+            // this might lead to a incorrect compilation.
+            // TODO(calin): We should just extract in this case.
+            classLoaderContext = SKIP_SHARED_LIBRARY_CHECK;
+        } else {
+            classLoaderContext = dexUseInfo.getClassLoaderContext();
+        }
+
         int reason = options.getCompilationReason();
         try {
             for (String isa : dexUseInfo.getLoaderIsas()) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 206a88b..0d0db94 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -250,6 +250,15 @@
     @GuardedBy("mLock")
     private int mParentSessionId;
 
+    @GuardedBy("mLock")
+    private boolean mStagedSessionApplied;
+    @GuardedBy("mLock")
+    private boolean mStagedSessionReady;
+    @GuardedBy("mLock")
+    private boolean mStagedSessionFailed;
+    @GuardedBy("mLock")
+    private int mStagedSessionErrorCode = SessionInfo.NO_ERROR;
+
     /**
      * Path to the validated base APK for this session, which may point at an
      * APK inside the session (when the session defines the base), or it may
@@ -470,6 +479,10 @@
             if (info.childSessionIds == null) {
                 info.childSessionIds = EMPTY_CHILD_SESSION_ARRAY;
             }
+            info.isSessionApplied = mStagedSessionApplied;
+            info.isSessionReady = mStagedSessionReady;
+            info.isSessionFailed = mStagedSessionFailed;
+            info.setStagedSessionErrorCode(mStagedSessionErrorCode);
         }
         return info;
     }
@@ -1051,6 +1064,7 @@
         }
         if (isStaged()) {
             // STOPSHIP: implement staged sessions
+            mStagedSessionReady = true;
             dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
             return;
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 37a35a2..357872e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -630,9 +630,13 @@
                     pw.print("=");
                 }
                 pw.print(info.packageName);
-                if (showVersionCode && !isApex) {
+                if (showVersionCode) {
                     pw.print(" versionCode:");
-                    pw.print(info.applicationInfo.versionCode);
+                    if (info.applicationInfo != null) {
+                        pw.print(info.applicationInfo.versionCode);
+                    } else {
+                        pw.print(info.versionCode);
+                    }
                 }
                 if (listInstaller && !isApex) {
                     pw.print("  installer=");
@@ -2779,7 +2783,7 @@
         pw.println("    Prints all system libraries.");
         pw.println("");
         pw.println("  list packages [-f] [-d] [-e] [-s] [-3] [-i] [-l] [-u] [-U] ");
-        pw.println("      [--apex-only] [--uid UID] [--user USER_ID] [FILTER]");
+        pw.println("      [--show-versioncode] [--apex-only] [--uid UID] [--user USER_ID] [FILTER]");
         pw.println("    Prints all packages; optionally only those whose name contains");
         pw.println("    the text in FILTER.  Options are:");
         pw.println("      -f: see their associated file");
@@ -2792,6 +2796,7 @@
         pw.println("      -l: ignored (used for compatibility with older releases)");
         pw.println("      -U: also show the package UID");
         pw.println("      -u: also include uninstalled packages");
+        pw.println("      --show-versioncode: also show the version code");
         pw.println("      --apex-only: only show APEX packages");
         pw.println("      --uid UID: filter to only show packages with the given UID");
         pw.println("      --user USER_ID: only list packages belonging to the given user");
diff --git a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
index 33a9650..e68c238 100644
--- a/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
+++ b/services/core/java/com/android/server/pm/dex/PackageDexUsage.java
@@ -875,15 +875,13 @@
 
         public String getClassLoaderContext() { return mClassLoaderContext; }
 
-        @VisibleForTesting
-        /* package */ boolean isUnknownClassLoaderContext() {
+        public boolean isUnknownClassLoaderContext() {
             // The class loader context may be unknown if we loaded the data from a previous version
             // which didn't save the context.
             return UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
         }
 
-        @VisibleForTesting
-        /* package */ boolean isVariableClassLoaderContext() {
+        public boolean isVariableClassLoaderContext() {
             return VARIABLE_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
         }
     }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 02d8c0b..fc21adb 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -718,12 +718,12 @@
             disabledData += " }";
             final UiState state = getUiState(displayId);
 
-            Log.d(TAG, "disabledlocked (b/113914868): displayId=" + displayId + "net1=" + net1
+            Log.d(TAG, "disabledlocked (b/113914868): displayId=" + displayId + ", net1=" + net1
                     + ", mDisabled1=" + state.mDisabled1 + ", token=" + token
                     + ", mDisableRecords=" + mDisableRecords.size() + " => " + disabledData);
         }
         final UiState state = getUiState(displayId);
-        if (state.disableEquals(net1, net2)) {
+        if (!state.disableEquals(net1, net2)) {
             state.setDisabled(net1, net2);
             mHandler.post(() -> mNotificationDelegate.onSetDisabled(net1));
             if (mBar != null) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 7c61e37..f008770 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -905,16 +905,14 @@
             return;
         }
         if (supportsMultiDisplay(systemConnection)
-                && fallbackConnection.getConnectedEngineSize() != 0) {
-            fallbackConnection.forEachDisplayConnector(
-                    WallpaperConnection.DisplayConnector::disconnectLocked);
+                && fallbackConnection.mDisplayConnector.size() != 0) {
+            fallbackConnection.forEachDisplayConnector(connector -> {
+                if (connector.mEngine != null) {
+                    connector.disconnectLocked();
+                }
+            });
             fallbackConnection.mDisplayConnector.clear();
         } else {
-            // TODO(b/121181553) Handle wallpaper service disconnect case.
-            if (fallbackConnection.mService == null) {
-                Slog.w(TAG, "There is no fallback wallpaper service");
-                return;
-            }
             fallbackConnection.appendConnectorWithCondition(display ->
                     fallbackConnection.isUsableDisplay(display)
                             && display.getDisplayId() != DEFAULT_DISPLAY
@@ -965,6 +963,10 @@
             }
 
             void connectLocked(WallpaperConnection connection, WallpaperData wallpaper) {
+                if (connection.mService == null) {
+                    Slog.w(TAG, "WallpaperService is not connected yet");
+                    return;
+                }
                 if (DEBUG) Slog.v(TAG, "Adding window token: " + mToken);
                 try {
                     mIWindowManager.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId);
@@ -980,7 +982,7 @@
                             wpdData.mPadding, mDisplayId);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Failed attaching wallpaper on display", e);
-                    if (mLastWallpaper != null && !mLastWallpaper.wallpaperUpdating
+                    if (wallpaper != null && !wallpaper.wallpaperUpdating
                             && connection.getConnectedEngineSize() == 0) {
                         bindWallpaperComponentLocked(null /* componentName */, false /* force */,
                                 false /* fromUser */, wallpaper, null /* reply */);
@@ -1067,8 +1069,11 @@
             for (Display display : displays) {
                 if (tester.test(display)) {
                     final int displayId = display.getDisplayId();
-                    mDisplayConnector.append(displayId,
-                            new DisplayConnector(displayId));
+                    final DisplayConnector connector = mDisplayConnector.get(displayId);
+                    if (connector == null) {
+                        mDisplayConnector.append(displayId,
+                                new DisplayConnector(displayId));
+                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5f00bcc..4d8440a8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -42,6 +42,7 @@
 import static android.content.Intent.ACTION_MAIN;
 import static android.content.Intent.CATEGORY_HOME;
 import static android.content.Intent.CATEGORY_LAUNCHER;
+import static android.content.Intent.CATEGORY_SECONDARY_HOME;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_NO_HISTORY;
 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
@@ -1178,7 +1179,8 @@
 
     private boolean isHomeIntent(Intent intent) {
         return ACTION_MAIN.equals(intent.getAction())
-                && intent.hasCategory(CATEGORY_HOME)
+                && (intent.hasCategory(CATEGORY_HOME)
+                || intent.hasCategory(CATEGORY_SECONDARY_HOME))
                 && intent.getCategories().size() == 1
                 && intent.getData() == null
                 && intent.getType() == null;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 9861157..f662d0c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5475,6 +5475,31 @@
         return intent;
     }
 
+    /**
+     * Return the intent set with {@link Intent#CATEGORY_SECONDARY_HOME} to resolve secondary home
+     * activities.
+     *
+     * @param preferredPackage Specify a preferred package name, otherwise use secondary home
+     *                        component defined in config_secondaryHomeComponent.
+     * @return the intent set with {@link Intent#CATEGORY_SECONDARY_HOME}
+     */
+    Intent getSecondaryHomeIntent(String preferredPackage) {
+        final Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
+        if (preferredPackage == null) {
+            // Using the component stored in config if no package name.
+            final String secondaryHomeComponent = mContext.getResources().getString(
+                    com.android.internal.R.string.config_secondaryHomeComponent);
+            intent.setComponent(ComponentName.unflattenFromString(secondaryHomeComponent));
+        } else {
+            intent.setPackage(preferredPackage);
+        }
+        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
+        if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
+            intent.addCategory(Intent.CATEGORY_SECONDARY_HOME);
+        }
+        return intent;
+    }
+
     ApplicationInfo getAppInfoForUser(ApplicationInfo info, int userId) {
         if (info == null) return null;
         ApplicationInfo newInfo = new ApplicationInfo(info);
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index ec2d673..cb9cbd6 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -134,10 +134,8 @@
 
         mWindowManager.deferSurfaceLayout();
         try {
-            final int userId = mService.getCurrentUserId();
-
             // Kick off the assist data request in the background before showing the target activity
-            requestAssistData(recentsComponent, recentsUid, assistDataReceiver, userId);
+            requestAssistData(recentsComponent, recentsUid, assistDataReceiver);
 
             if (hasExistingActivity) {
                 // Move the recents activity into place for the animation if it is not top most
@@ -164,7 +162,7 @@
                         .setCallingUid(recentsUid)
                         .setCallingPackage(recentsComponent.getPackageName())
                         .setActivityOptions(SafeActivityOptions.fromBundle(options.toBundle()))
-                        .setMayWait(userId)
+                        .setMayWait(mService.getCurrentUserId())
                         .execute();
 
                 // Move the recents activity into place for the animation
@@ -221,7 +219,7 @@
      * Requests assist data for the top visible activities.
      */
     private void requestAssistData(ComponentName recentsComponent, int recentsUid,
-            @Deprecated IAssistDataReceiver assistDataReceiver, int userId) {
+            @Deprecated IAssistDataReceiver assistDataReceiver) {
         final AppOpsManager appOpsManager = (AppOpsManager)
                 mService.mContext.getSystemService(Context.APP_OPS_SERVICE);
         final List<IBinder> topActivities =
@@ -237,8 +235,9 @@
                     final ContentCaptureManagerInternal imService =
                             LocalServices.getService(ContentCaptureManagerInternal.class);
                     final IBinder activityToken = topActivities.get(activityIndex);
-                    if (imService == null
-                            || !imService.sendActivityAssistData(userId, activityToken, data)) {
+                    final ActivityRecord r = ActivityRecord.forTokenLocked(activityToken);
+                    if (r != null && (imService == null
+                            || !imService.sendActivityAssistData(r.mUserId, activityToken, data))) {
                         // Otherwise, use the provided assist data receiver
                         super.onAssistDataReceivedLocked(data, activityIndex, activityCount);
                     }
@@ -263,7 +262,10 @@
                         int activityCount) {
                     // Try to notify the intelligence service
                     final IBinder activityToken = topActivities.get(activityIndex);
-                    imService.sendActivityAssistData(userId, activityToken, data);
+                    final ActivityRecord r = ActivityRecord.forTokenLocked(activityToken);
+                    if (r != null) {
+                        imService.sendActivityAssistData(r.mUserId, activityToken, data);
+                    }
                 }
             };
         }
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index d0144fd..8ec97c5 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -90,17 +90,18 @@
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.power.V1_0.PowerHint;
-import android.os.Build;
 import android.os.FactoryTest;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.IntArray;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -110,6 +111,7 @@
 import android.view.DisplayInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.ResolverActivity;
 import com.android.server.LocalServices;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.AppTimeTracker;
@@ -346,35 +348,53 @@
     }
 
     /**
-     * This starts home activity on displays that can have system decorations and only if the
-     * home activity can have multiple instances.
+     * This starts home activity on displays that can have system decorations based on displayId -
+     * Default display always use primary home component.
+     * For Secondary displays, the home activity must have category SECONDARY_HOME and then resolves
+     * according to the priorities listed below.
+     *  - If default home is not set, always use the secondary home defined in the config.
+     *  - Use currently selected primary home activity.
+     *  - Use the activity in the same package as currently selected primary home activity.
+     *    If there are multiple activities matched, use first one.
+     *  - Use the secondary home defined in the config.
      */
     boolean startHomeOnDisplay(int userId, String reason, int displayId) {
-        final Intent homeIntent = mService.getHomeIntent();
-        final ActivityInfo aInfo = resolveHomeActivity(userId, homeIntent);
+        Intent homeIntent;
+        ActivityInfo aInfo;
+        if (displayId == DEFAULT_DISPLAY) {
+            homeIntent = mService.getHomeIntent();
+            aInfo = resolveHomeActivity(userId, homeIntent);
+        } else {
+            Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, displayId);
+            aInfo = info.first;
+            homeIntent = info.second;
+        }
         if (aInfo == null) {
             return false;
         }
 
-        if (!canStartHomeOnDisplay(aInfo, displayId,
-                false /* allowInstrumenting */)) {
+        if (!canStartHomeOnDisplay(aInfo, displayId, false /* allowInstrumenting */)) {
             return false;
         }
 
+        // Updates the home component of the intent.
+        homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
+        homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
         // Update the reason for ANR debugging to verify if the user activity is the one that
         // actually launched.
         final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
-                aInfo.applicationInfo.uid);
+                aInfo.applicationInfo.uid) + ":" + displayId;
         mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
                 displayId);
         return true;
     }
 
     /**
-     * This resolves the home activity info and updates the home component of the given intent.
+     * This resolves the home activity info.
      * @return the home activity info if any.
      */
-    private ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) {
+    @VisibleForTesting
+    ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) {
         final int flags = ActivityManagerService.STOCK_PM_FLAGS;
         final ComponentName comp = homeIntent.getComponent();
         ActivityInfo aInfo = null;
@@ -400,13 +420,82 @@
             return null;
         }
 
-        homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
         aInfo = new ActivityInfo(aInfo);
         aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId);
-        homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
         return aInfo;
     }
 
+    @VisibleForTesting
+    Pair<ActivityInfo, Intent> resolveSecondaryHomeActivity(int userId, int displayId) {
+        if (displayId == DEFAULT_DISPLAY) {
+            throw new IllegalArgumentException(
+                    "resolveSecondaryHomeActivity: Should not be DEFAULT_DISPLAY");
+        }
+        // Resolve activities in the same package as currently selected primary home activity.
+        Intent homeIntent = mService.getHomeIntent();
+        ActivityInfo aInfo = resolveHomeActivity(userId, homeIntent);
+        if (aInfo != null) {
+            if (ResolverActivity.class.getName().equals(aInfo.name)) {
+                // Always fallback to secondary home component if default home is not set.
+                aInfo = null;
+            } else {
+                // Look for secondary home activities in the currently selected default home
+                // package.
+                homeIntent = mService.getSecondaryHomeIntent(aInfo.applicationInfo.packageName);
+                final List<ResolveInfo> resolutions = resolveActivities(userId, homeIntent);
+                final int size = resolutions.size();
+                final String targetName = aInfo.name;
+                aInfo = null;
+                for (int i = 0; i < size; i++) {
+                    ResolveInfo resolveInfo = resolutions.get(i);
+                    // We need to traverse all resolutions to check if the currently selected
+                    // default home activity is present.
+                    if (resolveInfo.activityInfo.name.equals(targetName)) {
+                        aInfo = resolveInfo.activityInfo;
+                        break;
+                    }
+                }
+                if (aInfo == null && size > 0) {
+                    // First one is the best.
+                    aInfo = resolutions.get(0).activityInfo;
+                }
+            }
+        }
+
+        if (aInfo != null) {
+            if (!canStartHomeOnDisplay(aInfo, displayId, false /* allowInstrumenting */)) {
+                aInfo = null;
+            }
+        }
+
+        // Fallback to secondary home component.
+        if (aInfo == null) {
+            homeIntent = mService.getSecondaryHomeIntent(null);
+            aInfo = resolveHomeActivity(userId, homeIntent);
+        }
+        return Pair.create(aInfo, homeIntent);
+    }
+
+    /**
+     * Retrieve all activities that match the given intent.
+     * The list should already ordered from best to worst matched.
+     * {@link android.content.pm.PackageManager#queryIntentActivities}
+     */
+    @VisibleForTesting
+    List<ResolveInfo> resolveActivities(int userId, Intent homeIntent) {
+        List<ResolveInfo> resolutions;
+        try {
+            final String resolvedType =
+                    homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver());
+            resolutions = AppGlobals.getPackageManager().queryIntentActivities(homeIntent,
+                    resolvedType, ActivityManagerService.STOCK_PM_FLAGS, userId).getList();
+
+        } catch (RemoteException e) {
+            resolutions = new ArrayList<>();
+        }
+        return resolutions;
+    }
+
     boolean resumeHomeActivity(ActivityRecord prev, String reason, int displayId) {
         if (!mService.isBooting() && !mService.isBooted()) {
             // Not ready yet!
@@ -457,6 +546,14 @@
             return true;
         }
 
+        final boolean deviceProvisioned = Settings.Global.getInt(
+                mService.mContext.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+        if (displayId != DEFAULT_DISPLAY && displayId != INVALID_DISPLAY && !deviceProvisioned) {
+            // Can't launch home on secondary display before device is provisioned.
+            return false;
+        }
+
         final ActivityDisplay display = getActivityDisplay(displayId);
         if (display == null || display.isRemoved() || !display.supportsSystemDecorations()) {
             // Can't launch home on display that doesn't support system decorations.
@@ -464,13 +561,9 @@
         }
 
         final boolean supportMultipleInstance = homeInfo.launchMode != LAUNCH_SINGLE_TASK
-                && homeInfo.launchMode != LAUNCH_SINGLE_INSTANCE
-                && homeInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q;
+                && homeInfo.launchMode != LAUNCH_SINGLE_INSTANCE;
         if (!supportMultipleInstance) {
-            // Can't launch home on other displays if it requested to be single instance. Also we
-            // don't allow home applications that target before Q to have multiple home activity
-            // instances because they may not be expected to have multiple home scenario and
-            // haven't explicitly request for single instance.
+            // Can't launch home on secondary displays if it requested to be single instance.
             return false;
         }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cf03d61..046c991 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -2116,30 +2116,33 @@
 
     private void startContentCaptureService(@NonNull Context context) {
 
-        // First check if it was explicitly enabled by Settings
-        boolean explicitlySupported = false;
+        // Check if it was explicitly enabled by Settings
         final String settings = Settings.Global.getString(context.getContentResolver(),
                 Settings.Global.CONTENT_CAPTURE_SERVICE_EXPLICITLY_ENABLED);
-        if (settings != null) {
-            explicitlySupported = Boolean.parseBoolean(settings);
-            if (explicitlySupported) {
+        if (settings == null) {
+            // Better be safe than sorry...
+            Slog.d(TAG, "ContentCaptureService disabled because its not set by OEM");
+            return;
+        }
+        switch (settings) {
+            case "always":
+                // Should be used only during development
                 Slog.d(TAG, "ContentCaptureService explicitly enabled by Settings");
-            } else {
-                Slog.d(TAG, "ContentCaptureService explicitly disabled by Settings");
+                break;
+            case "default":
+                // Default case: check if OEM overlaid the resource that defines the service.
+                final String serviceName = context.getString(
+                        com.android.internal.R.string.config_defaultContentCaptureService);
+                if (TextUtils.isEmpty(serviceName)) {
+                    Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid");
+                    return;
+                }
+                break;
+            default:
+                // Kill switch for OEMs
+                Slog.d(TAG, "ContentCaptureService disabled because its set to: " + settings);
                 return;
-            }
         }
-
-        // Then check if OEM overlaid the resource that defines the service.
-        if (!explicitlySupported) {
-            final String serviceName = context
-                    .getString(com.android.internal.R.string.config_defaultContentCaptureService);
-            if (TextUtils.isEmpty(serviceName)) {
-                Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid");
-                return;
-            }
-        }
-
         traceBeginAndSlog("StartContentCaptureService");
         mSystemServiceManager.startService(CONTENT_CAPTURE_MANAGER_SERVICE_CLASS);
         traceEnd();
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
index 83f66c5..b253e0a 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -23,6 +23,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -86,9 +87,7 @@
         mContext = application;
         mShadowContext = shadowOf(application);
 
-        // TODO(b/120212806): Hardcoding system user for now since most methods in BMS don't yet
-        // take an user parameter (and instead hardcode the system user).
-        mUserOneId = UserHandle.USER_SYSTEM;
+        mUserOneId = UserHandle.USER_SYSTEM + 1;
         mUserTwoId = mUserOneId + 1;
     }
 
@@ -176,9 +175,52 @@
         assertThat(serviceUsers.get(mUserOneId)).isEqualTo(mUserOneService);
     }
 
-    // TODO(b/120212806): When BMS methods take in a user parameter, modify unknown user tests to
-    // check that that we don't call the method on another registered user. Currently these tests
-    // have no registered users since we hardcode the system user in BMS.
+    /**
+     * Test that the backup services throws a {@link SecurityException} if the caller does not have
+     * INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
+     */
+    @Test
+    public void testGetServiceForUser_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
+
+        expectThrows(
+                SecurityException.class,
+                () ->
+                        backupManagerService.getServiceForUserIfCallerHasPermission(
+                                mUserOneId, "test"));
+    }
+
+    /**
+     * Test that the backup services does not throw a {@link SecurityException} if the caller has
+     * INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
+     */
+    @Test
+    public void testGetServiceForUserIfCallerHasPermission_withPermission_worksForNonCallingUser() {
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ true);
+
+        assertEquals(
+                mUserOneService,
+                backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test"));
+    }
+
+    /**
+     * Test that the backup services does not throw a {@link SecurityException} if the caller does
+     * not have INTERACT_ACROSS_USERS_FULL permission and passes in the calling user id.
+     */
+    @Test
+    public void testGetServiceForUserIfCallerHasPermission_withoutPermission_worksForCallingUser() {
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
+
+        assertEquals(
+                mUserOneService,
+                backupManagerService.getServiceForUserIfCallerHasPermission(mUserOneId, "test"));
+    }
 
     // ---------------------------------------------
     // Backup agent tests
@@ -189,8 +231,9 @@
     public void testDataChanged_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.dataChanged(TEST_PACKAGE);
+        backupManagerService.dataChanged(mUserOneId, TEST_PACKAGE);
 
         verify(mUserOneService).dataChanged(TEST_PACKAGE);
     }
@@ -198,9 +241,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testDataChanged_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.dataChanged(TEST_PACKAGE);
+        backupManagerService.dataChanged(mUserTwoId, TEST_PACKAGE);
 
         verify(mUserOneService, never()).dataChanged(TEST_PACKAGE);
     }
@@ -210,9 +255,10 @@
     public void testAgentConnected_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         IBinder agentBinder = mock(IBinder.class);
 
-        backupManagerService.agentConnected(TEST_PACKAGE, agentBinder);
+        backupManagerService.agentConnected(mUserOneId, TEST_PACKAGE, agentBinder);
 
         verify(mUserOneService).agentConnected(TEST_PACKAGE, agentBinder);
     }
@@ -220,10 +266,12 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testAgentConnected_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         IBinder agentBinder = mock(IBinder.class);
 
-        backupManagerService.agentConnected(TEST_PACKAGE, agentBinder);
+        backupManagerService.agentConnected(mUserTwoId, TEST_PACKAGE, agentBinder);
 
         verify(mUserOneService, never()).agentConnected(TEST_PACKAGE, agentBinder);
     }
@@ -233,8 +281,9 @@
     public void testAgentDisconnected_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.agentDisconnected(TEST_PACKAGE);
+        backupManagerService.agentDisconnected(mUserOneId, TEST_PACKAGE);
 
         verify(mUserOneService).agentDisconnected(TEST_PACKAGE);
     }
@@ -242,9 +291,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testAgentDisconnected_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.agentDisconnected(TEST_PACKAGE);
+        backupManagerService.agentDisconnected(mUserTwoId, TEST_PACKAGE);
 
         verify(mUserOneService, never()).agentDisconnected(TEST_PACKAGE);
     }
@@ -254,8 +305,9 @@
     public void testOpComplete_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.opComplete(/* token */ 0, /* result */ 0L);
+        backupManagerService.opComplete(mUserOneId, /* token */ 0, /* result */ 0L);
 
         verify(mUserOneService).opComplete(/* token */ 0, /* result */ 0L);
     }
@@ -263,9 +315,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testOpComplete_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.opComplete(/* token */ 0, /* result */ 0L);
+        backupManagerService.opComplete(mUserTwoId, /* token */ 0, /* result */ 0L);
 
         verify(mUserOneService, never()).opComplete(/* token */ 0, /* result */ 0L);
     }
@@ -279,9 +333,10 @@
     public void testInitializeTransports_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         String[] transports = {TEST_TRANSPORT};
 
-        backupManagerService.initializeTransports(transports, /* observer */ null);
+        backupManagerService.initializeTransports(mUserOneId, transports, /* observer */ null);
 
         verify(mUserOneService).initializeTransports(transports, /* observer */ null);
     }
@@ -289,10 +344,12 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testInitializeTransports_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         String[] transports = {TEST_TRANSPORT};
 
-        backupManagerService.initializeTransports(transports, /* observer */ null);
+        backupManagerService.initializeTransports(mUserTwoId, transports, /* observer */ null);
 
         verify(mUserOneService, never()).initializeTransports(transports, /* observer */ null);
     }
@@ -302,8 +359,9 @@
     public void testClearBackupData_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.clearBackupData(TEST_TRANSPORT, TEST_PACKAGE);
+        backupManagerService.clearBackupData(mUserOneId, TEST_TRANSPORT, TEST_PACKAGE);
 
         verify(mUserOneService).clearBackupData(TEST_TRANSPORT, TEST_PACKAGE);
     }
@@ -311,9 +369,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testClearBackupData_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.clearBackupData(TEST_TRANSPORT, TEST_PACKAGE);
+        backupManagerService.clearBackupData(mUserTwoId, TEST_TRANSPORT, TEST_PACKAGE);
 
         verify(mUserOneService, never()).clearBackupData(TEST_TRANSPORT, TEST_PACKAGE);
     }
@@ -323,8 +383,9 @@
     public void testGetCurrentTransport_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getCurrentTransport();
+        backupManagerService.getCurrentTransport(mUserOneId);
 
         verify(mUserOneService).getCurrentTransport();
     }
@@ -332,9 +393,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testGetCurrentTransport_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getCurrentTransport();
+        backupManagerService.getCurrentTransport(mUserTwoId);
 
         verify(mUserOneService, never()).getCurrentTransport();
     }
@@ -345,8 +408,9 @@
             throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getCurrentTransportComponent();
+        backupManagerService.getCurrentTransportComponent(mUserOneId);
 
         verify(mUserOneService).getCurrentTransportComponent();
     }
@@ -355,9 +419,11 @@
     @Test
     public void testGetCurrentTransportComponent_onUnknownUser_doesNotPropagateCall()
             throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getCurrentTransportComponent();
+        backupManagerService.getCurrentTransportComponent(mUserTwoId);
 
         verify(mUserOneService, never()).getCurrentTransportComponent();
     }
@@ -367,8 +433,9 @@
     public void testListAllTransports_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.listAllTransports();
+        backupManagerService.listAllTransports(mUserOneId);
 
         verify(mUserOneService).listAllTransports();
     }
@@ -376,9 +443,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testListAllTransports_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.listAllTransports();
+        backupManagerService.listAllTransports(mUserTwoId);
 
         verify(mUserOneService, never()).listAllTransports();
     }
@@ -389,8 +458,9 @@
             throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.listAllTransportComponents();
+        backupManagerService.listAllTransportComponents(mUserOneId);
 
         verify(mUserOneService).listAllTransportComponents();
     }
@@ -399,32 +469,13 @@
     @Test
     public void testListAllTransportComponents_onUnknownUser_doesNotPropagateCall()
             throws Exception {
-        BackupManagerService backupManagerService = createService();
-
-        backupManagerService.listAllTransportComponents();
-
-        verify(mUserOneService, never()).listAllTransportComponents();
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
-    public void testGetTransportWhitelist_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getTransportWhitelist();
+        backupManagerService.listAllTransportComponents(mUserTwoId);
 
-        verify(mUserOneService).getTransportWhitelist();
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testGetTransportWhitelist_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
-
-        backupManagerService.getTransportWhitelist();
-
-        verify(mUserOneService, never()).getTransportWhitelist();
+        verify(mUserOneService, never()).listAllTransportComponents();
     }
 
     /** Test that the backup service routes methods correctly to the user that requests it. */
@@ -433,11 +484,13 @@
             throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         TransportData transport = backupTransport();
         Intent configurationIntent = new Intent();
         Intent dataManagementIntent = new Intent();
 
         backupManagerService.updateTransportAttributes(
+                mUserOneId,
                 transport.getTransportComponent(),
                 transport.transportName,
                 configurationIntent,
@@ -459,12 +512,15 @@
     @Test
     public void testUpdateTransportAttributes_onUnknownUser_doesNotPropagateCall()
             throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         TransportData transport = backupTransport();
         Intent configurationIntent = new Intent();
         Intent dataManagementIntent = new Intent();
 
         backupManagerService.updateTransportAttributes(
+                mUserTwoId,
                 transport.getTransportComponent(),
                 transport.transportName,
                 configurationIntent,
@@ -487,8 +543,9 @@
     public void testSelectBackupTransport_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.selectBackupTransport(TEST_TRANSPORT);
+        backupManagerService.selectBackupTransport(mUserOneId, TEST_TRANSPORT);
 
         verify(mUserOneService).selectBackupTransport(TEST_TRANSPORT);
     }
@@ -496,9 +553,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testSelectBackupTransport_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.selectBackupTransport(TEST_TRANSPORT);
+        backupManagerService.selectBackupTransport(mUserTwoId, TEST_TRANSPORT);
 
         verify(mUserOneService, never()).selectBackupTransport(TEST_TRANSPORT);
     }
@@ -508,11 +567,12 @@
     public void testSelectTransportAsync_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         TransportData transport = backupTransport();
         ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
 
         backupManagerService.selectBackupTransportAsync(
-                transport.getTransportComponent(), callback);
+                mUserOneId, transport.getTransportComponent(), callback);
 
         verify(mUserOneService)
                 .selectBackupTransportAsync(transport.getTransportComponent(), callback);
@@ -522,12 +582,14 @@
     @Test
     public void testSelectBackupTransportAsync_onUnknownUser_doesNotPropagateCall()
             throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         TransportData transport = backupTransport();
         ISelectBackupTransportCallback callback = mock(ISelectBackupTransportCallback.class);
 
         backupManagerService.selectBackupTransportAsync(
-                transport.getTransportComponent(), callback);
+                mUserTwoId, transport.getTransportComponent(), callback);
 
         verify(mUserOneService, never())
                 .selectBackupTransportAsync(transport.getTransportComponent(), callback);
@@ -538,8 +600,9 @@
     public void testGetConfigurationIntent_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getConfigurationIntent(TEST_TRANSPORT);
+        backupManagerService.getConfigurationIntent(mUserOneId, TEST_TRANSPORT);
 
         verify(mUserOneService).getConfigurationIntent(TEST_TRANSPORT);
     }
@@ -547,9 +610,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testGetConfigurationIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getConfigurationIntent(TEST_TRANSPORT);
+        backupManagerService.getConfigurationIntent(mUserTwoId, TEST_TRANSPORT);
 
         verify(mUserOneService, never()).getConfigurationIntent(TEST_TRANSPORT);
     }
@@ -559,8 +624,9 @@
     public void testGetDestinationString_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getDestinationString(TEST_TRANSPORT);
+        backupManagerService.getDestinationString(mUserOneId, TEST_TRANSPORT);
 
         verify(mUserOneService).getDestinationString(TEST_TRANSPORT);
     }
@@ -568,9 +634,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testGetDestinationString_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getDestinationString(TEST_TRANSPORT);
+        backupManagerService.getDestinationString(mUserTwoId, TEST_TRANSPORT);
 
         verify(mUserOneService, never()).getDestinationString(TEST_TRANSPORT);
     }
@@ -580,8 +648,9 @@
     public void testGetDataManagementIntent_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getDataManagementIntent(TEST_TRANSPORT);
+        backupManagerService.getDataManagementIntent(mUserOneId, TEST_TRANSPORT);
 
         verify(mUserOneService).getDataManagementIntent(TEST_TRANSPORT);
     }
@@ -589,9 +658,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testGetDataManagementIntent_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getDataManagementIntent(TEST_TRANSPORT);
+        backupManagerService.getDataManagementIntent(mUserTwoId, TEST_TRANSPORT);
 
         verify(mUserOneService, never()).getDataManagementIntent(TEST_TRANSPORT);
     }
@@ -601,8 +672,9 @@
     public void testGetDataManagementLabel_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getDataManagementLabel(TEST_TRANSPORT);
+        backupManagerService.getDataManagementLabel(mUserOneId, TEST_TRANSPORT);
 
         verify(mUserOneService).getDataManagementLabel(TEST_TRANSPORT);
     }
@@ -610,9 +682,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testGetDataManagementLabel_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getDataManagementLabel(TEST_TRANSPORT);
+        backupManagerService.getDataManagementLabel(mUserTwoId, TEST_TRANSPORT);
 
         verify(mUserOneService, never()).getDataManagementLabel(TEST_TRANSPORT);
     }
@@ -620,7 +694,6 @@
     // ---------------------------------------------
     // Settings tests
     // ---------------------------------------------
-
     /**
      * Test that the backup services throws a {@link SecurityException} if the caller does not have
      * INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
@@ -681,8 +754,9 @@
     public void testSetAutoRestore_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.setAutoRestore(true);
+        backupManagerService.setAutoRestore(mUserOneId, true);
 
         verify(mUserOneService).setAutoRestore(true);
     }
@@ -690,66 +764,17 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testSetAutoRestore_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.setAutoRestore(true);
+        backupManagerService.setAutoRestore(mUserTwoId, true);
 
         verify(mUserOneService, never()).setAutoRestore(true);
     }
 
     /** Test that the backup service routes methods correctly to the user that requests it. */
     @Test
-    public void testSetBackupProvisioned_onRegisteredUser_callsMethodForUser() throws Exception {
-        BackupManagerService backupManagerService =
-                createServiceAndRegisterUser(mUserOneId, mUserOneService);
-
-        backupManagerService.setBackupProvisioned(true);
-
-        verify(mUserOneService).setBackupProvisioned(true);
-    }
-
-    /** Test that the backup service does not route methods for non-registered users. */
-    @Test
-    public void testSetBackupProvisioned_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
-
-        backupManagerService.setBackupProvisioned(true);
-
-        verify(mUserOneService, never()).setBackupProvisioned(true);
-    }
-
-    /**
-     * Test that the backup services throws a {@link SecurityException} if the caller does not have
-     * INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
-     */
-    @Test
-    public void testIsBackupEnabled_withoutPermission_throwsSecurityExceptionForNonCallingUser() {
-        BackupManagerService backupManagerService =
-                createServiceAndRegisterUser(mUserOneId, mUserOneService);
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
-
-        expectThrows(
-                SecurityException.class, () -> backupManagerService.isBackupEnabled(mUserTwoId));
-    }
-
-    /**
-     * Test that the backup service does not throw a {@link SecurityException} if the caller has
-     * INTERACT_ACROSS_USERS_FULL permission and passes a different user id.
-     */
-    @Test
-    public void testIsBackupEnabled_withPermission_propagatesForNonCallingUser() {
-        BackupManagerService backupManagerService =
-                createServiceAndRegisterUser(mUserOneId, mUserOneService);
-        backupManagerService.startServiceForUser(mUserTwoId, mUserTwoService);
-        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ true);
-
-        backupManagerService.isBackupEnabled(mUserTwoId);
-
-        verify(mUserTwoService).isBackupEnabled();
-    }
-
-    /** Test that the backup service routes methods correctly to the user that requests it. */
-    @Test
     public void testIsBackupEnabled_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
@@ -781,8 +806,9 @@
     public void testIsAppEligibleForBackup_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.isAppEligibleForBackup(TEST_PACKAGE);
+        backupManagerService.isAppEligibleForBackup(mUserOneId, TEST_PACKAGE);
 
         verify(mUserOneService).isAppEligibleForBackup(TEST_PACKAGE);
     }
@@ -790,9 +816,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testIsAppEligibleForBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.isAppEligibleForBackup(TEST_PACKAGE);
+        backupManagerService.isAppEligibleForBackup(mUserTwoId, TEST_PACKAGE);
 
         verify(mUserOneService, never()).isAppEligibleForBackup(TEST_PACKAGE);
     }
@@ -803,9 +831,10 @@
             throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         String[] packages = {TEST_PACKAGE};
 
-        backupManagerService.filterAppsEligibleForBackup(packages);
+        backupManagerService.filterAppsEligibleForBackup(mUserOneId, packages);
 
         verify(mUserOneService).filterAppsEligibleForBackup(packages);
     }
@@ -814,10 +843,12 @@
     @Test
     public void testFilterAppsEligibleForBackup_onUnknownUser_doesNotPropagateCall()
             throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         String[] packages = {TEST_PACKAGE};
 
-        backupManagerService.filterAppsEligibleForBackup(packages);
+        backupManagerService.filterAppsEligibleForBackup(mUserTwoId, packages);
 
         verify(mUserOneService, never()).filterAppsEligibleForBackup(packages);
     }
@@ -1001,7 +1032,7 @@
     @Test
     public void testBeginFullBackup_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
-                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+                createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
         FullBackupJob job = new FullBackupJob();
 
         backupManagerService.beginFullBackup(job);
@@ -1024,7 +1055,7 @@
     @Test
     public void testEndFullBackup_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
-                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+                createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
 
         backupManagerService.endFullBackup();
 
@@ -1046,9 +1077,10 @@
     public void testFullTransportBackup_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         String[] packages = {TEST_PACKAGE};
 
-        backupManagerService.fullTransportBackup(packages);
+        backupManagerService.fullTransportBackup(mUserOneId, packages);
 
         verify(mUserOneService).fullTransportBackup(packages);
     }
@@ -1056,10 +1088,12 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testFullTransportBackup_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         String[] packages = {TEST_PACKAGE};
 
-        backupManagerService.fullTransportBackup(packages);
+        backupManagerService.fullTransportBackup(mUserTwoId, packages);
 
         verify(mUserOneService, never()).fullTransportBackup(packages);
     }
@@ -1073,8 +1107,9 @@
     public void testRestoreAtInstall_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.restoreAtInstall(TEST_PACKAGE, /* token */ 0);
+        backupManagerService.restoreAtInstall(mUserOneId, TEST_PACKAGE, /* token */ 0);
 
         verify(mUserOneService).restoreAtInstall(TEST_PACKAGE, /* token */ 0);
     }
@@ -1082,9 +1117,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testRestoreAtInstall_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.restoreAtInstall(TEST_PACKAGE, /* token */ 0);
+        backupManagerService.restoreAtInstall(mUserTwoId, TEST_PACKAGE, /* token */ 0);
 
         verify(mUserOneService, never()).restoreAtInstall(TEST_PACKAGE, /* token */ 0);
     }
@@ -1094,8 +1131,9 @@
     public void testBeginRestoreSession_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT);
+        backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT);
 
         verify(mUserOneService).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT);
     }
@@ -1103,9 +1141,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testBeginRestoreSession_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT);
+        backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT);
 
         verify(mUserOneService, never()).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT);
     }
@@ -1116,8 +1156,9 @@
             throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getAvailableRestoreToken(TEST_PACKAGE);
+        backupManagerService.getAvailableRestoreToken(mUserOneId, TEST_PACKAGE);
 
         verify(mUserOneService).getAvailableRestoreToken(TEST_PACKAGE);
     }
@@ -1125,9 +1166,11 @@
     /** Test that the backup service does not route methods for non-registered users. */
     @Test
     public void testGetAvailableRestoreToken_onUnknownUser_doesNotPropagateCall() throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
 
-        backupManagerService.getAvailableRestoreToken(TEST_PACKAGE);
+        backupManagerService.getAvailableRestoreToken(mUserTwoId, TEST_PACKAGE);
 
         verify(mUserOneService, never()).getAvailableRestoreToken(TEST_PACKAGE);
     }
@@ -1140,7 +1183,7 @@
     @Test
     public void testSetBackupPassword_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
-                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+                createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
 
         backupManagerService.setBackupPassword("currentPassword", "newPassword");
 
@@ -1161,7 +1204,7 @@
     @Test
     public void testHasBackupPassword_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
-                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+                createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
 
         backupManagerService.hasBackupPassword();
 
@@ -1377,10 +1420,16 @@
             throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false);
         IFullBackupRestoreObserver observer = mock(IFullBackupRestoreObserver.class);
 
         backupManagerService.acknowledgeAdbBackupOrRestore(
-                /* token */ 0, /* allow */ true, "currentPassword", "encryptionPassword", observer);
+                mUserOneId,
+                /* token */ 0,
+                /* allow */ true,
+                "currentPassword",
+                "encryptionPassword",
+                observer);
 
         verify(mUserOneService)
                 .acknowledgeAdbBackupOrRestore(
@@ -1395,11 +1444,18 @@
     @Test
     public void testAcknowledgeAdbBackupOrRestore_onUnknownUser_doesNotPropagateCall()
             throws Exception {
-        BackupManagerService backupManagerService = createService();
+        BackupManagerService backupManagerService =
+                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+        setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false);
         IFullBackupRestoreObserver observer = mock(IFullBackupRestoreObserver.class);
 
         backupManagerService.acknowledgeAdbBackupOrRestore(
-                /* token */ 0, /* allow */ true, "currentPassword", "encryptionPassword", observer);
+                mUserTwoId,
+                /* token */ 0,
+                /* allow */ true,
+                "currentPassword",
+                "encryptionPassword",
+                observer);
 
         verify(mUserOneService, never())
                 .acknowledgeAdbBackupOrRestore(
@@ -1418,7 +1474,7 @@
     @Test
     public void testDump_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
-                createServiceAndRegisterUser(mUserOneId, mUserOneService);
+                createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
         File testFile = new File(mContext.getFilesDir(), "test");
         testFile.createNewFile();
         FileDescriptor fileDescriptor = new FileDescriptor();
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 5615dff..0851cf3 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -307,14 +307,17 @@
 
         mTrampoline.dataChangedForUser(mUserId, PACKAGE_NAME);
 
-        verify(mBackupManagerServiceMock).dataChanged(PACKAGE_NAME);
+        verify(mBackupManagerServiceMock).dataChanged(mUserId, PACKAGE_NAME);
     }
 
     @Test
     public void dataChanged_forwarded() throws RemoteException {
+        TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         mTrampoline.dataChanged(PACKAGE_NAME);
-        verify(mBackupManagerServiceMock).dataChanged(PACKAGE_NAME);
+
+        verify(mBackupManagerServiceMock).dataChanged(mUserId, PACKAGE_NAME);
     }
 
     @Test
@@ -329,14 +332,17 @@
 
         mTrampoline.clearBackupDataForUser(mUserId, TRANSPORT_NAME, PACKAGE_NAME);
 
-        verify(mBackupManagerServiceMock).clearBackupData(TRANSPORT_NAME, PACKAGE_NAME);
+        verify(mBackupManagerServiceMock).clearBackupData(mUserId, TRANSPORT_NAME, PACKAGE_NAME);
     }
 
     @Test
     public void clearBackupData_forwarded() throws RemoteException {
+        TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         mTrampoline.clearBackupData(TRANSPORT_NAME, PACKAGE_NAME);
-        verify(mBackupManagerServiceMock).clearBackupData(TRANSPORT_NAME, PACKAGE_NAME);
+
+        verify(mBackupManagerServiceMock).clearBackupData(mUserId, TRANSPORT_NAME, PACKAGE_NAME);
     }
 
     @Test
@@ -351,14 +357,17 @@
 
         mTrampoline.agentConnectedForUser(mUserId, PACKAGE_NAME, mAgentMock);
 
-        verify(mBackupManagerServiceMock).agentConnected(PACKAGE_NAME, mAgentMock);
+        verify(mBackupManagerServiceMock).agentConnected(mUserId, PACKAGE_NAME, mAgentMock);
     }
 
     @Test
     public void agentConnected_forwarded() throws RemoteException {
+        TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         mTrampoline.agentConnected(PACKAGE_NAME, mAgentMock);
-        verify(mBackupManagerServiceMock).agentConnected(PACKAGE_NAME, mAgentMock);
+
+        verify(mBackupManagerServiceMock).agentConnected(mUserId, PACKAGE_NAME, mAgentMock);
     }
 
     @Test
@@ -373,14 +382,17 @@
 
         mTrampoline.agentDisconnectedForUser(mUserId, PACKAGE_NAME);
 
-        verify(mBackupManagerServiceMock).agentDisconnected(PACKAGE_NAME);
+        verify(mBackupManagerServiceMock).agentDisconnected(mUserId, PACKAGE_NAME);
     }
 
     @Test
     public void agentDisconnected_forwarded() throws RemoteException {
+        TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         mTrampoline.agentDisconnected(PACKAGE_NAME);
-        verify(mBackupManagerServiceMock).agentDisconnected(PACKAGE_NAME);
+
+        verify(mBackupManagerServiceMock).agentDisconnected(mUserId, PACKAGE_NAME);
     }
 
     @Test
@@ -395,14 +407,17 @@
 
         mTrampoline.restoreAtInstallForUser(mUserId, PACKAGE_NAME, 123);
 
-        verify(mBackupManagerServiceMock).restoreAtInstall(PACKAGE_NAME, 123);
+        verify(mBackupManagerServiceMock).restoreAtInstall(mUserId, PACKAGE_NAME, 123);
     }
 
     @Test
     public void restoreAtInstall_forwarded() throws RemoteException {
+        TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         mTrampoline.restoreAtInstall(PACKAGE_NAME, 123);
-        verify(mBackupManagerServiceMock).restoreAtInstall(PACKAGE_NAME, 123);
+
+        verify(mBackupManagerServiceMock).restoreAtInstall(mUserId, PACKAGE_NAME, 123);
     }
 
     @Test
@@ -442,14 +457,17 @@
 
         mTrampoline.setAutoRestoreForUser(mUserId, true);
 
-        verify(mBackupManagerServiceMock).setAutoRestore(true);
+        verify(mBackupManagerServiceMock).setAutoRestore(mUserId, true);
     }
 
     @Test
     public void setAutoRestore_forwarded() throws RemoteException {
+        TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         mTrampoline.setAutoRestore(true);
-        verify(mBackupManagerServiceMock).setAutoRestore(true);
+
+        verify(mBackupManagerServiceMock).setAutoRestore(mUserId, true);
     }
 
     @Test
@@ -462,7 +480,7 @@
     public void setBackupProvisioned_forwarded() throws RemoteException {
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
         mTrampoline.setBackupProvisioned(true);
-        verify(mBackupManagerServiceMock).setBackupProvisioned(true);
+        verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
     @Test
@@ -568,8 +586,10 @@
     @Test
     public void fullTransportBackupForUser_forwarded() throws RemoteException {
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         mTrampoline.fullTransportBackupForUser(mUserId, PACKAGE_NAMES);
-        verify(mBackupManagerServiceMock).fullTransportBackup(PACKAGE_NAMES);
+
+        verify(mBackupManagerServiceMock).fullTransportBackup(mUserId, PACKAGE_NAMES);
     }
 
     @Test
@@ -605,17 +625,32 @@
                 ENCRYPTION_PASSWORD,
                 mFullBackupRestoreObserverMock);
 
-        verify(mBackupManagerServiceMock).acknowledgeAdbBackupOrRestore(123, true, CURRENT_PASSWORD,
-                ENCRYPTION_PASSWORD, mFullBackupRestoreObserverMock);
+        verify(mBackupManagerServiceMock)
+                .acknowledgeAdbBackupOrRestore(
+                        mUserId,
+                        123,
+                        true,
+                        CURRENT_PASSWORD,
+                        ENCRYPTION_PASSWORD,
+                        mFullBackupRestoreObserverMock);
     }
 
     @Test
     public void acknowledgeFullBackupOrRestore_forwarded() throws RemoteException {
+        TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         mTrampoline.acknowledgeFullBackupOrRestore(123, true, CURRENT_PASSWORD, ENCRYPTION_PASSWORD,
                 mFullBackupRestoreObserverMock);
-        verify(mBackupManagerServiceMock).acknowledgeAdbBackupOrRestore(123, true, CURRENT_PASSWORD,
-                ENCRYPTION_PASSWORD, mFullBackupRestoreObserverMock);
+
+        verify(mBackupManagerServiceMock)
+                .acknowledgeAdbBackupOrRestore(
+                        mUserId,
+                        123,
+                        true,
+                        CURRENT_PASSWORD,
+                        ENCRYPTION_PASSWORD,
+                        mFullBackupRestoreObserverMock);
     }
 
     @Test
@@ -626,22 +661,21 @@
 
     @Test
     public void getCurrentTransportForUser_forwarded() throws RemoteException {
-        when(mBackupManagerServiceMock.getCurrentTransport()).thenReturn(TRANSPORT_NAME);
+        when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME);
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
 
         assertEquals(TRANSPORT_NAME, mTrampoline.getCurrentTransportForUser(mUserId));
-
-        verify(mBackupManagerServiceMock).getCurrentTransport();
+        verify(mBackupManagerServiceMock).getCurrentTransport(mUserId);
     }
 
     @Test
     public void getCurrentTransport_forwarded() throws RemoteException {
-        when(mBackupManagerServiceMock.getCurrentTransport()).thenReturn(TRANSPORT_NAME);
-
+        TrampolineTestable.sCallingUserId = mUserId;
+        when(mBackupManagerServiceMock.getCurrentTransport(mUserId)).thenReturn(TRANSPORT_NAME);
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
 
         assertEquals(TRANSPORT_NAME, mTrampoline.getCurrentTransport());
-        verify(mBackupManagerServiceMock).getCurrentTransport();
+        verify(mBackupManagerServiceMock).getCurrentTransport(mUserId);
     }
 
     @Test
@@ -652,21 +686,22 @@
 
     @Test
     public void listAllTransportsForUser_forwarded() throws RemoteException {
-        when(mBackupManagerServiceMock.listAllTransports()).thenReturn(TRANSPORTS);
+        when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS);
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
 
         assertEquals(TRANSPORTS, mTrampoline.listAllTransportsForUser(mUserId));
-        verify(mBackupManagerServiceMock).listAllTransports();
+        verify(mBackupManagerServiceMock).listAllTransports(mUserId);
     }
 
 
     @Test
     public void listAllTransports_forwarded() throws RemoteException {
-        when(mBackupManagerServiceMock.listAllTransports()).thenReturn(TRANSPORTS);
-
+        TrampolineTestable.sCallingUserId = mUserId;
+        when(mBackupManagerServiceMock.listAllTransports(mUserId)).thenReturn(TRANSPORTS);
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         assertEquals(TRANSPORTS, mTrampoline.listAllTransports());
-        verify(mBackupManagerServiceMock).listAllTransports();
+        verify(mBackupManagerServiceMock).listAllTransports(mUserId);
     }
 
     @Test
@@ -678,12 +713,12 @@
 
     @Test
     public void listAllTransportComponentsForUser_forwarded() throws RemoteException {
-        when(mBackupManagerServiceMock.listAllTransportComponents()).thenReturn(
+        when(mBackupManagerServiceMock.listAllTransportComponents(mUserId)).thenReturn(
                 TRANSPORT_COMPONENTS);
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
 
         assertEquals(TRANSPORT_COMPONENTS, mTrampoline.listAllTransportComponentsForUser(mUserId));
-        verify(mBackupManagerServiceMock).listAllTransportComponents();
+        verify(mBackupManagerServiceMock).listAllTransportComponents(mUserId);
     }
 
     @Test
@@ -730,8 +765,15 @@
                 null,
                 "Data Management");
 
-        verify(mBackupManagerServiceMock).updateTransportAttributes(TRANSPORT_COMPONENT_NAME,
-                TRANSPORT_NAME, null, "Transport Destination", null, "Data Management");
+        verify(mBackupManagerServiceMock)
+                .updateTransportAttributes(
+                        mUserId,
+                        TRANSPORT_COMPONENT_NAME,
+                        TRANSPORT_NAME,
+                        null,
+                        "Transport Destination",
+                        null,
+                        "Data Management");
     }
 
     @Test
@@ -746,14 +788,17 @@
 
         mTrampoline.selectBackupTransportForUser(mUserId, TRANSPORT_NAME);
 
-        verify(mBackupManagerServiceMock).selectBackupTransport(TRANSPORT_NAME);
+        verify(mBackupManagerServiceMock).selectBackupTransport(mUserId, TRANSPORT_NAME);
     }
 
     @Test
     public void selectBackupTransport_forwarded() throws RemoteException {
+        TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         mTrampoline.selectBackupTransport(TRANSPORT_NAME);
-        verify(mBackupManagerServiceMock).selectBackupTransport(TRANSPORT_NAME);
+
+        verify(mBackupManagerServiceMock).selectBackupTransport(mUserId, TRANSPORT_NAME);
     }
 
     @Test
@@ -829,8 +874,8 @@
 
         mTrampoline.selectBackupTransportAsyncForUser(mUserId, TRANSPORT_COMPONENT_NAME, null);
 
-        verify(mBackupManagerServiceMock).selectBackupTransportAsync(TRANSPORT_COMPONENT_NAME,
-                null);
+        verify(mBackupManagerServiceMock)
+                .selectBackupTransportAsync(mUserId, TRANSPORT_COMPONENT_NAME, null);
     }
 
     @Test
@@ -842,25 +887,26 @@
     @Test
     public void getConfigurationIntentForUser_forwarded() throws RemoteException {
         Intent configurationIntentStub = new Intent();
-        when(mBackupManagerServiceMock.getConfigurationIntent(TRANSPORT_NAME)).thenReturn(
+        when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 configurationIntentStub);
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
 
         assertEquals(
                 configurationIntentStub,
                 mTrampoline.getConfigurationIntentForUser(mUserId, TRANSPORT_NAME));
-        verify(mBackupManagerServiceMock).getConfigurationIntent(TRANSPORT_NAME);
+        verify(mBackupManagerServiceMock).getConfigurationIntent(mUserId, TRANSPORT_NAME);
     }
 
     @Test
     public void getConfigurationIntent_forwarded() throws RemoteException {
+        TrampolineTestable.sCallingUserId = mUserId;
         Intent configurationIntentStub = new Intent();
-        when(mBackupManagerServiceMock.getConfigurationIntent(TRANSPORT_NAME)).thenReturn(
+        when(mBackupManagerServiceMock.getConfigurationIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 configurationIntentStub);
-
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         assertEquals(configurationIntentStub, mTrampoline.getConfigurationIntent(TRANSPORT_NAME));
-        verify(mBackupManagerServiceMock).getConfigurationIntent(TRANSPORT_NAME);
+        verify(mBackupManagerServiceMock).getConfigurationIntent(mUserId, TRANSPORT_NAME);
     }
 
     @Test
@@ -871,24 +917,25 @@
 
     @Test
     public void getDestinationStringForUser_forwarded() throws RemoteException {
-        when(mBackupManagerServiceMock.getDestinationString(TRANSPORT_NAME)).thenReturn(
+        when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn(
                 DESTINATION_STRING);
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
 
         assertEquals(
                 DESTINATION_STRING,
                 mTrampoline.getDestinationStringForUser(mUserId, TRANSPORT_NAME));
-        verify(mBackupManagerServiceMock).getDestinationString(TRANSPORT_NAME);
+        verify(mBackupManagerServiceMock).getDestinationString(mUserId, TRANSPORT_NAME);
     }
 
     @Test
     public void getDestinationString_forwarded() throws RemoteException {
-        when(mBackupManagerServiceMock.getDestinationString(TRANSPORT_NAME)).thenReturn(
+        TrampolineTestable.sCallingUserId = mUserId;
+        when(mBackupManagerServiceMock.getDestinationString(mUserId, TRANSPORT_NAME)).thenReturn(
                 DESTINATION_STRING);
 
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
         assertEquals(DESTINATION_STRING, mTrampoline.getDestinationString(TRANSPORT_NAME));
-        verify(mBackupManagerServiceMock).getDestinationString(TRANSPORT_NAME);
+        verify(mBackupManagerServiceMock).getDestinationString(mUserId, TRANSPORT_NAME);
     }
 
     @Test
@@ -900,25 +947,26 @@
     @Test
     public void getDataManagementIntentForUser_forwarded() throws RemoteException {
         Intent dataManagementIntent = new Intent();
-        when(mBackupManagerServiceMock.getDataManagementIntent(TRANSPORT_NAME)).thenReturn(
+        when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 dataManagementIntent);
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
 
         assertEquals(
                 dataManagementIntent,
                 mTrampoline.getDataManagementIntentForUser(mUserId, TRANSPORT_NAME));
-        verify(mBackupManagerServiceMock).getDataManagementIntent(TRANSPORT_NAME);
+        verify(mBackupManagerServiceMock).getDataManagementIntent(mUserId, TRANSPORT_NAME);
     }
 
     @Test
     public void getDataManagementIntent_forwarded() throws RemoteException {
+        TrampolineTestable.sCallingUserId = mUserId;
         Intent dataManagementIntent = new Intent();
-        when(mBackupManagerServiceMock.getDataManagementIntent(TRANSPORT_NAME)).thenReturn(
+        when(mBackupManagerServiceMock.getDataManagementIntent(mUserId, TRANSPORT_NAME)).thenReturn(
                 dataManagementIntent);
-
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         assertEquals(dataManagementIntent, mTrampoline.getDataManagementIntent(TRANSPORT_NAME));
-        verify(mBackupManagerServiceMock).getDataManagementIntent(TRANSPORT_NAME);
+        verify(mBackupManagerServiceMock).getDataManagementIntent(mUserId, TRANSPORT_NAME);
     }
 
     @Test
@@ -929,24 +977,25 @@
 
     @Test
     public void getDataManagementLabelForUser_forwarded() throws RemoteException {
-        when(mBackupManagerServiceMock.getDataManagementLabel(TRANSPORT_NAME)).thenReturn(
+        when(mBackupManagerServiceMock.getDataManagementLabel(mUserId, TRANSPORT_NAME)).thenReturn(
                 DATA_MANAGEMENT_LABEL);
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
 
         assertEquals(
                 DATA_MANAGEMENT_LABEL,
                 mTrampoline.getDataManagementLabelForUser(mUserId, TRANSPORT_NAME));
-        verify(mBackupManagerServiceMock).getDataManagementLabel(TRANSPORT_NAME);
+        verify(mBackupManagerServiceMock).getDataManagementLabel(mUserId, TRANSPORT_NAME);
     }
 
     @Test
     public void getDataManagementLabel_forwarded() throws RemoteException {
-        when(mBackupManagerServiceMock.getDataManagementLabel(TRANSPORT_NAME)).thenReturn(
+        TrampolineTestable.sCallingUserId = mUserId;
+        when(mBackupManagerServiceMock.getDataManagementLabel(mUserId, TRANSPORT_NAME)).thenReturn(
                 DATA_MANAGEMENT_LABEL);
-
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         assertEquals(DATA_MANAGEMENT_LABEL, mTrampoline.getDataManagementLabel(TRANSPORT_NAME));
-        verify(mBackupManagerServiceMock).getDataManagementLabel(TRANSPORT_NAME);
+        verify(mBackupManagerServiceMock).getDataManagementLabel(mUserId, TRANSPORT_NAME);
     }
 
     @Test
@@ -961,7 +1010,8 @@
 
         mTrampoline.beginRestoreSessionForUser(mUserId, PACKAGE_NAME, TRANSPORT_NAME);
 
-        verify(mBackupManagerServiceMock).beginRestoreSession(PACKAGE_NAME, TRANSPORT_NAME);
+        verify(mBackupManagerServiceMock)
+                .beginRestoreSession(mUserId, PACKAGE_NAME, TRANSPORT_NAME);
     }
 
     @Test
@@ -972,9 +1022,12 @@
 
     @Test
     public void opComplete_forwarded() throws RemoteException {
+        TrampolineTestable.sCallingUserId = mUserId;
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
+
         mTrampoline.opComplete(1, 2);
-        verify(mBackupManagerServiceMock).opComplete(1, 2);
+
+        verify(mBackupManagerServiceMock).opComplete(mUserId, 1, 2);
     }
 
     @Test
@@ -986,11 +1039,12 @@
 
     @Test
     public void getAvailableRestoreTokenForUser_forwarded() throws RemoteException {
-        when(mBackupManagerServiceMock.getAvailableRestoreToken(PACKAGE_NAME)).thenReturn(123L);
+        when(mBackupManagerServiceMock.getAvailableRestoreToken(mUserId, PACKAGE_NAME))
+                .thenReturn(123L);
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
 
         assertEquals(123, mTrampoline.getAvailableRestoreTokenForUser(mUserId, PACKAGE_NAME));
-        verify(mBackupManagerServiceMock).getAvailableRestoreToken(PACKAGE_NAME);
+        verify(mBackupManagerServiceMock).getAvailableRestoreToken(mUserId, PACKAGE_NAME);
     }
 
     @Test
@@ -1002,11 +1056,12 @@
 
     @Test
     public void isAppEligibleForBackupForUser_forwarded() throws RemoteException {
-        when(mBackupManagerServiceMock.isAppEligibleForBackup(PACKAGE_NAME)).thenReturn(true);
+        when(mBackupManagerServiceMock.isAppEligibleForBackup(mUserId, PACKAGE_NAME))
+                .thenReturn(true);
         mTrampoline.initializeService(UserHandle.USER_SYSTEM);
 
         assertTrue(mTrampoline.isAppEligibleForBackupForUser(mUserId, PACKAGE_NAME));
-        verify(mBackupManagerServiceMock).isAppEligibleForBackup(PACKAGE_NAME);
+        verify(mBackupManagerServiceMock).isAppEligibleForBackup(mUserId, PACKAGE_NAME);
     }
 
     @Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 527a1ee..371e8f4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -208,6 +208,7 @@
     private static class TestableNotificationManagerService extends NotificationManagerService {
         int countSystemChecks = 0;
         boolean isSystemUid = true;
+        int countLogSmartSuggestionsVisible = 0;
 
         public TestableNotificationManagerService(Context context) {
             super(context);
@@ -231,11 +232,6 @@
         }
 
         @Override
-        protected void reportSeen(NotificationRecord r) {
-            return;
-        }
-
-        @Override
         protected void reportUserInteraction(NotificationRecord r) {
             return;
         }
@@ -244,6 +240,14 @@
         protected void handleSavePolicyFile() {
             return;
         }
+
+        @Override
+        void logSmartSuggestionsVisible(NotificationRecord r) {
+            super.logSmartSuggestionsVisible(r);
+            countLogSmartSuggestionsVisible++;
+        }
+
+
     }
 
     private class TestableToastCallback extends ITransientNotification.Stub {
@@ -3507,6 +3511,12 @@
     }
 
     @Test
+    public void testAppOverlay() throws Exception {
+        mBinderService.setAppOverlaysAllowed(PKG, mUid, false);
+        assertFalse(mBinderService.areAppOverlaysAllowedForPackage(PKG, mUid));
+    }
+
+    @Test
     public void testIsCallerInstantApp_primaryUser() throws Exception {
         ApplicationInfo info = new ApplicationInfo();
         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
@@ -3777,4 +3787,66 @@
         verify(mAssistants).notifyAssistantActionClicked(
                 eq(r.sbn), eq(actionIndex), eq(action), eq(generatedByAssistant));
     }
+
+    @Test
+    public void testLogSmartSuggestionsVisible_triggerOnExpandAndVisible() {
+        NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+        mService.addNotification(r);
+
+        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true);
+        NotificationVisibility[] notificationVisibility = new NotificationVisibility[] {
+                NotificationVisibility.obtain(r.getKey(), 0, 0, true)
+        };
+        mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility,
+                new NotificationVisibility[0]);
+
+        assertEquals(1, mService.countLogSmartSuggestionsVisible);
+    }
+
+    @Test
+    public void testLogSmartSuggestionsVisible_noTriggerOnExpand() {
+        NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+        mService.addNotification(r);
+
+        mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true);
+
+        assertEquals(0, mService.countLogSmartSuggestionsVisible);
+    }
+
+    @Test
+    public void testLogSmartSuggestionsVisible_noTriggerOnVisible() {
+        NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+        mService.addNotification(r);
+
+        NotificationVisibility[] notificationVisibility = new NotificationVisibility[]{
+                NotificationVisibility.obtain(r.getKey(), 0, 0, true)
+        };
+        mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility,
+                new NotificationVisibility[0]);
+
+        assertEquals(0, mService.countLogSmartSuggestionsVisible);
+    }
+
+    public void testReportSeen_delegated() {
+        Notification.Builder nb =
+                new Notification.Builder(mContext, mTestNotificationChannel.getId())
+                        .setContentTitle("foo")
+                        .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, "opPkg", 0, "tag", mUid, 0,
+                nb.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord r =  new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mService.reportSeen(r);
+        verify(mAppUsageStats, never()).reportEvent(anyString(), anyInt(), anyInt());
+
+    }
+
+    @Test
+    public void testReportSeen_notDelegated() {
+        NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
+
+        mService.reportSeen(r);
+        verify(mAppUsageStats, times(1)).reportEvent(anyString(), anyInt(), anyInt());
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index b027935..0b73481 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -1584,39 +1584,6 @@
     }
 
     @Test
-    public void testUpdateGroup_fromSystem_appOverlay() {
-        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
-        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
-
-        // from system, allowed
-        NotificationChannelGroup update = ncg.clone();
-        update.setAllowAppOverlay(false);
-
-        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, update, false);
-        NotificationChannelGroup updated =
-                mHelper.getNotificationChannelGroup("group1", PKG_N_MR1, UID_N_MR1);
-        assertFalse(updated.canOverlayApps());
-        assertEquals(NotificationChannelGroup.USER_LOCKED_ALLOW_APP_OVERLAY,
-                updated.getUserLockedFields());
-    }
-
-    @Test
-    public void testUpdateGroup_fromApp_appOverlay() {
-        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
-        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
-
-        // from app, not allowed
-        NotificationChannelGroup update = new NotificationChannelGroup("group1", "name1");
-        update.setAllowAppOverlay(false);
-
-        mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
-        NotificationChannelGroup updated =
-                mHelper.getNotificationChannelGroup("group1", PKG_N_MR1, UID_N_MR1);
-        assertTrue(updated.canOverlayApps());
-        assertEquals(0, updated.getUserLockedFields());
-    }
-
-    @Test
     public void testCannotCreateChannel_badGroup() {
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
@@ -2192,4 +2159,32 @@
         mHelper.toggleNotificationDelegate(PKG_O, UID_O, true);
         assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
     }
+
+    @Test
+    public void testAllowAppOverlay_defaults() throws Exception {
+        assertTrue(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
+
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+        loadStreamXml(baos, false);
+
+        assertTrue(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
+        assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
+    }
+
+    @Test
+    public void testAllowAppOverlay_xml() throws Exception {
+        mHelper.setAppOverlaysAllowed(PKG_O, UID_O, false);
+        assertFalse(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
+        assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_APP_OVERLAY,
+                mHelper.getAppLockedFields(PKG_O, UID_O));
+
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+        mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
+        loadStreamXml(baos, false);
+
+        assertFalse(mHelper.areAppOverlaysAllowed(PKG_O, UID_O));
+        assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_APP_OVERLAY,
+                mHelper.getAppLockedFields(PKG_O, UID_O));
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index b955e56..49f134f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -76,7 +76,7 @@
         verify(mAm, times(1)).setExactAndAllowWhileIdle(
                 anyInt(), captor.capture(), any(PendingIntent.class));
         long actualSnoozedUntilDuration = captor.getValue() - SystemClock.elapsedRealtime();
-        assertTrue(Math.abs(actualSnoozedUntilDuration - 1000) < 25);
+        assertTrue(Math.abs(actualSnoozedUntilDuration - 1000) < 250);
         assertTrue(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 9b18388..58302d6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -23,8 +23,8 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
-import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
 import static android.view.Display.DEFAULT_DISPLAY;
+
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -36,7 +36,7 @@
 import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
 import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
-import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -47,18 +47,27 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.contains;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.refEq;
 
 import android.app.ActivityOptions;
+import android.content.ComponentName;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
 import android.graphics.Rect;
-import android.os.Build;
 import android.platform.test.annotations.Presubmit;
+import android.util.Pair;
+
 import androidx.test.filters.MediumTest;
+
+import com.android.internal.app.ResolverActivity;
+
 import org.junit.Before;
 import org.junit.Test;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Tests for the {@link ActivityStackSupervisor} class.
@@ -385,31 +394,10 @@
     }
 
     /**
-     * Tests home activities that targeted sdk before Q cannot start on secondary display.
-     */
-    @Test
-    public void testStartHomeTargetSdkBeforeQ() throws Exception {
-        final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay());
-        mRootActivityContainer.addChild(secondDisplay, POSITION_TOP);
-        doReturn(true).when(secondDisplay).supportsSystemDecorations();
-
-        final ActivityInfo info = new ActivityInfo();
-        info.launchMode = LAUNCH_MULTIPLE;
-        info.applicationInfo = new ApplicationInfo();
-        info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
-        assertTrue(mRootActivityContainer.canStartHomeOnDisplay(info, secondDisplay.mDisplayId,
-                false /* allowInstrumenting */));
-
-        info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.P;
-        assertFalse(mRootActivityContainer.canStartHomeOnDisplay(info, secondDisplay.mDisplayId,
-                false /* allowInstrumenting */));
-    }
-
-    /**
      * Tests that home activities can be started on the displays that supports system decorations.
      */
-    @Test
-    public void testStartHomeOnAllDisplays() {
+    // TODO (b/118206886): Will add it back once launcher's patch is merged into master.
+    private void testStartHomeOnAllDisplays() {
         // Create secondary displays.
         final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay());
         mRootActivityContainer.addChild(secondDisplay, POSITION_TOP);
@@ -477,4 +465,142 @@
         assertTrue(mRootActivityContainer.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
                 true /* allowInstrumenting*/));
     }
+
+    /**
+     * Tests that secondary home should be selected if default home not set.
+     */
+    @Test
+    public void testResolveSecondaryHomeActivityWhenDefaultHomeNotSet() {
+        final Intent defaultHomeIntent = mService.getHomeIntent();
+        final ActivityInfo aInfoDefault = new ActivityInfo();
+        aInfoDefault.name = ResolverActivity.class.getName();
+        doReturn(aInfoDefault).when(mRootActivityContainer).resolveHomeActivity(anyInt(),
+                refEq(defaultHomeIntent));
+
+        final String secondaryHomeComponent = mService.mContext.getResources().getString(
+                com.android.internal.R.string.config_secondaryHomeComponent);
+        final ComponentName comp = ComponentName.unflattenFromString(secondaryHomeComponent);
+        final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null);
+        final ActivityInfo aInfoSecondary = new ActivityInfo();
+        aInfoSecondary.name = comp.getClassName();
+        doReturn(aInfoSecondary).when(mRootActivityContainer).resolveHomeActivity(anyInt(),
+                refEq(secondaryHomeIntent));
+
+        // Should fallback to secondary home if default home not set.
+        final Pair<ActivityInfo, Intent> resolvedInfo = mRootActivityContainer
+                .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
+
+        assertEquals(comp.getClassName(), resolvedInfo.first.name);
+    }
+
+    /**
+     * Tests that secondary home should be selected if default home not support secondary displays
+     * or there is no matched activity in the same package as selected default home.
+     */
+    @Test
+    public void testResolveSecondaryHomeActivityWhenDefaultHomeNotSupportMultiDisplay() {
+        final Intent defaultHomeIntent = mService.getHomeIntent();
+        final ActivityInfo aInfoDefault = new ActivityInfo();
+        aInfoDefault.name = "fakeHomeActivity";
+        aInfoDefault.applicationInfo = new ApplicationInfo();
+        aInfoDefault.applicationInfo.packageName = "fakeHomePackage";
+        doReturn(aInfoDefault).when(mRootActivityContainer).resolveHomeActivity(anyInt(),
+                refEq(defaultHomeIntent));
+
+        final List<ResolveInfo> resolutions = new ArrayList<>();
+        doReturn(resolutions).when(mRootActivityContainer).resolveActivities(anyInt(), any());
+
+        final String secondaryHomeComponent = mService.mContext.getResources().getString(
+                com.android.internal.R.string.config_secondaryHomeComponent);
+        final ComponentName comp = ComponentName.unflattenFromString(secondaryHomeComponent);
+        final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null);
+        final ActivityInfo aInfoSecondary = new ActivityInfo();
+        aInfoSecondary.name = comp.getClassName();
+        doReturn(aInfoSecondary).when(mRootActivityContainer).resolveHomeActivity(anyInt(),
+                refEq(secondaryHomeIntent));
+
+        // Should fallback to secondary home if selected default home not support secondary displays
+        // or there is no matched activity in the same package as selected default home.
+        final Pair<ActivityInfo, Intent> resolvedInfo = mRootActivityContainer
+                .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
+
+        assertEquals(comp.getClassName(), resolvedInfo.first.name);
+    }
+
+    /**
+     * Tests that default home activity should be selected if it already support secondary displays.
+     */
+    @Test
+    public void testResolveSecondaryHomeActivityWhenDefaultHomeSupportMultiDisplay() {
+        final Intent homeIntent = mService.getHomeIntent();
+        final ActivityInfo aInfoDefault = new ActivityInfo();
+        aInfoDefault.name = "fakeHomeActivity";
+        aInfoDefault.applicationInfo = new ApplicationInfo();
+        aInfoDefault.applicationInfo.packageName = "fakeHomePackage";
+        doReturn(aInfoDefault).when(mRootActivityContainer).resolveHomeActivity(anyInt(),
+                refEq(homeIntent));
+
+        final List<ResolveInfo> resolutions = new ArrayList<>();
+        final ResolveInfo infoFake1 = new ResolveInfo();
+        infoFake1.activityInfo = new ActivityInfo();
+        infoFake1.activityInfo.name = "fakeActivity1";
+        infoFake1.activityInfo.applicationInfo = new ApplicationInfo();
+        infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1";
+        final ResolveInfo infoFake2 = new ResolveInfo();
+        infoFake2.activityInfo = aInfoDefault;
+        resolutions.add(infoFake1);
+        resolutions.add(infoFake2);
+        doReturn(resolutions).when(mRootActivityContainer).resolveActivities(anyInt(), any());
+
+        doReturn(true).when(mRootActivityContainer).canStartHomeOnDisplay(
+                any(), anyInt(), anyBoolean());
+
+        // Use default home activity if it support secondary displays.
+        final Pair<ActivityInfo, Intent> resolvedInfo = mRootActivityContainer
+                .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
+
+        assertEquals(aInfoDefault.applicationInfo.packageName,
+                resolvedInfo.first.applicationInfo.packageName);
+        assertEquals(aInfoDefault.name, resolvedInfo.first.name);
+    }
+
+    /**
+     * Tests that the first one that matches should be selected if there are multiple activities.
+     */
+    @Test
+    public void testResolveSecondaryHomeActivityWhenOtherActivitySupportMultiDisplay() {
+        final Intent homeIntent = mService.getHomeIntent();
+        final ActivityInfo aInfoDefault = new ActivityInfo();
+        aInfoDefault.name = "fakeHomeActivity";
+        aInfoDefault.applicationInfo = new ApplicationInfo();
+        aInfoDefault.applicationInfo.packageName = "fakeHomePackage";
+        doReturn(aInfoDefault).when(mRootActivityContainer).resolveHomeActivity(anyInt(),
+                refEq(homeIntent));
+
+        final List<ResolveInfo> resolutions = new ArrayList<>();
+        final ResolveInfo infoFake1 = new ResolveInfo();
+        infoFake1.activityInfo = new ActivityInfo();
+        infoFake1.activityInfo.name = "fakeActivity1";
+        infoFake1.activityInfo.applicationInfo = new ApplicationInfo();
+        infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1";
+        final ResolveInfo infoFake2 = new ResolveInfo();
+        infoFake2.activityInfo = new ActivityInfo();
+        infoFake2.activityInfo.name = "fakeActivity2";
+        infoFake2.activityInfo.applicationInfo = new ApplicationInfo();
+        infoFake2.activityInfo.applicationInfo.packageName = "fakePackage2";
+        resolutions.add(infoFake1);
+        resolutions.add(infoFake2);
+        doReturn(resolutions).when(mRootActivityContainer).resolveActivities(anyInt(), any());
+
+        doReturn(true).when(mRootActivityContainer).canStartHomeOnDisplay(
+                any(), anyInt(), anyBoolean());
+
+        // Use the first one of matched activities in the same package as selected default home.
+        final Pair<ActivityInfo, Intent> resolvedInfo = mRootActivityContainer
+                .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
+
+        assertEquals(infoFake1.activityInfo.applicationInfo.packageName,
+                resolvedInfo.first.applicationInfo.packageName);
+        assertEquals(infoFake1.activityInfo.name, resolvedInfo.first.name);
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index 3991e06..c343fe7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -20,6 +20,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertFalse;
@@ -66,6 +67,10 @@
         synchronized (mWm.mGlobalLock) {
             mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
         }
+
+        spyOn(mDisplayContent);
+        InputMonitor inputMonitor = mock(InputMonitor.class);
+        when(mDisplayContent.getInputMonitor()).thenReturn(inputMonitor);
     }
 
     @Test
diff --git a/telecomm/java/android/telecom/PhoneAccountSuggestion.aidl b/telecomm/java/android/telecom/PhoneAccountSuggestion.aidl
new file mode 100644
index 0000000..e2fa7e4
--- /dev/null
+++ b/telecomm/java/android/telecom/PhoneAccountSuggestion.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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 android.telecom;
+
+/**
+ * {@hide}
+  */
+parcelable PhoneAccountSuggestion;
\ No newline at end of file
diff --git a/telecomm/java/android/telecom/PhoneAccountSuggestion.java b/telecomm/java/android/telecom/PhoneAccountSuggestion.java
index 4e6a178..b401bcf 100644
--- a/telecomm/java/android/telecom/PhoneAccountSuggestion.java
+++ b/telecomm/java/android/telecom/PhoneAccountSuggestion.java
@@ -24,6 +24,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 public final class PhoneAccountSuggestion implements Parcelable {
 
@@ -132,4 +133,19 @@
         dest.writeInt(mReason);
         dest.writeByte((byte) (mShouldAutoSelect ? 1 : 0));
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        PhoneAccountSuggestion that = (PhoneAccountSuggestion) o;
+        return mReason == that.mReason
+                && mShouldAutoSelect == that.mShouldAutoSelect
+                && Objects.equals(mHandle, that.mHandle);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mHandle, mReason, mShouldAutoSelect);
+    }
 }
diff --git a/telecomm/java/android/telecom/PhoneAccountSuggestionService.java b/telecomm/java/android/telecom/PhoneAccountSuggestionService.java
new file mode 100644
index 0000000..ba3822c
--- /dev/null
+++ b/telecomm/java/android/telecom/PhoneAccountSuggestionService.java
@@ -0,0 +1,123 @@
+/*
+ * 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 android.telecom;
+
+import android.annotation.NonNull;
+import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.telecom.IPhoneAccountSuggestionCallback;
+import com.android.internal.telecom.IPhoneAccountSuggestionService;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Base class for service that allows system apps to suggest phone accounts for outgoing calls.
+ *
+ * Phone account suggestions allow OEMs to intelligently select phone accounts based on knowledge
+ * about the user's past behavior, carrier billing patterns, or other factors unknown to the AOSP
+ * Telecom system.
+ * OEMs who wish to provide a phone account suggestion service on their device should implement this
+ * service in an app that resides in the /system/priv-app/ directory on their device. For security
+ * reasons, the service's entry {@code AndroidManifest.xml} file must declare the
+ * {@link android.Manifest.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE} permission:
+ * <pre>
+ * {@code
+ * <service android:name="your.package.YourServiceName"
+ *          android:permission="android.permission.BIND_PHONE_ACCOUNT_SUGGESTION_SERVICE">
+ *      <intent-filter>
+ *          <action android:name="android.telecom.PhoneAccountSuggestionService"/>
+ *      </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ * Only one system app on each device may implement this service. If multiple system apps implement
+ * this service, none of them will be queried for suggestions.
+ * @hide
+ */
+@SystemApi
+@TestApi
+public class PhoneAccountSuggestionService extends Service {
+    /**
+     * The {@link Intent} that must be declared in the {@code intent-filter} element of the
+     * service's manifest entry.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService";
+
+    private IPhoneAccountSuggestionService mInterface = new IPhoneAccountSuggestionService.Stub() {
+        @Override
+        public void onAccountSuggestionRequest(IPhoneAccountSuggestionCallback callback,
+                String number) {
+            mCallbackMap.put(number, callback);
+            PhoneAccountSuggestionService.this.onAccountSuggestionRequest(number);
+        }
+    };
+
+    private final Map<String, IPhoneAccountSuggestionCallback> mCallbackMap =
+            new HashMap<>();
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mInterface.asBinder();
+    }
+
+    /**
+     * The system calls this method during the outgoing call flow if it needs account suggestions.
+     *
+     * The implementer of this service must override this method to implement its account suggestion
+     * logic. After preparing the suggestions, the implementation of the service must call
+     * {@link #suggestPhoneAccounts(String, List)} to deliver the suggestions back to the system.
+     *
+     * Note that the system will suspend the outgoing call process after it calls this method until
+     * this service calls {@link #suggestPhoneAccounts}.
+     *
+     * @param number The phone number to provide suggestions for.
+     */
+    public void onAccountSuggestionRequest(@NonNull String number) {}
+
+    /**
+     * The implementation of this service calls this method to deliver suggestions to the system.
+     *
+     * The implementation of this service must call this method after receiving a call to
+     * {@link #onAccountSuggestionRequest(String)}. If no suggestions are available, pass an empty
+     * list as the {@code suggestions} argument.
+     *
+     * @param number The phone number to provide suggestions for.
+     * @param suggestions The list of suggestions.
+     */
+    public final void suggestPhoneAccounts(@NonNull String number,
+            @NonNull List<PhoneAccountSuggestion> suggestions) {
+        IPhoneAccountSuggestionCallback callback = mCallbackMap.remove(number);
+        if (callback == null) {
+            Log.w(this, "No suggestions requested for the number %s", Log.pii(number));
+            return;
+        }
+        try {
+            callback.suggestPhoneAccounts(number, suggestions);
+        } catch (RemoteException e) {
+            Log.w(this, "Remote exception calling suggestPhoneAccounts");
+        }
+    }
+}
diff --git a/telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionCallback.aidl b/telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionCallback.aidl
new file mode 100644
index 0000000..cb14241
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionCallback.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.internal.telecom;
+
+import android.telecom.PhoneAccountSuggestion;
+/**
+ * Internal remote callback interface for a phone acct suggestion service.
+ * @hide
+ */
+oneway interface IPhoneAccountSuggestionCallback{
+    void suggestPhoneAccounts(in String number, in List<PhoneAccountSuggestion> suggestions);
+}
diff --git a/telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionService.aidl b/telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionService.aidl
new file mode 100644
index 0000000..0ffab93
--- /dev/null
+++ b/telecomm/java/com/android/internal/telecom/IPhoneAccountSuggestionService.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.internal.telecom;
+
+import com.android.internal.telecom.IPhoneAccountSuggestionCallback;
+
+/**
+ * Internal remote interface for a phone acct suggestion service.
+ * @hide
+ */
+oneway interface IPhoneAccountSuggestionService {
+    void onAccountSuggestionRequest(in IPhoneAccountSuggestionCallback callback,
+            in String number);
+}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 50204e7..954a709 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -292,6 +292,8 @@
 
     void setTestDefaultCallRedirectionApp(String packageName);
 
+    void setTestPhoneAcctSuggestionComponent(String flattenedComponentName);
+
     void setTestDefaultCallScreeningApp(String packageName);
 
     void addOrRemoveTestCallCompanionApp(String packageName, boolean isAdded);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index fd14916..f87472d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2400,6 +2400,34 @@
     public static final String KEY_5G_ICON_CONFIGURATION_STRING =
             "5g_icon_configuration_string";
 
+    /**
+     * Controls RSRP threshold at which AlternativeNetworkService will decide whether
+     * the opportunistic network is good enough for internet data.
+     */
+    public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT =
+            "opportunistic_network_entry_threshold_rsrp_int";
+
+    /**
+     * Controls RSSNR threshold at which AlternativeNetworkService will decide whether
+     * the opportunistic network is good enough for internet data.
+     */
+    public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT =
+            "opportunistic_network_entry_threshold_rssnr_int";
+
+    /**
+     * Controls RSRP threshold below which AlternativeNetworkService will decide whether
+     * the opportunistic network available is not good enough for internet data.
+     */
+    public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT =
+            "opportunistic_network_exit_threshold_rsrp_int";
+
+    /**
+     * Controls RSSNR threshold below which AlternativeNetworkService will decide whether
+     * the opportunistic network available is not good enough for internet data.
+     */
+    public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT =
+            "opportunistic_network_exit_threshold_rssnr_int";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -2761,6 +2789,14 @@
         sDefaults.putInt(KEY_CALL_WAITING_SERVICE_CLASS_INT, 1 /* SERVICE_CLASS_VOICE */);
         sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING,
                 "connected_mmwave:None,connected:5G,not_restricted:None,restricted:None");
+        /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */
+        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108);
+        /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_MODERATE */
+        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT, -118);
+        /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_GOOD */
+        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 45);
+        /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_MODERATE */
+        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, 10);
     }
 
     /**
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index c6f7d0e..c53b37d 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -15,151 +15,383 @@
  */
 package android.telephony;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.content.Context;
 import android.os.PersistableBundle;
 
+import com.android.internal.util.ArrayUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 /**
- * Returned as the reason for a connection failure as defined
- * by RIL_DataCallFailCause in ril.h and some local errors.
+ * Returned as the reason for a data connection failure as defined by modem and some local errors.
  * @hide
  */
-public enum DataFailCause {
-    NONE(0),
+public final class DataFailCause {
+    /** There is no failure */
+    public static final int NONE = 0;
 
     // This series of errors as specified by the standards
     // specified in ril.h
-    OPERATOR_BARRED(0x08),                  /* no retry */
-    NAS_SIGNALLING(0x0E),
-    LLC_SNDCP(0x19),
-    INSUFFICIENT_RESOURCES(0x1A),
-    MISSING_UNKNOWN_APN(0x1B),              /* no retry */
-    UNKNOWN_PDP_ADDRESS_TYPE(0x1C),         /* no retry */
-    USER_AUTHENTICATION(0x1D),              /* no retry */
-    ACTIVATION_REJECT_GGSN(0x1E),           /* no retry */
-    ACTIVATION_REJECT_UNSPECIFIED(0x1F),
-    SERVICE_OPTION_NOT_SUPPORTED(0x20),     /* no retry */
-    SERVICE_OPTION_NOT_SUBSCRIBED(0x21),    /* no retry */
-    SERVICE_OPTION_OUT_OF_ORDER(0x22),
-    NSAPI_IN_USE(0x23),                     /* no retry */
-    REGULAR_DEACTIVATION(0x24),             /* possibly restart radio, based on config */
-    QOS_NOT_ACCEPTED(0x25),
-    NETWORK_FAILURE(0x26),
-    UMTS_REACTIVATION_REQ(0x27),
-    FEATURE_NOT_SUPP(0x28),
-    TFT_SEMANTIC_ERROR(0x29),
-    TFT_SYTAX_ERROR(0x2A),
-    UNKNOWN_PDP_CONTEXT(0x2B),
-    FILTER_SEMANTIC_ERROR(0x2C),
-    FILTER_SYTAX_ERROR(0x2D),
-    PDP_WITHOUT_ACTIVE_TFT(0x2E),
-    ONLY_IPV4_ALLOWED(0x32),                /* no retry */
-    ONLY_IPV6_ALLOWED(0x33),                /* no retry */
-    ONLY_SINGLE_BEARER_ALLOWED(0x34),
-    ESM_INFO_NOT_RECEIVED(0x35),
-    PDN_CONN_DOES_NOT_EXIST(0x36),
-    MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED(0x37),
-    MAX_ACTIVE_PDP_CONTEXT_REACHED(0x41),
-    UNSUPPORTED_APN_IN_CURRENT_PLMN(0x42),
-    INVALID_TRANSACTION_ID(0x51),
-    MESSAGE_INCORRECT_SEMANTIC(0x5F),
-    INVALID_MANDATORY_INFO(0x60),
-    MESSAGE_TYPE_UNSUPPORTED(0x61),
-    MSG_TYPE_NONCOMPATIBLE_STATE(0x62),
-    UNKNOWN_INFO_ELEMENT(0x63),
-    CONDITIONAL_IE_ERROR(0x64),
-    MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE(0x65),
-    PROTOCOL_ERRORS(0x6F),                  /* no retry */
-    APN_TYPE_CONFLICT(0x70),
-    INVALID_PCSCF_ADDR(0x71),
-    INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN(0x72),
-    EMM_ACCESS_BARRED(0x73),
-    EMERGENCY_IFACE_ONLY(0x74),
-    IFACE_MISMATCH(0x75),
-    COMPANION_IFACE_IN_USE(0x76),
-    IP_ADDRESS_MISMATCH(0x77),
-    IFACE_AND_POL_FAMILY_MISMATCH(0x78),
-    EMM_ACCESS_BARRED_INFINITE_RETRY(0x79),
-    AUTH_FAILURE_ON_EMERGENCY_CALL(0x7A),
+    /** Operator determined barring. */
+    public static final int OPERATOR_BARRED = 0x08;
+    /** NAS signalling. */
+    public static final int NAS_SIGNALLING = 0x0E;
+    /** Logical Link Control (LLC) Sub Network Dependent Convergence Protocol (SNDCP). */
+    public static final int LLC_SNDCP = 0x19;
+    /** Insufficient resources. */
+    public static final int INSUFFICIENT_RESOURCES = 0x1A;
+    /** Missing or unknown APN. */
+    public static final int MISSING_UNKNOWN_APN = 0x1B;              /* no retry */
+    /** Unknown Packet Data Protocol (PDP) address type. */
+    public static final int UNKNOWN_PDP_ADDRESS_TYPE = 0x1C;         /* no retry */
+    /** User authentication. */
+    public static final int USER_AUTHENTICATION = 0x1D;              /* no retry */
+    /** Activation rejected by Gateway GPRS Support Node (GGSN), Serving Gateway or PDN Gateway. */
+    public static final int ACTIVATION_REJECT_GGSN = 0x1E;           /* no retry */
+    /** Activation rejected, unspecified. */
+    public static final int ACTIVATION_REJECT_UNSPECIFIED = 0x1F;
+    /** Service option not supported. */
+    public static final int SERVICE_OPTION_NOT_SUPPORTED = 0x20;     /* no retry */
+    /** Requested service option not subscribed. */
+    public static final int SERVICE_OPTION_NOT_SUBSCRIBED = 0x21;    /* no retry */
+    /** Service option temporarily out of order. */
+    public static final int SERVICE_OPTION_OUT_OF_ORDER = 0x22;
+    /** The Network Service Access Point Identifier (NSAPI) is in use. */
+    public static final int NSAPI_IN_USE = 0x23;                     /* no retry */
+    /* possibly restart radio, based on config */
+    /** Regular deactivation. */
+    public static final int REGULAR_DEACTIVATION = 0x24;
+    /** Quality of service (QoS) is not accepted. */
+    public static final int QOS_NOT_ACCEPTED = 0x25;
+    /** Network Failure. */
+    public static final int NETWORK_FAILURE = 0x26;
+    /** Universal Mobile Telecommunications System (UMTS) reactivation request. */
+    public static final int UMTS_REACTIVATION_REQ = 0x27;
+    /** Feature not supported. */
+    public static final int FEATURE_NOT_SUPP = 0x28;
+    /** Semantic error in the Traffic flow templates (TFT) operation. */
+    public static final int TFT_SEMANTIC_ERROR = 0x29;
+    /** Syntactical error in the Traffic flow templates (TFT) operation. */
+    public static final int TFT_SYTAX_ERROR = 0x2A;
+    /** Unknown Packet Data Protocol (PDP) context. */
+    public static final int UNKNOWN_PDP_CONTEXT = 0x2B;
+    /** Semantic errors in packet filter. */
+    public static final int FILTER_SEMANTIC_ERROR = 0x2C;
+    /** Syntactical errors in packet filter(s). */
+    public static final int FILTER_SYTAX_ERROR = 0x2D;
+    /** Packet Data Protocol (PDP) without active traffic flow template (TFT). */
+    public static final int PDP_WITHOUT_ACTIVE_TFT = 0x2E;
+    /** Packet Data Protocol (PDP) type IPv4 only allowed. */
+    public static final int ONLY_IPV4_ALLOWED = 0x32;                /* no retry */
+    /** Packet Data Protocol (PDP) type IPv6 only allowed. */
+    public static final int ONLY_IPV6_ALLOWED = 0x33;                /* no retry */
+    /** Single address bearers only allowed. */
+    public static final int ONLY_SINGLE_BEARER_ALLOWED = 0x34;
+    /** EPS Session Management (ESM) information is not received. */
+    public static final int ESM_INFO_NOT_RECEIVED = 0x35;
+    /** PDN connection does not exist. */
+    public static final int PDN_CONN_DOES_NOT_EXIST = 0x36;
+    /** Multiple connections to a same PDN is not allowed. */
+    public static final int MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 0x37;
+    /** Packet Data Protocol (PDP) */
+    public static final int MAX_ACTIVE_PDP_CONTEXT_REACHED = 0x41;
+    /** Unsupported APN in current public land mobile network (PLMN). */
+    public static final int UNSUPPORTED_APN_IN_CURRENT_PLMN = 0x42;
+    /** Invalid transaction id. */
+    public static final int INVALID_TRANSACTION_ID = 0x51;
+    /** Incorrect message semantic. */
+    public static final int MESSAGE_INCORRECT_SEMANTIC = 0x5F;
+    /** Invalid mandatory information. */
+    public static final int INVALID_MANDATORY_INFO = 0x60;
+    /** Unsupported message type. */
+    public static final int MESSAGE_TYPE_UNSUPPORTED = 0x61;
+    /** Message type uncompatible. */
+    public static final int MSG_TYPE_NONCOMPATIBLE_STATE = 0x62;
+    /** Unknown info element. */
+    public static final int UNKNOWN_INFO_ELEMENT = 0x63;
+    /** Conditional Information Element (IE) error. */
+    public static final int CONDITIONAL_IE_ERROR = 0x64;
+    /** Message and protocol state uncompatible. */
+    public static final int MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 0x65;
+    /** Protocol errors. */
+    public static final int PROTOCOL_ERRORS = 0x6F;                  /* no retry */
+    /** APN type conflict. */
+    public static final int APN_TYPE_CONFLICT = 0x70;
+    /** Invalid Proxy-Call Session Control Function (P-CSCF) address. */
+    public static final int INVALID_PCSCF_ADDR = 0x71;
+    /** Internal data call preempt by high priority APN. */
+    public static final int INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN = 0x72;
+    /** EPS (Evolved Packet System) Mobility Management (EMM) access barred. */
+    public static final int EMM_ACCESS_BARRED = 0x73;
+    /** Emergency interface only. */
+    public static final int EMERGENCY_IFACE_ONLY = 0x74;
+    /** Interface mismatch. */
+    public static final int IFACE_MISMATCH = 0x75;
+    /** Companion interface in use. */
+    public static final int COMPANION_IFACE_IN_USE = 0x76;
+    /** IP address mismatch. */
+    public static final int IP_ADDRESS_MISMATCH = 0x77;
+    public static final int IFACE_AND_POL_FAMILY_MISMATCH = 0x78;
+    /** EPS (Evolved Packet System) Mobility Management (EMM) access barred infinity retry. **/
+    public static final int EMM_ACCESS_BARRED_INFINITE_RETRY = 0x79;
+    /** Authentication failure on emergency call. */
+    public static final int AUTH_FAILURE_ON_EMERGENCY_CALL = 0x7A;
 
     // OEM sepecific error codes. To be used by OEMs when they don't
     // want to reveal error code which would be replaced by ERROR_UNSPECIFIED
-    OEM_DCFAILCAUSE_1(0x1001),
-    OEM_DCFAILCAUSE_2(0x1002),
-    OEM_DCFAILCAUSE_3(0x1003),
-    OEM_DCFAILCAUSE_4(0x1004),
-    OEM_DCFAILCAUSE_5(0x1005),
-    OEM_DCFAILCAUSE_6(0x1006),
-    OEM_DCFAILCAUSE_7(0x1007),
-    OEM_DCFAILCAUSE_8(0x1008),
-    OEM_DCFAILCAUSE_9(0x1009),
-    OEM_DCFAILCAUSE_10(0x100A),
-    OEM_DCFAILCAUSE_11(0x100B),
-    OEM_DCFAILCAUSE_12(0x100C),
-    OEM_DCFAILCAUSE_13(0x100D),
-    OEM_DCFAILCAUSE_14(0x100E),
-    OEM_DCFAILCAUSE_15(0x100F),
+    public static final int OEM_DCFAILCAUSE_1 = 0x1001;
+    public static final int OEM_DCFAILCAUSE_2 = 0x1002;
+    public static final int OEM_DCFAILCAUSE_3 = 0x1003;
+    public static final int OEM_DCFAILCAUSE_4 = 0x1004;
+    public static final int OEM_DCFAILCAUSE_5 = 0x1005;
+    public static final int OEM_DCFAILCAUSE_6 = 0x1006;
+    public static final int OEM_DCFAILCAUSE_7 = 0x1007;
+    public static final int OEM_DCFAILCAUSE_8 = 0x1008;
+    public static final int OEM_DCFAILCAUSE_9 = 0x1009;
+    public static final int OEM_DCFAILCAUSE_10 = 0x100A;
+    public static final int OEM_DCFAILCAUSE_11 = 0x100B;
+    public static final int OEM_DCFAILCAUSE_12 = 0x100C;
+    public static final int OEM_DCFAILCAUSE_13 = 0x100D;
+    public static final int OEM_DCFAILCAUSE_14 = 0x100E;
+    public static final int OEM_DCFAILCAUSE_15 = 0x100F;
 
     // Local errors generated by Vendor RIL
     // specified in ril.h
-    REGISTRATION_FAIL(-1),
-    GPRS_REGISTRATION_FAIL(-2),
-    SIGNAL_LOST(-3),                        /* no retry */
-    PREF_RADIO_TECH_CHANGED(-4),
-    RADIO_POWER_OFF(-5),                    /* no retry */
-    TETHERED_CALL_ACTIVE(-6),               /* no retry */
-    ERROR_UNSPECIFIED(0xFFFF),
+    public static final int REGISTRATION_FAIL = -1;
+    public static final int GPRS_REGISTRATION_FAIL = -2;
+    public static final int SIGNAL_LOST = -3;                        /* no retry */
+    public static final int PREF_RADIO_TECH_CHANGED = -4;
+    public static final int RADIO_POWER_OFF = -5;                    /* no retry */
+    public static final int TETHERED_CALL_ACTIVE = -6;               /* no retry */
+    public static final int ERROR_UNSPECIFIED = 0xFFFF;
 
     // Errors generated by the Framework
     // specified here
-    UNKNOWN(0x10000),
-    RADIO_NOT_AVAILABLE(0x10001),                   /* no retry */
-    UNACCEPTABLE_NETWORK_PARAMETER(0x10002),        /* no retry */
-    CONNECTION_TO_DATACONNECTIONAC_BROKEN(0x10003),
-    LOST_CONNECTION(0x10004),
-    RESET_BY_FRAMEWORK(0x10005);
+    public static final int UNKNOWN = 0x10000;
+    public static final int RADIO_NOT_AVAILABLE = 0x10001;                   /* no retry */
+    public static final int UNACCEPTABLE_NETWORK_PARAMETER = 0x10002;        /* no retry */
+    public static final int CONNECTION_TO_DATACONNECTIONAC_BROKEN = 0x10003;
+    public static final int LOST_CONNECTION = 0x10004;
+    /** Data was reset by framework. */
+    public static final int RESET_BY_FRAMEWORK = 0x10005;
 
-    private final int mErrorCode;
-    private static final HashMap<Integer, DataFailCause> sErrorCodeToFailCauseMap;
+    /** @hide */
+    @IntDef(value = {
+            NONE,
+            OPERATOR_BARRED,
+            NAS_SIGNALLING,
+            LLC_SNDCP,
+            INSUFFICIENT_RESOURCES,
+            MISSING_UNKNOWN_APN,
+            UNKNOWN_PDP_ADDRESS_TYPE,
+            USER_AUTHENTICATION,
+            ACTIVATION_REJECT_GGSN,
+            ACTIVATION_REJECT_UNSPECIFIED,
+            SERVICE_OPTION_NOT_SUPPORTED,
+            SERVICE_OPTION_NOT_SUBSCRIBED,
+            SERVICE_OPTION_OUT_OF_ORDER,
+            NSAPI_IN_USE,
+            REGULAR_DEACTIVATION,
+            QOS_NOT_ACCEPTED,
+            NETWORK_FAILURE,
+            UMTS_REACTIVATION_REQ,
+            FEATURE_NOT_SUPP,
+            TFT_SEMANTIC_ERROR,
+            TFT_SYTAX_ERROR,
+            UNKNOWN_PDP_CONTEXT,
+            FILTER_SEMANTIC_ERROR,
+            FILTER_SYTAX_ERROR,
+            PDP_WITHOUT_ACTIVE_TFT,
+            ONLY_IPV4_ALLOWED,
+            ONLY_IPV6_ALLOWED,
+            ONLY_SINGLE_BEARER_ALLOWED,
+            ESM_INFO_NOT_RECEIVED,
+            PDN_CONN_DOES_NOT_EXIST,
+            MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED,
+            MAX_ACTIVE_PDP_CONTEXT_REACHED,
+            UNSUPPORTED_APN_IN_CURRENT_PLMN,
+            INVALID_TRANSACTION_ID,
+            MESSAGE_INCORRECT_SEMANTIC,
+            INVALID_MANDATORY_INFO,
+            MESSAGE_TYPE_UNSUPPORTED,
+            MSG_TYPE_NONCOMPATIBLE_STATE,
+            UNKNOWN_INFO_ELEMENT,
+            CONDITIONAL_IE_ERROR,
+            MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE,
+            PROTOCOL_ERRORS,                 /* no retry */
+            APN_TYPE_CONFLICT,
+            INVALID_PCSCF_ADDR,
+            INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN,
+            EMM_ACCESS_BARRED,
+            EMERGENCY_IFACE_ONLY,
+            IFACE_MISMATCH,
+            COMPANION_IFACE_IN_USE,
+            IP_ADDRESS_MISMATCH,
+            IFACE_AND_POL_FAMILY_MISMATCH,
+            EMM_ACCESS_BARRED_INFINITE_RETRY,
+            AUTH_FAILURE_ON_EMERGENCY_CALL,
+            OEM_DCFAILCAUSE_1,
+            OEM_DCFAILCAUSE_2,
+            OEM_DCFAILCAUSE_3,
+            OEM_DCFAILCAUSE_4,
+            OEM_DCFAILCAUSE_5,
+            OEM_DCFAILCAUSE_6,
+            OEM_DCFAILCAUSE_7,
+            OEM_DCFAILCAUSE_8,
+            OEM_DCFAILCAUSE_9,
+            OEM_DCFAILCAUSE_10,
+            OEM_DCFAILCAUSE_11,
+            OEM_DCFAILCAUSE_12,
+            OEM_DCFAILCAUSE_13,
+            OEM_DCFAILCAUSE_14,
+            OEM_DCFAILCAUSE_15,
+            REGISTRATION_FAIL,
+            GPRS_REGISTRATION_FAIL,
+            SIGNAL_LOST,
+            PREF_RADIO_TECH_CHANGED,
+            RADIO_POWER_OFF,
+            TETHERED_CALL_ACTIVE,
+            ERROR_UNSPECIFIED,
+            UNKNOWN,
+            RADIO_NOT_AVAILABLE,
+            UNACCEPTABLE_NETWORK_PARAMETER,
+            CONNECTION_TO_DATACONNECTIONAC_BROKEN,
+            LOST_CONNECTION,
+            RESET_BY_FRAMEWORK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FailCause{}
+
+    private static final Map<Integer, String> sFailCauseMap;
     static {
-        sErrorCodeToFailCauseMap = new HashMap<Integer, DataFailCause>();
-        for (DataFailCause fc : values()) {
-            sErrorCodeToFailCauseMap.put(fc.getErrorCode(), fc);
-        }
+        sFailCauseMap = new HashMap<>();
+        sFailCauseMap.put(NONE, "NONE");
+        sFailCauseMap.put(OPERATOR_BARRED, "OPERATOR_BARRED");
+        sFailCauseMap.put(NAS_SIGNALLING, "NAS_SIGNALLING");
+        sFailCauseMap.put(LLC_SNDCP, "LLC_SNDCP");
+        sFailCauseMap.put(INSUFFICIENT_RESOURCES, "INSUFFICIENT_RESOURCES");
+        sFailCauseMap.put(MISSING_UNKNOWN_APN, "MISSING_UNKNOWN_APN");
+        sFailCauseMap.put(UNKNOWN_PDP_ADDRESS_TYPE, "UNKNOWN_PDP_ADDRESS_TYPE");
+        sFailCauseMap.put(USER_AUTHENTICATION, "USER_AUTHENTICATION");
+        sFailCauseMap.put(ACTIVATION_REJECT_GGSN, "ACTIVATION_REJECT_GGSN");
+        sFailCauseMap.put(ACTIVATION_REJECT_UNSPECIFIED,
+                "ACTIVATION_REJECT_UNSPECIFIED");
+        sFailCauseMap.put(SERVICE_OPTION_NOT_SUPPORTED,
+                "SERVICE_OPTION_NOT_SUPPORTED");
+        sFailCauseMap.put(SERVICE_OPTION_NOT_SUBSCRIBED,
+                "SERVICE_OPTION_NOT_SUBSCRIBED");
+        sFailCauseMap.put(SERVICE_OPTION_OUT_OF_ORDER, "SERVICE_OPTION_OUT_OF_ORDER");
+        sFailCauseMap.put(NSAPI_IN_USE, "NSAPI_IN_USE");
+        sFailCauseMap.put(REGULAR_DEACTIVATION, "REGULAR_DEACTIVATION");
+        sFailCauseMap.put(QOS_NOT_ACCEPTED, "QOS_NOT_ACCEPTED");
+        sFailCauseMap.put(NETWORK_FAILURE, "NETWORK_FAILURE");
+        sFailCauseMap.put(UMTS_REACTIVATION_REQ, "UMTS_REACTIVATION_REQ");
+        sFailCauseMap.put(FEATURE_NOT_SUPP, "FEATURE_NOT_SUPP");
+        sFailCauseMap.put(TFT_SEMANTIC_ERROR, "TFT_SEMANTIC_ERROR");
+        sFailCauseMap.put(TFT_SYTAX_ERROR, "TFT_SYTAX_ERROR");
+        sFailCauseMap.put(UNKNOWN_PDP_CONTEXT, "UNKNOWN_PDP_CONTEXT");
+        sFailCauseMap.put(FILTER_SEMANTIC_ERROR, "FILTER_SEMANTIC_ERROR");
+        sFailCauseMap.put(FILTER_SYTAX_ERROR, "FILTER_SYTAX_ERROR");
+        sFailCauseMap.put(PDP_WITHOUT_ACTIVE_TFT, "PDP_WITHOUT_ACTIVE_TFT");
+        sFailCauseMap.put(ONLY_IPV4_ALLOWED, "ONLY_IPV4_ALLOWED");
+        sFailCauseMap.put(ONLY_IPV6_ALLOWED, "ONLY_IPV6_ALLOWED");
+        sFailCauseMap.put(ONLY_SINGLE_BEARER_ALLOWED, "ONLY_SINGLE_BEARER_ALLOWED");
+        sFailCauseMap.put(ESM_INFO_NOT_RECEIVED, "ESM_INFO_NOT_RECEIVED");
+        sFailCauseMap.put(PDN_CONN_DOES_NOT_EXIST, "PDN_CONN_DOES_NOT_EXIST");
+        sFailCauseMap.put(MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED,
+                "MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED");
+        sFailCauseMap.put(MAX_ACTIVE_PDP_CONTEXT_REACHED,
+                "MAX_ACTIVE_PDP_CONTEXT_REACHED");
+        sFailCauseMap.put(UNSUPPORTED_APN_IN_CURRENT_PLMN,
+                "UNSUPPORTED_APN_IN_CURRENT_PLMN");
+        sFailCauseMap.put(INVALID_TRANSACTION_ID, "INVALID_TRANSACTION_ID");
+        sFailCauseMap.put(MESSAGE_INCORRECT_SEMANTIC, "MESSAGE_INCORRECT_SEMANTIC");
+        sFailCauseMap.put(INVALID_MANDATORY_INFO, "INVALID_MANDATORY_INFO");
+        sFailCauseMap.put(MESSAGE_TYPE_UNSUPPORTED, "MESSAGE_TYPE_UNSUPPORTED");
+        sFailCauseMap.put(MSG_TYPE_NONCOMPATIBLE_STATE, "MSG_TYPE_NONCOMPATIBLE_STATE");
+        sFailCauseMap.put(UNKNOWN_INFO_ELEMENT, "UNKNOWN_INFO_ELEMENT");
+        sFailCauseMap.put(CONDITIONAL_IE_ERROR, "CONDITIONAL_IE_ERROR");
+        sFailCauseMap.put(MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE,
+                "MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE");
+        sFailCauseMap.put(PROTOCOL_ERRORS, "PROTOCOL_ERRORS");
+        sFailCauseMap.put(APN_TYPE_CONFLICT, "APN_TYPE_CONFLICT");
+        sFailCauseMap.put(INVALID_PCSCF_ADDR, "INVALID_PCSCF_ADDR");
+        sFailCauseMap.put(INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN,
+                "INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN");
+        sFailCauseMap.put(EMM_ACCESS_BARRED, "EMM_ACCESS_BARRED");
+        sFailCauseMap.put(EMERGENCY_IFACE_ONLY, "EMERGENCY_IFACE_ONLY");
+        sFailCauseMap.put(IFACE_MISMATCH, "IFACE_MISMATCH");
+        sFailCauseMap.put(COMPANION_IFACE_IN_USE, "COMPANION_IFACE_IN_USE");
+        sFailCauseMap.put(IP_ADDRESS_MISMATCH, "IP_ADDRESS_MISMATCH");
+        sFailCauseMap.put(IFACE_AND_POL_FAMILY_MISMATCH,
+                "IFACE_AND_POL_FAMILY_MISMATCH");
+        sFailCauseMap.put(EMM_ACCESS_BARRED_INFINITE_RETRY,
+                "EMM_ACCESS_BARRED_INFINITE_RETRY");
+        sFailCauseMap.put(AUTH_FAILURE_ON_EMERGENCY_CALL,
+                "AUTH_FAILURE_ON_EMERGENCY_CALL");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_1, "OEM_DCFAILCAUSE_1");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_2, "OEM_DCFAILCAUSE_2");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_3, "OEM_DCFAILCAUSE_3");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_4, "OEM_DCFAILCAUSE_4");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_5, "OEM_DCFAILCAUSE_5");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_6, "OEM_DCFAILCAUSE_6");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_7, "OEM_DCFAILCAUSE_7");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_8, "OEM_DCFAILCAUSE_8");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_9, "OEM_DCFAILCAUSE_9");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_10, "OEM_DCFAILCAUSE_10");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_11, "OEM_DCFAILCAUSE_11");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_12, "OEM_DCFAILCAUSE_12");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_13, "OEM_DCFAILCAUSE_13");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_14, "OEM_DCFAILCAUSE_14");
+        sFailCauseMap.put(OEM_DCFAILCAUSE_15, "OEM_DCFAILCAUSE_15");
+        sFailCauseMap.put(REGISTRATION_FAIL, "REGISTRATION_FAIL");
+        sFailCauseMap.put(GPRS_REGISTRATION_FAIL, "GPRS_REGISTRATION_FAIL");
+        sFailCauseMap.put(SIGNAL_LOST, "SIGNAL_LOST");
+        sFailCauseMap.put(PREF_RADIO_TECH_CHANGED, "PREF_RADIO_TECH_CHANGED");
+        sFailCauseMap.put(RADIO_POWER_OFF, "RADIO_POWER_OFF");
+        sFailCauseMap.put(TETHERED_CALL_ACTIVE, "TETHERED_CALL_ACTIVE");
+        sFailCauseMap.put(ERROR_UNSPECIFIED, "ERROR_UNSPECIFIED");
+        sFailCauseMap.put(UNKNOWN, "UNKNOWN");
+        sFailCauseMap.put(RADIO_NOT_AVAILABLE, "RADIO_NOT_AVAILABLE");
+        sFailCauseMap.put(UNACCEPTABLE_NETWORK_PARAMETER,
+                "UNACCEPTABLE_NETWORK_PARAMETER");
+        sFailCauseMap.put(CONNECTION_TO_DATACONNECTIONAC_BROKEN,
+                "CONNECTION_TO_DATACONNECTIONAC_BROKEN");
+        sFailCauseMap.put(LOST_CONNECTION, "LOST_CONNECTION");
+        sFailCauseMap.put(RESET_BY_FRAMEWORK, "RESET_BY_FRAMEWORK");
     }
 
     /**
      * Map of subId -> set of data call setup permanent failure for the carrier.
      */
-    private static final HashMap<Integer, HashSet<DataFailCause>> sPermanentFailureCache =
+    private static final HashMap<Integer, Set<Integer>> sPermanentFailureCache =
             new HashMap<>();
 
-    DataFailCause(int errorCode) {
-        mErrorCode = errorCode;
-    }
-
-    public int getErrorCode() {
-        return mErrorCode;
-    }
-
     /**
      * Returns whether or not the fail cause is a failure that requires a modem restart
      *
      * @param context device context
+     * @param cause data disconnect cause
      * @param subId subscription index
      * @return true if the fail cause code needs platform to trigger a modem restart.
      */
-    public boolean isRadioRestartFailure(Context context, int subId) {
+    public static boolean isRadioRestartFailure(@NonNull Context context, @FailCause int cause,
+                                                int subId) {
         CarrierConfigManager configManager = (CarrierConfigManager)
                 context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
         if (configManager != null) {
             PersistableBundle b = configManager.getConfigForSubId(subId);
 
             if (b != null) {
-                if (this == REGULAR_DEACTIVATION
+                if (cause == REGULAR_DEACTIVATION
                         && b.getBoolean(CarrierConfigManager
                         .KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL)) {
                     // This is for backward compatibility support. We need to continue support this
@@ -170,7 +402,7 @@
                 int[] causeCodes = b.getIntArray(CarrierConfigManager
                         .KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY);
                 if (causeCodes != null) {
-                    return Arrays.stream(causeCodes).anyMatch(i -> i == getErrorCode());
+                    return Arrays.stream(causeCodes).anyMatch(i -> i == cause);
                 }
             }
         }
@@ -178,11 +410,11 @@
         return false;
     }
 
-    public boolean isPermanentFailure(Context context, int subId) {
-
+    public static boolean isPermanentFailure(@NonNull Context context, @FailCause int failCause,
+                                             int subId) {
         synchronized (sPermanentFailureCache) {
 
-            HashSet<DataFailCause> permanentFailureSet = sPermanentFailureCache.get(subId);
+            Set<Integer> permanentFailureSet = sPermanentFailureCache.get(subId);
 
             // In case of cache miss, we need to look up the settings from carrier config.
             if (permanentFailureSet == null) {
@@ -194,11 +426,12 @@
                     if (b != null) {
                         String[] permanentFailureStrings = b.getStringArray(CarrierConfigManager.
                                 KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS);
-
                         if (permanentFailureStrings != null) {
                             permanentFailureSet = new HashSet<>();
-                            for (String failure : permanentFailureStrings) {
-                                permanentFailureSet.add(DataFailCause.valueOf(failure));
+                            for (Map.Entry<Integer, String> e : sFailCauseMap.entrySet()) {
+                                if (ArrayUtils.contains(permanentFailureStrings, e.getValue())) {
+                                    permanentFailureSet.add(e.getKey());
+                                }
                             }
                         }
                     }
@@ -207,7 +440,7 @@
                 // If we are not able to find the configuration from carrier config, use the default
                 // ones.
                 if (permanentFailureSet == null) {
-                    permanentFailureSet = new HashSet<DataFailCause>() {
+                    permanentFailureSet = new HashSet<Integer>() {
                         {
                             add(OPERATOR_BARRED);
                             add(MISSING_UNKNOWN_APN);
@@ -232,28 +465,39 @@
                 sPermanentFailureCache.put(subId, permanentFailureSet);
             }
 
-            return permanentFailureSet.contains(this);
+            return permanentFailureSet.contains(failCause);
         }
     }
 
-    public boolean isEventLoggable() {
-        return (this == OPERATOR_BARRED) || (this == INSUFFICIENT_RESOURCES) ||
-                (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) ||
-                (this == ACTIVATION_REJECT_GGSN) || (this == ACTIVATION_REJECT_UNSPECIFIED) ||
-                (this == SERVICE_OPTION_NOT_SUBSCRIBED) ||
-                (this == SERVICE_OPTION_NOT_SUPPORTED) ||
-                (this == SERVICE_OPTION_OUT_OF_ORDER) || (this == NSAPI_IN_USE) ||
-                (this == ONLY_IPV4_ALLOWED) || (this == ONLY_IPV6_ALLOWED) ||
-                (this == PROTOCOL_ERRORS) || (this == SIGNAL_LOST) ||
-                (this == RADIO_POWER_OFF) || (this == TETHERED_CALL_ACTIVE) ||
-                (this == UNACCEPTABLE_NETWORK_PARAMETER);
+    public static boolean isEventLoggable(@FailCause int dataFailCause) {
+        return (dataFailCause == OPERATOR_BARRED) || (dataFailCause == INSUFFICIENT_RESOURCES)
+                || (dataFailCause == UNKNOWN_PDP_ADDRESS_TYPE)
+                || (dataFailCause == USER_AUTHENTICATION)
+                || (dataFailCause == ACTIVATION_REJECT_GGSN)
+                || (dataFailCause == ACTIVATION_REJECT_UNSPECIFIED)
+                || (dataFailCause == SERVICE_OPTION_NOT_SUBSCRIBED)
+                || (dataFailCause == SERVICE_OPTION_NOT_SUPPORTED)
+                || (dataFailCause == SERVICE_OPTION_OUT_OF_ORDER)
+                || (dataFailCause == NSAPI_IN_USE)
+                || (dataFailCause == ONLY_IPV4_ALLOWED)
+                || (dataFailCause == ONLY_IPV6_ALLOWED)
+                || (dataFailCause == PROTOCOL_ERRORS)
+                || (dataFailCause == SIGNAL_LOST)
+                || (dataFailCause == RADIO_POWER_OFF)
+                || (dataFailCause == TETHERED_CALL_ACTIVE)
+                || (dataFailCause == UNACCEPTABLE_NETWORK_PARAMETER);
     }
 
-    public static DataFailCause fromInt(int errorCode) {
-        DataFailCause fc = sErrorCodeToFailCauseMap.get(errorCode);
-        if (fc == null) {
-            fc = UNKNOWN;
+    public static String toString(@FailCause int dataFailCause) {
+        int cause = getFailCause(dataFailCause);
+        return (cause == UNKNOWN) ? "UNKNOWN(" + dataFailCause + ")" : sFailCauseMap.get(cause);
+    }
+
+    public static int getFailCause(@FailCause int failCause) {
+        if (sFailCauseMap.containsKey(failCause)) {
+            return failCause;
+        } else {
+            return UNKNOWN;
         }
-        return fc;
     }
 }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 29d32e9..f241d45 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6382,8 +6382,9 @@
     public @PrefNetworkMode int getPreferredNetworkType(int subId) {
         try {
             ITelephony telephony = getITelephony();
-            if (telephony != null)
+            if (telephony != null) {
                 return telephony.getPreferredNetworkType(subId);
+            }
         } catch (RemoteException ex) {
             Rlog.e(TAG, "getPreferredNetworkType RemoteException", ex);
         } catch (NullPointerException ex) {
@@ -6393,6 +6394,37 @@
     }
 
     /**
+     * Get the preferred network type bitmap.
+     *
+     * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+     * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
+     * @return a 32-bit bitmap.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @SystemApi
+    public @NetworkTypeBitMask int getPreferredNetworkTypeBitmap() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return RadioAccessFamily.getRafFromNetworkType(
+                        telephony.getPreferredNetworkType(getSubId()));
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "getPreferredNetworkTypeBitmap RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "getPreferredNetworkTypeBitmap NPE", ex);
+        }
+        return 0;
+    }
+
+    /**
      * Sets the network selection mode to automatic.
      *
      * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
@@ -6607,6 +6639,37 @@
     }
 
     /**
+     * Set the preferred network type bitmap.
+     *
+     * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+     * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *
+     * @param networkTypeBitmap a 32-bit bitmap.
+     * @return true on success; false on any failure.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @SystemApi
+    public boolean setPreferredNetworkTypeBitmap(@NetworkTypeBitMask int networkTypeBitmap) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.setPreferredNetworkType(
+                        getSubId(), RadioAccessFamily.getNetworkTypeFromRaf(networkTypeBitmap));
+            }
+        } catch (RemoteException ex) {
+            Rlog.e(TAG, "setPreferredNetworkType RemoteException", ex);
+        } catch (NullPointerException ex) {
+            Rlog.e(TAG, "setPreferredNetworkType NPE", ex);
+        }
+        return false;
+    }
+
+    /**
      * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
      *
      * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 553e3fb..0edc002 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -284,8 +284,6 @@
      */
     private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
             int uid, String callingPackage, String message) {
-        Log.wtf(LOG_TAG,
-                "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message);
         // If the device identifier check is enabled then enforce the new access requirements for
         // both 1P and 3P apps.
         boolean enableDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
@@ -295,17 +293,40 @@
         boolean relax3PDeviceIdentifierCheck = Settings.Global.getInt(context.getContentResolver(),
                 Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED, 0) == 1;
         boolean is3PApp = true;
+        // Also check if the application is a preloaded non-privileged app; if so there is a
+        // separate setting to relax the check for these apps to ensure users can relax the check
+        // for 3P or non-priv apps as needed while continuing to test the other.
+        boolean relaxNonPrivDeviceIdentifierCheck = Settings.Global.getInt(
+                context.getContentResolver(),
+                Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED, 0) == 1;
+        boolean isNonPrivApp = false;
         ApplicationInfo callingPackageInfo = null;
         try {
             callingPackageInfo = context.getPackageManager().getApplicationInfo(callingPackage, 0);
-            if (callingPackageInfo.isSystemApp()) {
+            if (callingPackageInfo.isPrivilegedApp()) {
                 is3PApp = false;
+            } else if (callingPackageInfo.isSystemApp()) {
+                is3PApp = false;
+                isNonPrivApp = true;
             }
         } catch (PackageManager.NameNotFoundException e) {
             // If the application info for the calling package could not be found then assume the
             // calling app is a 3P app to detect any issues with the check
+            Log.e(LOG_TAG, "Exception caught obtaining package info for package " + callingPackage,
+                    e);
         }
-        if (enableDeviceIdentifierCheck || (is3PApp && !relax3PDeviceIdentifierCheck)) {
+        Log.wtf(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message
+                + ":is3PApp=" + is3PApp + ":isNonPrivApp=" + isNonPrivApp);
+        // The new Q restrictions for device identifier access will be enforced if any of the
+        // following are true:
+        // - The PRIVILEGED_DEVICE_IDENTIFIER_CHECK_ENABLED setting has been set.
+        // - The app requesting a device identifier is not a preloaded app (3P), and the
+        //   PRIVILEGED_DEVICE_IDENTIFIER_3P_CHECK_RELAXED setting has not been set.
+        // - The app requesting a device identifier is a preloaded app but is not a privileged app,
+        //   and the PRIVILEGED_DEVICE_IDENTIFIER_NON_PRIV_CHECK_RELAXED setting has not been set.
+        if (enableDeviceIdentifierCheck
+                || (is3PApp && !relax3PDeviceIdentifierCheck)
+                || (isNonPrivApp && !relaxNonPrivDeviceIdentifierCheck)) {
             boolean targetQBehaviorDisabled = Settings.Global.getInt(context.getContentResolver(),
                     Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_TARGET_Q_BEHAVIOR_ENABLED, 0) == 0;
             if (callingPackage != null) {
diff --git a/tests/testables/src/android/testing/BaseFragmentTest.java b/tests/testables/src/android/testing/BaseFragmentTest.java
index 5fa065a..d18c126 100644
--- a/tests/testables/src/android/testing/BaseFragmentTest.java
+++ b/tests/testables/src/android/testing/BaseFragmentTest.java
@@ -21,7 +21,9 @@
 import android.app.FragmentController;
 import android.app.FragmentHostCallback;
 import android.app.FragmentManagerNonConfig;
+import android.content.Context;
 import android.graphics.PixelFormat;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Parcelable;
 import android.support.test.InstrumentationRegistry;
@@ -75,7 +77,7 @@
         TestableLooper.get(this).runWithLooper(() -> {
             mHandler = new Handler();
 
-            mFragment = mCls.newInstance();
+            mFragment = instantiate(mContext, mCls.getName(), null);
             mFragments = FragmentController.createController(new HostCallbacks());
             mFragments.attachHost(null);
             mFragments.getFragmentManager().beginTransaction()
@@ -187,6 +189,13 @@
         TestableLooper.get(this).processAllMessages();
     }
 
+    /**
+     * Method available for override to replace fragment instantiation.
+     */
+    protected Fragment instantiate(Context context, String className, @Nullable Bundle arguments) {
+        return Fragment.instantiate(context, className, arguments);
+    }
+
     private View findViewById(int id) {
         return mView.findViewById(id);
     }
@@ -206,6 +215,11 @@
         }
 
         @Override
+        public Fragment instantiate(Context context, String className, Bundle arguments) {
+            return BaseFragmentTest.this.instantiate(context, className, arguments);
+        }
+
+        @Override
         public boolean onShouldSaveFragmentState(Fragment fragment) {
             return true; // True for now.
         }
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index b5a990e..6476abd 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -209,24 +209,42 @@
         return self.raw
 
 
-def _parse_stream(f, clazz_cb=None, base_f=None):
+def _parse_stream(f, clazz_cb=None, base_f=None, out_classes_with_base=None,
+                  in_classes_with_base=[]):
     api = {}
+    in_classes_with_base = _retry_iterator(in_classes_with_base)
 
     if base_f:
-        base_classes = _parse_stream_to_generator(base_f)
+        base_classes = _retry_iterator(_parse_stream_to_generator(base_f))
     else:
         base_classes = []
 
-    for clazz in _parse_stream_to_generator(f):
-        base_class = _parse_to_matching_class(base_classes, clazz)
-        if base_class:
-            clazz.merge_from(base_class)
-
+    def handle_class(clazz):
         if clazz_cb:
             clazz_cb(clazz)
         else: # In callback mode, don't keep track of the full API
             api[clazz.fullname] = clazz
 
+    def handle_missed_classes_with_base(clazz):
+        for c in _yield_until_matching_class(in_classes_with_base, clazz):
+            base_class = _skip_to_matching_class(base_classes, c)
+            if base_class:
+                handle_class(base_class)
+
+    for clazz in _parse_stream_to_generator(f):
+        # Before looking at clazz, let's see if there's some classes that were not present, but
+        # may have an entry in the base stream.
+        handle_missed_classes_with_base(clazz)
+
+        base_class = _skip_to_matching_class(base_classes, clazz)
+        if base_class:
+            clazz.merge_from(base_class)
+            if out_classes_with_base is not None:
+                out_classes_with_base.append(clazz)
+        handle_class(clazz)
+
+    handle_missed_classes_with_base(None)
+
     return api
 
 def _parse_stream_to_generator(f):
@@ -257,18 +275,22 @@
         elif raw.startswith("    field"):
             clazz.fields.append(Field(clazz, line, raw, blame))
         elif raw.startswith("  }") and clazz:
-            while True:
-                retry = yield clazz
-                if not retry:
-                    break
-                # send() was called, asking us to redeliver clazz on next(). Still need to yield
-                # a dummy value to the send() first though.
-                if (yield "Returning clazz on next()"):
-                        raise TypeError("send() must be followed by next(), not send()")
+            yield clazz
 
+def _retry_iterator(it):
+    """Wraps an iterator, such that calling send(True) on it will redeliver the same element"""
+    for e in it:
+        while True:
+            retry = yield e
+            if not retry:
+                break
+            # send() was called, asking us to redeliver clazz on next(). Still need to yield
+            # a dummy value to the send() first though.
+            if (yield "Returning clazz on next()"):
+                raise TypeError("send() must be followed by next(), not send()")
 
-def _parse_to_matching_class(classes, needle):
-    """Takes a classes generator and parses it until it returns the class we're looking for
+def _skip_to_matching_class(classes, needle):
+    """Takes a classes iterator and consumes entries until it returns the class we're looking for
 
     This relies on classes being sorted by package and class name."""
 
@@ -276,8 +298,8 @@
         if clazz.pkg.name < needle.pkg.name:
             # We haven't reached the right package yet
             continue
-        if clazz.name < needle.name:
-            # We haven't reached the right class yet
+        if clazz.pkg.name == needle.pkg.name and clazz.fullname < needle.fullname:
+            # We're in the right package, but not the right class yet
             continue
         if clazz.fullname == needle.fullname:
             return clazz
@@ -285,6 +307,28 @@
         classes.send(clazz)
         return None
 
+def _yield_until_matching_class(classes, needle):
+    """Takes a class iterator and yields entries it until it reaches the class we're looking for.
+
+    This relies on classes being sorted by package and class name."""
+
+    for clazz in classes:
+        if needle is None:
+            yield clazz
+        elif clazz.pkg.name < needle.pkg.name:
+            # We haven't reached the right package yet
+            yield clazz
+        elif clazz.pkg.name == needle.pkg.name and clazz.fullname < needle.fullname:
+            # We're in the right package, but not the right class yet
+            yield clazz
+        elif clazz.fullname == needle.fullname:
+            # Class found, abort.
+            return
+        else:
+            # We ran past the right class. Send it back into the iterator, then abort.
+            classes.send(clazz)
+            return
+
 class Failure():
     def __init__(self, sig, clazz, detail, error, rule, msg):
         self.sig = sig
@@ -1543,12 +1587,14 @@
     verify_singleton(clazz)
 
 
-def examine_stream(stream, base_stream=None):
+def examine_stream(stream, base_stream=None, in_classes_with_base=[], out_classes_with_base=None):
     """Find all style issues in the given API stream."""
     global failures, noticed
     failures = {}
     noticed = {}
-    _parse_stream(stream, examine_clazz, base_f=base_stream)
+    _parse_stream(stream, examine_clazz, base_f=base_stream,
+                  in_classes_with_base=in_classes_with_base,
+                  out_classes_with_base=out_classes_with_base)
     return (failures, noticed)
 
 
@@ -1734,19 +1780,24 @@
         show_stats(cur, prev)
         sys.exit()
 
+    classes_with_base = []
+
     with current_file as f:
         if base_current_file:
             with base_current_file as base_f:
-                cur_fail, cur_noticed = examine_stream(f, base_f)
+                cur_fail, cur_noticed = examine_stream(f, base_f,
+                                                       out_classes_with_base=classes_with_base)
         else:
-            cur_fail, cur_noticed = examine_stream(f)
+            cur_fail, cur_noticed = examine_stream(f, out_classes_with_base=classes_with_base)
+
     if not previous_file is None:
         with previous_file as f:
             if base_previous_file:
                 with base_previous_file as base_f:
-                    prev_fail, prev_noticed = examine_stream(f, base_f)
+                    prev_fail, prev_noticed = examine_stream(f, base_f,
+                                                             in_classes_with_base=classes_with_base)
             else:
-                prev_fail, prev_noticed = examine_stream(f)
+                prev_fail, prev_noticed = examine_stream(f, in_classes_with_base=classes_with_base)
 
         # ignore errors from previous API level
         for p in prev_fail:
diff --git a/tools/apilint/apilint_sha_system.sh b/tools/apilint/apilint_sha_system.sh
new file mode 100755
index 0000000..8538a3d
--- /dev/null
+++ b/tools/apilint/apilint_sha_system.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# 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.
+
+if git show --name-only --pretty=format: $1 | grep api/ > /dev/null; then
+  python tools/apilint/apilint.py \
+    --base-current <(git show $1:api/current.txt) \
+    --base-previous <(git show $1^:api/current.txt) \
+    <(git show $1:api/system-current.txt) \
+    <(git show $1^:api/system-current.txt)
+fi
diff --git a/tools/apilint/apilint_test.py b/tools/apilint/apilint_test.py
new file mode 100644
index 0000000..ece69a9
--- /dev/null
+++ b/tools/apilint/apilint_test.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python
+
+# 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.
+
+import unittest
+
+import apilint
+
+def cls(pkg, name):
+    return apilint.Class(apilint.Package(999, "package %s {" % pkg, None), 999,
+                  "public final class %s {" % name, None)
+
+_ri = apilint._retry_iterator
+
+c1 = cls("android.app", "ActivityManager")
+c2 = cls("android.app", "Notification")
+c3 = cls("android.app", "Notification.Action")
+c4 = cls("android.graphics", "Bitmap")
+
+class UtilTests(unittest.TestCase):
+    def test_retry_iterator(self):
+        it = apilint._retry_iterator([1, 2, 3, 4])
+        self.assertEqual(it.next(), 1)
+        self.assertEqual(it.next(), 2)
+        self.assertEqual(it.next(), 3)
+        it.send("retry")
+        self.assertEqual(it.next(), 3)
+        self.assertEqual(it.next(), 4)
+        with self.assertRaises(StopIteration):
+            it.next()
+
+    def test_retry_iterator_one(self):
+        it = apilint._retry_iterator([1])
+        self.assertEqual(it.next(), 1)
+        it.send("retry")
+        self.assertEqual(it.next(), 1)
+        with self.assertRaises(StopIteration):
+            it.next()
+
+    def test_retry_iterator_one(self):
+        it = apilint._retry_iterator([1])
+        self.assertEqual(it.next(), 1)
+        it.send("retry")
+        self.assertEqual(it.next(), 1)
+        with self.assertRaises(StopIteration):
+            it.next()
+
+    def test_skip_to_matching_class_found(self):
+        it = _ri([c1, c2, c3, c4])
+        self.assertEquals(apilint._skip_to_matching_class(it, c3),
+                          c3)
+        self.assertEqual(it.next(), c4)
+
+    def test_skip_to_matching_class_not_found(self):
+        it = _ri([c1, c2, c3, c4])
+        self.assertEquals(apilint._skip_to_matching_class(it, cls("android.content", "ContentProvider")),
+                          None)
+        self.assertEqual(it.next(), c4)
+
+    def test_yield_until_matching_class_found(self):
+        it = _ri([c1, c2, c3, c4])
+        self.assertEquals(list(apilint._yield_until_matching_class(it, c3)),
+                          [c1, c2])
+        self.assertEqual(it.next(), c4)
+
+    def test_yield_until_matching_class_not_found(self):
+        it = _ri([c1, c2, c3, c4])
+        self.assertEquals(list(apilint._yield_until_matching_class(it, cls("android.content", "ContentProvider"))),
+                          [c1, c2, c3])
+        self.assertEqual(it.next(), c4)
+
+    def test_yield_until_matching_class_None(self):
+        it = _ri([c1, c2, c3, c4])
+        self.assertEquals(list(apilint._yield_until_matching_class(it, None)),
+                          [c1, c2, c3, c4])
+
+
+faulty_current_txt = """
+package android.app {
+  public final class Activity {
+  }
+
+  public final class WallpaperColors implements android.os.Parcelable {
+    ctor public WallpaperColors(android.os.Parcel);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR;
+  }
+}
+""".split('\n')
+
+ok_current_txt = """
+package android.app {
+  public final class Activity {
+  }
+
+  public final class WallpaperColors implements android.os.Parcelable {
+    ctor public WallpaperColors();
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.WallpaperColors> CREATOR;
+  }
+}
+""".split('\n')
+
+system_current_txt = """
+package android.app {
+  public final class WallpaperColors implements android.os.Parcelable {
+    method public int getSomething();
+  }
+}
+""".split('\n')
+
+
+
+class BaseFileTests(unittest.TestCase):
+    def test_base_file_avoids_errors(self):
+        failures, _ = apilint.examine_stream(system_current_txt, ok_current_txt)
+        self.assertEquals(failures, {})
+
+    def test_class_with_base_finds_same_errors(self):
+        failures_with_classes_with_base, _ = apilint.examine_stream("", faulty_current_txt,
+                                                                    in_classes_with_base=[cls("android.app", "WallpaperColors")])
+        failures_with_system_txt, _ = apilint.examine_stream(system_current_txt, faulty_current_txt)
+
+        self.assertEquals(failures_with_classes_with_base.keys(), failures_with_system_txt.keys())
+
+    def test_classes_with_base_is_emited(self):
+        classes_with_base = []
+        _, _ = apilint.examine_stream(system_current_txt, faulty_current_txt,
+                                      out_classes_with_base=classes_with_base)
+        self.assertEquals(map(lambda x: x.fullname, classes_with_base), ["android.app.WallpaperColors"])
+
+if __name__ == "__main__":
+    unittest.main()
\ No newline at end of file
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index faa3547..f6c9c0e 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -453,7 +453,7 @@
     map<string, bool> variableNames;
     set<string> parents;
     vector<const FieldDescriptor*> fieldsInOrder = sortFields(descriptor);
-    bool skip[fieldsInOrder.size()];
+    vector<bool> skip(fieldsInOrder.size());
     const Destination incidentDest = getPrivacyFlags(descriptor).dest();
 
     for (size_t i=0; i<fieldsInOrder.size(); i++) {
diff --git a/wifi/tests/Android.mk b/wifi/tests/Android.mk
index 73341ac..401b652 100644
--- a/wifi/tests/Android.mk
+++ b/wifi/tests/Android.mk
@@ -45,7 +45,7 @@
 LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude)
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-test \
+    androidx.test.rules \
     core-test-rules \
     guava \
     mockito-target-minus-junit4 \
diff --git a/wifi/tests/AndroidManifest.xml b/wifi/tests/AndroidManifest.xml
index 4eaca2b..b6c38bc 100644
--- a/wifi/tests/AndroidManifest.xml
+++ b/wifi/tests/AndroidManifest.xml
@@ -30,7 +30,7 @@
         </activity>
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="android.net.wifi.test"
         android:label="Frameworks Wifi API Tests">
     </instrumentation>
diff --git a/wifi/tests/AndroidTest.xml b/wifi/tests/AndroidTest.xml
index 45c7a17..cae19e4 100644
--- a/wifi/tests/AndroidTest.xml
+++ b/wifi/tests/AndroidTest.xml
@@ -22,7 +22,7 @@
     <option name="test-tag" value="FrameworksWifiApiTests" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.net.wifi.test" />
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
 </configuration>
diff --git a/wifi/tests/README.md b/wifi/tests/README.md
index b418abd..b0594f2 100644
--- a/wifi/tests/README.md
+++ b/wifi/tests/README.md
@@ -37,7 +37,7 @@
 If you manually build and push the test APK to the device you can run tests using
 
 ```
-adb shell am instrument -w 'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner'
+adb shell am instrument -w 'android.net.wifi.test/androidx.test.runner.AndroidJUnitRunner'
 ```
 
 ## Adding Tests
diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh
index 4e52b8f..2caf8a5 100755
--- a/wifi/tests/runtests.sh
+++ b/wifi/tests/runtests.sh
@@ -22,4 +22,4 @@
 adb install -r -g "$OUT/data/app/FrameworksWifiApiTests/FrameworksWifiApiTests.apk"
 
 adb shell am instrument --no-hidden-api-checks -w "$@" \
-  'android.net.wifi.test/android.support.test.runner.AndroidJUnitRunner'
+  'android.net.wifi.test/androidx.test.runner.AndroidJUnitRunner'
diff --git a/wifi/tests/src/android/net/wifi/ParcelUtilTest.java b/wifi/tests/src/android/net/wifi/ParcelUtilTest.java
index 0c3bf3b..917b1df 100644
--- a/wifi/tests/src/android/net/wifi/ParcelUtilTest.java
+++ b/wifi/tests/src/android/net/wifi/ParcelUtilTest.java
@@ -22,7 +22,8 @@
 import static org.junit.Assert.assertNull;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/wifi/tests/src/android/net/wifi/ScanResultTest.java b/wifi/tests/src/android/net/wifi/ScanResultTest.java
index 458c43d..54ec325 100644
--- a/wifi/tests/src/android/net/wifi/ScanResultTest.java
+++ b/wifi/tests/src/android/net/wifi/ScanResultTest.java
@@ -22,15 +22,14 @@
 import static org.mockito.Mockito.validateMockitoUsage;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
-import android.net.wifi.WifiScanner.ScanSettings;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.MockitoAnnotations;
 
-
 /**
  * Unit tests for {@link android.net.wifi.WifiScanner}.
  */
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 8d97307..c744f18 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -26,7 +26,8 @@
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index e569efe..6ec64ff 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -19,8 +19,8 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -28,7 +28,8 @@
 import android.net.wifi.WifiEnterpriseConfig.Phase2;
 import android.os.Parcel;
 import android.security.Credentials;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -36,7 +37,6 @@
 import java.security.PrivateKey;
 import java.security.cert.X509Certificate;
 
-
 /**
  * Unit tests for {@link android.net.wifi.WifiEnterpriseConfig}.
  */
diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
index f9fb062..fb0af5f 100644
--- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
@@ -21,7 +21,8 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 1001b10..c43948b 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -66,7 +66,8 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.test.TestLooper;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
index f8ab8a2..2258e4d 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkAgentSpecifierTest.java
@@ -25,9 +25,10 @@
 import android.net.NetworkRequest;
 import android.os.Parcel;
 import android.os.PatternMatcher;
-import android.support.test.filters.SmallTest;
 import android.util.Pair;
 
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 
 /**
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
index 2505499..83627ad 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
@@ -29,7 +29,8 @@
 import android.net.NetworkSpecifier;
 import android.os.PatternMatcher;
 import android.os.Process;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
index 997282b..fdd11a3 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
@@ -29,8 +29,9 @@
 import android.net.wifi.WifiNetworkScoreCache.CacheListener;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.google.common.collect.ImmutableList;
 
@@ -44,7 +45,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-
 /** Unit tests for {@link WifiNetworkScoreCache}. */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
index 856f0c7..2a8df8d 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -26,9 +26,10 @@
 import android.net.MatchAllNetworkSpecifier;
 import android.os.Parcel;
 import android.os.PatternMatcher;
-import android.support.test.filters.SmallTest;
 import android.util.Pair;
 
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 
 /**
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 5cc8217..31f501f 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -19,7 +19,8 @@
 import static org.junit.Assert.*;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index cf1ed8f..76bfff0 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -32,7 +32,8 @@
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.test.TestLooper;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.internal.util.test.BidirectionalAsyncChannelServer;
 
@@ -44,7 +45,6 @@
 
 import java.util.Arrays;
 
-
 /**
  * Unit tests for {@link android.net.wifi.WifiScanner}.
  */
diff --git a/wifi/tests/src/android/net/wifi/WifiSsidTest.java b/wifi/tests/src/android/net/wifi/WifiSsidTest.java
index b58f2c7..10a37c0 100644
--- a/wifi/tests/src/android/net/wifi/WifiSsidTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiSsidTest.java
@@ -19,7 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 
diff --git a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
index 6ecd931..83affed 100644
--- a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
@@ -18,7 +18,7 @@
 
 import static org.hamcrest.core.IsEqual.equalTo;
 
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
index 657e5a7..4189e40 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
@@ -21,7 +21,8 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 45e1720..e882b6b 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -38,7 +38,8 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.test.TestLooper;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import libcore.util.HexEncoding;
 
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
index f32fe59..d9a1d9af 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/ConfigParserTest.java
@@ -22,7 +22,10 @@
 import android.net.wifi.FakeKeys;
 import android.net.wifi.hotspot2.pps.Credential;
 import android.net.wifi.hotspot2.pps.HomeSp;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
 
 import java.io.BufferedReader;
 import java.io.IOException;
@@ -30,8 +33,6 @@
 import java.io.InputStreamReader;
 import java.util.Arrays;
 
-import org.junit.Test;
-
 /**
  * Unit tests for {@link android.net.wifi.hotspot2.ConfigParser}.
  */
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
index 89ecd0f..c7e009e 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/OsuProviderTest.java
@@ -23,7 +23,8 @@
 import android.net.Uri;
 import android.net.wifi.WifiSsid;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index ee5a75e..fc03e7e 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -25,9 +25,10 @@
 import android.net.wifi.hotspot2.pps.Policy;
 import android.net.wifi.hotspot2.pps.UpdateParameter;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
 import android.util.Base64;
 
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 
 import java.nio.charset.StandardCharsets;
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java
index 707b64f..66c595f 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/omadm/PpsMoParserTest.java
@@ -19,14 +19,13 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.net.wifi.hotspot2.omadm.PpsMoParser;
 import android.net.wifi.hotspot2.PasspointConfiguration;
 import android.net.wifi.hotspot2.pps.Credential;
 import android.net.wifi.hotspot2.pps.HomeSp;
 import android.net.wifi.hotspot2.pps.Policy;
 import android.net.wifi.hotspot2.pps.UpdateParameter;
-import android.support.test.filters.SmallTest;
-import android.text.TextUtils;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/omadm/XMLParserTest.java b/wifi/tests/src/android/net/wifi/hotspot2/omadm/XMLParserTest.java
index ef478c7..85d0a90 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/omadm/XMLParserTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/omadm/XMLParserTest.java
@@ -20,7 +20,8 @@
 
 import android.net.wifi.hotspot2.omadm.XMLNode;
 import android.net.wifi.hotspot2.omadm.XMLParser;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
index c07db6c..a9d4b8f 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java
@@ -22,7 +22,8 @@
 import android.net.wifi.EAPConstants;
 import android.net.wifi.FakeKeys;
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
index c7993e3..93d471a 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
@@ -20,7 +20,8 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
index 171d6ff..980b199 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
@@ -20,15 +20,15 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
 import android.util.Base64;
 
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java
index 2a7526b..0b8cd3d 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/UpdateParameterTest.java
@@ -20,17 +20,14 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.Parcel;
-import android.support.test.filters.SmallTest;
 import android.util.Base64;
 
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 
 import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
 
 /**
  * Unit tests for {@link android.net.wifi.hotspot2.pps.UpdateParameter}.
diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java
index 80f00a4..f61e6b7 100644
--- a/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java
+++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pDeviceTest.java
@@ -19,7 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
 
diff --git a/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java b/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java
index 2132b41..9e8dca4 100644
--- a/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/p2p/WifiP2pManagerTest.java
@@ -21,7 +21,8 @@
 
 import android.content.Context;
 import android.os.test.TestLooper;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import libcore.junit.util.ResourceLeakageDetector;
 
diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
index 8997ae9..afc7dff 100644
--- a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
@@ -31,7 +31,8 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.test.TestLooper;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
 
 import org.junit.Before;
 import org.junit.Test;