Merge "Improved logging and dump on TextClassification."
diff --git a/Android.bp b/Android.bp
index 7e71bdf..e135a50 100644
--- a/Android.bp
+++ b/Android.bp
@@ -614,6 +614,7 @@
         ":netd_aidl",
         ":vold_aidl",
         ":installd_aidl",
+        ":dumpstate_aidl",
 
         "lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl",
         "lowpan/java/android/net/lowpan/ILowpanNetScanCallback.aidl",
@@ -660,6 +661,7 @@
         include_dirs: [
             "system/update_engine/binder_bindings",
             "frameworks/native/aidl/binder",
+            "frameworks/native/cmds/dumpstate/binder",
             "frameworks/av/camera/aidl",
             "frameworks/av/media/libaudioclient/aidl",
             "frameworks/native/aidl/gui",
@@ -682,9 +684,6 @@
 
     no_framework_libs: true,
     libs: [
-        "conscrypt",
-        "okhttp",
-        "bouncycastle",
         "ext",
     ],
 
@@ -706,6 +705,7 @@
         "android.hardware.radio-V1.0-java",
         "android.hardware.radio-V1.3-java",
         "android.hardware.usb.gadget-V1.0-java",
+        "netd_aidl_interface-java",
     ],
 
     // Loaded with System.loadLibrary by android.view.textclassifier
@@ -835,7 +835,6 @@
         "cmds/statsd/src/**/*.proto",
         "core/proto/**/*.proto",
         "libs/incident/proto/**/*.proto",
-        "proto/src/stats_enums.proto",
     ],
     proto: {
         include_dirs: ["external/protobuf/src"],
@@ -873,7 +872,6 @@
     srcs: [
         "core/proto/**/*.proto",
         "libs/incident/proto/android/os/**/*.proto",
-        "proto/src/stats_enums.proto",
     ],
     // Protos have lots of MissingOverride and similar.
     errorprone: {
@@ -899,7 +897,6 @@
     srcs: [
         "core/proto/**/*.proto",
         "libs/incident/**/*.proto",
-        "proto/src/stats_enums.proto",
     ],
 
     target: {
@@ -1102,8 +1099,6 @@
      "-federationapi SupportLib $(location current/support-api.txt) "
 
 framework_docs_only_libs = [
-    "conscrypt",
-    "bouncycastle",
     "voip-common",
     "android.test.mock",
     "android-support-annotations",
@@ -1580,7 +1575,6 @@
         "core/java/org/apache/http/params/CoreConnectionPNames.java",
         "core/java/org/apache/http/params/HttpConnectionParams.java",
         "core/java/org/apache/http/params/HttpParams.java",
-        "core/java/android/net/http/HttpResponseCache.java",
         "core/java/android/net/http/SslCertificate.java",
         "core/java/android/net/http/SslError.java",
         "core/java/com/android/internal/util/HexDump.java",
diff --git a/api/current.txt b/api/current.txt
index 702e34d..0b6af29 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -9985,7 +9985,7 @@
     field public static final java.lang.String ACTION_INSERT = "android.intent.action.INSERT";
     field public static final java.lang.String ACTION_INSERT_OR_EDIT = "android.intent.action.INSERT_OR_EDIT";
     field public static final java.lang.String ACTION_INSTALL_FAILURE = "android.intent.action.INSTALL_FAILURE";
-    field public static final java.lang.String ACTION_INSTALL_PACKAGE = "android.intent.action.INSTALL_PACKAGE";
+    field public static final deprecated java.lang.String ACTION_INSTALL_PACKAGE = "android.intent.action.INSTALL_PACKAGE";
     field public static final java.lang.String ACTION_LOCALE_CHANGED = "android.intent.action.LOCALE_CHANGED";
     field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
     field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN";
@@ -10058,7 +10058,7 @@
     field public static final java.lang.String ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED";
     field public static final deprecated java.lang.String ACTION_UMS_CONNECTED = "android.intent.action.UMS_CONNECTED";
     field public static final deprecated java.lang.String ACTION_UMS_DISCONNECTED = "android.intent.action.UMS_DISCONNECTED";
-    field public static final java.lang.String ACTION_UNINSTALL_PACKAGE = "android.intent.action.UNINSTALL_PACKAGE";
+    field public static final deprecated java.lang.String ACTION_UNINSTALL_PACKAGE = "android.intent.action.UNINSTALL_PACKAGE";
     field public static final java.lang.String ACTION_USER_BACKGROUND = "android.intent.action.USER_BACKGROUND";
     field public static final java.lang.String ACTION_USER_FOREGROUND = "android.intent.action.USER_FOREGROUND";
     field public static final java.lang.String ACTION_USER_INITIALIZE = "android.intent.action.USER_INITIALIZE";
@@ -13262,6 +13262,7 @@
     method public void setPixels(int[], int, int, int, int, int, int);
     method public void setPremultiplied(boolean);
     method public void setWidth(int);
+    method public static android.graphics.Bitmap wrapHardwareBuffer(android.hardware.HardwareBuffer, android.graphics.ColorSpace);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.graphics.Bitmap> CREATOR;
     field public static final int DENSITY_NONE = 0; // 0x0
@@ -32539,7 +32540,7 @@
 
   public class Build {
     ctor public Build();
-    method public static java.util.List<android.os.Build.Partition> getPartitions();
+    method public static java.util.List<android.os.Build.Partition> getFingerprintedPartitions();
     method public static java.lang.String getRadioVersion();
     method public static java.lang.String getSerial();
     field public static final java.lang.String BOARD;
@@ -32570,9 +32571,9 @@
 
   public static class Build.Partition {
     ctor public Build.Partition();
+    method public long getBuildTimeMillis();
     method public java.lang.String getFingerprint();
     method public java.lang.String getName();
-    method public long getTimeMillis();
     field public static final java.lang.String PARTITION_NAME_SYSTEM = "system";
   }
 
@@ -42967,7 +42968,6 @@
     method public static int getDefaultSubscriptionId();
     method public static int getDefaultVoiceSubscriptionId();
     method public java.util.List<android.telephony.SubscriptionInfo> getOpportunisticSubscriptions(int);
-    method public static int getSlotIndex(int);
     method public static int[] getSubscriptionIds(int);
     method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
     method public boolean isActiveSubscriptionId(int);
@@ -42988,9 +42988,7 @@
     field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
     field public static final int DEFAULT_SUBSCRIPTION_ID = 2147483647; // 0x7fffffff
     field public static final java.lang.String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
-    field public static final int INVALID_SIM_SLOT_INDEX = -2; // 0xfffffffe
     field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
-    field public static final int SIM_NOT_INSERTED = -3; // 0xfffffffd
   }
 
   public static class SubscriptionManager.OnOpportunisticSubscriptionsChangedListener {
@@ -43325,7 +43323,7 @@
     field public static final int PROTOCOL_IPV6 = 1; // 0x1
     field public static final int PROTOCOL_PPP = 3; // 0x3
     field public static final int TYPE_CBS = 128; // 0x80
-    field public static final int TYPE_DEFAULT = 1; // 0x1
+    field public static final int TYPE_DEFAULT = 17; // 0x11
     field public static final int TYPE_DUN = 8; // 0x8
     field public static final int TYPE_EMERGENCY = 512; // 0x200
     field public static final int TYPE_FOTA = 32; // 0x20
@@ -48027,6 +48025,7 @@
 
   public class TouchDelegate {
     ctor public TouchDelegate(android.graphics.Rect, android.view.View);
+    method public android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo getTouchDelegateInfo();
     method public boolean onTouchEvent(android.view.MotionEvent);
     field public static final int ABOVE = 1; // 0x1
     field public static final int BELOW = 2; // 0x2
@@ -50009,6 +50008,7 @@
     method public int getTextSelectionEnd();
     method public int getTextSelectionStart();
     method public java.lang.CharSequence getTooltipText();
+    method public android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo getTouchDelegateInfo();
     method public android.view.accessibility.AccessibilityNodeInfo getTraversalAfter();
     method public android.view.accessibility.AccessibilityNodeInfo getTraversalBefore();
     method public java.lang.String getViewIdResourceName();
@@ -50099,6 +50099,7 @@
     method public void setTextEntryKey(boolean);
     method public void setTextSelection(int, int);
     method public void setTooltipText(java.lang.CharSequence);
+    method public void setTouchDelegateInfo(android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo);
     method public void setTraversalAfter(android.view.View);
     method public void setTraversalAfter(android.view.View, int);
     method public void setTraversalBefore(android.view.View);
@@ -50225,6 +50226,16 @@
     field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
   }
 
+  public static final class AccessibilityNodeInfo.TouchDelegateInfo implements android.os.Parcelable {
+    ctor public AccessibilityNodeInfo.TouchDelegateInfo(java.util.Map<android.graphics.Region, android.view.View>);
+    method public int describeContents();
+    method public android.graphics.Region getRegionAt(int);
+    method public int getRegionCount();
+    method public android.view.accessibility.AccessibilityNodeInfo getTargetForRegion(android.graphics.Region);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo> CREATOR;
+  }
+
   public abstract class AccessibilityNodeProvider {
     ctor public AccessibilityNodeProvider();
     method public void addExtraDataToAccessibilityNodeInfo(int, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
diff --git a/api/system-current.txt b/api/system-current.txt
index 85cc1e4..83a789a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -119,6 +119,7 @@
     field public static final java.lang.String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
     field public static final java.lang.String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
     field public static final java.lang.String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
+    field public static final java.lang.String NETWORK_SETUP_WIZARD = "android.permission.NETWORK_SETUP_WIZARD";
     field public static final java.lang.String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
     field public static final java.lang.String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
     field public static final java.lang.String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
@@ -523,11 +524,11 @@
     method public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
     method public java.lang.String getDeviceOwnerNameOnAnyUser();
     method public java.lang.CharSequence getDeviceOwnerOrganizationName();
-    method public int getDeviceOwnerUserId();
+    method public android.os.UserHandle getDeviceOwnerUser();
     method public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
     method public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
     method public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
-    method public android.content.ComponentName getProfileOwnerAsUser(int);
+    method public android.content.ComponentName getProfileOwnerAsUser(android.os.UserHandle);
     method public java.lang.String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
     method public int getUserProvisioningState();
     method public boolean isDeviceManaged();
@@ -1118,9 +1119,9 @@
   }
 
   public class PackageItemInfo {
+    method public static void forceSafeLabels();
     method public deprecated java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager, float, int);
-    method public static void setForceSafeLabels(boolean);
     field public static final int SAFE_LABEL_FLAG_FIRST_LINE = 4; // 0x4
     field public static final int SAFE_LABEL_FLAG_SINGLE_LINE = 2; // 0x2
     field public static final int SAFE_LABEL_FLAG_TRIM = 1; // 0x1
@@ -1280,14 +1281,6 @@
 
 }
 
-package android.graphics.drawable {
-
-  public final class Icon implements android.os.Parcelable {
-    method public static android.graphics.drawable.Icon createWithResource(android.content.res.Resources, int);
-  }
-
-}
-
 package android.hardware {
 
   public final class Sensor {
@@ -3189,6 +3182,7 @@
   public class ConnectivityManager {
     method public java.lang.String getCaptivePortalServerUrl();
     method public boolean isTetheringSupported();
+    method public void setAirplaneMode(boolean);
     method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
     method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
     method public void stopTethering(int);
@@ -4132,7 +4126,6 @@
     field public static final android.os.UserHandle ALL;
     field public static final android.os.UserHandle CURRENT;
     field public static final android.os.UserHandle SYSTEM;
-    field public static final int USER_NULL = -10000; // 0xffffd8f0
   }
 
   public class UserManager {
@@ -4202,8 +4195,8 @@
   }
 
   public static final class PermissionManager.SplitPermissionInfo {
-    method public java.lang.String[] getNewPermissions();
-    method public java.lang.String getRootPermission();
+    method public java.util.List<java.lang.String> getNewPermissions();
+    method public java.lang.String getSplitPermission();
     method public int getTargetSdk();
   }
 
@@ -5288,6 +5281,7 @@
     method public int getRejectCause();
     method public int getTransportType();
     method public boolean isEmergencyEnabled();
+    method public boolean isRoaming();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationState> CREATOR;
     field public static final int DOMAIN_CS = 1; // 0x1
@@ -5375,6 +5369,8 @@
     method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
     field public static final java.lang.String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
     field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
+    field public static final android.net.Uri ENHANCED_4G_ENABLED_CONTENT_URI;
+    field public static final android.net.Uri WFC_ENABLED_CONTENT_URI;
   }
 
   public final class SubscriptionPlan implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 937c266..463c9d3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1609,6 +1609,10 @@
     method public void writeToParcelNoRecycle(android.os.Parcel, int);
   }
 
+  public static final class AccessibilityNodeInfo.TouchDelegateInfo implements android.os.Parcelable {
+    method public long getAccessibilityIdForRegion(android.graphics.Region);
+  }
+
   public final class AccessibilityWindowInfo implements android.os.Parcelable {
     method public static void setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger);
   }
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 4091d95..6a9e8a1 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -39,7 +39,8 @@
     GET_DATA_CALLED = 4,
     ADB_DUMP = 5,
     CONFIG_RESET = 6,
-    STATSCOMPANION_DIED = 7
+    STATSCOMPANION_DIED = 7,
+    TERMINATION_SIGNAL_RECEIVED = 8
 };
 
 class StatsLogProcessor : public ConfigListener {
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 8da2d44..fb6f8c8 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -867,6 +867,13 @@
     mConfigManager->Startup();
 }
 
+void StatsService::Terminate() {
+    ALOGI("StatsService::Terminating");
+    if (mProcessor != nullptr) {
+        mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED);
+    }
+}
+
 void StatsService::OnLogEvent(LogEvent* event) {
     mProcessor->OnLogEvent(event);
     if (mShellSubscriber != nullptr) {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 1f1d782..cbf3429 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -84,6 +84,11 @@
     void Startup();
 
     /**
+     * Called when terminiation signal received.
+     */
+    void Terminate();
+
+    /**
      * Called by LogReader when there's a log event to process.
      */
     virtual void OnLogEvent(LogEvent* event);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 9d83afd..f704fb7 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -26,12 +26,11 @@
 import "frameworks/base/core/proto/android/bluetooth/enums.proto";
 import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/core/proto/android/server/enums.proto";
+import "frameworks/base/core/proto/android/service/procstats_enum.proto";
+import "frameworks/base/core/proto/android/stats/enums.proto";
 import "frameworks/base/core/proto/android/telecomm/enums.proto";
 import "frameworks/base/core/proto/android/telephony/enums.proto";
 import "frameworks/base/core/proto/android/view/enums.proto";
-import "frameworks/base/proto/src/stats_enums.proto";
-import "frameworks/base/core/proto/android/service/procstats.proto";
-import "frameworks/base/core/proto/android/internal/powerprofile.proto";
 
 /**
  * The master atom class. This message defines all of the available
@@ -142,6 +141,8 @@
         BatteryHealthSnapshot battery_health_snapshot = 91;
         SlowIo slow_io = 92;
         BatteryCausedShutdown battery_caused_shutdown = 93;
+        PhoneServiceStateChanged phone_service_state_changed = 94;
+        PhoneStateChanged phone_state_changed = 95;
     }
 
     // Pulled events will start at field 10000.
@@ -1406,6 +1407,33 @@
     optional android.telephony.SignalStrengthEnum signal_strength = 1;
 }
 
+
+/**
+ * Logs when the phone state, sim state or signal strength changes
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message PhoneServiceStateChanged {
+    optional android.telephony.ServiceStateEnum state = 1;
+    optional android.telephony.SimStateEnum sim_state = 2;
+    optional android.telephony.SignalStrengthEnum signal_strength = 3;
+}
+
+/**
+ * Logs when the phone becomes on or off.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/TelephonyRegistry.java
+ */
+message PhoneStateChanged {
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 1;
+}
+
 /**
  * Logs that a setting was updated.
  * Logged from:
@@ -1923,7 +1951,7 @@
     optional int32 uid = 1 [(is_uid) = true];
 
     // An event_id indicates the type of event.
-    optional android.os.statsd.EventType event_id = 2;
+    optional android.stats.EventType event_id = 2;
 }
 
 /**
@@ -2662,11 +2690,288 @@
     optional int32 num_fingerprints = 2;
 }
 
+message AggStats {
+    optional int64 min = 1;
+
+    optional int64 average = 2;
+
+    optional int64 max = 3;
+}
+
+message ProcessStatsStateProto {
+    optional android.service.procstats.ScreenState screen_state = 1;
+
+    optional android.service.procstats.MemoryState memory_state = 2;
+
+    // this enum list is from frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
+    // and not frameworks/base/core/java/android/app/ActivityManager.java
+    optional android.service.procstats.ProcessState process_state = 3;
+
+    // Millisecond uptime duration spent in this state
+    optional int64 duration_ms = 4;
+
+    // Millisecond elapsed realtime duration spent in this state
+    optional int64 realtime_duration_ms = 9;
+
+    // # of samples taken
+    optional int32 sample_size = 5;
+
+    // PSS is memory reserved for this process
+    optional AggStats pss = 6;
+
+    // USS is memory shared between processes, divided evenly for accounting
+    optional AggStats uss = 7;
+
+    // RSS is memory resident for this process
+    optional AggStats rss = 8;
+}
+
+// Next Tag: 7
+message ProcessStatsProto {
+    // Name of process.
+    optional string process = 1;
+
+    // Uid of the process.
+    optional int32 uid = 2;
+
+    // Information about how often kills occurred
+    message Kill {
+        // Count of excessive CPU kills
+        optional int32 cpu = 1;
+
+        // Count of kills when cached
+        optional int32 cached = 2;
+
+        // PSS stats during cached kill
+        optional AggStats cached_pss = 3;
+    }
+    optional Kill kill = 3;
+
+    // Time and memory spent in various states.
+    repeated ProcessStatsStateProto states = 5;
+
+    // Total time process has been running...  screen_state, memory_state, and process_state
+    // will not be set.
+    optional ProcessStatsStateProto total_running_state = 6;
+}
+
+message PackageServiceOperationStatsProto {
+    // Operate enum: Started, Foreground, Bound, Executing
+    optional android.service.procstats.ServiceOperationState operation = 1;
+
+    // Number of times the service was in this operation.
+    optional int32 count = 2;
+
+    // Information about a state the service can be in.
+    message StateStats {
+        // Screen state enum.
+        optional android.service.procstats.ScreenState screen_state = 1;
+        // Memory state enum.
+        optional android.service.procstats.MemoryState memory_state = 2;
+
+        // duration in milliseconds.
+        optional int64 duration_ms = 3;
+        // Millisecond elapsed realtime duration spent in this state
+        optional int64 realtime_duration_ms = 4;
+    }
+    repeated StateStats state_stats = 3;
+}
+
+message PackageServiceStatsProto {
+    // Name of service component.
+    optional string service_name = 1;
+
+    // The operation stats.
+    // The package_name, package_uid, package_version, service_name will not be set to save space.
+    repeated PackageServiceOperationStatsProto operation_stats = 2;
+}
+
+message PackageAssociationSourceProcessStatsProto {
+    // Uid of the process.
+    optional int32 process_uid = 1;
+    // Process name.
+    optional string process_name = 2;
+
+    // Total count of the times this association appeared.
+    optional int32 total_count = 3;
+
+    // Millisecond uptime total duration this association was around.
+    optional int64 total_duration_ms = 4;
+
+    // Total count of the times this association became actively impacting its target process.
+    optional int32 active_count = 5;
+
+    // Information on one source in this association.
+    message StateStats {
+        // Process state enum.
+        optional android.service.procstats.ProcessState process_state = 1;
+        // Millisecond uptime duration spent in this state
+        optional int64 duration_ms = 2;
+        // Millisecond elapsed realtime duration spent in this state
+        optional int64 realtime_duration_ms = 3;
+    }
+    repeated StateStats active_state_stats = 6;
+}
+
+message PackageAssociationProcessStatsProto {
+    // Name of the target component.
+    optional string component_name = 1;
+    // Information on one source in this association.
+    repeated PackageAssociationSourceProcessStatsProto sources = 2;
+}
+
+
+message ProcessStatsPackageProto {
+    // Name of package.
+    optional string package = 1;
+
+    // Uid of the package.
+    optional int32 uid = 2;
+
+    // Version of the package.
+    optional int64 version = 3;
+
+    // Stats for each process running with the package loaded in to it.
+    repeated ProcessStatsProto process_stats = 4;
+
+    // Stats for each of the package's services.
+    repeated PackageServiceStatsProto service_stats = 5;
+
+    // Stats for each association with the package.
+    repeated PackageAssociationProcessStatsProto association_stats = 6;
+}
+
+message ProcessStatsSectionProto {
+    // Elapsed realtime at start of report.
+    optional int64 start_realtime_ms = 1;
+
+    // Elapsed realtime at end of report.
+    optional int64 end_realtime_ms = 2;
+
+    // CPU uptime at start of report.
+    optional int64 start_uptime_ms = 3;
+
+    // CPU uptime at end of report.
+    optional int64 end_uptime_ms = 4;
+
+    // System runtime library. e.g. "libdvm.so", "libart.so".
+    optional string runtime = 5;
+
+    // whether kernel reports swapped pss.
+    optional bool has_swapped_pss = 6;
+
+    // Data completeness. e.g. "complete", "partial", shutdown", or "sysprops".
+    enum Status {
+        STATUS_UNKNOWN = 0;
+        STATUS_COMPLETE = 1;
+        STATUS_PARTIAL = 2;
+        STATUS_SHUTDOWN = 3;
+        STATUS_SYSPROPS = 4;
+    }
+    repeated Status status = 7;
+
+    // Stats for each process.
+    repeated ProcessStatsProto process_stats = 8;
+
+    // Stats for each package.
+    repeated ProcessStatsPackageProto package_stats = 9;
+}
+
 /**
  * Pulled from ProcessStatsService.java
  */
 message ProcStats {
-    optional android.service.procstats.ProcessStatsSectionProto proc_stats_section = 1;
+    optional ProcessStatsSectionProto proc_stats_section = 1;
+}
+
+message PowerProfileProto {
+    optional double cpu_suspend = 1;
+
+    optional double cpu_idle = 2;
+
+    optional double cpu_active = 3;
+
+    message CpuCluster {
+        optional int32 id = 1;
+        optional double cluster_power = 2;
+        optional int32 cores = 3;
+        repeated int64 speed = 4;
+        repeated double core_power = 5;
+    }
+
+    repeated CpuCluster cpu_cluster = 40;
+
+    optional double wifi_scan = 4;
+
+    optional double wifi_on = 5;
+
+    optional double wifi_active = 6;
+
+    optional double wifi_controller_idle = 7;
+
+    optional double wifi_controller_rx = 8;
+
+    optional double wifi_controller_tx = 9;
+
+    repeated double wifi_controller_tx_levels = 10;
+
+    optional double wifi_controller_operating_voltage = 11;
+
+    optional double bluetooth_controller_idle = 12;
+
+    optional double bluetooth_controller_rx = 13;
+
+    optional double bluetooth_controller_tx = 14;
+
+    optional double bluetooth_controller_operating_voltage = 15;
+
+    optional double modem_controller_sleep = 16;
+
+    optional double modem_controller_idle = 17;
+
+    optional double modem_controller_rx = 18;
+
+    repeated double modem_controller_tx = 19;
+
+    optional double modem_controller_operating_voltage = 20;
+
+    optional double gps_on = 21;
+
+    repeated double gps_signal_quality_based = 22;
+
+    optional double gps_operating_voltage = 23;
+
+    optional double bluetooth_on = 24;
+
+    optional double bluetooth_active = 25;
+
+    optional double bluetooth_at_cmd = 26;
+
+    optional double ambient_display = 27;
+
+    optional double screen_on = 28;
+
+    optional double radio_on = 29;
+
+    optional double radio_scanning = 30;
+
+    optional double radio_active = 31;
+
+    optional double screen_full = 32;
+
+    optional double audio = 33;
+
+    optional double video = 34;
+
+    optional double flashlight = 35;
+
+    optional double memory = 36;
+
+    optional double camera = 37;
+
+    optional double wifi_batched_scan = 38;
+
+    optional double battery_capacity = 39;
 }
 
 /**
@@ -2674,5 +2979,5 @@
  * Pulled from PowerProfile.java
  */
 message PowerProfile {
-    optional com.android.internal.os.PowerProfileProto power_profile_proto = 1;
-}
\ No newline at end of file
+    optional PowerProfileProto power_profile = 1;
+}
diff --git a/cmds/statsd/src/hash.cpp b/cmds/statsd/src/hash.cpp
index c501c9f..543a748 100644
--- a/cmds/statsd/src/hash.cpp
+++ b/cmds/statsd/src/hash.cpp
@@ -16,6 +16,10 @@
 
 #include "hash.h"
 
+#ifndef FALLTHROUGH_INTENDED
+#define FALLTHROUGH_INTENDED [[fallthrough]]
+#endif
+
 namespace android {
 namespace os {
 namespace statsd {
@@ -67,8 +71,10 @@
   switch (n) {
     case 3:
       h ^= ByteAs32(data[2]) << 16;
+      FALLTHROUGH_INTENDED;
     case 2:
       h ^= ByteAs32(data[1]) << 8;
+      FALLTHROUGH_INTENDED;
     case 1:
       h ^= ByteAs32(data[0]);
       h *= m;
@@ -104,16 +110,22 @@
   switch (n) {
     case 7:
       h ^= ByteAs64(data[6]) << 48;
+      FALLTHROUGH_INTENDED;
     case 6:
       h ^= ByteAs64(data[5]) << 40;
+      FALLTHROUGH_INTENDED;
     case 5:
       h ^= ByteAs64(data[4]) << 32;
+      FALLTHROUGH_INTENDED;
     case 4:
       h ^= ByteAs64(data[3]) << 24;
+      FALLTHROUGH_INTENDED;
     case 3:
       h ^= ByteAs64(data[2]) << 16;
+      FALLTHROUGH_INTENDED;
     case 2:
       h ^= ByteAs64(data[1]) << 8;
+      FALLTHROUGH_INTENDED;
     case 1:
       h ^= ByteAs64(data[0]);
       h *= m;
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index a5dac08..6b8c12a 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -46,6 +46,27 @@
     sp<StatsService> service;
 };
 
+
+sp<StatsService> gStatsService = nullptr;
+
+void sigHandler(int sig) {
+    if (gStatsService != nullptr) {
+        gStatsService->Terminate();
+    }
+}
+
+void registerSigHandler()
+{
+    struct sigaction sa;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = sigHandler;
+    sigaction(SIGHUP, &sa, nullptr);
+    sigaction(SIGINT, &sa, nullptr);
+    sigaction(SIGQUIT, &sa, nullptr);
+    sigaction(SIGTERM, &sa, nullptr);
+}
+
 int main(int /*argc*/, char** /*argv*/) {
     // Set up the looper
     sp<Looper> looper(Looper::prepare(0 /* opts */));
@@ -60,23 +81,25 @@
     ::android::hardware::configureRpcThreadpool(1 /*threads*/, false /*willJoin*/);
 
     // Create the service
-    sp<StatsService> service = new StatsService(looper);
-    if (defaultServiceManager()->addService(String16("stats"), service) != 0) {
+    gStatsService = new StatsService(looper);
+    if (defaultServiceManager()->addService(String16("stats"), gStatsService) != 0) {
         ALOGE("Failed to add service as AIDL service");
         return -1;
     }
 
-    auto ret = service->registerAsService();
+    auto ret = gStatsService->registerAsService();
     if (ret != ::android::OK) {
         ALOGE("Failed to add service as HIDL service");
         return 1; // or handle error
     }
 
-    service->sayHiToStatsCompanion();
+    registerSigHandler();
 
-    service->Startup();
+    gStatsService->sayHiToStatsCompanion();
 
-    sp<StatsSocketListener> socketListener = new StatsSocketListener(service);
+    gStatsService->Startup();
+
+    sp<StatsSocketListener> socketListener = new StatsSocketListener(gStatsService);
 
         ALOGI("using statsd socket");
         // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index ab0b23c..10ed7f3 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -271,6 +271,7 @@
       ADB_DUMP = 5;
       CONFIG_RESET = 6;
       STATSCOMPANION_DIED = 7;
+      TERMINATION_SIGNAL_RECEIVED = 8;
   }
   optional DumpReportReason dump_report_reason = 8;
 
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 6af34f9..b71274c 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -523,7 +523,6 @@
 Landroid/net/IConnectivityManager;->getTetheredIfaces()[Ljava/lang/String;
 Landroid/net/IConnectivityManager;->getTetheringErroredIfaces()[Ljava/lang/String;
 Landroid/net/IConnectivityManager;->reportInetCondition(II)V
-Landroid/net/IConnectivityManager;->setAirplaneMode(Z)V
 Landroid/net/IConnectivityManager;->startLegacyVpn(Lcom/android/internal/net/VpnProfile;)V
 Landroid/net/INetworkManagementEventObserver$Stub;-><init>()V
 Landroid/net/INetworkPolicyListener$Stub;-><init>()V
@@ -2216,6 +2215,7 @@
 Lcom/android/org/conscrypt/OpenSSLKey;->getNativeRef()Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;
 Lcom/android/org/conscrypt/OpenSSLKey;->getPublicKey()Ljava/security/PublicKey;
 Lcom/android/org/conscrypt/OpenSSLProvider;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLRandom;-><init>()V
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getChannelId()[B
 Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getHostname()Ljava/lang/String;
@@ -2791,6 +2791,7 @@
 Ljavax/net/ssl/SSLSocketFactory;->createSocket(Ljava/net/Socket;Ljava/io/InputStream;Z)Ljava/net/Socket;
 Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
 Llibcore/icu/ICU;->addLikelySubtags(Ljava/util/Locale;)Ljava/util/Locale;
+Llibcore/io/Libcore;->os:Llibcore/io/Os;
 Llibcore/io/Memory;->peekByte(J)B
 Llibcore/io/Memory;->peekByteArray(J[BII)V
 Llibcore/io/Memory;->peekInt(JZ)I
diff --git a/core/java/android/accounts/AccountAuthenticatorActivity.java b/core/java/android/accounts/AccountAuthenticatorActivity.java
index f9284e6..967aa04 100644
--- a/core/java/android/accounts/AccountAuthenticatorActivity.java
+++ b/core/java/android/accounts/AccountAuthenticatorActivity.java
@@ -48,7 +48,7 @@
     }
 
     /**
-     * Retreives the AccountAuthenticatorResponse from either the intent of the icicle, if the
+     * Retrieves the AccountAuthenticatorResponse from either the intent of the icicle, if the
      * icicle is non-zero.
      * @param icicle the save instance data of this Activity, may be null
      */
diff --git a/core/java/android/animation/Keyframe.java b/core/java/android/animation/Keyframe.java
index 5483c49..bcb94d1 100644
--- a/core/java/android/animation/Keyframe.java
+++ b/core/java/android/animation/Keyframe.java
@@ -76,7 +76,7 @@
      * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
      * of time elapsed of the overall animation duration.
      * @param value The value that the object will animate to as the animation time approaches
-     * the time in this keyframe, and the the value animated from as the time passes the time in
+     * the time in this keyframe, and the value animated from as the time passes the time in
      * this keyframe.
      */
     public static Keyframe ofInt(float fraction, int value) {
@@ -108,7 +108,7 @@
      * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
      * of time elapsed of the overall animation duration.
      * @param value The value that the object will animate to as the animation time approaches
-     * the time in this keyframe, and the the value animated from as the time passes the time in
+     * the time in this keyframe, and the value animated from as the time passes the time in
      * this keyframe.
      */
     public static Keyframe ofFloat(float fraction, float value) {
@@ -140,7 +140,7 @@
      * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
      * of time elapsed of the overall animation duration.
      * @param value The value that the object will animate to as the animation time approaches
-     * the time in this keyframe, and the the value animated from as the time passes the time in
+     * the time in this keyframe, and the value animated from as the time passes the time in
      * this keyframe.
      */
     public static Keyframe ofObject(float fraction, Object value) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 482ef2d..aca80b4 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2952,7 +2952,7 @@
     /**
      * Use with {@link #setDefaultKeyMode} to specify that unhandled keystrokes
      * will start an application-defined search.  (If the application or activity does not
-     * actually define a search, the the keys will be ignored.)
+     * actually define a search, the keys will be ignored.)
      *
      * <p>See {@link android.app.SearchManager android.app.SearchManager} for more details.
      *
@@ -3252,7 +3252,7 @@
      * interacted with the device in some way while your activity is running.
      * This callback and {@link #onUserLeaveHint} are intended to help
      * activities manage status bar notifications intelligently; specifically,
-     * for helping activities determine the proper time to cancel a notfication.
+     * for helping activities determine the proper time to cancel a notification.
      *
      * <p>All calls to your activity's {@link #onUserLeaveHint} callback will
      * be accompanied by calls to {@link #onUserInteraction}.  This
@@ -7906,7 +7906,7 @@
     }
 
     /**
-     * Specifies whether an {@link Activity} should be shown on top of the the lock screen whenever
+     * Specifies whether an {@link Activity} should be shown on top of the lock screen whenever
      * the lockscreen is up and the activity is resumed. Normally an activity will be transitioned
      * to the stopped state if it is started while the lockscreen is up, but with this flag set the
      * activity will remain in the resumed state visible on-top of the lock screen. This value can
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 63c61d3..3c9a2d4 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -1501,7 +1501,7 @@
     }
 
     /**
-     * Ask the the system track that time the user spends in the app being launched, and
+     * Ask the system track that time the user spends in the app being launched, and
      * report it back once done.  The report will be sent to the given receiver, with
      * the extras {@link #EXTRA_USAGE_TIME_REPORT} and {@link #EXTRA_USAGE_TIME_REPORT_PACKAGES}
      * filled in.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 6754df9..ff6aca6 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5666,7 +5666,7 @@
             }
         }
 
-        GraphicsEnvironment.getInstance().setup(context);
+        GraphicsEnvironment.getInstance().setup(context, mCoreSettings);
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
 
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 49917b4..dbc4e34 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -2259,7 +2259,7 @@
     }
 
     /**
-     * Sets whether the the exit transition and enter transition overlap or not.
+     * Sets whether the exit transition and enter transition overlap or not.
      * When true, the enter transition will start as soon as possible. When false, the
      * enter transition will wait until the exit transition completes before starting.
      *
@@ -2272,7 +2272,7 @@
     }
 
     /**
-     * Returns whether the the exit transition and enter transition overlap or not.
+     * Returns whether the exit transition and enter transition overlap or not.
      * When true, the enter transition will start as soon as possible. When false, the
      * enter transition will wait until the exit transition completes before starting.
      *
@@ -2286,7 +2286,7 @@
     }
 
     /**
-     * Sets whether the the return transition and reenter transition overlap or not.
+     * Sets whether the return transition and reenter transition overlap or not.
      * When true, the reenter transition will start as soon as possible. When false, the
      * reenter transition will wait until the return transition completes before starting.
      *
@@ -2299,7 +2299,7 @@
     }
 
     /**
-     * Returns whether the the return transition and reenter transition overlap or not.
+     * Returns whether the return transition and reenter transition overlap or not.
      * When true, the reenter transition will start as soon as possible. When false, the
      * reenter transition will wait until the return transition completes before starting.
      *
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index b720df8..853fccf 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -561,7 +561,7 @@
      * This will, if the keyguard is secure, bring up the unlock screen of
      * the keyguard.
      *
-     * @param callback Let's you know whether the operation was succesful and
+     * @param callback Lets you know whether the operation was successful and
      *   it is safe to launch anything that would normally be considered safe
      *   once the user has gotten past the keyguard.
      */
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 81df447..b57a7d9 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -68,6 +68,7 @@
 import android.text.style.TextAppearanceSpan;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.Gravity;
@@ -3129,6 +3130,37 @@
         return false;
     }
 
+
+    /**
+     * Finds and returns a remote input and its corresponding action.
+     *
+     * @param requiresFreeform requires the remoteinput to allow freeform or not.
+     * @return the result pair, {@code null} if no result is found.
+     *
+     * @hide
+     */
+    @Nullable
+    public Pair<RemoteInput, Action> findRemoteInputActionPair(boolean requiresFreeform) {
+        if (actions == null) {
+            return null;
+        }
+        for (Notification.Action action : actions) {
+            if (action.getRemoteInputs() == null) {
+                continue;
+            }
+            RemoteInput resultRemoteInput = null;
+            for (RemoteInput remoteInput : action.getRemoteInputs()) {
+                if (remoteInput.getAllowFreeFormInput() || !requiresFreeform) {
+                    resultRemoteInput = remoteInput;
+                }
+            }
+            if (resultRemoteInput != null) {
+                return Pair.create(resultRemoteInput, action);
+            }
+        }
+        return null;
+    }
+
     /**
      * Builder class for {@link Notification} objects.
      *
@@ -6203,7 +6235,7 @@
         public abstract boolean areNotificationsVisiblyDifferent(Style other);
 
         /**
-         * @return the the text that should be displayed in the statusBar when heads-upped.
+         * @return the text that should be displayed in the statusBar when heads-upped.
          * If {@code null} is returned, the default implementation will be used.
          *
          * @hide
@@ -6690,7 +6722,7 @@
         }
 
         /**
-         * @return the the text that should be displayed in the statusBar when heads upped.
+         * @return the text that should be displayed in the statusBar when heads upped.
          * If {@code null} is returned, the default implementation will be used.
          *
          * @hide
@@ -7346,7 +7378,7 @@
             }
 
             /**
-             * Get the the Uri pointing to the content of the message. Can be null, in which case
+             * Get the Uri pointing to the content of the message. Can be null, in which case
              * {@see #getText()} is used.
              */
             public Uri getDataUri() {
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 9539f34..acca6fc 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -169,7 +169,7 @@
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
      * {@link android.content.Intent#getStringExtra content.Intent.getStringExtra()}
      * to obtain the action message that was defined for a particular search action key and/or
-     * suggestion.  It will be null if the search was launched by typing "enter", touched the the
+     * suggestion.  It will be null if the search was launched by typing "enter", touching the
      * "GO" button, or other means not involving any action key.
      */
     public final static String ACTION_MSG = "action_msg";
@@ -404,7 +404,7 @@
      * Column name for suggestions cursor. <i>Optional.</i>  If your content is rentable, you
      * should provide this column to specify the displayable string representation of the rental
      * price of your content including the currency and the amount. If it's free, you should
-     * provide localized string to specify that it's free. This column can be ommitted if the
+     * provide localized string to specify that it's free. This column can be omitted if the
      * content is not applicable to rent.
      */
     public final static String SUGGEST_COLUMN_RENTAL_PRICE = "suggest_rental_price";
@@ -579,7 +579,7 @@
      *
      * @param initialQuery A search string can be pre-entered here, but this
      * is typically null or empty.
-     * @param selectInitialQuery If true, the intial query will be preselected, which means that
+     * @param selectInitialQuery If true, the initial query will be preselected, which means that
      * any further typing will replace it.  This is useful for cases where an entire pre-formed
      * query is being inserted.  If false, the selection point will be placed at the end of the
      * inserted query.  This is useful when the inserted query is text that the user entered,
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 6c87fe7..0044005 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -377,15 +377,11 @@
                 return new DisplayManager(ctx.getOuterContext());
             }});
 
-        // InputMethodManager has its own cache strategy based on display id to support apps that
-        // still assume InputMethodManager is a per-process singleton and it's safe to directly
-        // access internal fields via reflection.  Hence directly use ServiceFetcher instead of
-        // StaticServiceFetcher/CachedServiceFetcher.
         registerService(Context.INPUT_METHOD_SERVICE, InputMethodManager.class,
-                new ServiceFetcher<InputMethodManager>() {
+                new StaticServiceFetcher<InputMethodManager>() {
             @Override
-            public InputMethodManager getService(ContextImpl ctx) {
-                return InputMethodManager.forContext(ctx);
+            public InputMethodManager createService() {
+                return InputMethodManager.getInstanceInternal();
             }});
 
         registerService(Context.TEXT_SERVICES_MANAGER_SERVICE, TextServicesManager.class,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 09ab671..74fb4df 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3399,7 +3399,7 @@
      * restrictions on the parent profile.
      *
      * @param admin The name of the admin component to check, or {@code null} to aggregate
-     *         accross all participating admins.
+     *         across all participating admins.
      * @return The timeout in milliseconds or 0 if not configured for the provided admin.
      */
     public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin) {
@@ -5224,13 +5224,30 @@
     }
 
     /**
-     * @return ID of the user who runs device owner, or {@link UserHandle#USER_NULL} if there's
-     * no device owner.
+     * @return Handle of the user who runs device owner, or {@code null} if there's no device owner.
      *
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
     @SystemApi
+    public @Nullable UserHandle getDeviceOwnerUser() {
+        if (mService != null) {
+            try {
+                int userId = mService.getDeviceOwnerUserId();
+
+                if (userId != UserHandle.USER_NULL) {
+                    return UserHandle.of(userId);
+                }
+            } catch (RemoteException re) {
+                throw re.rethrowFromSystemServer();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @hide
+     */
     public int getDeviceOwnerUserId() {
         if (mService != null) {
             try {
@@ -5653,6 +5670,20 @@
     @RequiresPermission(value = android.Manifest.permission.INTERACT_ACROSS_USERS,
             conditional = true)
     @SystemApi
+    public @Nullable ComponentName getProfileOwnerAsUser(@NonNull UserHandle user) {
+        if (mService != null) {
+            try {
+                return mService.getProfileOwnerAsUser(user.getIdentifier());
+            } catch (RemoteException re) {
+                throw re.rethrowFromSystemServer();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @hide
+     */
     public @Nullable ComponentName getProfileOwnerAsUser(final int userId) {
         if (mService != null) {
             try {
@@ -5703,6 +5734,37 @@
     }
 
     /**
+     * Returns whether the specified package can read the device identifiers.
+     *
+     * @param packageName The package name of the app to check for device identifier access.
+     * @return whether the package can read the device identifiers.
+     *
+     * @hide
+     */
+    public boolean checkDeviceIdentifierAccess(String packageName) {
+        return checkDeviceIdentifierAccessAsUser(packageName, myUserId());
+    }
+
+    /**
+     * @hide
+     */
+    @RequiresPermission(value = android.Manifest.permission.MANAGE_USERS, conditional = true)
+    public boolean checkDeviceIdentifierAccessAsUser(String packageName, int userId) {
+        throwIfParentInstance("checkDeviceIdentifierAccessAsUser");
+        if (packageName == null) {
+            return false;
+        }
+        if (mService != null) {
+            try {
+                return mService.checkDeviceIdentifierAccess(packageName, userId);
+            } catch (RemoteException re) {
+                throw re.rethrowFromSystemServer();
+            }
+        }
+        return false;
+    }
+
+    /**
      * Called by a profile owner or device owner to set a default activity that the system selects
      * to handle intents that match the given {@link IntentFilter}. This activity will remain the
      * default intent handler even if the set of potential event handlers for the intent filter
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 35ea250..5e45450 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -153,6 +153,8 @@
     void clearProfileOwner(in ComponentName who);
     boolean hasUserSetupCompleted();
 
+    boolean checkDeviceIdentifierAccess(in String packageName, int userHandle);
+
     void setDeviceOwnerLockScreenInfo(in ComponentName who, CharSequence deviceOwnerInfo);
     CharSequence getDeviceOwnerLockScreenInfo();
 
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 173b766..fefb8d3 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -74,6 +74,7 @@
     ComponentName mActivityComponent;
     private boolean mIsHomeActivity;
     private int mFlags;
+    private int mAutofillFlags;
 
     final ArrayList<WindowNode> mWindowNodes = new ArrayList<>();
 
@@ -197,6 +198,7 @@
             mWriteStructure = as.waitForReady();
             ComponentName.writeToParcel(as.mActivityComponent, out);
             out.writeInt(as.mFlags);
+            out.writeInt(as.mAutofillFlags);
             out.writeLong(as.mAcquisitionStartTime);
             out.writeLong(as.mAcquisitionEndTime);
             mNumWindows = as.mWindowNodes.size();
@@ -352,6 +354,7 @@
             fetchData();
             mActivityComponent = ComponentName.readFromParcel(mCurParcel);
             mFlags = mCurParcel.readInt();
+            mAutofillFlags = mCurParcel.readInt();
             mAcquisitionStartTime = mCurParcel.readLong();
             mAcquisitionEndTime = mCurParcel.readLong();
             final int N = mCurParcel.readInt();
@@ -625,8 +628,6 @@
         String mIdType;
         String mIdEntry;
 
-        // TODO(b/37567426): once we have more flags, it might be better to store the individual
-        // fields (viewId and childId) of the field.
         AutofillId mAutofillId;
         @View.AutofillType int mAutofillType = View.AUTOFILL_TYPE_NONE;
         @Nullable String[] mAutofillHints;
@@ -669,11 +670,6 @@
         static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
         static final int FLAGS_OPAQUE = 0x00008000;
 
-        // TODO(b/37567426): autofill data is made of many fields and ideally we should verify
-        // one-by-one to optimize what's sent over, but there isn't enough flag bits for that, we'd
-        // need to create a 'flags2' or 'autoFillFlags' field and add these flags there.
-        // So, to keep thinkg simpler for now, let's just use on flag for all of them...
-        static final int FLAGS_HAS_AUTOFILL_DATA = 0x80000000;
         static final int FLAGS_HAS_MATRIX = 0x40000000;
         static final int FLAGS_HAS_ALPHA = 0x20000000;
         static final int FLAGS_HAS_ELEVATION = 0x10000000;
@@ -690,7 +686,20 @@
         static final int FLAGS_HAS_LOCALE_LIST = 0x00010000;
         static final int FLAGS_ALL_CONTROL = 0xfff00000;
 
+        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID =         0x001;
+        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID = 0x002;
+        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_VALUE =           0x004;
+        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_TYPE =            0x008;
+        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_HINTS =           0x010;
+        static final int AUTOFILL_FLAGS_HAS_AUTOFILL_OPTIONS =         0x020;
+        static final int AUTOFILL_FLAGS_HAS_HTML_INFO =                0x040;
+        static final int AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY =            0x080;
+        static final int AUTOFILL_FLAGS_HAS_MIN_TEXT_EMS =             0x100;
+        static final int AUTOFILL_FLAGS_HAS_MAX_TEXT_EMS =             0x200;
+        static final int AUTOFILL_FLAGS_HAS_MAX_TEXT_LENGTH =          0x400;
+
         int mFlags;
+        int mAutofillFlags;
 
         String mClassName;
         CharSequence mContentDescription;
@@ -714,6 +723,8 @@
             mClassName = preader.readString();
             mFlags = in.readInt();
             final int flags = mFlags;
+            mAutofillFlags = in.readInt();
+            final int autofillFlags = mAutofillFlags;
             if ((flags&FLAGS_HAS_ID) != 0) {
                 mId = in.readInt();
                 if (mId != View.NO_ID) {
@@ -725,22 +736,45 @@
                 }
             }
 
-            if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0) {
+            if (autofillFlags != 0) {
                 mSanitized = in.readInt() == 1;
-                mAutofillId = in.readParcelable(null);
-                mAutofillType = in.readInt();
-                mAutofillHints = in.readStringArray();
-                mAutofillValue = in.readParcelable(null);
-                mAutofillOptions = in.readCharSequenceArray();
-                final Parcelable p = in.readParcelable(null);
-                if (p instanceof HtmlInfo) {
-                    mHtmlInfo = (HtmlInfo) p;
-                }
-                mMinEms = in.readInt();
-                mMaxEms = in.readInt();
-                mMaxLength = in.readInt();
-                mTextIdEntry = preader.readString();
                 mImportantForAutofill = in.readInt();
+
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID) != 0) {
+                    int autofillViewId = in.readInt();
+                    if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID) != 0) {
+                        mAutofillId = new AutofillId(autofillViewId, in.readInt());
+                    } else {
+                        mAutofillId = new AutofillId(autofillViewId);
+                    }
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_TYPE) != 0) {
+                    mAutofillType = in.readInt();
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_HINTS) != 0) {
+                    mAutofillHints = in.readStringArray();
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VALUE) != 0) {
+                    mAutofillValue = in.readParcelable(null);
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
+                    mAutofillOptions = in.readCharSequenceArray();
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_HTML_INFO) != 0) {
+                    mHtmlInfo = in.readParcelable(null);
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_MIN_TEXT_EMS) != 0) {
+                    mMinEms = in.readInt();
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_MAX_TEXT_EMS) != 0) {
+                    mMaxEms = in.readInt();
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_MAX_TEXT_LENGTH) != 0) {
+                    mMaxLength = in.readInt();
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
+                    mTextIdEntry = preader.readString();
+                }
             }
             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                 mX = in.readInt();
@@ -808,13 +842,11 @@
             boolean writeSensitive = true;
 
             int flags = mFlags & ~FLAGS_ALL_CONTROL;
+            int autofillFlags = 0;
 
             if (mId != View.NO_ID) {
                 flags |= FLAGS_HAS_ID;
             }
-            if (mAutofillId != null) {
-                flags |= FLAGS_HAS_AUTOFILL_DATA;
-            }
             if ((mX&~0x7fff) != 0 || (mY&~0x7fff) != 0
                     || (mWidth&~0x7fff) != 0 | (mHeight&~0x7fff) != 0) {
                 flags |= FLAGS_HAS_LARGE_COORDS;
@@ -855,11 +887,44 @@
             if (mChildren != null) {
                 flags |= FLAGS_HAS_CHILDREN;
             }
+            if (mAutofillId != null) {
+                autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID;
+                if (mAutofillId.isVirtual()) {
+                    autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID;
+                }
+            }
+            if (mAutofillValue != null) {
+                autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_VALUE;
+            }
+            if (mAutofillType != View.AUTOFILL_TYPE_NONE) {
+                autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_TYPE;
+            }
+            if (mAutofillHints != null) {
+                autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_HINTS;
+            }
+            if (mAutofillOptions != null) {
+                autofillFlags |= AUTOFILL_FLAGS_HAS_AUTOFILL_OPTIONS;
+            }
+            if (mHtmlInfo instanceof Parcelable) {
+                autofillFlags |= AUTOFILL_FLAGS_HAS_HTML_INFO;
+            }
+            if (mMinEms > -1) {
+                autofillFlags |= AUTOFILL_FLAGS_HAS_MIN_TEXT_EMS;
+            }
+            if (mMaxEms > -1) {
+                autofillFlags |= AUTOFILL_FLAGS_HAS_MAX_TEXT_EMS;
+            }
+            if (mMaxLength > -1) {
+                autofillFlags |= AUTOFILL_FLAGS_HAS_MAX_TEXT_LENGTH;
+            }
+            if (mTextIdEntry != null) {
+                autofillFlags |= AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY;
+            }
 
             pwriter.writeString(mClassName);
 
             int writtenFlags = flags;
-            if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0 && (mSanitized || !sanitizeOnWrite)) {
+            if (autofillFlags != 0 && (mSanitized || !sanitizeOnWrite)) {
                 // Remove 'checked' from sanitized autofill request.
                 writtenFlags = flags & ~FLAGS_CHECKED;
             }
@@ -872,6 +937,7 @@
             }
 
             out.writeInt(writtenFlags);
+            out.writeInt(autofillFlags);
             if ((flags&FLAGS_HAS_ID) != 0) {
                 out.writeInt(mId);
                 if (mId != View.NO_ID) {
@@ -883,32 +949,51 @@
                 }
             }
 
-            if ((flags&FLAGS_HAS_AUTOFILL_DATA) != 0) {
-                writeSensitive = mSanitized || !sanitizeOnWrite;
+            if (autofillFlags != 0) {
                 out.writeInt(mSanitized ? 1 : 0);
-                out.writeParcelable(mAutofillId, 0);
-                out.writeInt(mAutofillType);
-                out.writeStringArray(mAutofillHints);
-                final AutofillValue sanitizedValue;
-                if (writeSensitive) {
-                    sanitizedValue = mAutofillValue;
-                } else if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
-                    sanitizedValue = mAutofillOverlay.value;
-                } else {
-                    sanitizedValue = null;
-                }
-                out.writeParcelable(sanitizedValue,  0);
-                out.writeCharSequenceArray(mAutofillOptions);
-                if (mHtmlInfo instanceof Parcelable) {
-                    out.writeParcelable((Parcelable) mHtmlInfo, 0);
-                } else {
-                    out.writeParcelable(null, 0);
-                }
-                out.writeInt(mMinEms);
-                out.writeInt(mMaxEms);
-                out.writeInt(mMaxLength);
-                pwriter.writeString(mTextIdEntry);
                 out.writeInt(mImportantForAutofill);
+                writeSensitive = mSanitized || !sanitizeOnWrite;
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VIEW_ID) != 0) {
+                    out.writeInt(mAutofillId.getViewId());
+                    if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VIRTUAL_VIEW_ID) != 0) {
+                        out.writeInt(mAutofillId.getVirtualChildId());
+                    }
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_TYPE) != 0) {
+                    out.writeInt(mAutofillType);
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_HINTS) != 0) {
+                    out.writeStringArray(mAutofillHints);
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_VALUE) != 0) {
+                    final AutofillValue sanitizedValue;
+                    if (writeSensitive) {
+                        sanitizedValue = mAutofillValue;
+                    } else if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
+                        sanitizedValue = mAutofillOverlay.value;
+                    } else {
+                        sanitizedValue = null;
+                    }
+                    out.writeParcelable(sanitizedValue, 0);
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_AUTOFILL_OPTIONS) != 0) {
+                    out.writeCharSequenceArray(mAutofillOptions);
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_HTML_INFO) != 0) {
+                    out.writeParcelable((Parcelable) mHtmlInfo, 0);
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_MIN_TEXT_EMS) != 0) {
+                    out.writeInt(mMinEms);
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_MAX_TEXT_EMS) != 0) {
+                    out.writeInt(mMaxEms);
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_MAX_TEXT_LENGTH) != 0) {
+                    out.writeInt(mMaxLength);
+                }
+                if ((autofillFlags & AUTOFILL_FLAGS_HAS_TEXT_ID_ENTRY) != 0) {
+                    pwriter.writeString(mTextIdEntry);
+                }
             }
             if ((flags&FLAGS_HAS_LARGE_COORDS) != 0) {
                 out.writeInt(mX);
@@ -1002,7 +1087,7 @@
         }
 
         /**
-         * Gets the the type of value that can be used to autofill the view contents.
+         * Gets the type of value that can be used to autofill the view contents.
          *
          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes.
          *
@@ -1028,7 +1113,7 @@
         }
 
         /**
-         * Gets the the value of this view.
+         * Gets the value of this view.
          *
          * <p>It's only relevant when the {@link AssistStructure} is used for autofill purposes,
          * not for assist purposes.
@@ -1350,7 +1435,7 @@
         }
 
         /**
-         * Returns the the list of locales associated with this view.
+         * Returns the list of locales associated with this view.
          */
         @Nullable public LocaleList getLocaleList() {
             return mLocaleList;
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 30d5fbc..0aa0535 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -107,20 +107,6 @@
             "android.bluetooth.device.action.FOUND";
 
     /**
-     * Broadcast Action: Remote device disappeared.
-     * <p>Sent when a remote device that was found in the last discovery is not
-     * found in the current discovery.
-     * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
-     *
-     * @hide
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    @UnsupportedAppUsage
-    public static final String ACTION_DISAPPEARED =
-            "android.bluetooth.device.action.DISAPPEARED";
-
-    /**
      * Broadcast Action: Bluetooth class of a remote device has changed.
      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
      * #EXTRA_CLASS}.
@@ -654,7 +640,7 @@
     public static final int ACCESS_REJECTED = 2;
 
     /**
-     * No preferrence of physical transport for GATT connections to remote dual-mode devices
+     * No preference of physical transport for GATT connections to remote dual-mode devices
      */
     public static final int TRANSPORT_AUTO = 0;
 
@@ -1971,9 +1957,7 @@
      * <p>The remote device will be authenticated and communication on this socket will be
      * encrypted.
      * <p> Use this socket if an authenticated socket link is possible. Authentication refers
-     * to the authentication of the link key to prevent man-in-the-middle type of attacks. When a
-     * secure socket connection is not possible, use {@link createInsecureLeL2capCocSocket(int,
-     * int)}.
+     * to the authentication of the link key to prevent man-in-the-middle type of attacks.
      *
      * @param psm dynamic PSM value from remote device
      * @return a CoC #BluetoothSocket ready for an outgoing connection
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 29d5a1c..9b7c173 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -1292,7 +1292,7 @@
      * <p>After all characteristics have been queued up and verified,
      * {@link #executeReliableWrite} will execute all writes. If a characteristic
      * was not written correctly, calling {@link #abortReliableWrite} will
-     * cancel the current transaction without commiting any values on the
+     * cancel the current transaction without committing any values on the
      * remote device.
      *
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index ef1b0bd..13b1b4f 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -522,7 +522,7 @@
      * {@link BluetoothGattServerCallback#onConnectionStateChange} callback will be
      * invoked when the connection state changes as a result of this function.
      *
-     * <p>The autoConnect paramter determines whether to actively connect to
+     * <p>The autoConnect parameter determines whether to actively connect to
      * the remote device, or rather passively scan and finalize the connection
      * when the remote device is in range/available. Generally, the first ever
      * connection to a device should be direct (autoConnect set to false) and
@@ -695,7 +695,7 @@
     /**
      * Add a service to the list of services to be hosted.
      *
-     * <p>Once a service has been addded to the the list, the service and its
+     * <p>Once a service has been addded to the list, the service and its
      * included characteristics will be provided by the local device.
      *
      * <p>If the local device has already exposed services when this function
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 758c68d..4e88625 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -203,8 +203,8 @@
     /**
      * Returns the assigned dynamic protocol/service multiplexer (PSM) value for the listening L2CAP
      * Connection-oriented Channel (CoC) server socket. This server socket must be returned by the
-     * {@link BluetoothAdapter.listenUsingL2capChannel()} or {@link
-     * BluetoothAdapter.listenUsingInsecureL2capChannel()}. The returned value is undefined if this
+     * {@link BluetoothAdapter#listenUsingL2capChannel()} or {@link
+     * BluetoothAdapter#listenUsingInsecureL2capChannel()}. The returned value is undefined if this
      * method is called on non-L2CAP server sockets.
      *
      * @return the assigned PSM or LE_PSM value depending on transport
diff --git a/core/java/android/bluetooth/le/AdvertisingSetCallback.java b/core/java/android/bluetooth/le/AdvertisingSetCallback.java
index 58a3696..51324fd 100644
--- a/core/java/android/bluetooth/le/AdvertisingSetCallback.java
+++ b/core/java/android/bluetooth/le/AdvertisingSetCallback.java
@@ -56,7 +56,7 @@
     /**
      * Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertisingSet}
      * indicating result of the operation. If status is ADVERTISE_SUCCESS, then advertisingSet
-     * contains the started set and it is advertising. If error occured, advertisingSet is
+     * contains the started set and it is advertising. If error occurred, advertisingSet is
      * null, and status will be set to proper error code.
      *
      * @param advertisingSet The advertising set that was started or null if error.
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index b528e39..a086a30 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -95,7 +95,7 @@
  * the SyncManager will wait until the sync adapter is not in use before requesting that
  * it sync an account's data.
  * <li><code>android:isAlwaysSyncable</code> defaults to false and if true tells the SyncManager
- * to intialize the isSyncable state to 1 for that sync adapter for each account that is added.
+ * to initialize the isSyncable state to 1 for that sync adapter for each account that is added.
  * <li><code>android:syncAdapterSettingsAction</code> defaults to null and if supplied it
  * specifies an Intent action of an activity that can be used to adjust the sync adapter's
  * sync settings. The activity must live in the same package as the sync adapter.
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 089cf10..ed3d455 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -224,7 +224,7 @@
          * Create an Item consisting of a single block of (possibly styled) text,
          * with an alternative HTML formatted representation.  You <em>must</em>
          * supply a plain text representation in addition to HTML text; coercion
-         * will not be done from HTML formated text into plain text.
+         * will not be done from HTML formatted text into plain text.
          */
         public Item(CharSequence text, String htmlText) {
             mText = text;
@@ -268,7 +268,7 @@
          * Create a complex Item, containing multiple representations of
          * text, HTML text, Intent, and/or URI.  If providing HTML text, you
          * <em>must</em> supply a plain text representation as well; coercion
-         * will not be done from HTML formated text into plain text.
+         * will not be done from HTML formatted text into plain text.
          */
         public Item(CharSequence text, String htmlText, Intent intent, Uri uri) {
             if (htmlText != null && text == null) {
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 7dc4577..6a3fa6b2 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -637,7 +637,7 @@
 
         /**
          * The selection and arguments to use. An occurrence of '?' in the selection will be
-         * replaced with the corresponding occurence of the selection argument. Any of the
+         * replaced with the corresponding occurrence of the selection argument. Any of the
          * selection arguments may be overwritten by a selection argument back reference as
          * specified by {@link #withSelectionBackReference}.
          * This can only be used with builders of type update, delete, or assert.
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index a882434..c19909d 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1877,7 +1877,7 @@
      * that services the content at uri, starting the provider if necessary. Returns
      * null if there is no provider associated wih the uri. The caller must indicate that they are
      * done with the provider by calling {@link ContentProviderClient#release} which will allow
-     * the system to release the provider it it determines that there is no other reason for
+     * the system to release the provider if it determines that there is no other reason for
      * keeping it active.
      * @param uri specifies which provider should be acquired
      * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
@@ -1897,7 +1897,7 @@
      * with the authority of name, starting the provider if necessary. Returns
      * null if there is no provider associated wih the uri. The caller must indicate that they are
      * done with the provider by calling {@link ContentProviderClient#release} which will allow
-     * the system to release the provider it it determines that there is no other reason for
+     * the system to release the provider if it determines that there is no other reason for
      * keeping it active.
      * @param name specifies which provider should be acquired
      * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d711574..db4adcf 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -187,7 +187,7 @@
      *
      * <p>This was the legacy (but undocumented) behavior in and
      * before Gingerbread (Android 2.3) and this flag is implied when
-     * targetting such releases.  For applications targetting SDK
+     * targeting such releases.  For applications targeting SDK
      * versions <em>greater than</em> Android 2.3, this flag must be
      * explicitly set if desired.
      *
@@ -2840,7 +2840,7 @@
      *
      * @param service Description of the service to be stopped.  The Intent must be either
      *      fully explicit (supplying a component name) or specify a specific package
-     *      name it is targetted to.
+     *      name it is targeted to.
      *
      * @return If there is a service matching the given Intent that is already
      * running, then it is stopped and {@code true} is returned; else {@code false} is returned.
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index 4e46d571..4ccafab 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -36,7 +36,7 @@
  * perform, either through the
  * {@link #CursorLoader(Context, Uri, String[], String, String[], String)} or
  * creating an empty instance with {@link #CursorLoader(Context)} and filling
- * in the desired paramters with {@link #setUri(Uri)}, {@link #setSelection(String)},
+ * in the desired parameters with {@link #setUri(Uri)}, {@link #setSelection(String)},
  * {@link #setSelectionArgs(String[])}, {@link #setSortOrder(String)},
  * and {@link #setProjection(String[])}.
  *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3c8d9d03..8913748 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1538,7 +1538,10 @@
      * @see #EXTRA_INSTALLER_PACKAGE_NAME
      * @see #EXTRA_NOT_UNKNOWN_SOURCE
      * @see #EXTRA_RETURN_RESULT
+     *
+     * @deprecated use {@link android.content.pm.PackageInstaller} instead
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_INSTALL_PACKAGE = "android.intent.action.INSTALL_PACKAGE";
 
@@ -1707,7 +1710,11 @@
      * <p>
      * Requires {@link android.Manifest.permission#REQUEST_DELETE_PACKAGES}
      * since {@link Build.VERSION_CODES#P}.
+     *
+     * @deprecated Use {@link android.content.pm.PackageInstaller#uninstall(String, IntentSender)}
+     *             instead
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_UNINSTALL_PACKAGE = "android.intent.action.UNINSTALL_PACKAGE";
 
@@ -3948,6 +3955,12 @@
     public static final String EXTRA_LTE_EARFCN_RSRP_BOOST = "LteEarfcnRsrpBoost";
 
     /**
+     * An parcelable extra used with {@link #ACTION_SERVICE_STATE} representing the service state.
+     * @hide
+     */
+    public static final String EXTRA_SERVICE_STATE = "android.intent.extra.SERVICE_STATE";
+
+    /**
      * The name of the extra used to define the text to be processed, as a
      * CharSequence. Note that this may be a styled CharSequence, so you must use
      * {@link Bundle#getCharSequence(String) Bundle.getCharSequence()} to retrieve it.
@@ -5516,7 +5529,7 @@
     /**
      * If set and this intent is being used to launch a new activity from an
      * existing one, then the reply target of the existing activity will be
-     * transfered to the new activity.  This way the new activity can call
+     * transferred to the new activity.  This way, the new activity can call
      * {@link android.app.Activity#setResult} and have that result sent back to
      * the reply target of the original activity.
      */
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 0469a90..36d8a37 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -479,7 +479,7 @@
     /**
      * Modify priority of this filter.  This only affects receiver filters.
      * The priority of activity filters are set in XML and cannot be changed
-     * programatically. The default priority is 0. Positive values will be
+     * programmatically. The default priority is 0. Positive values will be
      * before the default, lower values will be after it. Applications should
      * use a value that is larger than {@link #SYSTEM_LOW_PRIORITY} and
      * smaller than {@link #SYSTEM_HIGH_PRIORITY} .
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 5926af6..0a4f4eb 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1408,5 +1408,13 @@
          * @attr ref android.R.styleable#AndroidManifestLayout_minHeight
          */
         public final int minHeight;
+
+        /**
+         * Returns if this {@link WindowLayout} has specified bounds.
+         * @hide
+         */
+        public boolean hasSpecifiedSize() {
+            return width >= 0 || height >= 0 || widthFraction >= 0 || heightFraction >= 0;
+        }
     }
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 225b6cf..c33f143 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -236,7 +236,7 @@
     
     /**
      * Value for {@link #flags}: true when the application knows how to
-     * accomodate different screen densities.  Corresponds to
+     * accommodate different screen densities.  Corresponds to
      * {@link android.R.styleable#AndroidManifestSupportsScreens_anyDensity
      * android:anyDensity}.
      */
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 8fab7bb..e9cfa78 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -86,6 +86,19 @@
  * <p>
  * The ApiDemos project contains examples of using this API:
  * <code>ApiDemos/src/com/example/android/apis/content/InstallApk*.java</code>.
+ * <p>
+ * On Android Q or above, an app installed notification will be posted
+ * by system after a new app is installed.
+ * To customize installer's notification icon, you should declare the following in the manifest
+ * &lt;application> as follows: </p>
+ * <pre>
+ * &lt;meta-data android:name="com.android.packageinstaller.notification.smallIcon"
+ * android:resource="@drawable/installer_notification_icon"/>
+ * </pre>
+ * <pre>
+ * &lt;meta-data android:name="com.android.packageinstaller.notification.color"
+ * android:resource="@color/installer_notification_color"/>
+ * </pre>
  */
 public class PackageInstaller {
     private static final String TAG = "PackageInstaller";
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index 19af609..00aa5c2 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -105,13 +105,11 @@
     /**
      * Always use {@link #loadSafeLabel safe labels} when calling {@link #loadLabel}.
      *
-     * @param forceSafeLabels {@code true} to enforce safe labels
-     *
      * @hide
      */
     @SystemApi
-    public static void setForceSafeLabels(boolean forceSafeLabels) {
-        sForceSafeLabels = forceSafeLabels;
+    public static void forceSafeLabels() {
+        sForceSafeLabels = true;
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3032d16..733fbe5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5187,6 +5187,7 @@
      * @param packageName The name of the package to query
      * @throws IllegalArgumentException if the given package name is not installed
      */
+    @Nullable
     public abstract String getInstallerPackageName(String packageName);
 
     /**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 24675d3..1673c28 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2440,17 +2440,17 @@
         }
 
 
-        final int NS = PermissionManager.SPLIT_PERMISSIONS.length;
+        final int NS = PermissionManager.SPLIT_PERMISSIONS.size();
         for (int is=0; is<NS; is++) {
             final PermissionManager.SplitPermissionInfo spi =
-                    PermissionManager.SPLIT_PERMISSIONS[is];
+                    PermissionManager.SPLIT_PERMISSIONS.get(is);
             if (pkg.applicationInfo.targetSdkVersion >= spi.getTargetSdk()
-                    || !pkg.requestedPermissions.contains(spi.getRootPermission())) {
+                    || !pkg.requestedPermissions.contains(spi.getSplitPermission())) {
                 continue;
             }
-            final String[] newPerms = spi.getNewPermissions();
-            for (int in = 0; in < newPerms.length; in++) {
-                final String perm = newPerms[in];
+            final List<String> newPerms = spi.getNewPermissions();
+            for (int in = 0; in < newPerms.size(); in++) {
+                final String perm = newPerms.get(in);
                 if (!pkg.requestedPermissions.contains(perm)) {
                     pkg.requestedPermissions.add(perm);
                 }
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index 8f8f676..42e7ac7 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -53,7 +53,7 @@
     }
 
     /**
-     * Execute this SQL statement, if the the number of rows affected by execution of this SQL
+     * Execute this SQL statement, if the number of rows affected by execution of this SQL
      * statement is of any importance to the caller - for example, UPDATE / DELETE SQL statements.
      *
      * @return the number of rows affected by this SQL statement execution.
diff --git a/core/java/android/hardware/biometrics/BiometricAuthenticator.java b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
index 1734b41..79e15a7a 100644
--- a/core/java/android/hardware/biometrics/BiometricAuthenticator.java
+++ b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
@@ -201,11 +201,22 @@
         throw new UnsupportedOperationException("Stub!");
     }
 
+    /**
+     * @return true if the user has enrolled templates for this biometric.
+     */
     default boolean hasEnrolledTemplates(int userId) {
         throw new UnsupportedOperationException("Stub!");
     }
 
     /**
+     * Sets the active user. This is meant to be used to select the current profile
+     * to allow separate templates for work profile.
+     */
+    default void setActiveUser(int userId) {
+        throw new UnsupportedOperationException("Stub!");
+    }
+
+    /**
      * This call warms up the hardware and starts scanning for valid biometrics. It terminates
      * when {@link AuthenticationCallback#onAuthenticationError(int,
      * CharSequence)} is called or when {@link AuthenticationCallback#onAuthenticationSucceeded(
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 0faecb0..1d40001 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -107,4 +107,22 @@
             Slog.w(TAG, "registerEnabledOnKeyguardCallback(): Service not connected");
         }
     }
+
+    /**
+     * Sets the active user.
+     * @hide
+     */
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    public void setActiveUser(int userId) {
+        if (mService != null) {
+            try {
+                mService.setActiveUser(userId);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        } else {
+            Slog.w(TAG, "setActiveUser(): Service not connected");
+        }
+    }
 }
+
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 83998cc..7952c41 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -17,6 +17,7 @@
 package android.hardware.biometrics;
 
 import static android.Manifest.permission.USE_BIOMETRIC;
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
 
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
@@ -55,6 +56,10 @@
     /**
      * @hide
      */
+    public static final String KEY_USE_DEFAULT_TITLE = "use_default_title";
+    /**
+     * @hide
+     */
     public static final String KEY_SUBTITLE = "subtitle";
     /**
      * @hide
@@ -131,6 +136,17 @@
         }
 
         /**
+         * For internal use currently. Only takes effect if title is null/empty. Shows a default
+         * modality-specific title.
+         * @hide
+         */
+        @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+        public Builder setUseDefaultTitle() {
+            mBundle.putBoolean(KEY_USE_DEFAULT_TITLE, true);
+            return this;
+        }
+
+        /**
          * Optional: Set the subtitle to display.
          * @param subtitle
          * @return
@@ -206,8 +222,9 @@
         public BiometricPrompt build() {
             final CharSequence title = mBundle.getCharSequence(KEY_TITLE);
             final CharSequence negative = mBundle.getCharSequence(KEY_NEGATIVE_TEXT);
+            final boolean useDefaultTitle = mBundle.getBoolean(KEY_USE_DEFAULT_TITLE);
 
-            if (TextUtils.isEmpty(title)) {
+            if (TextUtils.isEmpty(title) && !useDefaultTitle) {
                 throw new IllegalArgumentException("Title must be set and non-empty");
             } else if (TextUtils.isEmpty(negative)) {
                 throw new IllegalArgumentException("Negative text must be set and non-empty");
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 51e4ecb..e17feff 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -43,4 +43,7 @@
 
     // Register callback for when keyguard biometric eligibility changes.
     void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback);
-}
\ No newline at end of file
+
+    // Explicitly set the active user.
+    void setActiveUser(int userId);
+}
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 486b054..d4dc181 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2090,7 +2090,7 @@
 
     /**
      * <p>Optimized for dim settings where the main light source
-     * is a flame.</p>
+     * is a candle.</p>
      * @see CaptureRequest#CONTROL_SCENE_MODE
      */
     public static final int CONTROL_SCENE_MODE_CANDLELIGHT = 15;
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 7aec43e..536c4a5 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -317,6 +317,7 @@
      * @hide
      */
     @RequiresPermission(MANAGE_BIOMETRIC)
+    @Override
     public void setActiveUser(int userId) {
         if (mService != null) {
             try {
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index bf2280d..bb98211 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -521,6 +521,7 @@
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
+    @Override
     public void setActiveUser(int userId) {
         if (mService != null) try {
             mService.setActiveUser(userId);
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index 917644d..6609b76 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -133,6 +133,7 @@
      *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     public boolean registerIntent(@NonNull PendingIntent intent, long nanoAppId) {
         // TODO: Implement this
         return false;
@@ -146,6 +147,7 @@
      *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     public boolean unregisterIntent(@NonNull PendingIntent intent) {
         // TODO: Implement this
         return false;
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 36f3586..f94d69b 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -749,6 +749,7 @@
      *
      * @see ContextHubClientCallback
      */
+    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     @NonNull public ContextHubClient createClient(
             @NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback,
             @NonNull @CallbackExecutor Executor executor) {
@@ -785,6 +786,7 @@
      *
      * @see ContextHubClientCallback
      */
+    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     @NonNull public ContextHubClient createClient(
             @NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback) {
         return createClient(hubInfo, callback, new HandlerExecutor(Handler.getMain()));
@@ -811,6 +813,7 @@
      *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     @NonNull public ContextHubClient createClient(
             @NonNull PendingIntent intent, @NonNull ContextHubInfo hubInfo,
             @NonNull ContextHubClientCallback callback,
@@ -835,6 +838,7 @@
      *
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     @NonNull public ContextHubClient createClient(
             @NonNull PendingIntent intent, @NonNull ContextHubInfo hubInfo,
             @NonNull ContextHubClientCallback callback) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 8333b81..c496ff4 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -83,6 +83,7 @@
 @SystemService(Context.CONNECTIVITY_SERVICE)
 public class ConnectivityManager {
     private static final String TAG = "ConnectivityManager";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     /**
      * A change in network connectivity has occurred. A default connection has either
@@ -2493,6 +2494,7 @@
      * {@hide}
      */
     public void reportInetCondition(int networkType, int percentage) {
+        printStackTrace();
         try {
             mService.reportInetCondition(networkType, percentage);
         } catch (RemoteException e) {
@@ -2513,6 +2515,7 @@
      */
     @Deprecated
     public void reportBadNetwork(Network network) {
+        printStackTrace();
         try {
             // One of these will be ignored because it matches system's current state.
             // The other will trigger the necessary reevaluation.
@@ -2535,6 +2538,7 @@
      *                        Internet using {@code network} or {@code false} if not.
      */
     public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
+        printStackTrace();
         try {
             mService.reportNetworkConnectivity(network, hasConnectivity);
         } catch (RemoteException e) {
@@ -2728,7 +2732,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
-    @UnsupportedAppUsage
+    @SystemApi
     public void setAirplaneMode(boolean enable) {
         try {
             mService.setAirplaneMode(enable);
@@ -3073,6 +3077,7 @@
 
     private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
             int timeoutMs, int action, int legacyType, CallbackHandler handler) {
+        printStackTrace();
         checkCallbackNotNull(callback);
         Preconditions.checkArgument(action == REQUEST || need != null, "null NetworkCapabilities");
         final NetworkRequest request;
@@ -3332,6 +3337,7 @@
      *         {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
      */
     public void requestNetwork(NetworkRequest request, PendingIntent operation) {
+        printStackTrace();
         checkPendingIntentNotNull(operation);
         try {
             mService.pendingRequestForNetwork(request.networkCapabilities, operation);
@@ -3355,6 +3361,7 @@
      *                  corresponding NetworkRequest you'd like to remove. Cannot be null.
      */
     public void releaseNetworkRequest(PendingIntent operation) {
+        printStackTrace();
         checkPendingIntentNotNull(operation);
         try {
             mService.releasePendingNetworkRequest(operation);
@@ -3439,6 +3446,7 @@
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
     public void registerNetworkCallback(NetworkRequest request, PendingIntent operation) {
+        printStackTrace();
         checkPendingIntentNotNull(operation);
         try {
             mService.pendingListenForNetwork(request.networkCapabilities, operation);
@@ -3520,6 +3528,7 @@
      * @param networkCallback The {@link NetworkCallback} used when making the request.
      */
     public void unregisterNetworkCallback(NetworkCallback networkCallback) {
+        printStackTrace();
         checkCallbackNotNull(networkCallback);
         final List<NetworkRequest> reqs = new ArrayList<>();
         // Find all requests associated to this callback and stop callback triggers immediately.
@@ -3948,4 +3957,19 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    private void printStackTrace() {
+        if (DEBUG) {
+            final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
+            final StringBuffer sb = new StringBuffer();
+            for (int i = 3; i < callStack.length; i++) {
+                final String stackTrace = callStack[i].toString();
+                if (stackTrace == null || stackTrace.contains("android.os")) {
+                    break;
+                }
+                sb.append(" [").append(stackTrace).append("]");
+            }
+            Log.d(TAG, "StackLog:" + sb.toString());
+        }
+    }
 }
diff --git a/core/java/android/nfc/cardemulation/OffHostApduService.java b/core/java/android/nfc/cardemulation/OffHostApduService.java
index 6a8aeee..2286e84 100644
--- a/core/java/android/nfc/cardemulation/OffHostApduService.java
+++ b/core/java/android/nfc/cardemulation/OffHostApduService.java
@@ -31,7 +31,7 @@
  * <div class="special reference">
  * <h3>Developer Guide</h3>
  * For a general introduction into the topic of card emulation,
- * please read the <a href="{@docRoot}guide/topics/nfc/ce.html">
+ * please read the <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html">
  * NFC card emulation developer guide.</a></p>
  * </div>
  *
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 8681893..412a700 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -17,9 +17,12 @@
 package android.os;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressAutoDoc;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.app.ActivityThread;
 import android.app.Application;
 import android.content.Context;
 import android.text.TextUtils;
@@ -127,14 +130,21 @@
      * <a href="/training/articles/security-key-attestation.html">key attestation</a> to obtain
      * proof of the device's original identifiers.
      *
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+     * device or profile owner. Profile owner access is deprecated and will be removed in a future
+     * release.
+     *
      * @return The serial number if specified.
      */
-    @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+    @SuppressAutoDoc // No support for device / profile owner.
+    @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public static String getSerial() {
         IDeviceIdentifiersPolicyService service = IDeviceIdentifiersPolicyService.Stub
                 .asInterface(ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE));
         try {
-            return service.getSerial();
+            Application application = ActivityThread.currentApplication();
+            String callingPackage = application != null ? application.getPackageName() : null;
+            return service.getSerialForPackage(callingPackage);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -1103,19 +1113,37 @@
         }
 
         /** The name of this partition, e.g. "system", or "vendor" */
+        @NonNull
         public String getName() {
             return mName;
         }
 
         /** The build fingerprint of this partition, see {@link Build#FINGERPRINT}. */
+        @NonNull
         public String getFingerprint() {
             return mFingerprint;
         }
 
         /** The time (ms since epoch), at which this partition was built, see {@link Build#TIME}. */
-        public long getTimeMillis() {
+        public long getBuildTimeMillis() {
             return mTimeMs;
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof Partition)) {
+                return false;
+            }
+            Partition op = (Partition) o;
+            return mName.equals(op.mName)
+                    && mFingerprint.equals(op.mFingerprint)
+                    && mTimeMs == op.mTimeMs;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mName, mFingerprint, mTimeMs);
+        }
     }
 
     /**
@@ -1124,7 +1152,8 @@
      * The list includes partitions that are suitable candidates for over-the-air updates. This is
      * not an exhaustive list of partitions on the device.
      */
-    public static List<Partition> getPartitions() {
+    @NonNull
+    public static List<Partition> getFingerprintedPartitions() {
         ArrayList<Partition> partitions = new ArrayList();
 
         String[] names = new String[] {
diff --git a/core/java/android/os/DumpstateOptions.java b/core/java/android/os/DumpstateOptions.java
new file mode 100644
index 0000000..53037b24
--- /dev/null
+++ b/core/java/android/os/DumpstateOptions.java
@@ -0,0 +1,57 @@
+/*
+ * 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.os;
+
+/**
+ * Options passed to dumpstate service.
+ *
+ * @hide
+ */
+public final class DumpstateOptions implements Parcelable {
+    // If true the caller can get callbacks with per-section
+    // progress details.
+    private final boolean mGetSectionDetails;
+    // Name of the caller.
+    private final String mName;
+
+    public DumpstateOptions(Parcel in) {
+        mGetSectionDetails = in.readBoolean();
+        mName = in.readString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+     public void writeToParcel(Parcel out, int flags) {
+        out.writeBoolean(mGetSectionDetails);
+        out.writeString(mName);
+    }
+
+    public static final Parcelable.Creator<DumpstateOptions> CREATOR =
+            new Parcelable.Creator<DumpstateOptions>() {
+        public DumpstateOptions createFromParcel(Parcel in) {
+            return new DumpstateOptions(in);
+        }
+
+        public DumpstateOptions[] newArray(int size) {
+            return new DumpstateOptions[size];
+        }
+    };
+}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 54be639..5f65620 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -54,9 +54,9 @@
     /**
      * Set up GraphicsEnvironment
      */
-    public void setup(Context context) {
+    public void setup(Context context, Bundle coreSettings) {
         setupGpuLayers(context);
-        setupAngle(context);
+        setupAngle(context, coreSettings);
         chooseDriver(context);
     }
 
@@ -135,11 +135,10 @@
     /**
      * Pass ANGLE details down to trigger enable logic
      */
-    private static void setupAngle(Context context) {
+    private static void setupAngle(Context context, Bundle coreSettings) {
 
         String angleEnabledApp =
-                Settings.Global.getString(context.getContentResolver(),
-                                          Settings.Global.ANGLE_ENABLED_APP);
+                coreSettings.getString(Settings.Global.ANGLE_ENABLED_APP);
 
         String packageName = context.getPackageName();
 
diff --git a/core/java/android/os/IDeviceIdentifiersPolicyService.aidl b/core/java/android/os/IDeviceIdentifiersPolicyService.aidl
index ac19f2b..87d358f 100644
--- a/core/java/android/os/IDeviceIdentifiersPolicyService.aidl
+++ b/core/java/android/os/IDeviceIdentifiersPolicyService.aidl
@@ -21,4 +21,5 @@
  */
 interface IDeviceIdentifiersPolicyService {
     String getSerial();
+    String getSerialForPackage(in String callingPackage);
 }
\ No newline at end of file
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index cd3f301..5d5e5e2 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -19,6 +19,8 @@
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 /**
  *
  * Defines a message containing a description and arbitrary data object that can be
@@ -111,7 +113,13 @@
 
     /*package*/ int flags;
 
-    /*package*/ long when;
+    /**
+     * The targeted delivery time of this message. The time-base is
+     * {@link SystemClock#uptimeMillis}.
+     * @hide Only for use within the tests.
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    public long when;
 
     /*package*/ Bundle data;
 
@@ -382,7 +390,7 @@
      * the <em>target</em> {@link Handler} that is receiving this Message to
      * dispatch it.  If
      * not set, the message will be dispatched to the receiving Handler's
-     * {@link Handler#handleMessage(Message Handler.handleMessage())}.
+     * {@link Handler#handleMessage(Message)}.
      */
     public Runnable getCallback() {
         return callback;
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 4fe2d58..f8feb7b 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -61,7 +61,6 @@
     public static final UserHandle CURRENT_OR_SELF = new UserHandle(USER_CURRENT_OR_SELF);
 
     /** @hide An undefined user id */
-    @SystemApi
     public static final @UserIdInt int USER_NULL = -10000;
 
     /**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1282170..8123744 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -268,7 +268,7 @@
     public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
 
     /**
-     * This restriction is a device-wide version of {@link DISALLOW_INSTALL_UNKNOWN_SOURCES}.
+     * This restriction is a device-wide version of {@link #DISALLOW_INSTALL_UNKNOWN_SOURCES}.
      *
      * Specifies if all users on the device are disallowed from enabling the
      * "Unknown Sources" setting, that allows installation of apps from unknown sources.
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 1f54ea5..63ff7b2 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -16,6 +16,9 @@
 
 package android.os.storage;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
 /**
  * Mount service local interface.
  *
@@ -81,18 +84,26 @@
     public abstract int getExternalStorageMountMode(int uid, String packageName);
 
     /**
-     * Mount external storage for the given package.
+     * Create storage sandbox for the given package.
      *
      * <p> This will involve calling into vold to setup appropriate bind mounts.
      *
-     * @param packageName The package for which external storage will be mounted.
+     * @param packageName The package for which the sandbox needs to be created.
      * @param appId The appId for the given package.
      * @param sharedUserId The sharedUserId for given package if it specified
      *      {@code android:sharedUserId} in the manifest, otherwise {@code null}
-     * @param userId The userId in which the storage needs to be mounted.
+     * @param userId The userId in which the sandbox needs to be created.
      */
-    public abstract void mountExternalStorageForApp(String packageName, int appId,
-            String sharedUserId, int userId);
+    public abstract void prepareSandboxForApp(@NonNull String packageName, int appId,
+            @Nullable String sharedUserId, int userId);
+
+    /**
+     * Delete storage sandbox for the given package.
+     *
+     * @param packageName The package for which the sandbox needs to be destroyed.
+     * @param userId The userId in which the sandbox needs to be destroyed.
+     */
+    public abstract void destroySandboxForApp(@NonNull String packageName, int userId);
 
     /**
      * @return Labels of storage volumes that are visible to the given userId.
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index aa44eb7..7ffb22f 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -25,7 +25,9 @@
 import com.android.internal.annotations.Immutable;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * System level service for accessing the permission capabilities of the platform.
@@ -40,26 +42,28 @@
      *
      * @hide
      */
-    public static final SplitPermissionInfo[] SPLIT_PERMISSIONS = new SplitPermissionInfo[]{
+    public static final List<SplitPermissionInfo> SPLIT_PERMISSIONS = Arrays.asList(
             // READ_EXTERNAL_STORAGE is always required when an app requests
             // WRITE_EXTERNAL_STORAGE, because we can't have an app that has
             // write access without read access.  The hack here with the target
             // target SDK version ensures that this grant is always done.
             new SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
-                    new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},
+                    Collections.singletonList(android.Manifest.permission.READ_EXTERNAL_STORAGE),
                     android.os.Build.VERSION_CODES.CUR_DEVELOPMENT + 1),
             new SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
-                    new String[]{android.Manifest.permission.READ_CALL_LOG},
+                    Collections.singletonList(android.Manifest.permission.READ_CALL_LOG),
                     android.os.Build.VERSION_CODES.JELLY_BEAN),
             new SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
-                    new String[]{android.Manifest.permission.WRITE_CALL_LOG},
+                    Collections.singletonList(android.Manifest.permission.WRITE_CALL_LOG),
                     android.os.Build.VERSION_CODES.JELLY_BEAN),
             new SplitPermissionInfo(Manifest.permission.ACCESS_FINE_LOCATION,
-                    new String[]{android.Manifest.permission.ACCESS_BACKGROUND_LOCATION},
+                    Collections.singletonList(
+                            android.Manifest.permission.ACCESS_BACKGROUND_LOCATION),
                     android.os.Build.VERSION_CODES.P0),
             new SplitPermissionInfo(Manifest.permission.ACCESS_COARSE_LOCATION,
-                    new String[]{android.Manifest.permission.ACCESS_BACKGROUND_LOCATION},
-                    android.os.Build.VERSION_CODES.P0)};
+                    Collections.singletonList(
+                            android.Manifest.permission.ACCESS_BACKGROUND_LOCATION),
+                    android.os.Build.VERSION_CODES.P0));
 
     private final @NonNull Context mContext;
 
@@ -74,7 +78,7 @@
     }
 
     /**
-     * Get list of permissions that have been split into more granular or dependent permissions.
+     * Get set of permissions that have been split into more granular or dependent permissions.
      *
      * <p>E.g. before {@link android.os.Build.VERSION_CODES#P0} an app that was granted
      * {@link Manifest.permission#ACCESS_COARSE_LOCATION} could access he location while it was in
@@ -82,7 +86,7 @@
      * the location permission only grants location access while the app is in foreground. This
      * would break apps that target before {@link android.os.Build.VERSION_CODES#P0}. Hence whenever
      * such an old app asks for a location permission (i.e. the
-     * {@link SplitPermissionInfo#getRootPermission()}), then the
+     * {@link SplitPermissionInfo#getSplitPermission()}), then the
      * {@link Manifest.permission#ACCESS_BACKGROUND_LOCATION} permission (inside
      * {@{@link SplitPermissionInfo#getNewPermissions}) is added.
      *
@@ -91,8 +95,9 @@
      *
      * @return All permissions that are split.
      */
-    public @NonNull List<SplitPermissionInfo> getSplitPermissions() {
-        return Arrays.asList(SPLIT_PERMISSIONS);
+    public @NonNull
+    List<SplitPermissionInfo> getSplitPermissions() {
+        return SPLIT_PERMISSIONS;
     }
 
     /**
@@ -101,21 +106,35 @@
      */
     @Immutable
     public static final class SplitPermissionInfo {
-        private final @NonNull String mRootPerm;
-        private final @NonNull String[] mNewPerms;
+        private final @NonNull String mSplitPerm;
+        private final @NonNull List<String> mNewPerms;
         private final int mTargetSdk;
 
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            SplitPermissionInfo that = (SplitPermissionInfo) o;
+            return mTargetSdk == that.mTargetSdk
+                    && Objects.equals(mSplitPerm, that.mSplitPerm);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mSplitPerm, mTargetSdk);
+        }
+
         /**
          * Get the permission that is split.
          */
-        public @NonNull String getRootPermission() {
-            return mRootPerm;
+        public @NonNull String getSplitPermission() {
+            return mSplitPerm;
         }
 
         /**
          * Get the permissions that are added.
          */
-        public @NonNull String[] getNewPermissions() {
+        public @NonNull List<String> getNewPermissions() {
             return mNewPerms;
         }
 
@@ -126,9 +145,9 @@
             return mTargetSdk;
         }
 
-        private SplitPermissionInfo(@NonNull String rootPerm, @NonNull String[] newPerms,
+        private SplitPermissionInfo(@NonNull String rootPerm, @NonNull List<String> newPerms,
                 int targetSdk) {
-            mRootPerm = rootPerm;
+            mSplitPerm = rootPerm;
             mNewPerms = newPerms;
             mTargetSdk = targetSdk;
         }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9bc17f2..acb7577 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7375,6 +7375,15 @@
         public static final String DIALER_DEFAULT_APPLICATION = "dialer_default_application";
 
         /**
+         * Specifies the package name currently configured to be the default application to perform
+         * the user-defined call redirection service with Telecom.
+         * @hide
+         */
+        @UnsupportedAppUsage
+        public static final String CALL_REDIRECTION_DEFAULT_APPLICATION =
+                "call_redirection_default_application";
+
+        /**
          * Specifies the package name currently configured to be the emergency assistance application
          *
          * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 5012d77..37a9b10 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -473,6 +473,15 @@
         }
     }
 
+    private static Long tryParseLong(String value, Long defValue) {
+        if (TextUtils.isEmpty(value)) return defValue;
+        try {
+            return Long.parseLong(value);
+        } catch (NumberFormatException e) {
+            return defValue;
+        }
+    }
+
     public static ZenModeConfig readXml(XmlPullParser parser)
             throws XmlPullParserException, IOException {
         int type = parser.getEventType();
@@ -1288,7 +1297,9 @@
                 .authority(SYSTEM_AUTHORITY)
                 .appendPath(EVENT_PATH)
                 .appendQueryParameter("userId", Long.toString(event.userId))
-                .appendQueryParameter("calendar", event.calendar != null ? event.calendar : "")
+                .appendQueryParameter("calendar", event.calName != null ? event.calName : "")
+                .appendQueryParameter("calendarId", event.calendarId != null
+                        ? event.calendarId.toString() : "")
                 .appendQueryParameter("reply", Integer.toString(event.reply))
                 .build();
     }
@@ -1306,10 +1317,11 @@
         if (!isEvent) return null;
         final EventInfo rt = new EventInfo();
         rt.userId = tryParseInt(conditionId.getQueryParameter("userId"), UserHandle.USER_NULL);
-        rt.calendar = conditionId.getQueryParameter("calendar");
-        if (TextUtils.isEmpty(rt.calendar) || tryParseLong(rt.calendar, -1L) != -1L) {
-            rt.calendar = null;
+        rt.calName = conditionId.getQueryParameter("calendar");
+        if (TextUtils.isEmpty(rt.calName)) {
+            rt.calName = null;
         }
+        rt.calendarId = tryParseLong(conditionId.getQueryParameter("calendarId"), null);
         rt.reply = tryParseInt(conditionId.getQueryParameter("reply"), 0);
         return rt;
     }
@@ -1324,12 +1336,13 @@
         public static final int REPLY_YES = 2;
 
         public int userId = UserHandle.USER_NULL;  // USER_NULL = unspecified - use current user
-        public String calendar;  // CalendarContract.Calendars.OWNER_ACCOUNT, or null for any
+        public String calName;  // CalendarContract.Calendars.DISPLAY_NAME, or null for any
+        public Long calendarId; // Calendars._ID, or null if restored from < Q calendar
         public int reply;
 
         @Override
         public int hashCode() {
-            return 0;
+            return Objects.hash(userId, calName, calendarId, reply);
         }
 
         @Override
@@ -1337,15 +1350,17 @@
             if (!(o instanceof EventInfo)) return false;
             final EventInfo other = (EventInfo) o;
             return userId == other.userId
-                    && Objects.equals(calendar, other.calendar)
-                    && reply == other.reply;
+                    && Objects.equals(calName, other.calName)
+                    && reply == other.reply
+                    && Objects.equals(calendarId, other.calendarId);
         }
 
         public EventInfo copy() {
             final EventInfo rt = new EventInfo();
             rt.userId = userId;
-            rt.calendar = calendar;
+            rt.calName = calName;
             rt.reply = reply;
+            rt.calendarId = calendarId;
             return rt;
         }
 
diff --git a/core/java/android/text/style/TextAppearanceSpan.java b/core/java/android/text/style/TextAppearanceSpan.java
index 2dc4f60..648bd1b 100644
--- a/core/java/android/text/style/TextAppearanceSpan.java
+++ b/core/java/android/text/style/TextAppearanceSpan.java
@@ -29,8 +29,33 @@
 import android.text.TextUtils;
 
 /**
- * Sets the text color, size, style, and typeface to match a TextAppearance
- * resource.
+ * Sets the text appearance using the given
+ * {@link android.R.styleable#TextAppearance TextAppearance} attributes.
+ * By default {@link TextAppearanceSpan} only changes the specified attributes in XML.
+ * {@link android.R.styleable#TextAppearance_textColorHighlight textColorHighlight},
+ * {@link android.R.styleable#TextAppearance_textColorHint textColorHint},
+ * {@link android.R.styleable#TextAppearance_textAllCaps textAllCaps} and
+ * {@link android.R.styleable#TextAppearance_fallbackLineSpacing fallbackLineSpacing}
+ * are not supported by {@link TextAppearanceSpan}.
+ *
+ * {@see android.widget.TextView#setTextAppearance(int)}
+ *
+ * @attr ref android.R.styleable#TextAppearance_fontFamily
+ * @attr ref android.R.styleable#TextAppearance_textColor
+ * @attr ref android.R.styleable#TextAppearance_textColorLink
+ * @attr ref android.R.styleable#TextAppearance_textFontWeight
+ * @attr ref android.R.styleable#TextAppearance_textSize
+ * @attr ref android.R.styleable#TextAppearance_textStyle
+ * @attr ref android.R.styleable#TextAppearance_typeface
+ * @attr ref android.R.styleable#TextAppearance_shadowColor
+ * @attr ref android.R.styleable#TextAppearance_shadowDx
+ * @attr ref android.R.styleable#TextAppearance_shadowDy
+ * @attr ref android.R.styleable#TextAppearance_shadowRadius
+ * @attr ref android.R.styleable#TextAppearance_elegantTextHeight
+ * @attr ref android.R.styleable#TextAppearance_letterSpacing
+ * @attr ref android.R.styleable#TextAppearance_fontFeatureSettings
+ * @attr ref android.R.styleable#TextAppearance_fontVariationSettings
+ *
  */
 public class TextAppearanceSpan extends MetricAffectingSpan implements ParcelableSpan {
     private final String mFamilyName;
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index f428c79..e9f1edf 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -245,9 +245,8 @@
      *                   passed, it's treated as an empty rectangle (0,0)-(0,0).
      */
     // TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
-    public DisplayCutout(
-            Insets safeInsets, @Nullable Rect boundLeft, @Nullable Rect boundTop,
-            @Nullable Rect boundRight, @Nullable Rect boundBottom) {
+    public DisplayCutout(@NonNull Insets safeInsets, @Nullable Rect boundLeft,
+            @Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom) {
         this(safeInsets.toRect(), boundLeft, boundTop, boundRight, boundBottom, true);
     }
 
@@ -262,7 +261,7 @@
      */
     // TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
     @Deprecated
-    public DisplayCutout(Rect safeInsets, List<Rect> boundingRects) {
+    public DisplayCutout(@Nullable Rect safeInsets, @Nullable List<Rect> boundingRects) {
         this(safeInsets, extractBoundsFromList(safeInsets, boundingRects),
                 true /* copyArguments */);
     }
@@ -313,18 +312,20 @@
         for (int i = 0; i < sortedBounds.length; ++i) {
             sortedBounds[i] = ZERO_RECT;
         }
-        for (Rect bound : boundingRects) {
-            // There will be at most one non-functional area per short edge of the device, and none
-            // on the long edges, so either safeInsets.right or safeInsets.bottom must be 0.
-            // TODO(b/117199965): Refine the logic to handle edge cases.
-            if (bound.left == 0) {
-                sortedBounds[BOUNDS_POSITION_LEFT] = bound;
-            } else if (bound.top == 0) {
-                sortedBounds[BOUNDS_POSITION_TOP] = bound;
-            } else if (safeInsets.right > 0) {
-                sortedBounds[BOUNDS_POSITION_RIGHT] = bound;
-            } else if (safeInsets.bottom > 0) {
-                sortedBounds[BOUNDS_POSITION_BOTTOM] = bound;
+        if (safeInsets != null && boundingRects != null) {
+            for (Rect bound : boundingRects) {
+                // There is at most one non-functional area per short edge of the device, but none
+                // on the long edges, so either safeInsets.right or safeInsets.bottom must be 0.
+                // TODO(b/117199965): Refine the logic to handle edge cases.
+                if (bound.left == 0) {
+                    sortedBounds[BOUNDS_POSITION_LEFT] = bound;
+                } else if (bound.top == 0) {
+                    sortedBounds[BOUNDS_POSITION_TOP] = bound;
+                } else if (safeInsets.right > 0) {
+                    sortedBounds[BOUNDS_POSITION_RIGHT] = bound;
+                } else if (safeInsets.bottom > 0) {
+                    sortedBounds[BOUNDS_POSITION_BOTTOM] = bound;
+                }
             }
         }
         return sortedBounds;
@@ -389,6 +390,7 @@
      * @return a list of bounding {@code Rect}s, one for each display cutout area. No empty Rect is
      * returned.
      */
+    @NonNull
     public List<Rect> getBoundingRects() {
         List<Rect> result = new ArrayList<>();
         for (Rect bound : getBoundingRectsAll()) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 7271a9e..0d33bbd 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -97,6 +97,8 @@
     private static native void nativeSetMatrix(long transactionObj, long nativeObject,
             float dsdx, float dtdx,
             float dtdy, float dsdy);
+    private static native void nativeSetColorTransform(long transactionObj, long nativeObject,
+            float[] matrix, float[] translation);
     private static native void nativeSetColor(long transactionObj, long nativeObject, float[] color);
     private static native void nativeSetFlags(long transactionObj, long nativeObject,
             int flags, int mask);
@@ -945,6 +947,18 @@
         }
     }
 
+    /**
+     * Sets the color transform for the Surface.
+     * @param matrix A float array with 9 values represents a 3x3 transform matrix
+     * @param translation A float array with 3 values represents a translation vector
+     */
+    public void setColorTransform(@Size(9) float[] matrix, @Size(3) float[] translation) {
+        checkNotReleased();
+        synchronized (SurfaceControl.class) {
+            sGlobalTransaction.setColorTransform(this, matrix, translation);
+        }
+    }
+
     public void setWindowCrop(Rect crop) {
         checkNotReleased();
         synchronized (SurfaceControl.class) {
@@ -1438,6 +1452,18 @@
             return this;
         }
 
+        /**
+         * Sets the color transform for the Surface.
+         * @param matrix A float array with 9 values represents a 3x3 transform matrix
+         * @param translation A float array with 3 values represents a translation vector
+         */
+        public Transaction setColorTransform(SurfaceControl sc, @Size(9) float[] matrix,
+                @Size(3) float[] translation) {
+            sc.checkNotReleased();
+            nativeSetColorTransform(mNativeObject, sc.mNativeObject, matrix, translation);
+            return this;
+        }
+
         @UnsupportedAppUsage
         public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
             sc.checkNotReleased();
diff --git a/core/java/android/view/TouchDelegate.java b/core/java/android/view/TouchDelegate.java
index b361ab4..06b73dd 100644
--- a/core/java/android/view/TouchDelegate.java
+++ b/core/java/android/view/TouchDelegate.java
@@ -16,8 +16,12 @@
 
 package android.view;
 
+import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Rect;
+import android.graphics.Region;
+import android.util.ArrayMap;
+import android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo;
 
 /**
  * Helper class to handle situations where you want a view to have a larger touch area than its
@@ -78,6 +82,11 @@
     private int mSlop;
 
     /**
+     * Touch delegate information for accessibility
+     */
+    private TouchDelegateInfo mTouchDelegateInfo;
+
+    /**
      * Constructor
      *
      * @param bounds Bounds in local coordinates of the containing view that should be mapped to
@@ -145,4 +154,20 @@
         }
         return handled;
     }
+
+    /**
+     * Return a {@link TouchDelegateInfo} mapping from regions (in view coordinates) to
+     * delegated views for accessibility usage.
+     *
+     * @return A TouchDelegateInfo.
+     */
+    @NonNull
+    public TouchDelegateInfo getTouchDelegateInfo() {
+        if (mTouchDelegateInfo == null) {
+            final ArrayMap<Region, View> targetMap = new ArrayMap<>(1);
+            targetMap.put(new Region(mBounds), mDelegateView);
+            mTouchDelegateInfo = new TouchDelegateInfo(targetMap);
+        }
+        return mTouchDelegateInfo;
+    }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cddd83c..c18187b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8881,6 +8881,10 @@
         populateAccessibilityNodeInfoDrawingOrderInParent(info);
         info.setPaneTitle(mAccessibilityPaneTitle);
         info.setHeading(isAccessibilityHeading());
+
+        if (mTouchDelegate != null) {
+            info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo());
+        }
     }
 
     /**
@@ -14255,9 +14259,10 @@
             }
 
             if (mParent instanceof ViewGroup) {
-                ((ViewGroup) mParent).onChildVisibilityChanged(this,
-                        (changed & VISIBILITY_MASK), newVisibility);
-                ((View) mParent).invalidate(true);
+                ViewGroup parent = (ViewGroup) mParent;
+                parent.onChildVisibilityChanged(this, (changed & VISIBILITY_MASK),
+                        newVisibility);
+                parent.invalidate(true);
             } else if (mParent != null) {
                 mParent.invalidateChild(this, null);
             }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 4d3f0fc..e129091 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -23,10 +23,12 @@
 
 import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -39,17 +41,21 @@
 import android.text.style.AccessibilityURLSpan;
 import android.text.style.ClickableSpan;
 import android.text.style.URLSpan;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.LongArray;
 import android.util.Pools.SynchronizedPool;
+import android.view.TouchDelegate;
 import android.view.View;
 
 import com.android.internal.R;
 import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -748,6 +754,8 @@
     private CollectionInfo mCollectionInfo;
     private CollectionItemInfo mCollectionItemInfo;
 
+    private TouchDelegateInfo mTouchDelegateInfo;
+
     /**
      * Hide constructor from clients.
      */
@@ -810,7 +818,7 @@
     public AccessibilityNodeInfo findFocus(int focus) {
         enforceSealed();
         enforceValidFocusType(focus);
-        if (!canPerformRequestOverConnection(mSourceNodeId)) {
+        if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
             return null;
         }
         return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId,
@@ -834,7 +842,7 @@
     public AccessibilityNodeInfo focusSearch(int direction) {
         enforceSealed();
         enforceValidFocusDirection(direction);
-        if (!canPerformRequestOverConnection(mSourceNodeId)) {
+        if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
             return null;
         }
         return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId,
@@ -866,7 +874,7 @@
     @UnsupportedAppUsage
     public boolean refresh(Bundle arguments, boolean bypassCache) {
         enforceSealed();
-        if (!canPerformRequestOverConnection(mSourceNodeId)) {
+        if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
             return false;
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -967,7 +975,7 @@
         if (mChildNodeIds == null) {
             return null;
         }
-        if (!canPerformRequestOverConnection(mSourceNodeId)) {
+        if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
             return null;
         }
         final long childId = mChildNodeIds.get(index);
@@ -1271,7 +1279,7 @@
      */
     public AccessibilityNodeInfo getTraversalBefore() {
         enforceSealed();
-        return getNodeForAccessibilityId(mTraversalBefore);
+        return getNodeForAccessibilityId(mConnectionId, mWindowId, mTraversalBefore);
     }
 
     /**
@@ -1332,7 +1340,7 @@
      */
     public AccessibilityNodeInfo getTraversalAfter() {
         enforceSealed();
-        return getNodeForAccessibilityId(mTraversalAfter);
+        return getNodeForAccessibilityId(mConnectionId, mWindowId, mTraversalAfter);
     }
 
     /**
@@ -1489,7 +1497,7 @@
      */
     public boolean performAction(int action) {
         enforceSealed();
-        if (!canPerformRequestOverConnection(mSourceNodeId)) {
+        if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
             return false;
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1512,7 +1520,7 @@
      */
     public boolean performAction(int action, Bundle arguments) {
         enforceSealed();
-        if (!canPerformRequestOverConnection(mSourceNodeId)) {
+        if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
             return false;
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1536,7 +1544,7 @@
      */
     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
         enforceSealed();
-        if (!canPerformRequestOverConnection(mSourceNodeId)) {
+        if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
             return Collections.emptyList();
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1567,7 +1575,7 @@
      */
     public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
         enforceSealed();
-        if (!canPerformRequestOverConnection(mSourceNodeId)) {
+        if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
             return Collections.emptyList();
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1584,7 +1592,7 @@
      */
     public AccessibilityWindowInfo getWindow() {
         enforceSealed();
-        if (!canPerformRequestOverConnection(mSourceNodeId)) {
+        if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
             return null;
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1603,7 +1611,7 @@
      */
     public AccessibilityNodeInfo getParent() {
         enforceSealed();
-        return getNodeForAccessibilityId(mParentNodeId);
+        return getNodeForAccessibilityId(mConnectionId, mWindowId, mParentNodeId);
     }
 
     /**
@@ -2783,7 +2791,7 @@
      */
     public AccessibilityNodeInfo getLabelFor() {
         enforceSealed();
-        return getNodeForAccessibilityId(mLabelForId);
+        return getNodeForAccessibilityId(mConnectionId, mWindowId, mLabelForId);
     }
 
     /**
@@ -2835,7 +2843,7 @@
      */
     public AccessibilityNodeInfo getLabeledBy() {
         enforceSealed();
-        return getNodeForAccessibilityId(mLabeledById);
+        return getNodeForAccessibilityId(mConnectionId, mWindowId, mLabeledById);
     }
 
     /**
@@ -2975,6 +2983,43 @@
     }
 
     /**
+     * Get the {@link TouchDelegateInfo} for touch delegate behavior with the represented view.
+     * It is possible for the same node to be pointed to by several regions. Use
+     * {@link TouchDelegateInfo#getRegionAt(int)} to get touch delegate target {@link Region}, and
+     * {@link TouchDelegateInfo#getTargetForRegion(Region)} for {@link AccessibilityNodeInfo} from
+     * the given region.
+     *
+     * @return {@link TouchDelegateInfo} or {@code null} if there are no touch delegates.
+     */
+    @Nullable
+    public TouchDelegateInfo getTouchDelegateInfo() {
+        if (mTouchDelegateInfo != null) {
+            mTouchDelegateInfo.setConnectionId(mConnectionId);
+            mTouchDelegateInfo.setWindowId(mWindowId);
+        }
+        return mTouchDelegateInfo;
+    }
+
+    /**
+     * Set touch delegate info if the represented view has a {@link TouchDelegate}.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an
+     *   AccessibilityService.
+     * </p>
+     *
+     * @param delegatedInfo {@link TouchDelegateInfo} returned from
+     *         {@link TouchDelegate#getTouchDelegateInfo()}.
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void setTouchDelegateInfo(@NonNull TouchDelegateInfo delegatedInfo) {
+        enforceNotSealed();
+        mTouchDelegateInfo = delegatedInfo;
+    }
+
+    /**
      * Gets the value of a boolean property.
      *
      * @param property The property.
@@ -3340,6 +3385,10 @@
         if (!Objects.equals(mCollectionItemInfo, DEFAULT.mCollectionItemInfo)) {
             nonDefaultFields |= bitAt(fieldIndex);
         }
+        fieldIndex++;
+        if (!Objects.equals(mTouchDelegateInfo, DEFAULT.mTouchDelegateInfo)) {
+            nonDefaultFields |= bitAt(fieldIndex);
+        }
         int totalFields = fieldIndex;
         parcel.writeLong(nonDefaultFields);
 
@@ -3462,6 +3511,10 @@
             parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0);
         }
 
+        if (isBitSet(nonDefaultFields, fieldIndex++)) {
+            mTouchDelegateInfo.writeToParcel(parcel, flags);
+        }
+
         if (DEBUG) {
             fieldIndex--;
             if (totalFields != fieldIndex) {
@@ -3543,6 +3596,10 @@
         if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
         mCollectionItemInfo =  (other.mCollectionItemInfo != null)
                 ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
+
+        final TouchDelegateInfo otherInfo = other.mTouchDelegateInfo;
+        mTouchDelegateInfo = (otherInfo != null)
+                ? new TouchDelegateInfo(otherInfo.mTargetMap, true) : null;
     }
 
     /**
@@ -3665,6 +3722,10 @@
                         parcel.readInt() == 1)
                 : null;
 
+        if (isBitSet(nonDefaultFields, fieldIndex++)) {
+            mTouchDelegateInfo = TouchDelegateInfo.CREATOR.createFromParcel(parcel);
+        }
+
         mSealed = sealed;
     }
 
@@ -3813,10 +3874,11 @@
         }
     }
 
-    private boolean canPerformRequestOverConnection(long accessibilityNodeId) {
-        return ((mWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
+    private static boolean canPerformRequestOverConnection(int connectionId,
+            int windowId, long accessibilityNodeId) {
+        return ((windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
                 && (getAccessibilityViewId(accessibilityNodeId) != UNDEFINED_ITEM_ID)
-                && (mConnectionId != UNDEFINED_CONNECTION_ID));
+                && (connectionId != UNDEFINED_CONNECTION_ID));
     }
 
     @Override
@@ -3919,13 +3981,14 @@
         return builder.toString();
     }
 
-    private AccessibilityNodeInfo getNodeForAccessibilityId(long accessibilityId) {
-        if (!canPerformRequestOverConnection(accessibilityId)) {
+    private static AccessibilityNodeInfo getNodeForAccessibilityId(int connectionId,
+            int windowId, long accessibilityId) {
+        if (!canPerformRequestOverConnection(connectionId, windowId, accessibilityId)) {
             return null;
         }
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
-        return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
-                mWindowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
+        return client.findAccessibilityNodeInfoByAccessibilityId(connectionId,
+                windowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
                         | FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS, null);
     }
 
@@ -4896,6 +4959,176 @@
     }
 
     /**
+     * Class with information of touch delegated views and regions from {@link TouchDelegate} for
+     * the {@link AccessibilityNodeInfo}.
+     *
+     * @see AccessibilityNodeInfo#setTouchDelegateInfo(TouchDelegateInfo)
+     */
+    public static final class TouchDelegateInfo implements Parcelable {
+        private ArrayMap<Region, Long> mTargetMap;
+        // Two ids are initialized lazily in AccessibilityNodeInfo#getTouchDelegateInfo
+        private int mConnectionId;
+        private int mWindowId;
+
+        /**
+         * Create a new instance of {@link TouchDelegateInfo}.
+         *
+         * @param targetMap A map from regions (in view coordinates) to delegated views.
+         * @throws IllegalArgumentException if targetMap is empty or {@code null} in
+         * Regions or Views.
+         */
+        public TouchDelegateInfo(@NonNull Map<Region, View> targetMap) {
+            Preconditions.checkArgument(!targetMap.isEmpty()
+                    && !targetMap.containsKey(null) && !targetMap.containsValue(null));
+            mTargetMap = new ArrayMap<>(targetMap.size());
+            for (final Region region : targetMap.keySet()) {
+                final View view = targetMap.get(region);
+                mTargetMap.put(region, (long) view.getAccessibilityViewId());
+            }
+        }
+
+        /**
+         * Create a new instance from target map.
+         *
+         * @param targetMap A map from regions (in view coordinates) to delegated views'
+         *                  accessibility id.
+         * @param doCopy True if shallow copy targetMap.
+         * @throws IllegalArgumentException if targetMap is empty or {@code null} in
+         * Regions or Views.
+         */
+        TouchDelegateInfo(@NonNull ArrayMap<Region, Long> targetMap, boolean doCopy) {
+            Preconditions.checkArgument(!targetMap.isEmpty()
+                    && !targetMap.containsKey(null) && !targetMap.containsValue(null));
+            if (doCopy) {
+                mTargetMap = new ArrayMap<>(targetMap.size());
+                mTargetMap.putAll(targetMap);
+            } else {
+                mTargetMap = targetMap;
+            }
+        }
+
+        /**
+         * Set the connection ID.
+         *
+         * @param connectionId The connection id.
+         */
+        private void setConnectionId(int connectionId) {
+            mConnectionId = connectionId;
+        }
+
+        /**
+         * Set the window ID.
+         *
+         * @param windowId The window id.
+         */
+        private void setWindowId(int windowId) {
+            mWindowId = windowId;
+        }
+
+        /**
+         * Returns the number of touch delegate target region.
+         *
+         * @return Number of touch delegate target region.
+         */
+        public int getRegionCount() {
+            return mTargetMap.size();
+        }
+
+        /**
+         * Return the {@link Region} at the given index in the {@link TouchDelegateInfo}.
+         *
+         * @param index The desired index, must be between 0 and {@link #getRegionCount()}-1.
+         * @return Returns the {@link Region} stored at the given index.
+         */
+        @NonNull
+        public Region getRegionAt(int index) {
+            return mTargetMap.keyAt(index);
+        }
+
+        /**
+         * Return the target {@link AccessibilityNodeInfo} for the given {@link Region}.
+         * <p>
+         *   <strong>Note:</strong> This api can only be called from {@link AccessibilityService}.
+         * </p>
+         * <p>
+         *   <strong>Note:</strong> It is a client responsibility to recycle the
+         *     received info by calling {@link AccessibilityNodeInfo#recycle()}
+         *     to avoid creating of multiple instances.
+         * </p>
+         *
+         * @param region The region retrieved from {@link #getRegionAt(int)}.
+         * @return The target node associates with the given region.
+         */
+        @Nullable
+        public AccessibilityNodeInfo getTargetForRegion(@NonNull Region region) {
+            return getNodeForAccessibilityId(mConnectionId, mWindowId, mTargetMap.get(region));
+        }
+
+        /**
+         * Return the accessibility id of target node.
+         *
+         * @param region The region retrieved from {@link #getRegionAt(int)}.
+         * @return The accessibility id of target node.
+         *
+         * @hide
+         */
+        @TestApi
+        public long getAccessibilityIdForRegion(@NonNull Region region) {
+            return mTargetMap.get(region);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mTargetMap.size());
+            for (int i = 0; i < mTargetMap.size(); i++) {
+                final Region region = mTargetMap.keyAt(i);
+                final Long accessibilityId = mTargetMap.valueAt(i);
+                region.writeToParcel(dest, flags);
+                dest.writeLong(accessibilityId);
+            }
+        }
+
+        /**
+         * @see android.os.Parcelable.Creator
+         */
+        public static final Parcelable.Creator<TouchDelegateInfo> CREATOR =
+                new Parcelable.Creator<TouchDelegateInfo>() {
+            @Override
+            public TouchDelegateInfo createFromParcel(Parcel parcel) {
+                final int size = parcel.readInt();
+                if (size == 0) {
+                    return null;
+                }
+                final ArrayMap<Region, Long> targetMap = new ArrayMap<>(size);
+                for (int i = 0; i < size; i++) {
+                    final Region region = Region.CREATOR.createFromParcel(parcel);
+                    final long accessibilityId = parcel.readLong();
+                    targetMap.put(region, accessibilityId);
+                }
+                final TouchDelegateInfo touchDelegateInfo = new TouchDelegateInfo(
+                        targetMap, false);
+                return touchDelegateInfo;
+            }
+
+            @Override
+            public TouchDelegateInfo[] newArray(int size) {
+                return new TouchDelegateInfo[size];
+            }
+        };
+    }
+
+    /**
      * @see android.os.Parcelable.Creator
      */
     public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 08ed9d1..ca2ccaf 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -48,7 +48,6 @@
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
 import android.util.SparseArray;
-import android.view.Display;
 import android.view.InputChannel;
 import android.view.InputEvent;
 import android.view.InputEventSender;
@@ -266,7 +265,7 @@
      * @hide
      */
     public static void ensureDefaultInstanceForDefaultDisplayIfNecessary() {
-        forContextInternal(Display.DEFAULT_DISPLAY, Looper.getMainLooper());
+        getInstanceInternal();
     }
 
     private static final Object sLock = new Object();
@@ -280,17 +279,6 @@
     static InputMethodManager sInstance;
 
     /**
-     * Global map between display to {@link InputMethodManager}.
-     *
-     * <p>Currently this map works like a so-called leaky singleton.  Once an instance is registered
-     * for the associated display ID, that instance will never be garbage collected.</p>
-     *
-     * <p>TODO(Bug 116699479): Implement instance clean up mechanism.</p>
-     */
-    @GuardedBy("sLock")
-    private static final SparseArray<InputMethodManager> sInstanceMap = new SparseArray<>();
-
-    /**
      * @hide Flag for IInputMethodManager.windowGainedFocus: a view in
      * the window has input focus.
      */
@@ -347,8 +335,6 @@
     // Our generic input connection if the current target does not have its own.
     final IInputContext mIInputContext;
 
-    private final int mDisplayId;
-
     /**
      * True if this input method client is active, initially false.
      */
@@ -466,29 +452,6 @@
         return afm != null && afm.isAutofillUiShowing();
     }
 
-    /**
-     * Checks the consistency between {@link InputMethodManager} state and {@link View} state.
-     *
-     * @param view {@link View} to be checked
-     * @return {@code true} if {@code view} is not {@code null} and there is a {@link Context}
-     *         mismatch between {@link InputMethodManager} and {@code view}
-     */
-    private boolean shouldDispatchToViewContext(@Nullable View view) {
-        if (view == null) {
-            return false;
-        }
-        final int viewDisplayId = getDisplayId(view.getContext());
-        if (viewDisplayId != mDisplayId) {
-            Log.w(TAG, "b/117267690: Context mismatch found. view=" + view + " belongs to"
-                    + " displayId=" + viewDisplayId
-                    + " but InputMethodManager belongs to displayId=" + mDisplayId
-                    + ". Use the right InputMethodManager instance to avoid performance overhead.",
-                    new Throwable());
-            return true;
-        }
-        return false;
-    }
-
     private static boolean canStartInput(View servedView) {
         // We can start input ether the servedView has window focus
         // or the activity is showing autofill ui.
@@ -770,57 +733,33 @@
                 });
     }
 
-    InputMethodManager(int displayId, Looper looper) throws ServiceNotFoundException {
+    InputMethodManager(Looper looper) throws ServiceNotFoundException {
         mService = getIInputMethodManager();
         mMainLooper = looper;
         mH = new H(looper);
-        mDisplayId = displayId;
         mIInputContext = new ControlledInputConnectionWrapper(looper,
                 mDummyInputConnection, this);
     }
 
-    private static int getDisplayId(Context context) {
-        final Display display = context.getDisplay();
-        return display != null ? display.getDisplayId() : Display.DEFAULT_DISPLAY;
-    }
-
     /**
-     * Retrieve an instance for the given {@link Context}, creating it if it doesn't already exist.
+     * Retrieve the global {@link InputMethodManager} instance, creating it if it doesn't already
+     * exist.
      *
-     * @param context {@link Context} for which IME APIs need to work
-     * @return {@link InputMethodManager} instance
+     * @return global {@link InputMethodManager} instance
      * @hide
      */
-    @Nullable
-    public static InputMethodManager forContext(Context context) {
-        final int displayId = getDisplayId(context);
-        // For better backward compatibility, we always use Looper.getMainLooper() for the default
-        // display case.
-        final Looper looper = displayId == Display.DEFAULT_DISPLAY
-                ? Looper.getMainLooper() : context.getMainLooper();
-        return forContextInternal(displayId, looper);
-    }
-
-    @Nullable
-    private static InputMethodManager forContextInternal(int displayId, Looper looper) {
-        final boolean isDefaultDisplay = displayId == Display.DEFAULT_DISPLAY;
+    public static InputMethodManager getInstanceInternal() {
         synchronized (sLock) {
-            InputMethodManager instance = sInstanceMap.get(displayId);
-            if (instance != null) {
-                return instance;
+            if (sInstance == null) {
+                try {
+                    final InputMethodManager imm = new InputMethodManager(Looper.getMainLooper());
+                    imm.mService.addClient(imm.mClient, imm.mIInputContext);
+                    sInstance = imm;
+                } catch (ServiceNotFoundException | RemoteException e) {
+                    throw new IllegalStateException(e);
+                }
             }
-            try {
-                instance = new InputMethodManager(displayId, looper);
-                instance.mService.addClient(instance.mClient, instance.mIInputContext, displayId);
-            } catch (ServiceNotFoundException | RemoteException e) {
-                throw new IllegalStateException(e);
-            }
-            // For backward compatibility, store the instance also to sInstance for default display.
-            if (sInstance == null && isDefaultDisplay) {
-                sInstance = instance;
-            }
-            sInstanceMap.put(displayId, instance);
-            return instance;
+            return sInstance;
         }
     }
 
@@ -977,11 +916,6 @@
      * input method.
      */
     public boolean isActive(View view) {
-        // Re-dispatch if there is a context mismatch.
-        if (shouldDispatchToViewContext(view)) {
-            return view.getContext().getSystemService(InputMethodManager.class).isActive(view);
-        }
-
         checkFocus();
         synchronized (mH) {
             return (mServedView == view
@@ -1072,13 +1006,6 @@
     }
 
     public void displayCompletions(View view, CompletionInfo[] completions) {
-        // Re-dispatch if there is a context mismatch.
-        if (shouldDispatchToViewContext(view)) {
-            view.getContext().getSystemService(InputMethodManager.class)
-                    .displayCompletions(view, completions);
-            return;
-        }
-
         checkFocus();
         synchronized (mH) {
             if (mServedView != view && (mServedView == null
@@ -1097,13 +1024,6 @@
     }
 
     public void updateExtractedText(View view, int token, ExtractedText text) {
-        // Re-dispatch if there is a context mismatch.
-        if (shouldDispatchToViewContext(view)) {
-            view.getContext().getSystemService(InputMethodManager.class)
-                    .updateExtractedText(view, token, text);
-            return;
-        }
-
         checkFocus();
         synchronized (mH) {
             if (mServedView != view && (mServedView == null
@@ -1145,12 +1065,6 @@
      * 0 or have the {@link #SHOW_IMPLICIT} bit set.
      */
     public boolean showSoftInput(View view, int flags) {
-        // Re-dispatch if there is a context mismatch.
-        if (shouldDispatchToViewContext(view)) {
-            return view.getContext().getSystemService(InputMethodManager.class)
-                    .showSoftInput(view, flags);
-        }
-
         return showSoftInput(view, flags, null);
     }
 
@@ -1213,12 +1127,6 @@
      * {@link #RESULT_HIDDEN}.
      */
     public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
-        // Re-dispatch if there is a context mismatch.
-        if (shouldDispatchToViewContext(view)) {
-            return view.getContext().getSystemService(InputMethodManager.class)
-                    .showSoftInput(view, flags, resultReceiver);
-        }
-
         checkFocus();
         synchronized (mH) {
             if (mServedView != view && (mServedView == null
@@ -1382,12 +1290,6 @@
      * @param view The view whose text has changed.
      */
     public void restartInput(View view) {
-        // Re-dispatch if there is a context mismatch.
-        if (shouldDispatchToViewContext(view)) {
-            view.getContext().getSystemService(InputMethodManager.class).restartInput(view);
-            return;
-        }
-
         checkFocus();
         synchronized (mH) {
             if (mServedView != view && (mServedView == null
@@ -1812,13 +1714,6 @@
      */
     public void updateSelection(View view, int selStart, int selEnd,
             int candidatesStart, int candidatesEnd) {
-        // Re-dispatch if there is a context mismatch.
-        if (shouldDispatchToViewContext(view)) {
-            view.getContext().getSystemService(InputMethodManager.class)
-                    .updateSelection(view, selStart, selEnd, candidatesStart, candidatesEnd);
-            return;
-        }
-
         checkFocus();
         synchronized (mH) {
             if ((mServedView != view && (mServedView == null
@@ -1856,12 +1751,6 @@
      * Notify the event when the user tapped or clicked the text view.
      */
     public void viewClicked(View view) {
-        // Re-dispatch if there is a context mismatch.
-        if (shouldDispatchToViewContext(view)) {
-            view.getContext().getSystemService(InputMethodManager.class).viewClicked(view);
-            return;
-        }
-
         final boolean focusChanged = mServedView != mNextServedView;
         checkFocus();
         synchronized (mH) {
@@ -1926,13 +1815,6 @@
      */
     @Deprecated
     public void updateCursor(View view, int left, int top, int right, int bottom) {
-        // Re-dispatch if there is a context mismatch.
-        if (shouldDispatchToViewContext(view)) {
-            view.getContext().getSystemService(InputMethodManager.class)
-                    .updateCursor(view, left, top, right, bottom);
-            return;
-        }
-
         checkFocus();
         synchronized (mH) {
             if ((mServedView != view && (mServedView == null
@@ -1964,13 +1846,6 @@
         if (view == null || cursorAnchorInfo == null) {
             return;
         }
-        // Re-dispatch if there is a context mismatch.
-        if (shouldDispatchToViewContext(view)) {
-            view.getContext().getSystemService(InputMethodManager.class)
-                    .updateCursorAnchorInfo(view, cursorAnchorInfo);
-            return;
-        }
-
         checkFocus();
         synchronized (mH) {
             if ((mServedView != view &&
@@ -2016,13 +1891,6 @@
      * @param data Any data to include with the command.
      */
     public void sendAppPrivateCommand(View view, String action, Bundle data) {
-        // Re-dispatch if there is a context mismatch.
-        if (shouldDispatchToViewContext(view)) {
-            view.getContext().getSystemService(InputMethodManager.class)
-                    .sendAppPrivateCommand(view, action, data);
-            return;
-        }
-
         checkFocus();
         synchronized (mH) {
             if ((mServedView != view && (mServedView == null
@@ -2194,13 +2062,6 @@
      */
     public void dispatchKeyEventFromInputMethod(@Nullable View targetView,
             @NonNull KeyEvent event) {
-        // Re-dispatch if there is a context mismatch.
-        if (shouldDispatchToViewContext(targetView)) {
-            targetView.getContext().getSystemService(InputMethodManager.class)
-                    .dispatchKeyEventFromInputMethod(targetView, event);
-            return;
-        }
-
         synchronized (mH) {
             ViewRootImpl viewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
             if (viewRootImpl == null) {
@@ -2690,7 +2551,6 @@
         sb.append(",windowFocus=" + view.hasWindowFocus());
         sb.append(",autofillUiShowing=" + isAutofillUIShowing(view));
         sb.append(",window=" + view.getWindowToken());
-        sb.append(",displayId=" + getDisplayId(view.getContext()));
         sb.append(",temporaryDetach=" + view.isTemporarilyDetached());
         return sb.toString();
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9d06680..f74c234 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3521,7 +3521,7 @@
         Typeface mFontTypeface = null;
         boolean mFontFamilyExplicit = false;
         int mTypefaceIndex = -1;
-        int mStyleIndex = -1;
+        int mTextStyle = 0;
         int mFontWeight = -1;
         boolean mAllCaps = false;
         int mShadowColor = 0;
@@ -3547,7 +3547,7 @@
                     + "    mFontTypeface:" + mFontTypeface + "\n"
                     + "    mFontFamilyExplicit:" + mFontFamilyExplicit + "\n"
                     + "    mTypefaceIndex:" + mTypefaceIndex + "\n"
-                    + "    mStyleIndex:" + mStyleIndex + "\n"
+                    + "    mTextStyle:" + mTextStyle + "\n"
                     + "    mFontWeight:" + mFontWeight + "\n"
                     + "    mAllCaps:" + mAllCaps + "\n"
                     + "    mShadowColor:" + mShadowColor + "\n"
@@ -3672,7 +3672,7 @@
                     attributes.mFontFamilyExplicit = true;
                     break;
                 case com.android.internal.R.styleable.TextAppearance_textStyle:
-                    attributes.mStyleIndex = appearance.getInt(attr, attributes.mStyleIndex);
+                    attributes.mTextStyle = appearance.getInt(attr, attributes.mTextStyle);
                     break;
                 case com.android.internal.R.styleable.TextAppearance_textFontWeight:
                     attributes.mFontWeight = appearance.getInt(attr, attributes.mFontWeight);
@@ -3742,7 +3742,7 @@
             attributes.mFontFamily = null;
         }
         setTypefaceFromAttrs(attributes.mFontTypeface, attributes.mFontFamily,
-                attributes.mTypefaceIndex, attributes.mStyleIndex, attributes.mFontWeight);
+                attributes.mTypefaceIndex, attributes.mTextStyle, attributes.mFontWeight);
 
         if (attributes.mShadowColor != 0) {
             setShadowLayer(attributes.mShadowRadius, attributes.mShadowDx, attributes.mShadowDy,
diff --git a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
index 0080ace..d4c451e 100644
--- a/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
+++ b/core/java/com/android/internal/hardware/AmbientDisplayConfiguration.java
@@ -72,7 +72,8 @@
     }
 
     public boolean wakeLockScreenGestureAvailable() {
-        return !TextUtils.isEmpty(wakeLockScreenSensorType());
+        return mContext.getResources()
+                .getBoolean(R.bool.config_dozeWakeLockScreenSensorAvailable);
     }
 
     public boolean wakeScreenGestureEnabled(int user) {
@@ -92,10 +93,6 @@
         return mContext.getResources().getString(R.string.config_dozeLongPressSensorType);
     }
 
-    public String wakeLockScreenSensorType() {
-        return mContext.getResources().getString(R.string.config_dozeWakeLockScreenSensorType);
-    }
-
     public String wakeScreenSensorType() {
         return mContext.getResources().getString(R.string.config_dozeWakeScreenSensorType);
     }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 33b9ff7..017da55 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -5330,6 +5330,7 @@
                 if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: "
                         + Integer.toHexString(mHistoryCur.states));
                 mPhoneSignalScanningTimer.startRunningLocked(elapsedRealtime);
+                StatsLog.write(StatsLog.PHONE_SERVICE_STATE_CHANGED, state, simState, strengthBin);
             }
         }
 
@@ -5341,6 +5342,7 @@
                         + Integer.toHexString(mHistoryCur.states));
                 newHistory = true;
                 mPhoneSignalScanningTimer.stopRunningLocked(elapsedRealtime);
+                StatsLog.write(StatsLog.PHONE_SERVICE_STATE_CHANGED, state, simState, strengthBin);
             }
         }
 
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index e4724ff..8dc97fe 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -66,6 +66,7 @@
             session = session == null ? new DispatchSession() : session;
             session.startTimeMicro = getElapsedRealtimeMicro();
             session.cpuStartMicro = getThreadTimeMicro();
+            session.systemUptimeMillis = getSystemUptimeMillis();
             return session;
         }
 
@@ -85,12 +86,18 @@
                 entry.messageCount++;
                 if (session != DispatchSession.NOT_SAMPLED) {
                     entry.recordedMessageCount++;
-                    long latency = getElapsedRealtimeMicro() - session.startTimeMicro;
-                    long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro;
+                    final long latency = getElapsedRealtimeMicro() - session.startTimeMicro;
+                    final long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro;
                     entry.totalLatencyMicro += latency;
                     entry.maxLatencyMicro = Math.max(entry.maxLatencyMicro, latency);
                     entry.cpuUsageMicro += cpuUsage;
                     entry.maxCpuUsageMicro = Math.max(entry.maxCpuUsageMicro, cpuUsage);
+                    if (msg.getWhen() > 0) {
+                        final long delay = Math.max(0L, session.systemUptimeMillis - msg.getWhen());
+                        entry.delayMillis += delay;
+                        entry.maxDelayMillis = Math.max(entry.maxDelayMillis, delay);
+                        entry.recordedDelayMessageCount++;
+                    }
                 }
             }
         }
@@ -206,6 +213,10 @@
         return SystemClock.elapsedRealtimeNanos() / 1000;
     }
 
+    protected long getSystemUptimeMillis() {
+        return SystemClock.uptimeMillis();
+    }
+
     protected boolean shouldCollectDetailedData() {
         return ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0;
     }
@@ -214,6 +225,7 @@
         static final DispatchSession NOT_SAMPLED = new DispatchSession();
         public long startTimeMicro;
         public long cpuStartMicro;
+        public long systemUptimeMillis;
     }
 
     private static class Entry {
@@ -228,6 +240,9 @@
         public long maxLatencyMicro;
         public long cpuUsageMicro;
         public long maxCpuUsageMicro;
+        public long recordedDelayMessageCount;
+        public long delayMillis;
+        public long maxDelayMillis;
 
         Entry(Message msg, boolean isInteractive) {
             this.workSourceUid = msg.workSourceUid;
@@ -251,6 +266,9 @@
             maxLatencyMicro = 0;
             cpuUsageMicro = 0;
             maxCpuUsageMicro = 0;
+            delayMillis = 0;
+            maxDelayMillis = 0;
+            recordedDelayMessageCount = 0;
         }
 
         static int idFor(Message msg, boolean isInteractive) {
@@ -281,6 +299,9 @@
         public final long maxLatencyMicros;
         public final long cpuUsageMicros;
         public final long maxCpuUsageMicros;
+        public final long maxDelayMillis;
+        public final long delayMillis;
+        public final long recordedDelayMessageCount;
 
         ExportedEntry(Entry entry) {
             this.workSourceUid = entry.workSourceUid;
@@ -301,6 +322,9 @@
             this.maxLatencyMicros = entry.maxLatencyMicro;
             this.cpuUsageMicros = entry.cpuUsageMicro;
             this.maxCpuUsageMicros = entry.maxCpuUsageMicro;
+            this.delayMillis = entry.delayMillis;
+            this.maxDelayMillis = entry.maxDelayMillis;
+            this.recordedDelayMessageCount = entry.recordedDelayMessageCount;
         }
     }
 }
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 989c58b..27c2478 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -101,7 +101,7 @@
 
     public static LatencyTracker getInstance(Context context) {
         if (sLatencyTracker == null) {
-            sLatencyTracker = new LatencyTracker(context);
+            sLatencyTracker = new LatencyTracker(context.getApplicationContext());
         }
         return sLatencyTracker;
     }
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index dceacda..5f1243f 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -31,8 +31,7 @@
  * applications.
  */
 interface IInputMethodManager {
-    void addClient(in IInputMethodClient client, in IInputContext inputContext,
-            int untrustedDisplayId);
+    void addClient(in IInputMethodClient client, in IInputContext inputContext);
 
     // TODO: Use ParceledListSlice instead
     List<InputMethodInfo> getInputMethodList();
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index ec8e8da..101fd41 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -51,9 +51,6 @@
             ResultCode.ERROR_INVALID_USER,
             ResultCode.ERROR_NULL_EDITOR_INFO,
             ResultCode.ERROR_NOT_IME_TARGET_WINDOW,
-            ResultCode.ERROR_NO_EDITOR,
-            ResultCode.ERROR_DISPLAY_ID_MISMATCH,
-            ResultCode.ERROR_INVALID_DISPLAY_ID,
     })
     public @interface ResultCode {
         /**
@@ -142,22 +139,13 @@
          * The client should try to restart input when its {@link android.view.Window} is focused
          * again.</p>
          *
-         * @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int, int)
+         * @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int)
          */
         int ERROR_NOT_IME_TARGET_WINDOW = 11;
         /**
          * Indicates that focused view in the current window is not an editor.
          */
         int ERROR_NO_EDITOR = 12;
-        /**
-         * Indicates that there is a mismatch in display ID between IME client and focused Window.
-         */
-        int ERROR_DISPLAY_ID_MISMATCH = 13;
-        /**
-         * Indicates that current IME client is no longer allowed to access to the associated
-         * display.
-         */
-        int ERROR_INVALID_DISPLAY_ID = 14;
     }
 
     @ResultCode
@@ -283,10 +271,6 @@
                 return "ERROR_NULL_EDITOR_INFO";
             case ResultCode.ERROR_NOT_IME_TARGET_WINDOW:
                 return "ERROR_NOT_IME_TARGET_WINDOW";
-            case ResultCode.ERROR_DISPLAY_ID_MISMATCH:
-                return "ERROR_DISPLAY_ID_MISMATCH";
-            case ResultCode.ERROR_INVALID_DISPLAY_ID:
-                return "ERROR_INVALID_DISPLAY_ID";
             default:
                 return "Unknown(" + result + ")";
         }
@@ -332,15 +316,4 @@
      */
     public static final InputBindResult INVALID_USER = error(ResultCode.ERROR_INVALID_USER);
 
-    /**
-     * Predefined error object for {@link ResultCode#ERROR_DISPLAY_ID_MISMATCH}.
-     */
-    public static final InputBindResult DISPLAY_ID_MISMATCH =
-            error(ResultCode.ERROR_DISPLAY_ID_MISMATCH);
-
-    /**
-     * Predefined error object for {@link ResultCode#ERROR_INVALID_DISPLAY_ID}.
-     */
-    public static final InputBindResult INVALID_DISPLAY_ID =
-            error(ResultCode.ERROR_INVALID_DISPLAY_ID);
 }
diff --git a/core/java/com/android/internal/widget/AlertDialogLayout.java b/core/java/com/android/internal/widget/AlertDialogLayout.java
index 9bf0948..7a01749 100644
--- a/core/java/com/android/internal/widget/AlertDialogLayout.java
+++ b/core/java/com/android/internal/widget/AlertDialogLayout.java
@@ -18,6 +18,7 @@
 
 import android.annotation.AttrRes;
 import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
 import android.annotation.StyleRes;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
@@ -50,6 +51,7 @@
         super(context);
     }
 
+    @UnsupportedAppUsage
     public AlertDialogLayout(@Nullable Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
     }
diff --git a/core/java/com/android/internal/widget/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java
index ab8be33..0ca6743 100644
--- a/core/java/com/android/internal/widget/ButtonBarLayout.java
+++ b/core/java/com/android/internal/widget/ButtonBarLayout.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.widget;
 
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
@@ -40,6 +41,7 @@
 
     private int mMinimumHeight = 0;
 
+    @UnsupportedAppUsage
     public ButtonBarLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
 
diff --git a/core/java/com/android/internal/widget/DialogTitle.java b/core/java/com/android/internal/widget/DialogTitle.java
index 7ea3d6b..405436c 100644
--- a/core/java/com/android/internal/widget/DialogTitle.java
+++ b/core/java/com/android/internal/widget/DialogTitle.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.widget;
 
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.text.Layout;
@@ -37,6 +38,7 @@
         super(context, attrs, defStyleAttr);
     }
 
+    @UnsupportedAppUsage
     public DialogTitle(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 0a787b9..d68e8f8 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -331,13 +331,11 @@
         readPermissions(Environment.buildPath(
                 Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
 
-        // Allow Product to customize system configs around libs, features, permissions and apps
-        int productPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
-                ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS;
+        // Allow Product to customize all system configs
         readPermissions(Environment.buildPath(
-                Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag);
+                Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL);
         readPermissions(Environment.buildPath(
-                Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag);
+                Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL);
 
         // Allow /product_services to customize system configs around libs, features, permissions
         // and apps.
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 2635969..c32de0a 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -21,6 +21,10 @@
 #include <hwui/Bitmap.h>
 #include <renderthread/RenderProxy.h>
 
+#include <android_runtime/android_hardware_HardwareBuffer.h>
+
+#include <private/android/AHardwareBufferHelpers.h>
+
 #include "core_jni_helpers.h"
 
 #include <jni.h>
@@ -1104,8 +1108,7 @@
 
 static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) {
     sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
-    // Bitmap::createFrom currently can only attach to a GraphicBuffer with PIXEL_FORMAT_RGBA_8888
-    // format and SRGB color space.
+    // Bitmap::createFrom currently assumes SRGB color space for RGBA images.
     // To support any color space, we need to pass an additional ColorSpace argument to
     // java Bitmap.createHardwareBitmap.
     sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
@@ -1116,6 +1119,22 @@
     return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
 }
 
+static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject hardwareBuffer,
+                                               jfloatArray xyzD50, jobject transferParameters) {
+    SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
+    SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
+    sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
+    AHardwareBuffer* hwBuf = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env,
+        hardwareBuffer);
+    sp<GraphicBuffer> buffer(AHardwareBuffer_to_GraphicBuffer(hwBuf));
+    sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer, colorSpace);
+    if (!bitmap.get()) {
+        ALOGW("failed to create hardware bitmap from hardware buffer");
+        return NULL;
+    }
+    return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
+}
+
 static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
     LocalScopedBitmap bitmapHandle(bitmapPtr);
     LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
@@ -1195,6 +1214,8 @@
         (void*)Bitmap_copyPreserveInternalConfig },
     {   "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;",
         (void*) Bitmap_createHardwareBitmap },
+    {   "nativeWrapHardwareBufferBitmap", "(Landroid/hardware/HardwareBuffer;[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;",
+        (void*) Bitmap_wrapHardwareBufferBitmap },
     {   "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
         (void*) Bitmap_createGraphicBufferHandle },
     {   "nativeGetColorSpace",      "(J[F[F)Z", (void*)Bitmap_getColorSpace },
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index b70177f..2e1e130 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -339,6 +339,17 @@
     transaction->setMatrix(ctrl, dsdx, dtdx, dtdy, dsdy);
 }
 
+static void nativeSetColorTransform(JNIEnv* env, jclass clazz, jlong transactionObj,
+        jlong nativeObject, jfloatArray fMatrix, jfloatArray fTranslation) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+    SurfaceControl* const surfaceControl = reinterpret_cast<SurfaceControl*>(nativeObject);
+    float* floatMatrix = env->GetFloatArrayElements(fMatrix, 0);
+    mat3 matrix(static_cast<float const*>(floatMatrix));
+    float* floatTranslation = env->GetFloatArrayElements(fTranslation, 0);
+    vec3 translation(floatTranslation[0], floatTranslation[1], floatTranslation[2]);
+    transaction->setColorTransform(surfaceControl, matrix, translation);
+}
+
 static void nativeSetWindowCrop(JNIEnv* env, jclass clazz, jlong transactionObj,
         jlong nativeObject,
         jint l, jint t, jint r, jint b) {
@@ -849,6 +860,8 @@
             (void*)nativeSetColor },
     {"nativeSetMatrix", "(JJFFFF)V",
             (void*)nativeSetMatrix },
+    {"nativeSetColorTransform", "(JJ[F[F)V",
+            (void*)nativeSetColorTransform },
     {"nativeSetFlags", "(JJII)V",
             (void*)nativeSetFlags },
     {"nativeSetWindowCrop", "(JJIIII)V",
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index ed42e2e..30a9a01 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -7,6 +7,8 @@
 joeo@google.com
 kwekua@google.com
 singhtejinder@google.com
+yanglu@google.com
+yaochen@google.com
 
 # Frameworks
 ogunwale@google.com
diff --git a/core/proto/android/internal/powerprofile.proto b/core/proto/android/internal/powerprofile.proto
index 9dd5e7e..b0c8b56 100644
--- a/core/proto/android/internal/powerprofile.proto
+++ b/core/proto/android/internal/powerprofile.proto
@@ -35,7 +35,7 @@
         repeated double core_power = 5;
     }
 
-    repeated CpuCluster cpu_cluster = 41;
+    repeated CpuCluster cpu_cluster = 40;
 
     optional double wifi_scan = 4;
 
@@ -85,27 +85,27 @@
 
     optional double ambient_display = 27;
 
-    optional double screen_on = 29;
+    optional double screen_on = 28;
 
-    optional double radio_on = 30;
+    optional double radio_on = 29;
 
-    optional double radio_scanning = 31;
+    optional double radio_scanning = 30;
 
-    optional double radio_active = 32;
+    optional double radio_active = 31;
 
-    optional double screen_full = 33;
+    optional double screen_full = 32;
 
-    optional double audio = 34;
+    optional double audio = 33;
 
-    optional double video = 35;
+    optional double video = 34;
 
-    optional double flashlight = 36;
+    optional double flashlight = 35;
 
-    optional double memory = 37;
+    optional double memory = 36;
 
-    optional double camera = 38;
+    optional double camera = 37;
 
-    optional double wifi_batched_scan = 39;
+    optional double wifi_batched_scan = 38;
 
-    optional double battery_capacity = 40;
+    optional double battery_capacity = 39;
 }
diff --git a/proto/src/stats_enums.proto b/core/proto/android/stats/enums.proto
similarity index 91%
rename from proto/src/stats_enums.proto
rename to core/proto/android/stats/enums.proto
index 6c892cf..2320a01 100644
--- a/proto/src/stats_enums.proto
+++ b/core/proto/android/stats/enums.proto
@@ -16,8 +16,7 @@
 
 syntax = "proto2";
 
-package android.os.statsd;
-option java_package = "com.android.os";
+package android.stats;
 option java_outer_classname = "StatsEnums";
 
 enum EventType {
diff --git a/core/proto/android/telephony/enums.proto b/core/proto/android/telephony/enums.proto
index 32975a5..fba2e51 100644
--- a/core/proto/android/telephony/enums.proto
+++ b/core/proto/android/telephony/enums.proto
@@ -61,3 +61,64 @@
     SIGNAL_STRENGTH_GOOD = 3;
     SIGNAL_STRENGTH_GREAT = 4;
 }
+
+
+enum ServiceStateEnum {
+    /**
+     * Normal operation condition, the phone is registered
+     * with an operator either in home network or in roaming.
+     */
+    SERVICE_STATE_IN_SERVICE = 0;
+
+    /**
+     * Phone is not registered with any operator, the phone
+     * can be currently searching a new operator to register to, or not
+     * searching to registration at all, or registration is denied, or radio
+     * signal is not available.
+     */
+    SERVICE_STATE_OUT_OF_SERVICE = 1;
+
+    /**
+     * The phone is registered and locked.  Only emergency numbers are allowed. {@more}
+     */
+    SERVICE_STATE_EMERGENCY_ONLY = 2;
+
+    /**
+     * Radio of telephony is explicitly powered off.
+     */
+    SERVICE_STATE_POWER_OFF = 3;
+}
+
+enum SimStateEnum {
+    SIM_STATE_UNKNOWN = 0;
+    /** SIM card state: no SIM card is available in the device */
+    SIM_STATE_ABSENT = 1;
+    /** SIM card state: Locked: requires the user's SIM PIN to unlock */
+    SIM_STATE_PIN_REQUIRED = 2;
+    /** SIM card state: Locked: requires the user's SIM PUK to unlock */
+    SIM_STATE_PUK_REQUIRED = 3;
+    /** SIM card state: Locked: requires a network PIN to unlock */
+    SIM_STATE_NETWORK_LOCKED = 4;
+    /** SIM card state: Ready */
+    SIM_STATE_READY = 5;
+    /** SIM card state: SIM Card is NOT READY */
+    SIM_STATE_NOT_READY = 6;
+    /** SIM card state: SIM Card Error, permanently disabled */
+    SIM_STATE_PERM_DISABLED = 7;
+    /** SIM card state: SIM Card Error, present but faulty */
+    SIM_STATE_CARD_IO_ERROR = 8;
+    /** SIM card state: SIM Card restricted, present but not usable due to
+     * carrier restrictions.
+     */
+    SIM_STATE_CARD_RESTRICTED = 9;
+    /**
+     * SIM card state: Loaded: SIM card applications have been loaded
+     * @hide
+     */
+    SIM_STATE_LOADED = 10;
+    /**
+     * SIM card state: SIM Card is present
+     * @hide
+     */
+    SIM_STATE_PRESENT = 11;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f3f012d..401ffa3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -138,7 +138,6 @@
     <protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" />
     <protected-broadcast android:name="android.bluetooth.device.action.ALIAS_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
-    <protected-broadcast android:name="android.bluetooth.device.action.DISAPPEARED" />
     <protected-broadcast android:name="android.bluetooth.device.action.CLASS_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.device.action.ACL_CONNECTED" />
     <protected-broadcast android:name="android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED" />
@@ -1546,6 +1545,7 @@
 
     <!-- Allows SetupWizard to call methods in Networking services
          <p>Not for use by any other third-party or privileged applications.
+         @SystemApi
          @hide This should only be used by SetupWizard.
     -->
     <permission android:name="android.permission.NETWORK_SETUP_WIZARD"
diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml
index c8d4d05..931674a 100644
--- a/core/res/res/values-night/themes_device_defaults.xml
+++ b/core/res/res/values-night/themes_device_defaults.xml
@@ -50,7 +50,9 @@
          {@code TextAppearance.DeviceDefault.Widget.PopupMenu.Large}).</p>
           -->
     <!-- DeviceDefault theme for a window that should look like the Settings app.  -->
-    <style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault"/>
+    <style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault">
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
+    </style>
 
     <!-- Theme for the dialog shown when an app crashes or ANRs. -->
     <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 8b73b67..aeeba59 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2113,8 +2113,8 @@
     <!-- Type of the long press sensor. Empty if long press is not supported. -->
     <string name="config_dozeLongPressSensorType" translatable="false"></string>
 
-    <!-- Type of sensor that wakes up the lock screen. Empty if not supported. -->
-    <string name="config_dozeWakeLockScreenSensorType" translatable="false"></string>
+    <!-- If the sensor that wakes up the lock screen is available or not. -->
+    <bool name="config_dozeWakeLockScreenSensorAvailable">false</bool>
 
     <!-- Type of the wake up sensor. Empty if not supported. -->
     <string name="config_dozeWakeScreenSensorType" translatable="false"></string>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 1e3aeae..6bf893d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1418,6 +1418,9 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_mediaLocation">Allows the app to read locations from your media collection.</string>
 
+    <!-- Title shown when the system-provided biometric dialog is shown, asking the user to authenticate. [CHAR LIMIT=40] -->
+    <string name="biometric_dialog_default_title">Application <xliff:g id="app" example="Gmail">%s</xliff:g> wants to authenticate.</string>
+
     <!-- Message shown when biometric hardware is not available [CHAR LIMIT=50] -->
     <string name="biometric_error_hw_unavailable">Biometric hardware unavailable</string>
 
@@ -5005,33 +5008,33 @@
 
     <!-- Title for the autofill save dialog shown when the the contents of the activity can be saved
          by an autofill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
-    <string name="autofill_save_title">Save to &lt;b><xliff:g id="label" example="MyPass">%1$s</xliff:g>&lt;/b>?</string>
+    <string name="autofill_save_title">Save to <b><xliff:g id="label" example="MyPass">%1$s</xliff:g></b>?</string>
     <!-- Title for the autofill save dialog shown when the the contents of the activity can be saved
-         by an autofill service, and the service does knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
-    <string name="autofill_save_title_with_type">Save <xliff:g id="type" example="Credit Card">%1$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%2$s</xliff:g>&lt;/b>?</string>
+         by an autofill service, and the service knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
+    <string name="autofill_save_title_with_type">Save <xliff:g id="type" example="Credit Card">%1$s</xliff:g> to <b><xliff:g id="label" example="MyPass">%2$s</xliff:g></b>?</string>
     <!-- Title for the autofill save dialog shown when the the contents of the activity can be saved
-         by an autofill service, and the service does knows what the activity represents, and it represents 2 types of
+         by an autofill service, and the service knows what the activity represents, and it represents 2 types of
          data (for example, password and credit card info) [CHAR LIMIT=NONE] -->
-    <string name="autofill_save_title_with_2types">Save <xliff:g id="type" example="Password">%1$s</xliff:g> and <xliff:g id="type" example="Credit Card">%2$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%3$s</xliff:g>&lt;/b>?</string>
+    <string name="autofill_save_title_with_2types">Save <xliff:g id="type" example="Password">%1$s</xliff:g> and <xliff:g id="type" example="Credit Card">%2$s</xliff:g> to <b><xliff:g id="label" example="MyPass">%3$s</xliff:g></b>?</string>
     <!-- Title for the autofill save dialog shown when the the contents of the activity can be saved
-         by an autofill service, and the service does knows what the activity represents, and it represents 3 types of
+         by an autofill service, and the service knows what the activity represents, and it represents 3 types of
          data (for example, username, password and credit card info) [CHAR LIMIT=NONE] -->
-    <string name="autofill_save_title_with_3types">Save <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%4$s</xliff:g>&lt;/b>?</string>
+    <string name="autofill_save_title_with_3types">Save <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g> to <b><xliff:g id="label" example="MyPass">%4$s</xliff:g></b>?</string>
 
     <!-- Title for the autofill update dialog shown when the the contents of the activity can be updated
-         by an autofill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
-    <string name="autofill_update_title">Update to &lt;b><xliff:g id="label" example="MyPass">%1$s</xliff:g>&lt;/b>?</string>
+         in an autofill service, but the service does not know what the activity represents [CHAR LIMIT=NONE] -->
+    <string name="autofill_update_title">Update in <b><xliff:g id="label" example="MyPass">%1$s</xliff:g></b>?</string>
     <!-- Title for the autofill update dialog shown when the the contents of the activity can be updated
-         by an autofill service, and the service does knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
-    <string name="autofill_update_title_with_type">Update <xliff:g id="type" example="Credit Card">%1$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%2$s</xliff:g>&lt;/b>?</string>
+         in an autofill service, and the service knows what the activity represents (for example, credit card info) [CHAR LIMIT=NONE] -->
+    <string name="autofill_update_title_with_type">Update <xliff:g id="type" example="Credit Card">%1$s</xliff:g> in <b><xliff:g id="label" example="MyPass">%2$s</xliff:g></b>?</string>
     <!-- Title for the autofill update dialog shown when the the contents of the activity can be updated
-         by an autofill service, and the service does knows what the activity represents, and it represents 2 types of
+         in an autofill service, and the service knows what the activity represents, and it represents 2 types of
          data (for example, password and credit card info) [CHAR LIMIT=NONE] -->
-    <string name="autofill_update_title_with_2types">Update <xliff:g id="type" example="Password">%1$s</xliff:g> and <xliff:g id="type" example="Credit Card">%2$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%3$s</xliff:g>&lt;/b>?</string>
+    <string name="autofill_update_title_with_2types">Update <xliff:g id="type" example="Password">%1$s</xliff:g> and <xliff:g id="type" example="Credit Card">%2$s</xliff:g> in <b><xliff:g id="label" example="MyPass">%3$s</xliff:g></b>?</string>
     <!-- Title for the autofill update dialog shown when the the contents of the activity can be updated
-         by an autofill service, and the service does knows what the activity represents, and it represents 3 types of
+         in an autofill service, and the service knows what the activity represents, and it represents 3 types of
          data (for example, username, password and credit card info) [CHAR LIMIT=NONE] -->
-    <string name="autofill_update_title_with_3types">Update <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g> to &lt;b><xliff:g id="label" example="MyPass">%4$s</xliff:g>&lt;/b>?</string>
+    <string name="autofill_update_title_with_3types">Update these items in <b><xliff:g id="label" example="MyPass">%4$s</xliff:g></b>: <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g> ?</string>
 
 
     <!-- Label for the autofill save button [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a7b6dde..6f28b2c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2394,6 +2394,7 @@
   <java-symbol type="string" name="config_keyguardComponent" />
 
   <!-- Biometric messages -->
+  <java-symbol type="string" name="biometric_dialog_default_title" />
   <java-symbol type="string" name="biometric_error_hw_unavailable" />
   <java-symbol type="string" name="biometric_not_recognized" />
 
@@ -3279,7 +3280,7 @@
   <java-symbol type="array" name="config_hideWhenDisabled_packageNames" />
 
   <java-symbol type="string" name="config_dozeLongPressSensorType" />
-  <java-symbol type="string" name="config_dozeWakeLockScreenSensorType" />
+  <java-symbol type="bool" name="config_dozeWakeLockScreenSensorAvailable" />
 
   <java-symbol type="array" name="config_allowedGlobalInstantAppSettings" />
   <java-symbol type="array" name="config_allowedSystemInstantAppSettings" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index fb78b3b..7b3d940 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -109,12 +109,12 @@
     <!-- France: 5 digits, free: 3xxxx, premium [4-8]xxxx, plus EU:
          http://clients.txtnation.com/entries/161972-france-premium-sms-short-code-requirements,
          visual voicemail code for Orange: 21101 -->
-    <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}|21101|20366" />
+    <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}|21101|20366|555|2051" />
 
     <!-- United Kingdom (Great Britain): 4-6 digits, common codes [5-8]xxxx, plus EU:
          http://www.short-codes.com/media/Co-regulatoryCodeofPracticeforcommonshortcodes170206.pdf,
          visual voicemail code for EE: 887 -->
-    <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|2020|35890|61002|61202|887|83669|34664|40406|60174|7726|37726" />
+    <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|2020|35890|61002|61202|887|83669|34664|40406|60174|7726|37726|88555|9017|9018" />
 
     <!-- Georgia: 4 digits, known premium codes listed -->
     <shortcode country="ge" pattern="\\d{4}" premium="801[234]|888[239]" />
@@ -189,11 +189,14 @@
     <!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
     <shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223" />
 
+    <!-- Nigeria -->
+    <shortcode country="ng" pattern="\\d{1,5}" free="2441" />
+
     <!-- Norway: 4-5 digits (not confirmed), known premium codes listed -->
     <shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" free="2171" />
 
     <!-- New Zealand: 3-4 digits, known premium codes listed -->
-    <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="3067|3068|4053" />
+    <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="1737|2141|3067|3068|3110|4006|4053|4061|4062|4202|4300|4334|4412|4575|5626|8006|8681" />
 
     <!-- Peru: 4-5 digits (not confirmed), known premium codes listed -->
     <shortcode country="pe" pattern="\\d{4,5}" free="9963" />
@@ -209,7 +212,7 @@
 
     <!-- Portugal: 5 digits, plus EU:
          http://clients.txtnation.com/entries/158326-portugal-premium-sms-short-code-regulations -->
-    <shortcode country="pt" premium="6[1289]\\d{3}" free="116\\d{3}|1262" />
+    <shortcode country="pt" premium="6[1289]\\d{3}" free="116\\d{3}|1262|12666" />
 
     <!-- Qatar: 1-5 digits (standard system default, not country specific) -->
     <shortcode country="qa" pattern="\\d{1,5}" free="92451" />
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
index 4a58f88..2989df8 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
@@ -16,6 +16,7 @@
 
 package com.android.bandwidthtest;
 
+import android.app.UiAutomation;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo.State;
@@ -74,7 +75,13 @@
         Log.v(LOG_TAG, "Initialized mConnectionUtil");
         mUid = Process.myUid();
         mTManager = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        mDeviceId = mTManager.getDeviceId();
+        final UiAutomation uiAutomation = getInstrumentation().getUiAutomation();
+        try {
+            uiAutomation.adoptShellPermissionIdentity();
+            mDeviceId = mTManager.getDeviceId();
+        } finally {
+            uiAutomation.dropShellPermissionIdentity();
+        }
     }
 
     @Override
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index e0d5393..307e2e8 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -67,10 +67,6 @@
 
 # Disable AAPT2 because the hacks below depend on the AAPT rules implementation
 LOCAL_USE_AAPT2 := false
-# When AAPT2 is enabled it will need --warn-manifest-validation to fix:
-# frameworks/base/core/tests/coretests/AndroidManifest.xml:26: error: unknown element <meta-data> found.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-# LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_PACKAGE)
 # Rules to copy all the test apks to the intermediate raw resource directory
diff --git a/core/tests/coretests/apks/install_multi_package/Android.mk b/core/tests/coretests/apks/install_multi_package/Android.mk
index 9727593..3f163de 100644
--- a/core/tests/coretests/apks/install_multi_package/Android.mk
+++ b/core/tests/coretests/apks/install_multi_package/Android.mk
@@ -8,10 +8,6 @@
 LOCAL_PACKAGE_NAME := install_multi_package
 
 LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml:46: error: unexpected element <package> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(FrameworkCoreTests_BUILD_PACKAGE)
 #include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_verifier_bad/Android.mk b/core/tests/coretests/apks/install_verifier_bad/Android.mk
index 679327c..745b4d3 100644
--- a/core/tests/coretests/apks/install_verifier_bad/Android.mk
+++ b/core/tests/coretests/apks/install_verifier_bad/Android.mk
@@ -6,9 +6,5 @@
 LOCAL_PACKAGE_NAME := install_verifier_bad
 
 LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/core/tests/coretests/apks/install_verifier_bad/AndroidManifest.xml:19: error: unexpected element <package-verifier> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_verifier_good/Android.mk b/core/tests/coretests/apks/install_verifier_good/Android.mk
index 7d621b3..150fd8d 100644
--- a/core/tests/coretests/apks/install_verifier_good/Android.mk
+++ b/core/tests/coretests/apks/install_verifier_good/Android.mk
@@ -6,9 +6,5 @@
 LOCAL_PACKAGE_NAME := install_verifier_good
 
 LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/core/tests/coretests/apks/install_verifier_good/AndroidManifest.xml:19: error: unexpected element <package-verifier> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
index bdb3e08..fe51a39 100644
--- a/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
+++ b/core/tests/coretests/src/android/app/assist/AssistStructureTest.java
@@ -15,7 +15,9 @@
  */
 package android.app.assist;
 
+import static android.view.View.AUTOFILL_TYPE_TEXT;
 import static android.view.View.IMPORTANT_FOR_AUTOFILL_AUTO;
+import static android.view.View.IMPORTANT_FOR_AUTOFILL_YES;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -27,7 +29,9 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
+import android.text.InputFilter;
 import android.util.Log;
+import android.view.autofill.AutofillId;
 import android.widget.EditText;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
@@ -68,6 +72,16 @@
     // Cannot be much big because it could hang test due to blocking GC
     private static final int NUMBER_SMALL_VIEWS = 10_000;
 
+    // Autofill field constants
+    private static final AutofillId AUTOFILL_ID = new AutofillId(2);
+    private static final String AUTOFILL_HINTS = "hints";
+    private static final int MIN_TEXT_EMS = 5;
+    private static final int MAX_TEXT_EMS = 17;
+    private static final int MAX_TEXT_LENGTH = 23;
+
+    // ViewNodeBuilder structure for editing autofill fields
+    private AssistStructure.ViewNodeBuilder mBuilder;
+
     private EmptyLayoutActivity mActivity;
 
     private final ActivityTestRule<EmptyLayoutActivity> mActivityTestRule =
@@ -211,6 +225,12 @@
     private EditText newSmallView() {
         EditText view = new EditText(mContext);
         view.setText("I AM GROOT");
+        view.setMinEms(MIN_TEXT_EMS);
+        view.setMaxEms(MAX_TEXT_EMS);
+        view.setAutofillId(AUTOFILL_ID);
+        view.setAutofillHints(AUTOFILL_HINTS);
+        view.setFilters(new InputFilter[] { new InputFilter.LengthFilter(MAX_TEXT_LENGTH) });
+        view.setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_YES);
         return view;
     }
 
@@ -220,6 +240,16 @@
         assertThat(view.getIdEntry()).isNull();
         assertThat(view.getAutofillId()).isNotNull();
         assertThat(view.getText().toString()).isEqualTo("I AM GROOT");
+
+        assertThat(view.getAutofillType()).isEqualTo(AUTOFILL_TYPE_TEXT);
+
+        // fields controlled by mAutofillFlag
+        assertThat(view.getAutofillId().getViewId()).isEqualTo(2);
+        assertThat(view.getAutofillHints()[0]).isEqualTo(AUTOFILL_HINTS);
+        assertThat(view.getMinTextEms()).isEqualTo(MIN_TEXT_EMS);
+        assertThat(view.getMaxTextEms()).isEqualTo(MAX_TEXT_EMS);
+        assertThat(view.getMaxTextLength()).isEqualTo(MAX_TEXT_LENGTH);
+        assertThat(view.getImportantForAutofill()).isEqualTo(IMPORTANT_FOR_AUTOFILL_YES);
     }
 
     private EditText newBigView() {
diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
index 584257b..e248a77 100644
--- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
@@ -45,7 +45,7 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
-import libcore.io.IoUtils;
+import libcore.testing.io.TestIoUtils;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -63,7 +63,7 @@
 
     @Before
     public void setUp() {
-        mTmpDir = IoUtils.createTemporaryDirectory("DexMetadataHelperTest");
+        mTmpDir = TestIoUtils.createTemporaryDirectory("DexMetadataHelperTest");
     }
 
     @After
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 20fe162..80281b6 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -48,7 +48,6 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 
-import libcore.io.IoUtils;
 import libcore.io.Streams;
 
 import com.google.android.collect.Sets;
@@ -95,7 +94,7 @@
 
     @After
     public void tearDown() throws Exception {
-        IoUtils.deleteContents(mDir);
+        FileUtils.deleteContents(mDir);
         FileUtils.deleteContents(mTarget);
     }
 
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 014ae1f..60abd94 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -543,6 +543,7 @@
                  Settings.Secure.BACKUP_ENABLED,
                  Settings.Secure.BACKUP_PROVISIONED,
                  Settings.Secure.BACKUP_TRANSPORT,
+                 Settings.Secure.CALL_REDIRECTION_DEFAULT_APPLICATION,
                  Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED, // Candidate for backup?
                  Settings.Secure.CARRIER_APPS_HANDLED,
                  Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG,
diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
index f8e3b4d..872b71a 100644
--- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java
+++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
@@ -117,7 +117,7 @@
     @Test
     public void testFormatSameDayTime() {
         // This test assumes a default DateFormat.is24Hour setting.
-        DateFormat.is24Hour = null;
+        DateFormat.set24HourTimePref(null);
         Date date = new Date(109, 0, 19, 3, 30, 15);
         long fixedTime = date.getTime();
 
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index c8d994c..8e4f2cd 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -103,6 +103,18 @@
                 equalTo(new Rect[]{ZERO_RECT, boundTop, ZERO_RECT, boundBottom}));
     }
 
+    @Test
+    public void testExtractBoundsFromList_nullBoundingRects() {
+        Rect safeInsets = new Rect(0, 0, 0, 0);
+        assertThat(extractBoundsFromList(safeInsets, null /* boundingRects */),
+                equalTo(new Rect[]{ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT}));
+    }
+
+    @Test
+    public void testExtractBoundsFromList_nullSafeInsets() {
+        assertThat(extractBoundsFromList(null /* safeInsets */, Collections.emptyList()),
+                equalTo(new Rect[]{ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT}));
+    }
 
     @Test
     public void hasCutout() throws Exception {
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 69d2828..506e544 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -45,7 +45,7 @@
     // The number of fields tested in the corresponding CTS AccessibilityNodeInfoTest:
     // See fullyPopulateAccessibilityNodeInfo, assertEqualsAccessibilityNodeInfo,
     // and assertAccessibilityNodeInfoCleared in that class.
-    private static final int NUM_MARSHALLED_PROPERTIES = 33;
+    private static final int NUM_MARSHALLED_PROPERTIES = 34;
 
     /**
      * The number of properties that are purposely not marshalled
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 0c8dd9d..f637b7c 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -77,9 +77,13 @@
 
         Message message = mHandlerFirst.obtainMessage(1000);
         message.workSourceUid = 1000;
+        message.when = looperStats.getSystemUptimeMillis();
+
+        looperStats.tickUptime(30);
         Object token = looperStats.messageDispatchStarting();
         looperStats.tickRealtime(100);
         looperStats.tickThreadTime(10);
+        looperStats.tickUptime(200);
         looperStats.messageDispatched(token, message);
 
         List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
@@ -98,6 +102,10 @@
         assertThat(entry.maxLatencyMicros).isEqualTo(100);
         assertThat(entry.cpuUsageMicros).isEqualTo(10);
         assertThat(entry.maxCpuUsageMicros).isEqualTo(10);
+        assertThat(entry.recordedDelayMessageCount).isEqualTo(1);
+        assertThat(entry.delayMillis).isEqualTo(30);
+        assertThat(entry.maxDelayMillis).isEqualTo(30);
+
     }
 
     @Test
@@ -215,6 +223,56 @@
     }
 
     @Test
+    public void testDispatchDelayIsRecorded() {
+        TestableLooperStats looperStats = new TestableLooperStats(1, 100);
+
+        // Dispatched right on time.
+        Message message1 = mHandlerFirst.obtainMessage(1000);
+        message1.when = looperStats.getSystemUptimeMillis();
+        Object token1 = looperStats.messageDispatchStarting();
+        looperStats.tickUptime(10);
+        looperStats.messageDispatched(token1, message1);
+
+        // Dispatched 100ms late.
+        Message message2 = mHandlerFirst.obtainMessage(1000);
+        message2.when = looperStats.getSystemUptimeMillis() - 100;
+        Object token2 = looperStats.messageDispatchStarting();
+        looperStats.tickUptime(10);
+        looperStats.messageDispatched(token2, message2);
+
+        // No target dispatching time.
+        Message message3 = mHandlerFirst.obtainMessage(1000);
+        message3.when = 0;
+        Object token3 = looperStats.messageDispatchStarting();
+        looperStats.tickUptime(10);
+        looperStats.messageDispatched(token3, message3);
+
+        // Dispatched too soon (should never happen).
+        Message message4 = mHandlerFirst.obtainMessage(1000);
+        message4.when = looperStats.getSystemUptimeMillis() + 200;
+        Object token4 = looperStats.messageDispatchStarting();
+        looperStats.tickUptime(10);
+        looperStats.messageDispatched(token4, message4);
+
+        // Dispatched 300ms late.
+        Message message5 = mHandlerFirst.obtainMessage(1000);
+        message5.when = looperStats.getSystemUptimeMillis() - 300;
+        Object token5 = looperStats.messageDispatchStarting();
+        looperStats.tickUptime(10);
+        looperStats.messageDispatched(token5, message5);
+
+        List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
+        assertThat(entries).hasSize(1);
+
+        LooperStats.ExportedEntry entry = entries.get(0);
+        assertThat(entry.messageCount).isEqualTo(5);
+        assertThat(entry.recordedMessageCount).isEqualTo(5);
+        assertThat(entry.recordedDelayMessageCount).isEqualTo(4);
+        assertThat(entry.delayMillis).isEqualTo(400);
+        assertThat(entry.maxDelayMillis).isEqualTo(300);
+    }
+
+    @Test
     public void testDataNotCollectedBeforeDeviceStateSet() {
         TestableLooperStats looperStats = new TestableLooperStats(1, 100);
         looperStats.setDeviceState(null);
@@ -385,6 +443,7 @@
         private int mCount;
         private long mRealtimeMicros;
         private long mThreadTimeMicros;
+        private long mUptimeMillis;
         private int mSamplingInterval;
 
         TestableLooperStats(int samplingInterval, int sizeCap) {
@@ -401,6 +460,10 @@
             mThreadTimeMicros += micros;
         }
 
+        void tickUptime(long millis) {
+            mUptimeMillis += millis;
+        }
+
         @Override
         protected long getElapsedRealtimeMicro() {
             return INITIAL_MICROS + mRealtimeMicros;
@@ -412,6 +475,11 @@
         }
 
         @Override
+        protected long getSystemUptimeMillis() {
+            return INITIAL_MICROS / 1000 + mUptimeMillis;
+        }
+
+        @Override
         protected boolean shouldCollectDetailedData() {
             return mCount++ % mSamplingInterval == 0;
         }
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
index edad4b2..97a3d00 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
@@ -20,4 +20,6 @@
 LOCAL_SDK_VERSION := current
 LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_CERTIFICATE := platform
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_FLAGS := --no-resource-removal
 include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
index 3fae8e1..a347025 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
@@ -20,4 +20,6 @@
 LOCAL_SDK_VERSION := current
 LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_CERTIFICATE := platform
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_FLAGS := --no-resource-removal
 include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
index c352c05..e4819e1 100644
--- a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk
@@ -20,4 +20,6 @@
 LOCAL_SDK_VERSION := current
 LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_CERTIFICATE := platform
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_FLAGS := --no-resource-removal
 include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
index ab3faf0..8656781 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
@@ -21,6 +21,8 @@
 LOCAL_SDK_VERSION := current
 LOCAL_COMPATIBILITY_SUITE := general-tests
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_USE_AAPT2 := true
+LOCAL_AAPT_FLAGS := --no-resource-removal
 include $(BUILD_PACKAGE)
 
 my_package_prefix := com.android.server.om.hosttest.framework_overlay
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 114c228..44f8737 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -139,6 +139,7 @@
         <permission name="android.permission.USE_RESERVED_DISK"/>
         <permission name="android.permission.MANAGE_USERS"/>
         <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+        <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.permissioncontroller">
@@ -322,7 +323,9 @@
         <permission name="android.permission.PACKAGE_USAGE_STATS" />
         <permission name="android.permission.READ_FRAME_BUFFER"/>
         <permission name="android.permission.READ_LOWPAN_CREDENTIAL"/>
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.REAL_GET_TASKS"/>
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.REGISTER_CALL_PROVIDER"/>
         <permission name="android.permission.REGISTER_CONNECTION_MANAGER"/>
         <permission name="android.permission.REGISTER_SIM_SUBSCRIPTION"/>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 9cbbf4e..1cd756f 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -24,6 +24,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.annotation.WorkerThread;
 import android.content.res.ResourcesImpl;
+import android.hardware.HardwareBuffer;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.StrictMode;
@@ -724,6 +725,48 @@
     }
 
     /**
+     * Create a hardware bitmap backed by a {@link HardwareBuffer}.
+     *
+     * <p>The passed HardwareBuffer's usage flags must contain
+     * {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE}.
+     *
+     * <p>The bitmap will keep a reference to the buffer so that callers can safely close the
+     * HardwareBuffer without affecting the Bitmap. However the HardwareBuffer must not be
+     * modified while a wrapped Bitmap is accessing it. Doing so will result in undefined behavior.
+     *
+     * @param hardwareBuffer The HardwareBuffer to wrap.
+     * @param colorSpace The color space of the bitmap. Must be a {@link ColorSpace.Rgb} colorspace.
+     *                   If null, SRGB is assumed.
+     * @return A bitmap wrapping the buffer, or null if there was a problem creating the bitmap.
+     * @throws IllegalArgumentException if the HardwareBuffer has an invalid usage, or an invalid
+     *                                  colorspace is given.
+     */
+    @Nullable
+    public static Bitmap wrapHardwareBuffer(@NonNull HardwareBuffer hardwareBuffer,
+            @Nullable ColorSpace colorSpace) {
+        if ((hardwareBuffer.getUsage() & HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) == 0) {
+            throw new IllegalArgumentException("usage flags must contain USAGE_GPU_SAMPLED_IMAGE.");
+        }
+        int format = hardwareBuffer.getFormat();
+        ColorSpace.Rgb rgb = null;
+        if (colorSpace != null) {
+            if (!(colorSpace instanceof ColorSpace.Rgb)) {
+                throw new IllegalArgumentException("colorSpace must be an RGB color space");
+            }
+            rgb = (ColorSpace.Rgb) colorSpace;
+        } else {
+            rgb = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+        }
+        ColorSpace.Rgb.TransferParameters parameters = rgb.getTransferParameters();
+        if (parameters == null) {
+            throw new IllegalArgumentException("colorSpace must use an ICC "
+                    + "parametric transfer function");
+        }
+        ColorSpace.Rgb d50 = (ColorSpace.Rgb) ColorSpace.adapt(rgb, ColorSpace.ILLUMINANT_D50);
+        return nativeWrapHardwareBufferBitmap(hardwareBuffer, d50.getTransform(), parameters);
+    }
+
+    /**
      * Creates a new bitmap, scaled from an existing bitmap, when possible. If the
      * specified width and height are the same as the current width and height of
      * the source bitmap, the source bitmap is returned and no new bitmap is
@@ -2118,6 +2161,9 @@
     private static native int nativeGetAllocationByteCount(long nativeBitmap);
     private static native Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap);
     private static native Bitmap nativeCreateHardwareBitmap(GraphicBuffer buffer);
+    private static native Bitmap nativeWrapHardwareBufferBitmap(HardwareBuffer buffer,
+                                                              @Size(9) float[] xyzD50,
+                                                              ColorSpace.Rgb.TransferParameters p);
     private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap);
     private static native boolean nativeGetColorSpace(long nativePtr, float[] xyz, float[] params);
     private static native boolean nativeIsSRGB(long nativePtr);
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 8414d6a..b65fb9c 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -2525,9 +2525,7 @@
                     gamma == 1.0 ? DoubleUnaryOperator.identity() :
                             x -> Math.pow(x < 0.0 ? 0.0 : x, gamma),
                     min, max, id);
-            mTransferParameters = gamma == 1.0 ?
-                    new TransferParameters(0.0, 0.0, 1.0, 1.0 + Math.ulp(1.0f), gamma) :
-                    new TransferParameters(1.0, 0.0, 0.0, 0.0, gamma);
+            mTransferParameters = new TransferParameters(1.0, 0.0, 0.0, 0.0, gamma);
         }
 
         /**
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 7efe522..f41cc7e 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -21,7 +21,6 @@
 import android.annotation.IdRes;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -570,7 +569,7 @@
      * Version of createWithResource that takes Resources. Do not use.
      * @hide
      */
-    @SystemApi
+    @UnsupportedAppUsage
     public static Icon createWithResource(Resources res, @DrawableRes int resId) {
         if (res == null) {
             throw new IllegalArgumentException("Resource must not be null.");
diff --git a/keystore/OWNERS b/keystore/OWNERS
new file mode 100644
index 0000000..a63ca46
--- /dev/null
+++ b/keystore/OWNERS
@@ -0,0 +1,4 @@
+jbires@google.com
+jdanis@google.com
+robbarnes@google.com
+swillden@google.com
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 74cab92..98af3eb 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -50,6 +50,7 @@
         "LocaleData.cpp",
         "misc.cpp",
         "ObbFile.cpp",
+        "PosixUtils.cpp",
         "ResourceTypes.cpp",
         "ResourceUtils.cpp",
         "StreamingZipInflater.cpp",
@@ -157,6 +158,7 @@
             srcs: [
                 "tests/BackupData_test.cpp",
                 "tests/ObbFile_test.cpp",
+                "tests/PosixUtils_test.cpp",
             ],
             shared_libs: common_test_libs + ["libui"],
         },
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 9c1629b..04cc5bb 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -67,10 +67,10 @@
 }
 
 bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
-                                 bool invalidate_caches) {
+                                 bool invalidate_caches, bool filter_incompatible_configs) {
   apk_assets_ = apk_assets;
   BuildDynamicRefTable();
-  RebuildFilterList();
+  RebuildFilterList(filter_incompatible_configs);
   if (invalidate_caches) {
     InvalidateCaches(static_cast<uint32_t>(-1));
   }
@@ -825,7 +825,7 @@
   return 0u;
 }
 
-void AssetManager2::RebuildFilterList() {
+void AssetManager2::RebuildFilterList(bool filter_incompatible_configs) {
   for (PackageGroup& group : package_groups_) {
     for (ConfiguredPackage& impl : group.packages_) {
       // Destroy it.
@@ -841,7 +841,7 @@
         for (auto iter = spec->types; iter != iter_end; ++iter) {
           ResTable_config this_config;
           this_config.copyFromDtoH((*iter)->config);
-          if (this_config.match(configuration_)) {
+          if (!filter_incompatible_configs || this_config.match(configuration_)) {
             group.configurations.push_back(this_config);
             group.types.push_back(*iter);
           }
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index c2740c9..68d216d 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -203,6 +203,39 @@
   return true;
 }
 
+LoadedPackage::iterator::iterator(const LoadedPackage* lp, size_t ti, size_t ei)
+    : loadedPackage_(lp),
+      typeIndex_(ti),
+      entryIndex_(ei),
+      typeIndexEnd_(lp->resource_ids_.size() + 1) {
+  while (typeIndex_ < typeIndexEnd_ && loadedPackage_->resource_ids_[typeIndex_] == 0) {
+    typeIndex_++;
+  }
+}
+
+LoadedPackage::iterator& LoadedPackage::iterator::operator++() {
+  while (typeIndex_ < typeIndexEnd_) {
+    if (entryIndex_ + 1 < loadedPackage_->resource_ids_[typeIndex_]) {
+      entryIndex_++;
+      break;
+    }
+    entryIndex_ = 0;
+    typeIndex_++;
+    if (typeIndex_ < typeIndexEnd_ && loadedPackage_->resource_ids_[typeIndex_] != 0) {
+      break;
+    }
+  }
+  return *this;
+}
+
+uint32_t LoadedPackage::iterator::operator*() const {
+  if (typeIndex_ >= typeIndexEnd_) {
+    return 0;
+  }
+  return make_resid(loadedPackage_->package_id_, typeIndex_ + loadedPackage_->type_id_offset_,
+          entryIndex_);
+}
+
 const ResTable_entry* LoadedPackage::GetEntry(const ResTable_type* type_chunk,
                                               uint16_t entry_index) {
   uint32_t entry_offset = GetEntryOffset(type_chunk, entry_index);
@@ -488,6 +521,7 @@
         std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type_spec->id - 1];
         if (builder_ptr == nullptr) {
           builder_ptr = util::make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
+          loaded_package->resource_ids_.set(type_spec->id, entry_count);
         } else {
           LOG(WARNING) << StringPrintf("RES_TABLE_TYPE_SPEC_TYPE already defined for ID %02x",
                                        type_spec->id);
diff --git a/libs/androidfw/PosixUtils.cpp b/libs/androidfw/PosixUtils.cpp
new file mode 100644
index 0000000..df0dd7c
--- /dev/null
+++ b/libs/androidfw/PosixUtils.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#ifdef _WIN32
+// nothing to see here
+#else
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "android-base/logging.h"
+
+#include "androidfw/PosixUtils.h"
+
+namespace {
+
+std::unique_ptr<std::string> ReadFile(int fd) {
+  std::unique_ptr<std::string> str(new std::string());
+  char buf[1024];
+  ssize_t r;
+  while ((r = read(fd, buf, sizeof(buf))) > 0) {
+    str->append(buf, r);
+  }
+  if (r != 0) {
+    return nullptr;
+  }
+  return str;
+}
+
+}
+
+namespace android {
+namespace util {
+
+std::unique_ptr<ProcResult> ExecuteBinary(const std::vector<std::string>& argv) {
+  int stdout[2];  // stdout[0] read, stdout[1] write
+  if (pipe(stdout) != 0) {
+    PLOG(ERROR) << "pipe";
+    return nullptr;
+  }
+
+  int stderr[2];  // stdout[0] read, stdout[1] write
+  if (pipe(stderr) != 0) {
+    PLOG(ERROR) << "pipe";
+    close(stdout[0]);
+    close(stdout[1]);
+    return nullptr;
+  }
+
+  char const** argv0 = (char const**)malloc(sizeof(char*) * (argv.size() + 1));
+  for (size_t i = 0; i < argv.size(); i++) {
+    argv0[i] = argv[i].c_str();
+  }
+  argv0[argv.size()] = nullptr;
+  switch (fork()) {
+    case -1: // error
+      free(argv0);
+      PLOG(ERROR) << "fork";
+      return nullptr;
+    case 0: // child
+      close(stdout[0]);
+      if (dup2(stdout[1], STDOUT_FILENO) == -1) {
+        abort();
+      }
+      close(stderr[0]);
+      if (dup2(stderr[1], STDERR_FILENO) == -1) {
+        abort();
+      }
+      execvp(argv0[0], const_cast<char* const*>(argv0));
+      PLOG(ERROR) << "execv";
+      abort();
+    default: // parent
+      free(argv0);
+      close(stdout[1]);
+      close(stderr[1]);
+      int status;
+      wait(&status);
+      if (!WIFEXITED(status)) {
+          return nullptr;
+      }
+      std::unique_ptr<ProcResult> result(new ProcResult());
+      result->status = status;
+      const auto out = ReadFile(stdout[0]);
+      result->stdout = out ? *out : "";
+      close(stdout[0]);
+      const auto err = ReadFile(stderr[0]);
+      result->stderr = err ? *err : "";
+      close(stderr[0]);
+      return result;
+  }
+}
+
+} // namespace util
+} // namespace android
+#endif
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index ad31f69..2f0ee01 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -96,7 +96,12 @@
   // Only pass invalidate_caches=false when it is known that the structure
   // change in ApkAssets is due to a safe addition of resources with completely
   // new resource IDs.
-  bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true);
+  //
+  // Only pass in filter_incompatible_configs=false when you want to load all
+  // configurations (including incompatible ones) such as when constructing an
+  // idmap.
+  bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true,
+          bool filter_incompatible_configs = true);
 
   inline const std::vector<const ApkAssets*> GetApkAssets() const {
     return apk_assets_;
@@ -274,7 +279,7 @@
 
   // Triggers the re-construction of lists of types that match the set configuration.
   // This should always be called when mutating the AssetManager's configuration or ApkAssets set.
-  void RebuildFilterList();
+  void RebuildFilterList(bool filter_incompatible_configs = true);
 
   // AssetManager2::GetBag(resid) wraps this function to track which resource ids have already
   // been seen while traversing bag parents.
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 35ae5fc..349b379 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -78,6 +78,55 @@
 
 class LoadedPackage {
  public:
+  class iterator {
+   public:
+    iterator& operator=(const iterator& rhs) {
+      loadedPackage_ = rhs.loadedPackage_;
+      typeIndex_ = rhs.typeIndex_;
+      entryIndex_ = rhs.entryIndex_;
+      return *this;
+    }
+
+    bool operator==(const iterator& rhs) const {
+      return loadedPackage_ == rhs.loadedPackage_ &&
+             typeIndex_ == rhs.typeIndex_ &&
+             entryIndex_ == rhs.entryIndex_;
+    }
+
+    bool operator!=(const iterator& rhs) const {
+      return !(*this == rhs);
+    }
+
+    iterator operator++(int) {
+      size_t prevTypeIndex_ = typeIndex_;
+      size_t prevEntryIndex_ = entryIndex_;
+      operator++();
+      return iterator(loadedPackage_, prevTypeIndex_, prevEntryIndex_);
+    }
+
+    iterator& operator++();
+
+    uint32_t operator*() const;
+
+   private:
+    friend class LoadedPackage;
+
+    iterator(const LoadedPackage* lp, size_t ti, size_t ei);
+
+    const LoadedPackage* loadedPackage_;
+    size_t typeIndex_;
+    size_t entryIndex_;
+    const size_t typeIndexEnd_;  // STL style end, so one past the last element
+  };
+
+  iterator begin() const {
+    return iterator(this, 0, 0);
+  }
+
+  iterator end() const {
+    return iterator(this, resource_ids_.size() + 1, 0);
+  }
+
   static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk,
                                                    const LoadedIdmap* loaded_idmap, bool system,
                                                    bool load_as_shared_library);
@@ -182,6 +231,7 @@
   bool overlay_ = false;
 
   ByteBucketArray<TypeSpecPtr> type_specs_;
+  ByteBucketArray<uint32_t> resource_ids_;
   std::vector<DynamicPackageEntry> dynamic_package_map_;
 };
 
diff --git a/libs/androidfw/include/androidfw/PosixUtils.h b/libs/androidfw/include/androidfw/PosixUtils.h
new file mode 100644
index 0000000..8fc3ee2
--- /dev/null
+++ b/libs/androidfw/include/androidfw/PosixUtils.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace util {
+
+struct ProcResult {
+  int status;
+  std::string stdout;
+  std::string stderr;
+};
+
+// Fork, exec and wait for an external process. Return nullptr if the process could not be launched,
+// otherwise a ProcResult containing the external process' exit status and captured stdout and
+// stderr.
+std::unique_ptr<ProcResult> ExecuteBinary(const std::vector<std::string>& argv);
+
+} // namespace util
+} // namespace android
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index cae632d..ffa4836 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -278,4 +278,52 @@
 // sizeof(Res_value) might not be backwards compatible.
 TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
 
+TEST(LoadedArscTest, ResourceIdentifierIterator) {
+  std::string contents;
+  ASSERT_TRUE(
+      ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
+
+  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
+  ASSERT_EQ(1u, packages.size());
+  EXPECT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName());
+
+  const auto& loaded_package = packages[0];
+  auto iter = loaded_package->begin();
+  auto end = loaded_package->end();
+
+  ASSERT_NE(end, iter);
+  ASSERT_EQ(0x7f010000u, *iter++);
+  ASSERT_EQ(0x7f010001u, *iter++);
+  ASSERT_EQ(0x7f020000u, *iter++);
+  ASSERT_EQ(0x7f020001u, *iter++);
+  ASSERT_EQ(0x7f030000u, *iter++);
+  ASSERT_EQ(0x7f030001u, *iter++);
+  ASSERT_EQ(0x7f030002u, *iter++);  // note: string without default, excluded by aapt2 dump
+  ASSERT_EQ(0x7f040000u, *iter++);
+  ASSERT_EQ(0x7f040001u, *iter++);
+  ASSERT_EQ(0x7f040002u, *iter++);
+  ASSERT_EQ(0x7f040003u, *iter++);
+  ASSERT_EQ(0x7f040004u, *iter++);
+  ASSERT_EQ(0x7f040005u, *iter++);
+  ASSERT_EQ(0x7f040006u, *iter++);
+  ASSERT_EQ(0x7f040007u, *iter++);
+  ASSERT_EQ(0x7f040008u, *iter++);
+  ASSERT_EQ(0x7f040009u, *iter++);
+  ASSERT_EQ(0x7f04000au, *iter++);
+  ASSERT_EQ(0x7f04000bu, *iter++);
+  ASSERT_EQ(0x7f04000cu, *iter++);
+  ASSERT_EQ(0x7f04000du, *iter++);
+  ASSERT_EQ(0x7f050000u, *iter++);
+  ASSERT_EQ(0x7f050001u, *iter++);
+  ASSERT_EQ(0x7f060000u, *iter++);
+  ASSERT_EQ(0x7f070000u, *iter++);
+  ASSERT_EQ(0x7f070001u, *iter++);
+  ASSERT_EQ(0x7f070002u, *iter++);
+  ASSERT_EQ(0x7f070003u, *iter++);
+  ASSERT_EQ(end, iter);
+}
+
 }  // namespace android
diff --git a/libs/androidfw/tests/PosixUtils_test.cpp b/libs/androidfw/tests/PosixUtils_test.cpp
new file mode 100644
index 0000000..cf97f87
--- /dev/null
+++ b/libs/androidfw/tests/PosixUtils_test.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utility>
+
+#include "androidfw/PosixUtils.h"
+
+#include "TestHelpers.h"
+
+using ::testing::IsNull;
+using ::testing::NotNull;
+
+namespace android {
+namespace util {
+
+TEST(PosixUtilsTest, AbsolutePathToBinary) {
+  const auto result = ExecuteBinary({"/bin/date", "--help"});
+  ASSERT_THAT(result, NotNull());
+  ASSERT_EQ(result->status, 0);
+  ASSERT_EQ(result->stdout.find("usage: date "), 0);
+}
+
+TEST(PosixUtilsTest, RelativePathToBinary) {
+  const auto result = ExecuteBinary({"date", "--help"});
+  ASSERT_THAT(result, NotNull());
+  ASSERT_EQ(result->status, 0);
+  ASSERT_EQ(result->stdout.find("usage: date "), 0);
+}
+
+TEST(PosixUtilsTest, BadParameters) {
+  const auto result = ExecuteBinary({"/bin/date", "--this-parameter-is-not-supported"});
+  ASSERT_THAT(result, NotNull());
+  ASSERT_NE(result->status, 0);
+}
+
+TEST(PosixUtilsTest, NoSuchBinary) {
+  const auto result = ExecuteBinary({"/this/binary/does/not/exist"});
+  ASSERT_THAT(result, IsNull());
+}
+
+} // android
+} // util
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 494e513..e3ec45b 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -61,6 +61,7 @@
     shared_libs: [
         "liblog",
         "libcutils",
+        "libstatslog",
         "libutils",
         "libEGL",
         "libGLESv2",
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index f2d50cd..e7ae767 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -18,6 +18,7 @@
 
 #include <errno.h>
 #include <inttypes.h>
+#include <statslog.h>
 #include <sys/mman.h>
 
 #include <algorithm>
@@ -181,6 +182,7 @@
         ALOGI("%s", ss.str().c_str());
         // Just so we have something that counts up, the value is largely irrelevant
         ATRACE_INT(ss.str().c_str(), ++sDaveyCount);
+        android::util::stats_write(android::util::DAVEY_OCCURRED, getuid(), ns2ms(totalDuration));
     }
 }
 
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 9c28453..b04194f 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -134,14 +134,15 @@
 }
 
 sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
-    PixelFormat format = graphicBuffer->getPixelFormat();
-    if (!graphicBuffer.get() ||
-        (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
-        return nullptr;
-    }
+    return createFrom(graphicBuffer, SkColorSpace::MakeSRGB());
+}
+
+sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer, sk_sp<SkColorSpace> colorSpace) {
+    // As we will be effectively texture-sampling the buffer (using either EGL or Vulkan), we can
+    // view the colorspace as RGBA8888.
     SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
                                          kRGBA_8888_SkColorType, kPremul_SkAlphaType,
-                                         SkColorSpace::MakeSRGB());
+                                         colorSpace);
     return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
 }
 
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 43d457a..238c764 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -64,6 +64,8 @@
                                               size_t rowBytes);
 
     static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer);
+    static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer,
+                                    sk_sp<SkColorSpace> colorSpace);
 
     static sk_sp<Bitmap> createFrom(const SkImageInfo&, SkPixelRef&);
 
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.h b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
index 6594bd22..d746978 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.h
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include "SkiaUtils.h"
+
 #include <SkCanvas.h>
 #include <SkDrawable.h>
 #include <SkMatrix.h>
@@ -89,7 +91,7 @@
     virtual SkRect onGetBounds() override {
         // We don't want to enable a record time quick reject because the properties
         // of the RenderNode may be updated on subsequent frames.
-        return SkRect::MakeLargest();
+        return SkRectMakeLargest();
     }
     /**
      * This function draws into a canvas as forceDraw, but does nothing if the render node has a
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
index 3c48d36..26cfa90 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "RenderNodeDrawable.h"
+#include "SkiaUtils.h"
 
 #include <SkCanvas.h>
 #include <SkDrawable.h>
@@ -41,7 +42,7 @@
     explicit StartReorderBarrierDrawable(SkiaDisplayList* data);
 
 protected:
-    virtual SkRect onGetBounds() override { return SkRect::MakeLargest(); }
+    virtual SkRect onGetBounds() override { return SkRectMakeLargest(); }
     virtual void onDraw(SkCanvas* canvas) override;
 
 private:
@@ -65,7 +66,7 @@
     explicit EndReorderBarrierDrawable(StartReorderBarrierDrawable* startBarrier);
 
 protected:
-    virtual SkRect onGetBounds() override { return SkRect::MakeLargest(); }
+    virtual SkRect onGetBounds() override { return SkRectMakeLargest(); }
     virtual void onDraw(SkCanvas* canvas) override;
 
 private:
diff --git a/proto/src/stats_enums.proto b/libs/hwui/pipeline/skia/SkiaUtils.h
similarity index 75%
copy from proto/src/stats_enums.proto
copy to libs/hwui/pipeline/skia/SkiaUtils.h
index 6c892cf..8344469 100644
--- a/proto/src/stats_enums.proto
+++ b/libs/hwui/pipeline/skia/SkiaUtils.h
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-syntax = "proto2";
+#pragma once
 
-package android.os.statsd;
-option java_package = "com.android.os";
-option java_outer_classname = "StatsEnums";
+#include <SkRect.h>
 
-enum EventType {
-  // Unknown.
-  TYPE_UNKNOWN = 0;
-}
+namespace android {
+
+static inline SkRect SkRectMakeLargest() {
+    const SkScalar v = SK_ScalarMax;
+    return { -v, -v, v, v };
+};
+
+} /* namespace android */
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index cdf31da..65b4e26 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -24,6 +24,7 @@
 #include "DamageAccumulator.h"
 #include "IContextFactory.h"
 #include "SkiaCanvas.h"
+#include "pipeline/skia/SkiaUtils.h"
 #include "pipeline/skia/SkiaDisplayList.h"
 #include "pipeline/skia/SkiaOpenGLPipeline.h"
 #include "pipeline/skia/SkiaRecordingCanvas.h"
@@ -41,7 +42,7 @@
                 redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
             });
     LayerUpdateQueue layerUpdateQueue;
-    SkRect dirty = SkRect::MakeLargest();
+    SkRect dirty = SkRectMakeLargest();
     std::vector<sp<RenderNode>> renderNodes;
     renderNodes.push_back(redNode);
     bool opaque = true;
@@ -62,7 +63,7 @@
             });
 
     LayerUpdateQueue layerUpdateQueue;
-    SkRect dirty = SkRect::MakeLargest();
+    SkRect dirty = SkRectMakeLargest();
     std::vector<sp<RenderNode>> renderNodes;
     renderNodes.push_back(redNode);
     bool opaque = true;
@@ -97,7 +98,7 @@
                 bottomHalfGreenCanvas.drawRect(0, 1, 2, 2, greenPaint);
             });
     LayerUpdateQueue layerUpdateQueue;
-    SkRect dirty = SkRect::MakeLargest();
+    SkRect dirty = SkRectMakeLargest();
     std::vector<sp<RenderNode>> renderNodes;
     renderNodes.push_back(halfGreenNode);
     android::uirenderer::Rect contentDrawBounds(0, 0, 2, 2);
@@ -160,7 +161,7 @@
 
     // attach both layers to the update queue
     LayerUpdateQueue layerUpdateQueue;
-    SkRect dirty = SkRect::MakeLargest();
+    SkRect dirty = SkRectMakeLargest();
     layerUpdateQueue.enqueueLayerWithDamage(redNode.get(), dirty);
     layerUpdateQueue.enqueueLayerWithDamage(blueNode.get(), SkRect::MakeWH(2, 1));
     ASSERT_EQ(layerUpdateQueue.entries().size(), 2UL);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 6d10c2d..b1968ba 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2380,10 +2380,12 @@
     }
 
     /**
+     * Return the package that implements the {@link #NETWORK_PROVIDER} functionality.
+     *
      * @hide
      */
     @SystemApi
-    public String getNetworkProviderPackage() {
+    public @Nullable String getNetworkProviderPackage() {
         try {
             return mService.getNetworkProviderPackage();
         } catch (RemoteException e) {
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 2395b24..b96a585 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -3252,7 +3252,7 @@
             int thumbnailLength = jpegInterchangeFormatLengthAttribute.getIntValue(mExifByteOrder);
 
             // The following code limits the size of thumbnail size not to overflow EXIF data area.
-            thumbnailLength = Math.min(thumbnailLength, in.available() - thumbnailOffset);
+            thumbnailLength = Math.min(thumbnailLength, in.getLength() - thumbnailOffset);
             if (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_RAF
                     || mMimeType == IMAGE_TYPE_RW2) {
                 thumbnailOffset += mExifOffset;
@@ -3981,6 +3981,10 @@
         public double readDouble() throws IOException {
             return Double.longBitsToDouble(readLong());
         }
+
+        public int getLength() {
+            return mLength;
+        }
     }
 
     // An output stream to write EXIF data area, which can be written in either little or big endian
diff --git a/media/java/android/media/MediaCrypto.java b/media/java/android/media/MediaCrypto.java
index 474d8b9..889a5f7 100644
--- a/media/java/android/media/MediaCrypto.java
+++ b/media/java/android/media/MediaCrypto.java
@@ -56,13 +56,15 @@
     private static final native boolean isCryptoSchemeSupportedNative(@NonNull byte[] uuid);
 
     /**
-     * Instantiate a MediaCrypto object using opaque, crypto scheme specific
-     * data.
+     * Instantiate a MediaCrypto object and associate it with a MediaDrm session
+     *
      * @param uuid The UUID of the crypto scheme.
-     * @param initData Opaque initialization data specific to the crypto scheme.
+     * @param sessionId The MediaDrm sessionId to associate with this
+     * MediaCrypto session. The sessionId may be changed after the MediaCrypto
+     * is created using {@link #setMediaDrmSession}
      */
-    public MediaCrypto(@NonNull UUID uuid, @NonNull byte[] initData) throws MediaCryptoException {
-        native_setup(getByteArrayFromUUID(uuid), initData);
+    public MediaCrypto(@NonNull UUID uuid, @NonNull byte[] sessionId) throws MediaCryptoException {
+        native_setup(getByteArrayFromUUID(uuid), sessionId);
     }
 
     /**
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 850be78..6d122d7 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -1202,7 +1202,6 @@
      * The maximum security level supported by the device. This is the default
      * security level when a session is opened.
      */
-    @SecurityLevel
     public static final int getMaxSecurityLevel() {
         return SECURITY_LEVEL_MAX;
     }
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index 8665f28..db6da8c 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -32,9 +32,6 @@
 
 import dalvik.system.CloseGuard;
 
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InputStream;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -232,8 +229,7 @@
  * successful transition. Any other value will be an error. Call {@link #getState()} to
  * determine the current state. </p>
  */
-public abstract class MediaPlayer2 implements SubtitleController.Listener
-                                            , AutoCloseable
+public abstract class MediaPlayer2 implements AutoCloseable
                                             , AudioRouting {
     private final CloseGuard mGuard = CloseGuard.get();
 
@@ -242,8 +238,8 @@
      *
      * @return A MediaPlayer2 object created
      */
-    public static final MediaPlayer2 create() {
-        return new MediaPlayer2Impl();
+    public static final MediaPlayer2 create(Context context) {
+        return new MediaPlayer2Impl(context);
     }
 
     private static final String[] decodeMediaPlayer2Uri(String location) {
@@ -1081,16 +1077,6 @@
     public abstract void reset();
 
     /**
-     * Set up a timer for {@link #TimeProvider}. {@link #TimeProvider} will be
-     * notified when the presentation time reaches (becomes greater than or equal to)
-     * the value specified.
-     *
-     * @param mediaTimeUs presentation time to get timed event callback at
-     * @hide
-     */
-    public void notifyAt(long mediaTimeUs) { }
-
-    /**
      * Checks whether the MediaPlayer2 is looping or non-looping.
      *
      * @return true if the MediaPlayer2 is currently looping, false otherwise
@@ -1237,95 +1223,6 @@
      */
     public static final String MEDIA_MIMETYPE_TEXT_CEA_708 = "text/cea-708";
 
-    /** @hide */
-    public void setSubtitleAnchor(
-            SubtitleController controller,
-            SubtitleController.Anchor anchor) { }
-
-    /** @hide */
-    @Override
-    public void onSubtitleTrackSelected(SubtitleTrack track) { }
-
-    /** @hide */
-    public void addSubtitleSource(InputStream is, MediaFormat format) { }
-
-    /* TODO: Limit the total number of external timed text source to a reasonable number.
-     */
-    /**
-     * Adds an external timed text source file.
-     *
-     * Currently supported format is SubRip with the file extension .srt, case insensitive.
-     * Note that a single external timed text source may contain multiple tracks in it.
-     * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
-     * additional tracks become available after this method call.
-     *
-     * @param path The file path of external timed text source file.
-     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
-     * @throws IOException if the file cannot be accessed or is corrupted.
-     * @throws IllegalArgumentException if the mimeType is not supported.
-     * @throws IllegalStateException if called in an invalid state.
-     * @hide
-     */
-    public void addTimedTextSource(String path, String mimeType) throws IOException { }
-
-    /**
-     * Adds an external timed text source file (Uri).
-     *
-     * Currently supported format is SubRip with the file extension .srt, case insensitive.
-     * Note that a single external timed text source may contain multiple tracks in it.
-     * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
-     * additional tracks become available after this method call.
-     *
-     * @param context the Context to use when resolving the Uri
-     * @param uri the Content URI of the data you want to play
-     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
-     * @throws IOException if the file cannot be accessed or is corrupted.
-     * @throws IllegalArgumentException if the mimeType is not supported.
-     * @throws IllegalStateException if called in an invalid state.
-     * @hide
-     */
-    public void addTimedTextSource(Context context, Uri uri, String mimeType) throws IOException { }
-
-    /**
-     * Adds an external timed text source file (FileDescriptor).
-     *
-     * It is the caller's responsibility to close the file descriptor.
-     * It is safe to do so as soon as this call returns.
-     *
-     * Currently supported format is SubRip. Note that a single external timed text source may
-     * contain multiple tracks in it. One can find the total number of available tracks
-     * using {@link #getTrackInfo()} to see what additional tracks become available
-     * after this method call.
-     *
-     * @param fd the FileDescriptor for the file you want to play
-     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
-     * @throws IllegalArgumentException if the mimeType is not supported.
-     * @throws IllegalStateException if called in an invalid state.
-     * @hide
-     */
-    public void addTimedTextSource(FileDescriptor fd, String mimeType) { }
-
-    /**
-     * Adds an external timed text file (FileDescriptor).
-     *
-     * It is the caller's responsibility to close the file descriptor.
-     * It is safe to do so as soon as this call returns.
-     *
-     * Currently supported format is SubRip. Note that a single external timed text source may
-     * contain multiple tracks in it. One can find the total number of available tracks
-     * using {@link #getTrackInfo()} to see what additional tracks become available
-     * after this method call.
-     *
-     * @param fd the FileDescriptor for the file you want to play
-     * @param offset the offset into the file where the data to be played starts, in bytes
-     * @param length the length in bytes of the data to be played
-     * @param mime The mime type of the file. Must be one of the mime types listed above.
-     * @throws IllegalArgumentException if the mimeType is not supported.
-     * @throws IllegalStateException if called in an invalid state.
-     * @hide
-     */
-    public abstract void addTimedTextSource(FileDescriptor fd, long offset, long length, String mime);
-
     /**
      * Returns the index of the audio, video, or subtitle track currently selected for playback,
      * The return value is an index into the array returned by {@link #getTrackInfo()}, and can
@@ -1393,11 +1290,6 @@
     // This is an asynchronous call.
     public abstract void deselectTrack(int index);
 
-    /** @hide */
-    public MediaTimeProvider getMediaTimeProvider() {
-        return null;
-    }
-
     /**
      * Interface definition for callbacks to be invoked when the player has the corresponding
      * events.
@@ -1679,12 +1571,6 @@
      */
     public static final int MEDIA_INFO_METADATA_UPDATE = 802;
 
-    /** A new set of external-only metadata is available.  Used by
-     *  JAVA framework to avoid triggering track scanning.
-     * @hide
-     */
-    public static final int MEDIA_INFO_EXTERNAL_METADATA_UPDATE = 803;
-
     /** Informs that audio is not playing. Note that playback of the video
      * is not interrupted.
      * @see EventCallback#onInfo
@@ -1733,7 +1619,6 @@
             MEDIA_INFO_BAD_INTERLEAVING,
             MEDIA_INFO_NOT_SEEKABLE,
             MEDIA_INFO_METADATA_UPDATE,
-            MEDIA_INFO_EXTERNAL_METADATA_UPDATE,
             MEDIA_INFO_AUDIO_NOT_PLAYING,
             MEDIA_INFO_VIDEO_NOT_PLAYING,
             MEDIA_INFO_TIMED_TEXT_ERROR,
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 678cb9a..5604ffd 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -19,7 +19,6 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.ActivityThread;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -29,8 +28,6 @@
 import android.media.MediaPlayer2Proto;
 import android.media.MediaPlayer2Proto.PlayerMessage;
 import android.media.MediaPlayer2Proto.Value;
-import android.media.SubtitleController.Anchor;
-import android.media.SubtitleTrack.RenderingWidget;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -38,23 +35,17 @@
 import android.os.Message;
 import android.os.PersistableBundle;
 import android.os.PowerManager;
-import android.os.Process;
 import android.os.SystemProperties;
 import android.provider.Settings;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
 import android.view.Surface;
 import android.view.SurfaceHolder;
-import android.widget.VideoView;
 
 import com.android.framework.protobuf.InvalidProtocolBufferException;
 import com.android.internal.annotations.GuardedBy;
 
-import libcore.io.IoBridge;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -69,15 +60,12 @@
 import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.BitSet;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Scanner;
 import java.util.UUID;
-import java.util.Vector;
 import java.util.concurrent.Executor;
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -93,6 +81,8 @@
 
     private final static String TAG = "MediaPlayer2Impl";
 
+    private Context mContext;
+
     private long mNativeContext; // accessed by native methods
     private long mNativeSurfaceTexture;  // accessed by native methods
     private int mListenerContext; // accessed by native methods
@@ -149,15 +139,13 @@
      * to free the resources. If not released, too many MediaPlayer2Impl instances may
      * result in an exception.</p>
      */
-    public MediaPlayer2Impl() {
+    public MediaPlayer2Impl(Context context) {
+        mContext = context;
         mHandlerThread = new HandlerThread("MediaPlayer2TaskThread");
         mHandlerThread.start();
         Looper looper = mHandlerThread.getLooper();
         mTaskHandler = new TaskHandler(this, looper);
 
-        mTimeProvider = new TimeProvider(this);
-        mOpenSubtitleSources = new Vector<InputStream>();
-
         /* Native setup requires a weak reference to our object.
          * It's easier to create it here than in C++.
          */
@@ -1503,24 +1491,6 @@
      */
     @Override
     public void reset() {
-        mSelectedSubtitleTrackIndex = -1;
-        synchronized(mOpenSubtitleSources) {
-            for (final InputStream is: mOpenSubtitleSources) {
-                try {
-                    is.close();
-                } catch (IOException e) {
-                }
-            }
-            mOpenSubtitleSources.clear();
-        }
-        if (mSubtitleController != null) {
-            mSubtitleController.reset();
-        }
-        if (mTimeProvider != null) {
-            mTimeProvider.close();
-            mTimeProvider = null;
-        }
-
         synchronized (mEventCbLock) {
             mEventCallbackRecords.clear();
         }
@@ -1543,31 +1513,11 @@
             mTaskHandler.removeCallbacksAndMessages(null);
         }
 
-        synchronized (mIndexTrackPairs) {
-            mIndexTrackPairs.clear();
-            mInbandTrackIndices.clear();
-        };
-
         resetDrmState();
     }
 
     private native void _reset();
 
-    /**
-     * Set up a timer for {@link #TimeProvider}. {@link #TimeProvider} will be
-     * notified when the presentation time reaches (becomes greater than or equal to)
-     * the value specified.
-     *
-     * @param mediaTimeUs presentation time to get timed event callback at
-     * @hide
-     */
-    @Override
-    public void notifyAt(long mediaTimeUs) {
-        _notifyAt(mediaTimeUs);
-    }
-
-    private native void _notifyAt(long mediaTimeUs);
-
     // Keep KEY_PARAMETER_* in sync with include/media/mediaplayer2.h
     private final static int KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400;
     /**
@@ -1781,16 +1731,6 @@
         }
     };
 
-    // We would like domain specific classes with more informative names than the `first` and `second`
-    // in generic Pair, but we would also like to avoid creating new/trivial classes. As a compromise
-    // we document the meanings of `first` and `second` here:
-    //
-    // Pair.first - inband track index; non-null iff representing an inband track.
-    // Pair.second - a SubtitleTrack registered with mSubtitleController; non-null iff representing
-    //               an inband subtitle track or any out-of-band track (subtitle or timedtext).
-    private Vector<Pair<Integer, SubtitleTrack>> mIndexTrackPairs = new Vector<>();
-    private BitSet mInbandTrackIndices = new BitSet();
-
     /**
      * Returns a List of track information.
      *
@@ -1802,21 +1742,7 @@
     @Override
     public List<TrackInfo> getTrackInfo() {
         TrackInfoImpl trackInfo[] = getInbandTrackInfoImpl();
-        // add out-of-band tracks
-        synchronized (mIndexTrackPairs) {
-            TrackInfoImpl allTrackInfo[] = new TrackInfoImpl[mIndexTrackPairs.size()];
-            for (int i = 0; i < allTrackInfo.length; i++) {
-                Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
-                if (p.first != null) {
-                    // inband track
-                    allTrackInfo[i] = trackInfo[p.first];
-                } else {
-                    SubtitleTrack track = p.second;
-                    allTrackInfo[i] = new TrackInfoImpl(track.getTrackType(), track.getFormat());
-                }
-            }
-            return Arrays.asList(allTrackInfo);
-        }
+        return Arrays.asList(trackInfo);
     }
 
     private TrackInfoImpl[] getInbandTrackInfoImpl() throws IllegalStateException {
@@ -1849,419 +1775,6 @@
         return false;
     }
 
-    private SubtitleController mSubtitleController;
-
-    /** @hide */
-    @Override
-    public void setSubtitleAnchor(
-            SubtitleController controller,
-            SubtitleController.Anchor anchor) {
-        // TODO: create SubtitleController in MediaPlayer2
-        mSubtitleController = controller;
-        mSubtitleController.setAnchor(anchor);
-    }
-
-    /**
-     * The private version of setSubtitleAnchor is used internally to set mSubtitleController if
-     * necessary when clients don't provide their own SubtitleControllers using the public version
-     * {@link #setSubtitleAnchor(SubtitleController, Anchor)} (e.g. {@link VideoView} provides one).
-     */
-    private synchronized void setSubtitleAnchor() {
-        if ((mSubtitleController == null) && (ActivityThread.currentApplication() != null)) {
-            final HandlerThread thread = new HandlerThread("SetSubtitleAnchorThread");
-            thread.start();
-            Handler handler = new Handler(thread.getLooper());
-            handler.post(new Runnable() {
-                @Override
-                public void run() {
-                    Context context = ActivityThread.currentApplication();
-                    mSubtitleController = new SubtitleController(context, mTimeProvider, MediaPlayer2Impl.this);
-                    mSubtitleController.setAnchor(new Anchor() {
-                        @Override
-                        public void setSubtitleWidget(RenderingWidget subtitleWidget) {
-                        }
-
-                        @Override
-                        public Looper getSubtitleLooper() {
-                            return Looper.getMainLooper();
-                        }
-                    });
-                    thread.getLooper().quitSafely();
-                }
-            });
-            try {
-                thread.join();
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-                Log.w(TAG, "failed to join SetSubtitleAnchorThread");
-            }
-        }
-    }
-
-    private int mSelectedSubtitleTrackIndex = -1;
-    private Vector<InputStream> mOpenSubtitleSources;
-
-    private EventCallback mSubtitleDataCallback = new EventCallback() {
-        @Override
-        public void onSubtitleData(MediaPlayer2 mp, DataSourceDesc dsd, SubtitleData data) {
-            int index = data.getTrackIndex();
-            synchronized (mIndexTrackPairs) {
-                for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
-                    if (p.first != null && p.first == index && p.second != null) {
-                        // inband subtitle track that owns data
-                        SubtitleTrack track = p.second;
-                        track.onData(data);
-                    }
-                }
-            }
-        }
-    };
-
-    /** @hide */
-    @Override
-    public void onSubtitleTrackSelected(SubtitleTrack track) {
-        if (mSelectedSubtitleTrackIndex >= 0) {
-            try {
-                selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, false);
-            } catch (IllegalStateException e) {
-            }
-            mSelectedSubtitleTrackIndex = -1;
-        }
-        unregisterEventCallback(mSubtitleDataCallback);
-        if (track == null) {
-            return;
-        }
-
-        synchronized (mIndexTrackPairs) {
-            for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) {
-                if (p.first != null && p.second == track) {
-                    // inband subtitle track that is selected
-                    mSelectedSubtitleTrackIndex = p.first;
-                    break;
-                }
-            }
-        }
-
-        if (mSelectedSubtitleTrackIndex >= 0) {
-            try {
-                selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true);
-            } catch (IllegalStateException e) {
-            }
-            final Executor executor = (runnable) -> mTaskHandler.post(runnable);
-            registerEventCallback(executor, mSubtitleDataCallback);
-        }
-        // no need to select out-of-band tracks
-    }
-
-    /** @hide */
-    @Override
-    public void addSubtitleSource(InputStream is, MediaFormat format)
-            throws IllegalStateException
-    {
-        final InputStream fIs = is;
-        final MediaFormat fFormat = format;
-
-        if (is != null) {
-            // Ensure all input streams are closed.  It is also a handy
-            // way to implement timeouts in the future.
-            synchronized(mOpenSubtitleSources) {
-                mOpenSubtitleSources.add(is);
-            }
-        } else {
-            Log.w(TAG, "addSubtitleSource called with null InputStream");
-        }
-
-        getMediaTimeProvider();
-
-        // process each subtitle in its own thread
-        final HandlerThread thread = new HandlerThread("SubtitleReadThread",
-              Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
-        thread.start();
-        Handler handler = new Handler(thread.getLooper());
-        handler.post(new Runnable() {
-            private int addTrack() {
-                if (fIs == null || mSubtitleController == null) {
-                    return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
-                }
-
-                SubtitleTrack track = mSubtitleController.addTrack(fFormat);
-                if (track == null) {
-                    return MEDIA_INFO_UNSUPPORTED_SUBTITLE;
-                }
-
-                // TODO: do the conversion in the subtitle track
-                Scanner scanner = new Scanner(fIs, "UTF-8");
-                String contents = scanner.useDelimiter("\\A").next();
-                synchronized(mOpenSubtitleSources) {
-                    mOpenSubtitleSources.remove(fIs);
-                }
-                scanner.close();
-                synchronized (mIndexTrackPairs) {
-                    mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
-                }
-                Handler h = mTimeProvider.mEventHandler;
-                int what = TimeProvider.NOTIFY;
-                int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
-                Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, contents.getBytes());
-                Message m = h.obtainMessage(what, arg1, 0, trackData);
-                h.sendMessage(m);
-                return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
-            }
-
-            public void run() {
-                int res = addTrack();
-                if (mTaskHandler != null) {
-                    Message m = mTaskHandler.obtainMessage(MEDIA_INFO, res, 0, null);
-                    mTaskHandler.sendMessage(m);
-                }
-                thread.getLooper().quitSafely();
-            }
-        });
-    }
-
-    private void scanInternalSubtitleTracks() {
-        setSubtitleAnchor();
-
-        populateInbandTracks();
-
-        if (mSubtitleController != null) {
-            mSubtitleController.selectDefaultTrack();
-        }
-    }
-
-    private void populateInbandTracks() {
-        TrackInfoImpl[] tracks = getInbandTrackInfoImpl();
-        synchronized (mIndexTrackPairs) {
-            for (int i = 0; i < tracks.length; i++) {
-                if (mInbandTrackIndices.get(i)) {
-                    continue;
-                } else {
-                    mInbandTrackIndices.set(i);
-                }
-
-                // newly appeared inband track
-                if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
-                    SubtitleTrack track = mSubtitleController.addTrack(
-                            tracks[i].getFormat());
-                    mIndexTrackPairs.add(Pair.create(i, track));
-                } else {
-                    mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(i, null));
-                }
-            }
-        }
-    }
-
-    /* TODO: Limit the total number of external timed text source to a reasonable number.
-     */
-    /**
-     * Adds an external timed text source file.
-     *
-     * Currently supported format is SubRip with the file extension .srt, case insensitive.
-     * Note that a single external timed text source may contain multiple tracks in it.
-     * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
-     * additional tracks become available after this method call.
-     *
-     * @param path The file path of external timed text source file.
-     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
-     * @throws IOException if the file cannot be accessed or is corrupted.
-     * @throws IllegalArgumentException if the mimeType is not supported.
-     * @throws IllegalStateException if called in an invalid state.
-     * @hide
-     */
-    @Override
-    public void addTimedTextSource(String path, String mimeType)
-            throws IOException {
-        if (!availableMimeTypeForExternalSource(mimeType)) {
-            final String msg = "Illegal mimeType for timed text source: " + mimeType;
-            throw new IllegalArgumentException(msg);
-        }
-
-        File file = new File(path);
-        if (file.exists()) {
-            FileInputStream is = new FileInputStream(file);
-            FileDescriptor fd = is.getFD();
-            addTimedTextSource(fd, mimeType);
-            is.close();
-        } else {
-            // We do not support the case where the path is not a file.
-            throw new IOException(path);
-        }
-    }
-
-
-    /**
-     * Adds an external timed text source file (Uri).
-     *
-     * Currently supported format is SubRip with the file extension .srt, case insensitive.
-     * Note that a single external timed text source may contain multiple tracks in it.
-     * One can find the total number of available tracks using {@link #getTrackInfo()} to see what
-     * additional tracks become available after this method call.
-     *
-     * @param context the Context to use when resolving the Uri
-     * @param uri the Content URI of the data you want to play
-     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
-     * @throws IOException if the file cannot be accessed or is corrupted.
-     * @throws IllegalArgumentException if the mimeType is not supported.
-     * @throws IllegalStateException if called in an invalid state.
-     * @hide
-     */
-    @Override
-    public void addTimedTextSource(Context context, Uri uri, String mimeType)
-            throws IOException {
-        String scheme = uri.getScheme();
-        if(scheme == null || scheme.equals("file")) {
-            addTimedTextSource(uri.getPath(), mimeType);
-            return;
-        }
-
-        AssetFileDescriptor fd = null;
-        try {
-            ContentResolver resolver = context.getContentResolver();
-            fd = resolver.openAssetFileDescriptor(uri, "r");
-            if (fd == null) {
-                return;
-            }
-            addTimedTextSource(fd.getFileDescriptor(), mimeType);
-            return;
-        } catch (SecurityException ex) {
-        } catch (IOException ex) {
-        } finally {
-            if (fd != null) {
-                fd.close();
-            }
-        }
-    }
-
-    /**
-     * Adds an external timed text source file (FileDescriptor).
-     *
-     * It is the caller's responsibility to close the file descriptor.
-     * It is safe to do so as soon as this call returns.
-     *
-     * Currently supported format is SubRip. Note that a single external timed text source may
-     * contain multiple tracks in it. One can find the total number of available tracks
-     * using {@link #getTrackInfo()} to see what additional tracks become available
-     * after this method call.
-     *
-     * @param fd the FileDescriptor for the file you want to play
-     * @param mimeType The mime type of the file. Must be one of the mime types listed above.
-     * @throws IllegalArgumentException if the mimeType is not supported.
-     * @throws IllegalStateException if called in an invalid state.
-     * @hide
-     */
-    @Override
-    public void addTimedTextSource(FileDescriptor fd, String mimeType) {
-        // intentionally less than LONG_MAX
-        addTimedTextSource(fd, 0, 0x7ffffffffffffffL, mimeType);
-    }
-
-    /**
-     * Adds an external timed text file (FileDescriptor).
-     *
-     * It is the caller's responsibility to close the file descriptor.
-     * It is safe to do so as soon as this call returns.
-     *
-     * Currently supported format is SubRip. Note that a single external timed text source may
-     * contain multiple tracks in it. One can find the total number of available tracks
-     * using {@link #getTrackInfo()} to see what additional tracks become available
-     * after this method call.
-     *
-     * @param fd the FileDescriptor for the file you want to play
-     * @param offset the offset into the file where the data to be played starts, in bytes
-     * @param length the length in bytes of the data to be played
-     * @param mime The mime type of the file. Must be one of the mime types listed above.
-     * @throws IllegalArgumentException if the mimeType is not supported.
-     * @throws IllegalStateException if called in an invalid state.
-     * @hide
-     */
-    @Override
-    public void addTimedTextSource(FileDescriptor fd, long offset, long length, String mime) {
-        if (!availableMimeTypeForExternalSource(mime)) {
-            throw new IllegalArgumentException("Illegal mimeType for timed text source: " + mime);
-        }
-
-        final FileDescriptor dupedFd;
-        try {
-            dupedFd = Os.dup(fd);
-        } catch (ErrnoException ex) {
-            Log.e(TAG, ex.getMessage(), ex);
-            throw new RuntimeException(ex);
-        }
-
-        final MediaFormat fFormat = new MediaFormat();
-        fFormat.setString(MediaFormat.KEY_MIME, mime);
-        fFormat.setInteger(MediaFormat.KEY_IS_TIMED_TEXT, 1);
-
-        // A MediaPlayer2 created by a VideoView should already have its mSubtitleController set.
-        if (mSubtitleController == null) {
-            setSubtitleAnchor();
-        }
-
-        if (!mSubtitleController.hasRendererFor(fFormat)) {
-            // test and add not atomic
-            Context context = ActivityThread.currentApplication();
-            mSubtitleController.registerRenderer(new SRTRenderer(context, mTaskHandler));
-        }
-        final SubtitleTrack track = mSubtitleController.addTrack(fFormat);
-        synchronized (mIndexTrackPairs) {
-            mIndexTrackPairs.add(Pair.<Integer, SubtitleTrack>create(null, track));
-        }
-
-        getMediaTimeProvider();
-
-        final long offset2 = offset;
-        final long length2 = length;
-        final HandlerThread thread = new HandlerThread(
-                "TimedTextReadThread",
-                Process.THREAD_PRIORITY_BACKGROUND + Process.THREAD_PRIORITY_MORE_FAVORABLE);
-        thread.start();
-        Handler handler = new Handler(thread.getLooper());
-        handler.post(new Runnable() {
-            private int addTrack() {
-                final ByteArrayOutputStream bos = new ByteArrayOutputStream();
-                try {
-                    Os.lseek(dupedFd, offset2, OsConstants.SEEK_SET);
-                    byte[] buffer = new byte[4096];
-                    for (long total = 0; total < length2;) {
-                        int bytesToRead = (int) Math.min(buffer.length, length2 - total);
-                        int bytes = IoBridge.read(dupedFd, buffer, 0, bytesToRead);
-                        if (bytes < 0) {
-                            break;
-                        } else {
-                            bos.write(buffer, 0, bytes);
-                            total += bytes;
-                        }
-                    }
-                    Handler h = mTimeProvider.mEventHandler;
-                    int what = TimeProvider.NOTIFY;
-                    int arg1 = TimeProvider.NOTIFY_TRACK_DATA;
-                    Pair<SubtitleTrack, byte[]> trackData = Pair.create(track, bos.toByteArray());
-                    Message m = h.obtainMessage(what, arg1, 0, trackData);
-                    h.sendMessage(m);
-                    return MEDIA_INFO_EXTERNAL_METADATA_UPDATE;
-                } catch (Exception e) {
-                    Log.e(TAG, e.getMessage(), e);
-                    return MEDIA_INFO_TIMED_TEXT_ERROR;
-                } finally {
-                    try {
-                        Os.close(dupedFd);
-                    } catch (ErrnoException e) {
-                        Log.e(TAG, e.getMessage(), e);
-                    }
-                }
-            }
-
-            public void run() {
-                int res = addTrack();
-                if (mTaskHandler != null) {
-                    Message m = mTaskHandler.obtainMessage(MEDIA_INFO, res, 0, null);
-                    mTaskHandler.sendMessage(m);
-                }
-                thread.getLooper().quitSafely();
-            }
-        });
-    }
-
     /**
      * Returns the index of the audio, video, or subtitle track currently selected for playback,
      * The return value is an index into the array returned by {@link #getTrackInfo()}, and can
@@ -2281,22 +1794,6 @@
      */
     @Override
     public int getSelectedTrack(int trackType) {
-        if (mSubtitleController != null
-                && (trackType == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE
-                || trackType == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT)) {
-            SubtitleTrack subtitleTrack = mSubtitleController.getSelectedTrack();
-            if (subtitleTrack != null) {
-                synchronized (mIndexTrackPairs) {
-                    for (int i = 0; i < mIndexTrackPairs.size(); i++) {
-                        Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
-                        if (p.second == subtitleTrack && subtitleTrack.getTrackType() == trackType) {
-                            return i;
-                        }
-                    }
-                }
-            }
-        }
-
         PlayerMessage request = PlayerMessage.newBuilder()
                 .addValues(Value.newBuilder().setInt32Value(INVOKE_ID_GET_SELECTED_TRACK))
                 .addValues(Value.newBuilder().setInt32Value(trackType))
@@ -2305,16 +1802,7 @@
         if (response == null) {
             return -1;
         }
-        int inbandTrackIndex = response.getValues(0).getInt32Value();
-        synchronized (mIndexTrackPairs) {
-            for (int i = 0; i < mIndexTrackPairs.size(); i++) {
-                Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i);
-                if (p.first != null && p.first == inbandTrackIndex) {
-                    return i;
-                }
-            }
-        }
-        return -1;
+        return response.getValues(0).getInt32Value();
     }
 
     /**
@@ -2381,56 +1869,6 @@
 
     private void selectOrDeselectTrack(int index, boolean select)
             throws IllegalStateException {
-        // handle subtitle track through subtitle controller
-        populateInbandTracks();
-
-        Pair<Integer,SubtitleTrack> p = null;
-        try {
-            p = mIndexTrackPairs.get(index);
-        } catch (ArrayIndexOutOfBoundsException e) {
-            // ignore bad index
-            return;
-        }
-
-        SubtitleTrack track = p.second;
-        if (track == null) {
-            // inband (de)select
-            selectOrDeselectInbandTrack(p.first, select);
-            return;
-        }
-
-        if (mSubtitleController == null) {
-            return;
-        }
-
-        if (!select) {
-            // out-of-band deselect
-            if (mSubtitleController.getSelectedTrack() == track) {
-                mSubtitleController.selectTrack(null);
-            } else {
-                Log.w(TAG, "trying to deselect track that was not selected");
-            }
-            return;
-        }
-
-        // out-of-band select
-        if (track.getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
-            int ttIndex = getSelectedTrack(TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT);
-            synchronized (mIndexTrackPairs) {
-                if (ttIndex >= 0 && ttIndex < mIndexTrackPairs.size()) {
-                    Pair<Integer,SubtitleTrack> p2 = mIndexTrackPairs.get(ttIndex);
-                    if (p2.first != null && p2.second == null) {
-                        // deselect inband counterpart
-                        selectOrDeselectInbandTrack(p2.first, false);
-                    }
-                }
-            }
-        }
-        mSubtitleController.selectTrack(track);
-    }
-
-    private void selectOrDeselectInbandTrack(int index, boolean select)
-            throws IllegalStateException {
         PlayerMessage request = PlayerMessage.newBuilder()
                 .addValues(Value.newBuilder().setInt32Value(
                             select? INVOKE_ID_SELECT_TRACK: INVOKE_ID_DESELECT_TRACK))
@@ -2460,10 +1898,6 @@
             mHandlerThread.quitSafely();
             mHandlerThread = null;
         }
-        if (mTimeProvider != null) {
-            mTimeProvider.close();
-            mTimeProvider = null;
-        }
 
         // Modular DRM clean up
         mOnDrmConfigHelper = null;
@@ -2500,17 +1934,6 @@
     private static final int MEDIA_DRM_INFO = 210;
     private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
 
-    private TimeProvider mTimeProvider;
-
-    /** @hide */
-    @Override
-    public MediaTimeProvider getMediaTimeProvider() {
-        if (mTimeProvider == null) {
-            mTimeProvider = new TimeProvider(this);
-        }
-        return mTimeProvider;
-    }
-
     private class TaskHandler extends Handler {
         private MediaPlayer2Impl mMediaPlayer;
 
@@ -2550,17 +1973,6 @@
             switch(msg.what) {
             case MEDIA_PREPARED:
             {
-                try {
-                    scanInternalSubtitleTracks();
-                } catch (RuntimeException e) {
-                    // send error message instead of crashing;
-                    // send error message instead of inlining a call to onError
-                    // to avoid code duplication.
-                    Message msg2 = obtainMessage(
-                            MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
-                    sendMessage(msg2);
-                }
-
                 if (dsd != null) {
                     sendEvent(new EventNotifier() {
                         @Override
@@ -2656,21 +2068,13 @@
             }
 
             case MEDIA_STOPPED:
-            {
-                TimeProvider timeProvider = mTimeProvider;
-                if (timeProvider != null) {
-                    timeProvider.onStopped();
-                }
-                break;
-            }
-
             case MEDIA_STARTED:
             case MEDIA_PAUSED:
+            case MEDIA_SKIPPED:
+            case MEDIA_NOTIFY_TIME:
             {
-                TimeProvider timeProvider = mTimeProvider;
-                if (timeProvider != null) {
-                    timeProvider.onPaused(msg.what == MEDIA_PAUSED);
-                }
+                // Do nothing. The client should have enough information with
+                // {@link EventCallback#onMediaTimeDiscontinuity}.
                 break;
             }
 
@@ -2706,15 +2110,6 @@
                         processPendingTask_l();
                     }
                 }
-            }
-                // fall through
-
-            case MEDIA_SKIPPED:
-            {
-                TimeProvider timeProvider = mTimeProvider;
-                if (timeProvider != null) {
-                    timeProvider.onSeekComplete(mMediaPlayer);
-                }
                 return;
             }
 
@@ -2759,33 +2154,6 @@
                     case MEDIA_INFO_VIDEO_TRACK_LAGGING:
                         Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
                         break;
-
-                    case MEDIA_INFO_METADATA_UPDATE:
-                        try {
-                            scanInternalSubtitleTracks();
-                        } catch (RuntimeException e) {
-                            Message msg2 = obtainMessage(
-                                    MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED,
-                                    null);
-                            sendMessage(msg2);
-                        }
-                        // fall through
-
-                    case MEDIA_INFO_EXTERNAL_METADATA_UPDATE:
-                        msg.arg1 = MEDIA_INFO_METADATA_UPDATE;
-                        // update default track selection
-                        if (mSubtitleController != null) {
-                            mSubtitleController.selectDefaultTrack();
-                        }
-                        break;
-
-                    case MEDIA_INFO_BUFFERING_START:
-                    case MEDIA_INFO_BUFFERING_END:
-                        TimeProvider timeProvider = mTimeProvider;
-                        if (timeProvider != null) {
-                            timeProvider.onBuffering(msg.arg1 == MEDIA_INFO_BUFFERING_START);
-                        }
-                        break;
                 }
 
                 sendEvent(new EventNotifier() {
@@ -2806,15 +2174,6 @@
                 return;
             }
 
-            case MEDIA_NOTIFY_TIME:
-            {
-                TimeProvider timeProvider = mTimeProvider;
-                if (timeProvider != null) {
-                    timeProvider.onNotifyTime();
-                }
-                return;
-            }
-
             case MEDIA_TIMED_TEXT:
             {
                 final TimedText text;
@@ -4241,396 +3600,6 @@
         }
     }
 
-    /** @hide */
-    static class TimeProvider implements MediaTimeProvider {
-        private static final String TAG = "MTP";
-        private static final long MAX_NS_WITHOUT_POSITION_CHECK = 5000000000L;
-        private static final long MAX_EARLY_CALLBACK_US = 1000;
-        private static final long TIME_ADJUSTMENT_RATE = 2;  /* meaning 1/2 */
-        private long mLastTimeUs = 0;
-        private MediaPlayer2Impl mPlayer;
-        private boolean mPaused = true;
-        private boolean mStopped = true;
-        private boolean mBuffering;
-        private long mLastReportedTime;
-        // since we are expecting only a handful listeners per stream, there is
-        // no need for log(N) search performance
-        private MediaTimeProvider.OnMediaTimeListener mListeners[];
-        private long mTimes[];
-        private EventHandler mEventHandler;
-        private boolean mRefresh = false;
-        private boolean mPausing = false;
-        private boolean mSeeking = false;
-        private static final int NOTIFY = 1;
-        private static final int NOTIFY_TIME = 0;
-        private static final int NOTIFY_STOP = 2;
-        private static final int NOTIFY_SEEK = 3;
-        private static final int NOTIFY_TRACK_DATA = 4;
-        private HandlerThread mHandlerThread;
-
-        /** @hide */
-        public boolean DEBUG = false;
-
-        public TimeProvider(MediaPlayer2Impl mp) {
-            mPlayer = mp;
-            try {
-                getCurrentTimeUs(true, false);
-            } catch (IllegalStateException e) {
-                // we assume starting position
-                mRefresh = true;
-            }
-
-            Looper looper;
-            if ((looper = Looper.myLooper()) == null &&
-                (looper = Looper.getMainLooper()) == null) {
-                // Create our own looper here in case MP was created without one
-                mHandlerThread = new HandlerThread("MediaPlayer2MTPEventThread",
-                      Process.THREAD_PRIORITY_FOREGROUND);
-                mHandlerThread.start();
-                looper = mHandlerThread.getLooper();
-            }
-            mEventHandler = new EventHandler(looper);
-
-            mListeners = new MediaTimeProvider.OnMediaTimeListener[0];
-            mTimes = new long[0];
-            mLastTimeUs = 0;
-        }
-
-        private void scheduleNotification(int type, long delayUs) {
-            // ignore time notifications until seek is handled
-            if (mSeeking && type == NOTIFY_TIME) {
-                return;
-            }
-
-            if (DEBUG) Log.v(TAG, "scheduleNotification " + type + " in " + delayUs);
-            mEventHandler.removeMessages(NOTIFY);
-            Message msg = mEventHandler.obtainMessage(NOTIFY, type, 0);
-            mEventHandler.sendMessageDelayed(msg, (int) (delayUs / 1000));
-        }
-
-        /** @hide */
-        public void close() {
-            mEventHandler.removeMessages(NOTIFY);
-            if (mHandlerThread != null) {
-                mHandlerThread.quitSafely();
-                mHandlerThread = null;
-            }
-        }
-
-        /** @hide */
-        protected void finalize() {
-            if (mHandlerThread != null) {
-                mHandlerThread.quitSafely();
-            }
-        }
-
-        /** @hide */
-        public void onNotifyTime() {
-            synchronized (this) {
-                if (DEBUG) Log.d(TAG, "onNotifyTime: ");
-                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
-            }
-        }
-
-        /** @hide */
-        public void onPaused(boolean paused) {
-            synchronized(this) {
-                if (DEBUG) Log.d(TAG, "onPaused: " + paused);
-                if (mStopped) { // handle as seek if we were stopped
-                    mStopped = false;
-                    mSeeking = true;
-                    scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
-                } else {
-                    mPausing = paused;  // special handling if player disappeared
-                    mSeeking = false;
-                    scheduleNotification(NOTIFY_TIME, 0 /* delay */);
-                }
-            }
-        }
-
-        /** @hide */
-        public void onBuffering(boolean buffering) {
-            synchronized (this) {
-                if (DEBUG) Log.d(TAG, "onBuffering: " + buffering);
-                mBuffering = buffering;
-                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
-            }
-        }
-
-        /** @hide */
-        public void onStopped() {
-            synchronized(this) {
-                if (DEBUG) Log.d(TAG, "onStopped");
-                mPaused = true;
-                mStopped = true;
-                mSeeking = false;
-                mBuffering = false;
-                scheduleNotification(NOTIFY_STOP, 0 /* delay */);
-            }
-        }
-
-        /** @hide */
-        public void onSeekComplete(MediaPlayer2Impl mp) {
-            synchronized(this) {
-                mStopped = false;
-                mSeeking = true;
-                scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
-            }
-        }
-
-        /** @hide */
-        public void onNewPlayer() {
-            if (mRefresh) {
-                synchronized(this) {
-                    mStopped = false;
-                    mSeeking = true;
-                    mBuffering = false;
-                    scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
-                }
-            }
-        }
-
-        private synchronized void notifySeek() {
-            mSeeking = false;
-            try {
-                long timeUs = getCurrentTimeUs(true, false);
-                if (DEBUG) Log.d(TAG, "onSeekComplete at " + timeUs);
-
-                for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
-                    if (listener == null) {
-                        break;
-                    }
-                    listener.onSeek(timeUs);
-                }
-            } catch (IllegalStateException e) {
-                // we should not be there, but at least signal pause
-                if (DEBUG) Log.d(TAG, "onSeekComplete but no player");
-                mPausing = true;  // special handling if player disappeared
-                notifyTimedEvent(false /* refreshTime */);
-            }
-        }
-
-        private synchronized void notifyTrackData(Pair<SubtitleTrack, byte[]> trackData) {
-            SubtitleTrack track = trackData.first;
-            byte[] data = trackData.second;
-            track.onData(data, true /* eos */, ~0 /* runID: keep forever */);
-        }
-
-        private synchronized void notifyStop() {
-            for (MediaTimeProvider.OnMediaTimeListener listener: mListeners) {
-                if (listener == null) {
-                    break;
-                }
-                listener.onStop();
-            }
-        }
-
-        private int registerListener(MediaTimeProvider.OnMediaTimeListener listener) {
-            int i = 0;
-            for (; i < mListeners.length; i++) {
-                if (mListeners[i] == listener || mListeners[i] == null) {
-                    break;
-                }
-            }
-
-            // new listener
-            if (i >= mListeners.length) {
-                MediaTimeProvider.OnMediaTimeListener[] newListeners =
-                    new MediaTimeProvider.OnMediaTimeListener[i + 1];
-                long[] newTimes = new long[i + 1];
-                System.arraycopy(mListeners, 0, newListeners, 0, mListeners.length);
-                System.arraycopy(mTimes, 0, newTimes, 0, mTimes.length);
-                mListeners = newListeners;
-                mTimes = newTimes;
-            }
-
-            if (mListeners[i] == null) {
-                mListeners[i] = listener;
-                mTimes[i] = MediaTimeProvider.NO_TIME;
-            }
-            return i;
-        }
-
-        public void notifyAt(
-                long timeUs, MediaTimeProvider.OnMediaTimeListener listener) {
-            synchronized(this) {
-                if (DEBUG) Log.d(TAG, "notifyAt " + timeUs);
-                mTimes[registerListener(listener)] = timeUs;
-                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
-            }
-        }
-
-        public void scheduleUpdate(MediaTimeProvider.OnMediaTimeListener listener) {
-            synchronized(this) {
-                if (DEBUG) Log.d(TAG, "scheduleUpdate");
-                int i = registerListener(listener);
-
-                if (!mStopped) {
-                    mTimes[i] = 0;
-                    scheduleNotification(NOTIFY_TIME, 0 /* delay */);
-                }
-            }
-        }
-
-        public void cancelNotifications(
-                MediaTimeProvider.OnMediaTimeListener listener) {
-            synchronized(this) {
-                int i = 0;
-                for (; i < mListeners.length; i++) {
-                    if (mListeners[i] == listener) {
-                        System.arraycopy(mListeners, i + 1,
-                                mListeners, i, mListeners.length - i - 1);
-                        System.arraycopy(mTimes, i + 1,
-                                mTimes, i, mTimes.length - i - 1);
-                        mListeners[mListeners.length - 1] = null;
-                        mTimes[mTimes.length - 1] = NO_TIME;
-                        break;
-                    } else if (mListeners[i] == null) {
-                        break;
-                    }
-                }
-
-                scheduleNotification(NOTIFY_TIME, 0 /* delay */);
-            }
-        }
-
-        private synchronized void notifyTimedEvent(boolean refreshTime) {
-            // figure out next callback
-            long nowUs;
-            try {
-                nowUs = getCurrentTimeUs(refreshTime, true);
-            } catch (IllegalStateException e) {
-                // assume we paused until new player arrives
-                mRefresh = true;
-                mPausing = true; // this ensures that call succeeds
-                nowUs = getCurrentTimeUs(refreshTime, true);
-            }
-            long nextTimeUs = nowUs;
-
-            if (mSeeking) {
-                // skip timed-event notifications until seek is complete
-                return;
-            }
-
-            if (DEBUG) {
-                StringBuilder sb = new StringBuilder();
-                sb.append("notifyTimedEvent(").append(mLastTimeUs).append(" -> ")
-                        .append(nowUs).append(") from {");
-                boolean first = true;
-                for (long time: mTimes) {
-                    if (time == NO_TIME) {
-                        continue;
-                    }
-                    if (!first) sb.append(", ");
-                    sb.append(time);
-                    first = false;
-                }
-                sb.append("}");
-                Log.d(TAG, sb.toString());
-            }
-
-            Vector<MediaTimeProvider.OnMediaTimeListener> activatedListeners =
-                new Vector<MediaTimeProvider.OnMediaTimeListener>();
-            for (int ix = 0; ix < mTimes.length; ix++) {
-                if (mListeners[ix] == null) {
-                    break;
-                }
-                if (mTimes[ix] <= NO_TIME) {
-                    // ignore, unless we were stopped
-                } else if (mTimes[ix] <= nowUs + MAX_EARLY_CALLBACK_US) {
-                    activatedListeners.add(mListeners[ix]);
-                    if (DEBUG) Log.d(TAG, "removed");
-                    mTimes[ix] = NO_TIME;
-                } else if (nextTimeUs == nowUs || mTimes[ix] < nextTimeUs) {
-                    nextTimeUs = mTimes[ix];
-                }
-            }
-
-            if (nextTimeUs > nowUs && !mPaused) {
-                // schedule callback at nextTimeUs
-                if (DEBUG) Log.d(TAG, "scheduling for " + nextTimeUs + " and " + nowUs);
-                mPlayer.notifyAt(nextTimeUs);
-            } else {
-                mEventHandler.removeMessages(NOTIFY);
-                // no more callbacks
-            }
-
-            for (MediaTimeProvider.OnMediaTimeListener listener: activatedListeners) {
-                listener.onTimedEvent(nowUs);
-            }
-        }
-
-        public long getCurrentTimeUs(boolean refreshTime, boolean monotonic)
-                throws IllegalStateException {
-            synchronized (this) {
-                // we always refresh the time when the paused-state changes, because
-                // we expect to have received the pause-change event delayed.
-                if (mPaused && !refreshTime) {
-                    return mLastReportedTime;
-                }
-
-                try {
-                    mLastTimeUs = mPlayer.getCurrentPosition() * 1000L;
-                    mPaused = !mPlayer.isPlaying() || mBuffering;
-                    if (DEBUG) Log.v(TAG, (mPaused ? "paused" : "playing") + " at " + mLastTimeUs);
-                } catch (IllegalStateException e) {
-                    if (mPausing) {
-                        // if we were pausing, get last estimated timestamp
-                        mPausing = false;
-                        if (!monotonic || mLastReportedTime < mLastTimeUs) {
-                            mLastReportedTime = mLastTimeUs;
-                        }
-                        mPaused = true;
-                        if (DEBUG) Log.d(TAG, "illegal state, but pausing: estimating at " + mLastReportedTime);
-                        return mLastReportedTime;
-                    }
-                    // TODO get time when prepared
-                    throw e;
-                }
-                if (monotonic && mLastTimeUs < mLastReportedTime) {
-                    /* have to adjust time */
-                    if (mLastReportedTime - mLastTimeUs > 1000000) {
-                        // schedule seeked event if time jumped significantly
-                        // TODO: do this properly by introducing an exception
-                        mStopped = false;
-                        mSeeking = true;
-                        scheduleNotification(NOTIFY_SEEK, 0 /* delay */);
-                    }
-                } else {
-                    mLastReportedTime = mLastTimeUs;
-                }
-
-                return mLastReportedTime;
-            }
-        }
-
-        private class EventHandler extends Handler {
-            public EventHandler(Looper looper) {
-                super(looper);
-            }
-
-            @Override
-            public void handleMessage(Message msg) {
-                if (msg.what == NOTIFY) {
-                    switch (msg.arg1) {
-                    case NOTIFY_TIME:
-                        notifyTimedEvent(true /* refreshTime */);
-                        break;
-                    case NOTIFY_STOP:
-                        notifyStop();
-                        break;
-                    case NOTIFY_SEEK:
-                        notifySeek();
-                        break;
-                    case NOTIFY_TRACK_DATA:
-                        notifyTrackData((Pair<SubtitleTrack, byte[]>)msg.obj);
-                        break;
-                    }
-                }
-            }
-        }
-    }
-
     private abstract class Task implements Runnable {
         private final int mMediaCallType;
         private final boolean mNeedToWaitForEventToComplete;
@@ -4651,6 +3620,17 @@
                         && getState() == PLAYER_STATE_ERROR) {
                     status = CALL_STATUS_INVALID_OPERATION;
                 } else {
+                    if (mMediaCallType == CALL_COMPLETED_SEEK_TO) {
+                        synchronized (mTaskLock) {
+                            if (!mPendingTasks.isEmpty()) {
+                                Task nextTask = mPendingTasks.get(0);
+                                if (nextTask.mMediaCallType == mMediaCallType) {
+                                    throw new CommandSkippedException(
+                                            "consecutive seekTo is skipped except last one");
+                                }
+                            }
+                        }
+                    }
                     process();
                 }
             } catch (IllegalStateException e) {
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 693a3d0..b52da36 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -769,18 +769,6 @@
                               NULL, NULL);
 }
 
-static void
-android_media_MediaPlayer2_notifyAt(JNIEnv *env, jobject thiz, jlong mediaTimeUs)
-{
-    sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
-    if (mp == NULL) {
-        jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return;
-    }
-    ALOGV("notifyAt: %lld", (long long)mediaTimeUs);
-    process_media_player_call( env, thiz, mp->notifyAt((int64_t)mediaTimeUs), NULL, NULL );
-}
-
 static jint
 android_media_MediaPlayer2_getState(JNIEnv *env, jobject thiz)
 {
@@ -1482,7 +1470,6 @@
     {"_setSyncParams",     "(Landroid/media/SyncParams;)V",  (void *)android_media_MediaPlayer2_setSyncParams},
     {"getSyncParams",     "()Landroid/media/SyncParams;",   (void *)android_media_MediaPlayer2_getSyncParams},
     {"_seekTo",             "(JI)V",                            (void *)android_media_MediaPlayer2_seekTo},
-    {"_notifyAt",           "(J)V",                             (void *)android_media_MediaPlayer2_notifyAt},
     {"_pause",              "()V",                              (void *)android_media_MediaPlayer2_pause},
     {"isPlaying",           "()Z",                              (void *)android_media_MediaPlayer2_isPlaying},
     {"getCurrentPosition",  "()J",                              (void *)android_media_MediaPlayer2_getCurrentPosition},
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index cdaabdc..d0ca04b 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -184,7 +184,6 @@
         if (shouldScan(mBluetoothFilters)) {
             final IntentFilter intentFilter = new IntentFilter();
             intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
-            intentFilter.addAction(BluetoothDevice.ACTION_DISAPPEARED);
 
             mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver();
             registerReceiver(mBluetoothBroadcastReceiver, intentFilter);
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index e645adc..03eb0d9 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -67,10 +67,6 @@
 LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
 
 LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# out/target/common/obj/APPS/CtsShimPriv_intermediates/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_PACKAGE)
 
@@ -113,10 +109,6 @@
 LOCAL_MANIFEST_FILE := shim/AndroidManifest.xml
 
 LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/packages/CtsShim/build/shim/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_PACKAGE)
 
diff --git a/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
index 164fc5a..9855565 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
@@ -26,15 +26,16 @@
     private var _insets: WindowInsets? = null
 
     constructor(context: Context) : super(context) {
-        init(null, 0)
     }
 
     constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
-        init(attrs, 0)
     }
 
-    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
-        init(attrs, defStyle)
+    constructor(
+        context: Context,
+        attrs: AttributeSet,
+        defStyle: Int
+    ) : super(context, attrs, defStyle) {
     }
 
     override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
@@ -81,8 +82,4 @@
             requestLayout()
         }
     }
-
-    private fun init(attrs: AttributeSet?, defStyle: Int) {
-    }
-
 }
diff --git a/packages/EasterEgg/src/com/android/egg/paint/Painting.kt b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
index a4a3d3d..fc7e8b0 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
@@ -17,7 +17,6 @@
 package com.android.egg.paint
 
 import android.content.Context
-import android.content.res.Resources
 import android.graphics.*
 import android.provider.Settings
 import android.util.AttributeSet
@@ -26,7 +25,6 @@
 import android.view.View
 import android.view.WindowInsets
 import java.util.concurrent.TimeUnit
-import android.util.Log
 import android.provider.Settings.System
 
 import org.json.JSONObject
@@ -86,11 +84,11 @@
         }
 
     var bitmap: Bitmap? = null
-    var paperColor : Int = 0xFFFFFFFF.toInt()
+    var paperColor: Int = 0xFFFFFFFF.toInt()
 
     private var _paintCanvas: Canvas? = null
     private val _bitmapLock = Object()
-    
+
     private var _drawPaint = Paint(Paint.ANTI_ALIAS_FLAG)
     private var _lastX = 0f
     private var _lastY = 0f
@@ -113,7 +111,9 @@
                         FADE_TO_BLACK_CF
 
                 synchronized(_bitmapLock) {
-                    c.drawBitmap(bitmap, 0f, 0f, pt)
+                    bitmap?.let {
+                        c.drawBitmap(bitmap!!, 0f, 0f, pt)
+                    }
                 }
                 invalidate()
             }
@@ -122,18 +122,22 @@
     }
 
     constructor(context: Context) : super(context) {
-        init(null, 0)
+        init()
     }
 
     constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
-        init(attrs, 0)
+        init()
     }
 
-    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
-        init(attrs, defStyle)
+    constructor(
+        context: Context,
+        attrs: AttributeSet,
+        defStyle: Int
+    ) : super(context, attrs, defStyle) {
+        init()
     }
 
-    private fun init(attrs: AttributeSet?, defStyle: Int) {
+    private fun init() {
         loadDevicePressureData()
     }
 
@@ -264,7 +268,7 @@
         super.onDraw(canvas)
 
         bitmap?.let {
-            canvas.drawBitmap(bitmap, 0f, 0f, _drawPaint);
+            canvas.drawBitmap(bitmap!!, 0f, 0f, _drawPaint)
         }
     }
 
@@ -330,8 +334,8 @@
                 }
                 if (bits.width != oldBits.height || bits.height != oldBits.width) {
                     matrix.postScale(
-                            bits.width.toFloat()/oldBits.height,
-                            bits.height.toFloat()/oldBits.width)
+                            bits.width.toFloat() / oldBits.height,
+                            bits.height.toFloat() / oldBits.width)
                 }
                 c.matrix = matrix
             }
@@ -350,9 +354,10 @@
         val invertPaint = Paint()
         invertPaint.colorFilter = INVERT_CF
         synchronized(_bitmapLock) {
-            _paintCanvas?.drawBitmap(bitmap, 0f, 0f, invertPaint)
+            bitmap?.let {
+                _paintCanvas?.drawBitmap(bitmap!!, 0f, 0f, invertPaint)
+            }
         }
         invalidate()
     }
 }
-
diff --git a/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
index 86b11e7..460fa3a 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
@@ -17,19 +17,10 @@
 package com.android.egg.paint
 
 import android.content.Context
-import android.graphics.Canvas
-import android.graphics.Color
-import android.graphics.Paint
-import android.graphics.Rect
-import android.graphics.drawable.Drawable
-import android.text.TextPaint
-import android.transition.ChangeBounds
 import android.transition.Transition
 import android.transition.TransitionListenerAdapter
-import android.transition.TransitionManager
 import android.util.AttributeSet
 import android.view.*
-import android.view.animation.OvershootInterpolator
 import android.widget.FrameLayout
 
 class ToolbarView : FrameLayout {
@@ -44,15 +35,16 @@
     }
 
     constructor(context: Context) : super(context) {
-        init(null, 0)
     }
 
     constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
-        init(attrs, 0)
     }
 
-    constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
-        init(attrs, defStyle)
+    constructor(
+        context: Context,
+        attrs: AttributeSet,
+        defStyle: Int
+    ) : super(context, attrs, defStyle) {
     }
 
     override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
@@ -70,8 +62,4 @@
 
         return super.onApplyWindowInsets(insets)
     }
-
-    private fun init(attrs: AttributeSet?, defStyle: Int) {
-    }
-
 }
diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml
index 7c81399..4801f62 100644
--- a/packages/PackageInstaller/AndroidManifest.xml
+++ b/packages/PackageInstaller/AndroidManifest.xml
@@ -12,6 +12,7 @@
     <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
     <uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
 
     <uses-permission android:name="com.google.android.permission.INSTALL_WEARABLE_PACKAGES" />
 
diff --git a/packages/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml
index ba81278..0f065ab 100644
--- a/packages/PackageInstaller/res/values/strings.xml
+++ b/packages/PackageInstaller/res/values/strings.xml
@@ -228,4 +228,14 @@
     <!-- Label for the notification channel containing notifications for embedded app operations [CHAR LIMIT=40] -->
     <string name="wear_app_channel">Installing/uninstalling wear apps</string>
 
+    <!-- Description for the app installer notification channel [CHAR LIMIT=40] -->
+    <string name="app_installed_notification_channel_description">App installed notification</string>
+
+    <!-- Notification message shown in status bar when an application is successfully installed.
+         [CHAR LIMIT=30] -->
+    <string name="notification_installation_success_message">Successfully installed</string>
+
+    <!-- Notification shown in status bar when an application is successfully installed.
+         [CHAR LIMIT=50] -->
+    <string name="notification_installation_success_status">Successfully installed \u201c<xliff:g id="appname" example="Package Installer">%1$s</xliff:g>\u201d</string>
 </resources>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
index b3f1105..8fed367 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
@@ -106,6 +106,9 @@
 
             if (packageUri != null && (packageUri.getScheme().equals(ContentResolver.SCHEME_FILE)
                     || packageUri.getScheme().equals(ContentResolver.SCHEME_CONTENT))) {
+                // [IMPORTANT] This path is deprecated, but should still work. Only necessary
+                // features should be added.
+
                 // Copy file to prevent it from being changed underneath this process
                 nextActivity.setClass(this, InstallStaging.class);
             } else if (packageUri != null && packageUri.getScheme().equals(
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java
new file mode 100644
index 0000000..2ebbefa
--- /dev/null
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledNotificationUtils.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.packageinstaller;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.Log;
+
+/**
+ * A util class that handle and post new app installed notifications.
+ */
+class PackageInstalledNotificationUtils {
+    private static final String TAG = PackageInstalledNotificationUtils.class.getSimpleName();
+
+    private static final String NEW_APP_INSTALLED_CHANNEL_ID_PREFIX = "INSTALLER:";
+    private static final String META_DATA_INSTALLER_NOTIFICATION_SMALL_ICON_KEY =
+            "com.android.packageinstaller.notification.smallIcon";
+    private static final String META_DATA_INSTALLER_NOTIFICATION_COLOR_KEY =
+            "com.android.packageinstaller.notification.color";
+
+    private static final float DEFAULT_MAX_LABEL_SIZE_PX = 500f;
+
+    private final Context mContext;
+    private final NotificationManager mNotificationManager;
+
+    private final String mInstallerPackage;
+    private final String mInstallerAppLabel;
+    private final Icon mInstallerAppSmallIcon;
+    private final Integer mInstallerAppColor;
+
+    private final String mInstalledPackage;
+    private final String mInstalledAppLabel;
+    private final Icon mInstalledAppLargeIcon;
+
+    private final String mChannelId;
+
+    PackageInstalledNotificationUtils(@NonNull Context context, @NonNull String installerPackage,
+            @NonNull String installedPackage) {
+        mContext = context;
+        mNotificationManager = context.getSystemService(NotificationManager.class);
+        ApplicationInfo installerAppInfo;
+        ApplicationInfo installedAppInfo;
+
+        try {
+            installerAppInfo = context.getPackageManager().getApplicationInfo(installerPackage,
+                    PackageManager.GET_META_DATA);
+        } catch (PackageManager.NameNotFoundException e) {
+            // Should not happen
+            throw new IllegalStateException("Unable to get application info: " + installerPackage);
+        }
+        try {
+            installedAppInfo = context.getPackageManager().getApplicationInfo(installedPackage,
+                    PackageManager.GET_META_DATA);
+        } catch (PackageManager.NameNotFoundException e) {
+            // Should not happen
+            throw new IllegalStateException("Unable to get application info: " + installedPackage);
+        }
+        mInstallerPackage = installerPackage;
+        mInstallerAppLabel = getAppLabel(context, installerAppInfo, installerPackage);
+        mInstallerAppSmallIcon = getAppNotificationIcon(context, installerAppInfo);
+        mInstallerAppColor = getAppNotificationColor(context, installerAppInfo);
+
+        mInstalledPackage = installedPackage;
+        mInstalledAppLabel = getAppLabel(context, installedAppInfo, installerPackage);
+        mInstalledAppLargeIcon = getAppLargeIcon(installedAppInfo);
+
+        mChannelId = NEW_APP_INSTALLED_CHANNEL_ID_PREFIX + installerPackage;
+    }
+
+    /**
+     * Get app label from app's manifest.
+     *
+     * @param context     A context of the current app
+     * @param appInfo     Application info of targeted app
+     * @param packageName Package name of targeted app
+     * @return The label of targeted application, or package name if label is not found
+     */
+    private static String getAppLabel(@NonNull Context context, @NonNull ApplicationInfo appInfo,
+            @NonNull String packageName) {
+        CharSequence label = appInfo.loadSafeLabel(context.getPackageManager(),
+                DEFAULT_MAX_LABEL_SIZE_PX,
+                PackageItemInfo.SAFE_LABEL_FLAG_TRIM
+                        | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE).toString();
+        if (label != null) {
+            return label.toString();
+        }
+        return packageName;
+    }
+
+    /**
+     * The app icon from app's manifest.
+     *
+     * @param appInfo Application info of targeted app
+     * @return App icon of targeted app, or Android default app icon if icon is not found
+     */
+    private static Icon getAppLargeIcon(@NonNull ApplicationInfo appInfo) {
+        if (appInfo.icon != 0) {
+            return Icon.createWithResource(appInfo.packageName, appInfo.icon);
+        } else {
+            return Icon.createWithResource("android", android.R.drawable.sym_def_app_icon);
+        }
+    }
+
+    /**
+     * Get notification icon from installer's manifest meta-data.
+     *
+     * @param context A context of the current app
+     * @param appInfo Installer application info
+     * @return Notification icon that listed in installer's manifest meta-data.
+     * If icon is not found in meta-data, then it returns Android default download icon.
+     */
+    private static Icon getAppNotificationIcon(@NonNull Context context,
+            @NonNull ApplicationInfo appInfo) {
+        if (appInfo.metaData == null) {
+            return Icon.createWithResource(context, R.drawable.ic_file_download);
+        }
+
+        int iconResId = appInfo.metaData.getInt(
+                META_DATA_INSTALLER_NOTIFICATION_SMALL_ICON_KEY, 0);
+        if (iconResId != 0) {
+            return Icon.createWithResource(appInfo.packageName, iconResId);
+        }
+        return Icon.createWithResource(context, R.drawable.ic_file_download);
+    }
+
+    /**
+     * Get notification color from installer's manifest meta-data.
+     *
+     * @param context A context of the current app
+     * @param appInfo Installer application info
+     * @return Notification color that listed in installer's manifest meta-data, or null if
+     * meta-data is not found.
+     */
+    private static Integer getAppNotificationColor(@NonNull Context context,
+            @NonNull ApplicationInfo appInfo) {
+        if (appInfo.metaData == null) {
+            return null;
+        }
+
+        int colorResId = appInfo.metaData.getInt(
+                META_DATA_INSTALLER_NOTIFICATION_COLOR_KEY, 0);
+        if (colorResId != 0) {
+            try {
+                PackageManager pm = context.getPackageManager();
+                Resources resources = pm.getResourcesForApplication(appInfo.packageName);
+                return resources.getColor(colorResId, context.getTheme());
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.e(TAG, "Error while loading notification color: " + colorResId + " for "
+                        + appInfo.packageName);
+            }
+        }
+        return null;
+    }
+
+    private static Intent getAppDetailIntent(@NonNull String packageName) {
+        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+        intent.setData(Uri.fromParts("package", packageName, null));
+        return intent;
+    }
+
+    private static Intent resolveIntent(@NonNull Context context, @NonNull Intent i) {
+        ResolveInfo result = context.getPackageManager().resolveActivity(i, 0);
+        if (result == null) {
+            return null;
+        }
+        return new Intent(i.getAction()).setClassName(result.activityInfo.packageName,
+                result.activityInfo.name);
+    }
+
+    private static Intent getAppStoreLink(@NonNull Context context,
+            @NonNull String installerPackageName, @NonNull String packageName) {
+        Intent intent = new Intent(Intent.ACTION_SHOW_APP_INFO)
+                .setPackage(installerPackageName);
+
+        Intent result = resolveIntent(context, intent);
+        if (result != null) {
+            result.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+            return result;
+        }
+        return null;
+    }
+
+    /**
+     * Create notification channel for showing apps installed notifications.
+     */
+    private void createChannel() {
+        NotificationChannel channel = new NotificationChannel(mChannelId, mInstallerAppLabel,
+                NotificationManager.IMPORTANCE_DEFAULT);
+        channel.setDescription(
+                mContext.getString(R.string.app_installed_notification_channel_description));
+        channel.enableVibration(false);
+        channel.setSound(null, null);
+        channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
+        channel.setBlockableSystem(true);
+
+        mNotificationManager.createNotificationChannel(channel);
+    }
+
+    /**
+     * Returns a pending intent when user clicks on apps installed notification.
+     * It should launch the app if possible, otherwise it will return app store's app page.
+     * If app store's app page is not available, it will return Android app details page.
+     */
+    private PendingIntent getInstalledAppLaunchIntent() {
+        Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(mInstalledPackage);
+
+        // If installed app does not have a launch intent, bring user to app store page
+        if (intent == null) {
+            intent = getAppStoreLink(mContext, mInstallerPackage, mInstalledPackage);
+        }
+
+        // If app store cannot handle this, bring user to app settings page
+        if (intent == null) {
+            intent = getAppDetailIntent(mInstalledPackage);
+        }
+
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return PendingIntent.getActivity(mContext,
+                0 /* request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+    }
+
+    /**
+     * Returns a pending intent that starts installer's launch intent.
+     * If it doesn't have a launch intent, it will return installer's Android app details page.
+     */
+    private PendingIntent getInstallerEntranceIntent() {
+        Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(mInstallerPackage);
+
+        // If installer does not have a launch intent, bring user to app settings page
+        if (intent == null) {
+            intent = getAppDetailIntent(mInstallerPackage);
+        }
+
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return PendingIntent.getActivity(mContext,
+                0 /* request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+    }
+
+    /**
+     * Returns a notification builder for grouped notifications.
+     */
+    private Notification.Builder getGroupNotificationBuilder() {
+        PendingIntent contentIntent = getInstallerEntranceIntent();
+
+        Bundle extras = new Bundle();
+        extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, mInstallerAppLabel);
+
+        Notification.Builder builder =
+                new Notification.Builder(mContext, mChannelId)
+                        .setSmallIcon(mInstallerAppSmallIcon)
+                        .setGroup(mChannelId)
+                        .setExtras(extras)
+                        .setLocalOnly(true)
+                        .setCategory(Notification.CATEGORY_STATUS)
+                        .setContentIntent(contentIntent)
+                        .setGroupSummary(true);
+
+        if (mInstallerAppColor != null) {
+            builder.setColor(mInstallerAppColor);
+        }
+        return builder;
+    }
+
+    /**
+     * Returns notification build for individual installed applications.
+     */
+    private Notification.Builder getAppInstalledNotificationBuilder() {
+        PendingIntent contentIntent = getInstalledAppLaunchIntent();
+
+        Bundle extras = new Bundle();
+        extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, mInstallerAppLabel);
+
+        String tickerText = String.format(
+                mContext.getString(R.string.notification_installation_success_status),
+                mInstalledAppLabel);
+
+        Notification.Builder builder =
+                new Notification.Builder(mContext, mChannelId)
+                        .setAutoCancel(true)
+                        .setSmallIcon(mInstallerAppSmallIcon)
+                        .setContentTitle(mInstalledAppLabel)
+                        .setContentText(mContext.getString(
+                                R.string.notification_installation_success_message))
+                        .setContentIntent(contentIntent)
+                        .setTicker(tickerText)
+                        .setCategory(Notification.CATEGORY_STATUS)
+                        .setShowWhen(true)
+                        .setWhen(System.currentTimeMillis())
+                        .setLocalOnly(true)
+                        .setGroup(mChannelId)
+                        .addExtras(extras)
+                        .setStyle(new Notification.BigTextStyle());
+
+        if (mInstalledAppLargeIcon != null) {
+            builder.setLargeIcon(mInstalledAppLargeIcon);
+        }
+        if (mInstallerAppColor != null) {
+            builder.setColor(mInstallerAppColor);
+        }
+        return builder;
+    }
+
+    /**
+     * Post new app installed notification.
+     */
+    void postAppInstalledNotification() {
+        createChannel();
+
+        // Post app installed notification
+        Notification.Builder appNotificationBuilder = getAppInstalledNotificationBuilder();
+        mNotificationManager.notify(mInstalledPackage, mInstalledPackage.hashCode(),
+                appNotificationBuilder.build());
+
+        // Post installer group notification
+        Notification.Builder groupNotificationBuilder = getGroupNotificationBuilder();
+        mNotificationManager.notify(mInstallerPackage, mInstallerPackage.hashCode(),
+                groupNotificationBuilder.build());
+    }
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
index 67ac99f..1eb423e 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstalledReceiver.java
@@ -19,16 +19,54 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.net.Uri;
+import android.util.Log;
 
 /**
  * Receive new app installed broadcast and notify user new app installed.
  */
 public class PackageInstalledReceiver extends BroadcastReceiver {
+    private static final String TAG = PackageInstalledReceiver.class.getSimpleName();
 
-    private static final String TAG = "PackageInstalledReceiver";
+    private static final boolean DEBUG = false;
+    private static final boolean APP_INSTALLED_NOTIFICATION_ENABLED = false;
 
     @Override
     public void onReceive(Context context, Intent intent) {
-        // TODO: Add logic to handle new app installed.
+        if (!APP_INSTALLED_NOTIFICATION_ENABLED) {
+            return;
+        }
+
+        String action = intent.getAction();
+
+        if (DEBUG) {
+            Log.i(TAG, "Received action: " + action);
+        }
+
+        if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+            Uri packageUri = intent.getData();
+            if (packageUri == null) {
+                return;
+            }
+
+            String packageName = packageUri.getSchemeSpecificPart();
+            if (packageName == null) {
+                Log.e(TAG, "No package name");
+                return;
+            }
+
+            if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                if (DEBUG) {
+                    Log.i(TAG, "Not new app, skip it: " + packageName);
+                }
+                return;
+            }
+
+            // TODO: Make sure the installer information here is accurate
+            String installer =
+                    context.getPackageManager().getInstallerPackageName(packageName);
+            new PackageInstalledNotificationUtils(context, installer,
+                    packageName).postAppInstalledNotification();
+        }
     }
 }
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerApplication.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerApplication.java
index 9b7e64e..a0f0ae9 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerApplication.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerApplication.java
@@ -23,6 +23,6 @@
     @Override
     public void onCreate() {
         super.onCreate();
-        PackageItemInfo.setForceSafeLabels(true);
+        PackageItemInfo.forceSafeLabels();
     }
 }
diff --git a/packages/PrintSpooler/Android.bp b/packages/PrintSpooler/Android.bp
new file mode 100644
index 0000000..c40a817
--- /dev/null
+++ b/packages/PrintSpooler/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2013 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.
+
+android_app {
+    name: "PrintSpooler",
+
+    resource_dirs: ["res"],
+
+    srcs: [
+        "src/**/*.java",
+        "src/com/android/printspooler/renderer/IPdfRenderer.aidl",
+        "src/com/android/printspooler/renderer/IPdfEditor.aidl",
+    ],
+
+    platform_apis: true,
+
+    jni_libs: ["libprintspooler_jni"],
+    static_libs: [
+        "android-support-v7-recyclerview",
+        "android-support-compat",
+        "android-support-media-compat",
+        "android-support-core-utils",
+        "android-support-core-ui",
+        "android-support-fragment",
+        "android-support-annotations",
+    ],
+}
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk
deleted file mode 100644
index e356f38..0000000
--- a/packages/PrintSpooler/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2013 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_USE_AAPT2 := true
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SRC_FILES += \
-    src/com/android/printspooler/renderer/IPdfRenderer.aidl \
-    src/com/android/printspooler/renderer/IPdfEditor.aidl
-
-LOCAL_PACKAGE_NAME := PrintSpooler
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_JNI_SHARED_LIBRARIES := libprintspooler_jni
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-    android-support-v7-recyclerview \
-    android-support-compat \
-    android-support-media-compat \
-    android-support-core-utils \
-    android-support-core-ui \
-    android-support-fragment
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-annotations
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/PrintSpooler/tests/Android.mk b/packages/PrintSpooler/tests/Android.mk
deleted file mode 100644
index 83e00ce..0000000
--- a/packages/PrintSpooler/tests/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.bp b/packages/PrintSpooler/tests/outofprocess/Android.bp
new file mode 100644
index 0000000..e88074e
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2016 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.
+
+android_test {
+    name: "PrintSpoolerOutOfProcessTests",
+
+    srcs: ["src/**/*.java"],
+
+    libs: ["android.test.runner.stubs"],
+    static_libs: [
+        "android-support-test",
+        "ub-uiautomator",
+        "mockito-target-minus-junit4",
+        "print-test-util-lib",
+    ],
+
+    sdk_version: "test_current",
+    test_suites: ["device-tests"],
+}
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.mk b/packages/PrintSpooler/tests/outofprocess/Android.mk
deleted file mode 100644
index 161a600..0000000
--- a/packages/PrintSpooler/tests/outofprocess/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2016 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4 print-test-util-lib
-
-LOCAL_PACKAGE_NAME := PrintSpoolerOutOfProcessTests
-LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 89438e5..d60dbe7 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -16,6 +16,7 @@
         "SettingsLibRestrictedLockUtils",
         "SettingsLibAppPreference",
         "SettingsLibSearchWidget",
+        "SettingsLibSettingsSpinner",
     ],
 
     // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
diff --git a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
index 738181d..b87c9e8 100644
--- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
@@ -33,13 +33,13 @@
  * support message dialog.
  */
 public class RestrictedLockUtils {
-    public static EnforcedAdmin getProfileOrDeviceOwner(Context context, int userId) {
-        return getProfileOrDeviceOwner(context, null, userId);
+    public static EnforcedAdmin getProfileOrDeviceOwner(Context context, UserHandle user) {
+        return getProfileOrDeviceOwner(context, null, user);
     }
 
     public static EnforcedAdmin getProfileOrDeviceOwner(
-            Context context, String enforcedRestriction, int userId) {
-        if (userId == UserHandle.USER_NULL) {
+            Context context, String enforcedRestriction, UserHandle user) {
+        if (user == null) {
             return null;
         }
         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
@@ -47,14 +47,14 @@
         if (dpm == null) {
             return null;
         }
-        ComponentName adminComponent = dpm.getProfileOwnerAsUser(userId);
+        ComponentName adminComponent = dpm.getProfileOwnerAsUser(user);
         if (adminComponent != null) {
-            return new EnforcedAdmin(adminComponent, enforcedRestriction, userId);
+            return new EnforcedAdmin(adminComponent, enforcedRestriction, user);
         }
-        if (dpm.getDeviceOwnerUserId() == userId) {
+        if (Objects.equals(dpm.getDeviceOwnerUser(), user)) {
             adminComponent = dpm.getDeviceOwnerComponentOnAnyUser();
             if (adminComponent != null) {
-                return new EnforcedAdmin(adminComponent, enforcedRestriction, userId);
+                return new EnforcedAdmin(adminComponent, enforcedRestriction, user);
             }
         }
         return null;
@@ -66,9 +66,9 @@
     public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
         final Intent intent = getShowAdminSupportDetailsIntent(context, admin);
         int targetUserId = UserHandle.myUserId();
-        if (admin != null && admin.userId != UserHandle.USER_NULL
-                && isCurrentUserOrProfile(context, admin.userId)) {
-            targetUserId = admin.userId;
+        if (admin != null && admin.user != null
+                && isCurrentUserOrProfile(context, admin.user.getIdentifier())) {
+            targetUserId = admin.user.getIdentifier();
         }
         intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, admin.enforcedRestriction);
         context.startActivityAsUser(intent, UserHandle.of(targetUserId));
@@ -81,8 +81,8 @@
                 intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin.component);
             }
             int adminUserId = UserHandle.myUserId();
-            if (admin.userId != UserHandle.USER_NULL) {
-                adminUserId = admin.userId;
+            if (admin.user != null) {
+                adminUserId = admin.user.getIdentifier();
             }
             intent.putExtra(Intent.EXTRA_USER_ID, adminUserId);
         }
@@ -109,7 +109,8 @@
          */
         @Nullable
         public String enforcedRestriction = null;
-        public int userId = UserHandle.USER_NULL;
+        @Nullable
+        public UserHandle user = null;
 
         // We use this to represent the case where a policy is enforced by multiple admins.
         public final static EnforcedAdmin MULTIPLE_ENFORCED_ADMIN = new EnforcedAdmin();
@@ -121,15 +122,15 @@
             return enforcedAdmin;
         }
 
-        public EnforcedAdmin(ComponentName component, int userId) {
+        public EnforcedAdmin(ComponentName component, UserHandle user) {
             this.component = component;
-            this.userId = userId;
+            this.user = user;
         }
 
-        public EnforcedAdmin(ComponentName component, String enforcedRestriction, int userId) {
+        public EnforcedAdmin(ComponentName component, String enforcedRestriction, UserHandle user) {
             this.component = component;
             this.enforcedRestriction = enforcedRestriction;
-            this.userId = userId;
+            this.user = user;
         }
 
         public EnforcedAdmin(EnforcedAdmin other) {
@@ -138,7 +139,7 @@
             }
             this.component = other.component;
             this.enforcedRestriction = other.enforcedRestriction;
-            this.userId = other.userId;
+            this.user = other.user;
         }
 
         public EnforcedAdmin() {
@@ -149,14 +150,14 @@
             if (this == o) return true;
             if (o == null || getClass() != o.getClass()) return false;
             EnforcedAdmin that = (EnforcedAdmin) o;
-            return userId == that.userId &&
+            return Objects.equals(user, that.user) &&
                     Objects.equals(component, that.component) &&
                     Objects.equals(enforcedRestriction, that.enforcedRestriction);
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(component, enforcedRestriction, userId);
+            return Objects.hash(component, enforcedRestriction, user);
         }
 
         @Override
@@ -164,7 +165,7 @@
             return "EnforcedAdmin{" +
                     "component=" + component +
                     ", enforcedRestriction='" + enforcedRestriction +
-                    ", userId=" + userId +
+                    ", user=" + user +
                     '}';
         }
     }
diff --git a/packages/SettingsLib/SettingsSpinner/Android.bp b/packages/SettingsLib/SettingsSpinner/Android.bp
new file mode 100644
index 0000000..f18917c
--- /dev/null
+++ b/packages/SettingsLib/SettingsSpinner/Android.bp
@@ -0,0 +1,9 @@
+android_library {
+    name: "SettingsLibSettingsSpinner",
+
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+
+    sdk_version: "system_current",
+    min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/SettingsSpinner/AndroidManifest.xml b/packages/SettingsLib/SettingsSpinner/AndroidManifest.xml
new file mode 100644
index 0000000..5db9335
--- /dev/null
+++ b/packages/SettingsLib/SettingsSpinner/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.settingslib.widget.settingsspinner">
+
+    <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/SettingsSpinner/res/drawable/arrow_drop_down_24dp.xml b/packages/SettingsLib/SettingsSpinner/res/drawable/arrow_drop_down_24dp.xml
new file mode 100644
index 0000000..827d0b5
--- /dev/null
+++ b/packages/SettingsLib/SettingsSpinner/res/drawable/arrow_drop_down_24dp.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2018 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:width="24dp"
+        android:height="24dp">
+    <path
+        android:pathData="M7 10l5 5 5 -5z"
+        android:fillColor="?android:attr/textColorPrimary"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml b/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml
new file mode 100644
index 0000000..af30425
--- /dev/null
+++ b/packages/SettingsLib/SettingsSpinner/res/drawable/settings_spinner_background.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+            android:paddingMode="stack">
+    <item>
+        <shape>
+            <corners
+                android:radius="20dp"/>
+            <stroke
+                android:color="?android:attr/textColorSecondary"
+                android:width="1dp"/>
+            <size
+                android:height="32dp"/>
+        </shape>
+    </item>
+
+    <item
+        android:gravity="center|end"
+        android:width="24dp"
+        android:height="24dp"
+        android:end="4dp"
+        android:drawable="@drawable/arrow_drop_down_24dp"/>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsSpinner/res/layout/settings_spinner_view.xml b/packages/SettingsLib/SettingsSpinner/res/layout/settings_spinner_view.xml
new file mode 100644
index 0000000..bdd370f
--- /dev/null
+++ b/packages/SettingsLib/SettingsSpinner/res/layout/settings_spinner_view.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    style="@style/SettingsSpinnerTitleBar"
+    android:maxLines="1"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:ellipsize="marquee"/>
diff --git a/packages/SettingsLib/SettingsSpinner/res/values/styles.xml b/packages/SettingsLib/SettingsSpinner/res/values/styles.xml
new file mode 100644
index 0000000..8447b08
--- /dev/null
+++ b/packages/SettingsLib/SettingsSpinner/res/values/styles.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  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.
+  -->
+
+<resources>
+    <style name="SettingsSpinnerTitleBar">
+        <item name="android:textAppearance">?android:attr/textAppearance</item>
+        <item name="android:paddingStart">16dp</item>
+        <item name="android:paddingEnd">36dp</item>
+        <item name="android:paddingTop">8dp</item>
+        <item name="android:paddingBottom">8dp</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java
new file mode 100644
index 0000000..130cef2
--- /dev/null
+++ b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java
@@ -0,0 +1,122 @@
+/*
+ * 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.settingslib.widget.settingsspinner;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.Spinner;
+
+/**
+ * A {@link Spinner} with settings style.
+ *
+ * The items in the SettingsSpinner come from the {@link SettingsSpinnerAdapter} associated with
+ * this view.
+ */
+public class SettingsSpinner extends Spinner {
+
+    /**
+     * Constructs a new SettingsSpinner with the given context's theme.
+     * And it also set a background resource with settings style.
+     *
+     * @param context The Context the view is running in, through which it can
+     *                access the current theme, resources, etc.
+     */
+    public SettingsSpinner(Context context) {
+        super(context);
+        setBackgroundResource(R.drawable.settings_spinner_background);
+    }
+
+    /**
+     * Constructs a new SettingsSpinner with the given context's theme and the supplied
+     * mode of displaying choices. <code>mode</code> may be one of
+     * {@link Spinner#MODE_DIALOG} or {@link Spinner#MODE_DROPDOWN}.
+     * And it also set a background resource with settings style.
+     *
+     * @param context The Context the view is running in, through which it can
+     *                access the current theme, resources, etc.
+     * @param mode Constant describing how the user will select choices from
+     *             the spinner.
+     *
+     * @see Spinner#MODE_DIALOG
+     * @see Spinner#MODE_DROPDOWN
+     */
+    public SettingsSpinner(Context context, int mode) {
+        super(context, mode);
+        setBackgroundResource(R.drawable.settings_spinner_background);
+    }
+
+    /**
+     * Constructs a new SettingsSpinner with the given context's theme and the supplied
+     * attribute set.
+     * And it also set a background resource with settings 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.
+     */
+    public SettingsSpinner(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setBackgroundResource(R.drawable.settings_spinner_background);
+    }
+
+    /**
+     * Constructs a new SettingsSpinner with the given context's theme, the supplied
+     * attribute set, and default style attribute.
+     * And it also set a background resource with settings 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 SettingsSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        setBackgroundResource(R.drawable.settings_spinner_background);
+    }
+
+    /**
+     * Constructs a new SettingsSpinner with the given context's theme, the supplied
+     * attribute set, and default styles. <code>mode</code> may be one of
+     * {@link Spinner#MODE_DIALOG} or {@link Spinner#MODE_DROPDOWN} and determines how the
+     * user will select choices from the spinner.
+     * And it also set a background resource with settings 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.
+     * @param mode Constant describing how the user will select choices from
+     *             the spinner.
+     *
+     * @see Spinner#MODE_DIALOG
+     * @see Spinner#MODE_DROPDOWN
+     */
+    public SettingsSpinner(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes,
+            int mode) {
+        super(context, attrs, defStyleAttr, defStyleRes, mode, null);
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java
new file mode 100644
index 0000000..8bf8fce
--- /dev/null
+++ b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java
@@ -0,0 +1,40 @@
+/*
+ * 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.settingslib.widget.settingsspinner;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+
+/**
+ * An ArrayAdapter which was used by {@link SettingsSpinner} with settings style.
+ */
+public class SettingsSpinnerAdapter<T> extends ArrayAdapter<T> {
+
+    /**
+     * Constructs a new SettingsSpinnerAdapter with the given context.
+     * And it customizes title bar with a settings style.
+     *
+     * @param context The Context the view is running in, through which it can
+     *                access the current theme, resources, etc.
+     */
+    public SettingsSpinnerAdapter(Context context) {
+        super(context, R.layout.settings_spinner_view);
+        setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index c03ba9a..f57122e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -164,6 +164,17 @@
     }
 
     /**
+     * @return the UserHandle for a userId. Return null for USER_NULL
+     */
+    private static UserHandle getUserHandleOf(@UserIdInt int userId) {
+        if (userId == UserHandle.USER_NULL) {
+            return null;
+        } else {
+            return UserHandle.of(userId);
+        }
+    }
+
+    /**
      * Filter a set of device admins based on a predicate {@code check}. This is equivalent to
      * {@code admins.stream().filter(check).map(x → new EnforcedAdmin(admin, userId)} except it's
      * returning a zero/one/many-type thing.
@@ -183,11 +194,13 @@
         if (admins == null) {
             return null;
         }
+
+        final UserHandle user = getUserHandleOf(userId);
         EnforcedAdmin enforcedAdmin = null;
         for (ComponentName admin : admins) {
             if (check.isEnforcing(dpm, admin, userId)) {
                 if (enforcedAdmin == null) {
-                    enforcedAdmin = new EnforcedAdmin(admin, userId);
+                    enforcedAdmin = new EnforcedAdmin(admin, user);
                 } else {
                     return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
                 }
@@ -211,7 +224,7 @@
         IPackageManager ipm = AppGlobals.getPackageManager();
         try {
             if (ipm.getBlockUninstallForUser(packageName, userId)) {
-                return getProfileOrDeviceOwner(context, userId);
+                return getProfileOrDeviceOwner(context, getUserHandleOf(userId));
             }
         } catch (RemoteException e) {
             // Nothing to do
@@ -230,7 +243,7 @@
         IPackageManager ipm = AppGlobals.getPackageManager();
         try {
             if (ipm.isPackageSuspendedForUser(packageName, userId)) {
-                return getProfileOrDeviceOwner(context, userId);
+                return getProfileOrDeviceOwner(context, getUserHandleOf(userId));
             }
         } catch (RemoteException | IllegalArgumentException e) {
             // Nothing to do
@@ -245,14 +258,15 @@
         if (dpm == null) {
             return null;
         }
-        EnforcedAdmin admin = getProfileOrDeviceOwner(context, userId);
+        EnforcedAdmin admin = getProfileOrDeviceOwner(context, getUserHandleOf(userId));
         boolean permitted = true;
         if (admin != null) {
             permitted = dpm.isInputMethodPermittedByAdmin(admin.component,
                     packageName, userId);
         }
         int managedProfileId = getManagedProfileId(context, userId);
-        EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context, managedProfileId);
+        EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context,
+                getUserHandleOf(managedProfileId));
         boolean permittedByProfileAdmin = true;
         if (profileAdmin != null) {
             permittedByProfileAdmin = dpm.isInputMethodPermittedByAdmin(profileAdmin.component,
@@ -298,14 +312,15 @@
         if (dpm == null) {
             return null;
         }
-        EnforcedAdmin admin = getProfileOrDeviceOwner(context, userId);
+        EnforcedAdmin admin = getProfileOrDeviceOwner(context, getUserHandleOf(userId));
         boolean permitted = true;
         if (admin != null) {
             permitted = dpm.isAccessibilityServicePermittedByAdmin(admin.component,
                     packageName, userId);
         }
         int managedProfileId = getManagedProfileId(context, userId);
-        EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context, managedProfileId);
+        EnforcedAdmin profileAdmin = getProfileOrDeviceOwner(context,
+                getUserHandleOf(managedProfileId));
         boolean permittedByProfileAdmin = true;
         if (profileAdmin != null) {
             permittedByProfileAdmin = dpm.isAccessibilityServicePermittedByAdmin(
@@ -365,7 +380,7 @@
         if (!isAccountTypeDisabled) {
             return null;
         }
-        return getProfileOrDeviceOwner(context, userId);
+        return getProfileOrDeviceOwner(context, getUserHandleOf(userId));
     }
 
     /**
@@ -377,7 +392,8 @@
      */
     public static EnforcedAdmin checkIfMeteredDataRestricted(Context context,
             String packageName, int userId) {
-        final EnforcedAdmin enforcedAdmin = getProfileOrDeviceOwner(context, userId);
+        final EnforcedAdmin enforcedAdmin = getProfileOrDeviceOwner(context,
+                getUserHandleOf(userId));
         if (enforcedAdmin == null) {
             return null;
         }
@@ -402,7 +418,7 @@
             return null;
         }
         ComponentName adminComponent = dpm.getDeviceOwnerComponentOnCallingUser();
-        return new EnforcedAdmin(adminComponent, UserHandle.myUserId());
+        return new EnforcedAdmin(adminComponent, getUserHandleOf(UserHandle.myUserId()));
     }
 
     /**
@@ -434,10 +450,11 @@
                 return null;
             }
             EnforcedAdmin enforcedAdmin = null;
+            final UserHandle user = getUserHandleOf(userId);
             for (ComponentName admin : admins) {
                 if (check.isEnforcing(dpm, admin, userId)) {
                     if (enforcedAdmin == null) {
-                        enforcedAdmin = new EnforcedAdmin(admin, userId);
+                        enforcedAdmin = new EnforcedAdmin(admin, user);
                     } else {
                         return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
                     }
@@ -488,13 +505,14 @@
             if (admins == null) {
                 continue;
             }
+            final UserHandle user = getUserHandleOf(userInfo.id);
             final boolean isSeparateProfileChallengeEnabled =
                     sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userInfo.id);
             for (ComponentName admin : admins) {
                 if (!isSeparateProfileChallengeEnabled) {
                     if (check.isEnforcing(dpm, admin, userInfo.id)) {
                         if (enforcedAdmin == null) {
-                            enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+                            enforcedAdmin = new EnforcedAdmin(admin, user);
                         } else {
                             return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
                         }
@@ -511,7 +529,7 @@
                     DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm, userInfo);
                     if (check.isEnforcing(parentDpm, admin, userInfo.id)) {
                         if (enforcedAdmin == null) {
-                            enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+                            enforcedAdmin = new EnforcedAdmin(admin, user);
                         } else {
                             return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
                         }
@@ -535,7 +553,7 @@
         ComponentName adminComponent = dpm.getDeviceOwnerComponentOnAnyUser();
         if (adminComponent != null) {
             return new EnforcedAdmin(
-                    adminComponent, enforcedRestriction, dpm.getDeviceOwnerUserId());
+                    adminComponent, enforcedRestriction, dpm.getDeviceOwnerUser());
         }
         return null;
     }
@@ -556,7 +574,7 @@
         }
         ComponentName adminComponent = dpm.getProfileOwnerAsUser(userId);
         if (adminComponent != null) {
-            return new EnforcedAdmin(adminComponent, enforcedRestriction, userId);
+            return new EnforcedAdmin(adminComponent, enforcedRestriction, getUserHandleOf(userId));
         }
         return null;
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index fc8d9db..88ac8ce 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -156,7 +156,7 @@
         final EnforcedAdmin enforcedAdmin = RestrictedLockUtilsInternal
                 .checkIfKeyguardFeaturesDisabled(mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
 
-        assertThat(enforcedAdmin).isEqualTo(new EnforcedAdmin(mAdmin1, mUserId));
+        assertThat(enforcedAdmin).isEqualTo(new EnforcedAdmin(mAdmin1, UserHandle.of(mUserId)));
     }
 
     @Test
@@ -189,12 +189,12 @@
         // Querying the parent should return the policy, since it affects the parent.
         EnforcedAdmin parent = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
                 mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
-        assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+        assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, UserHandle.of(mProfileId)));
 
         // Querying the child should return that too.
         EnforcedAdmin profile = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
                 mContext, KEYGUARD_DISABLE_FINGERPRINT, mProfileId);
-        assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+        assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, UserHandle.of(mProfileId)));
 
         // Querying for some unrelated feature should return nothing. Nothing!
         assertThat(RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
@@ -224,7 +224,7 @@
         // Querying the child should still return the policy.
         EnforcedAdmin profile = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
                 mContext, KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS, mProfileId);
-        assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+        assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, UserHandle.of(mProfileId)));
     }
 
     @Test
@@ -251,7 +251,7 @@
         // Querying the child should still return the policy.
         EnforcedAdmin profile = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
                 mContext, KEYGUARD_DISABLE_FINGERPRINT, mProfileId);
-        assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+        assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, UserHandle.of(mProfileId)));
     }
 
     /**
@@ -278,7 +278,7 @@
         // Parent should get the policy.
         EnforcedAdmin parent = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
                 mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
-        assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+        assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, UserHandle.of(mProfileId)));
 
         // Profile should not get the policy.
         EnforcedAdmin profile = RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled(
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index ce503b3..dcc6cba 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -27,6 +27,7 @@
     <uses-permission android:name="android.permission.READ_SMS" />
     <uses-permission android:name="android.permission.CALL_PHONE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
     <uses-permission android:name="android.permission.WRITE_CONTACTS" />
     <uses-permission android:name="android.permission.READ_CALENDAR" />
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
new file mode 100644
index 0000000..ba4eb5f
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
@@ -0,0 +1,91 @@
+/*
+ * 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.plugins;
+
+import android.hardware.Sensor;
+import android.hardware.TriggerEventListener;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Allows for additional sensors to be retrieved from
+ * {@link com.android.systemui.util.AsyncSensorManager}.
+ */
+@ProvidesInterface(action = SensorManagerPlugin.ACTION, version = SensorManagerPlugin.VERSION)
+public interface SensorManagerPlugin extends Plugin {
+    String ACTION = "com.android.systemui.action.PLUGIN_SENSOR_MANAGER";
+    int VERSION = 1;
+
+    /**
+     * Registers for trigger events from the sensor. Trigger events are one-shot and need to
+     * re-registered in order for them to be fired again.
+     * @param sensor
+     * @param listener
+     * @see android.hardware.SensorManager#requestTriggerSensor(
+     *     android.hardware.TriggerEventListener, android.hardware.Sensor)
+     */
+    void registerTriggerEvent(Sensor sensor, TriggerEventListener listener);
+
+    /**
+     * Unregisters trigger events from the sensor.
+     * @param sensor
+     * @param listener
+     */
+    void unregisterTriggerEvent(Sensor sensor, TriggerEventListener listener);
+
+    interface TriggerEventListener {
+        void onTrigger(TriggerEvent event);
+    }
+
+    class Sensor {
+        public static int TYPE_WAKE_LOCK_SCREEN = 1;
+
+        int mType;
+
+        public int getType() {
+            return mType;
+        }
+
+        public Sensor(int type) {
+            mType = type;
+        }
+    }
+
+    class TriggerEvent {
+        Sensor mSensor;
+        int mVendorType;
+
+        /**
+         * Creates a trigger event
+         * @param sensor The type of sensor, e.g. TYPE_WAKE_LOCK_SCREEN
+         * @param vendorType The vendor type, which should be unique for each type of sensor,
+         *                   e.g. SINGLE_TAP = 1, DOUBLE_TAP = 2, etc.
+         */
+        public TriggerEvent(Sensor sensor, int vendorType) {
+            mSensor = sensor;
+            mVendorType = vendorType;
+        }
+
+        public Sensor getSensor() {
+            return mSensor;
+        }
+
+        public int getVendorType() {
+            return mVendorType;
+        }
+    }
+}
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 7a38899..f138685 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -24,8 +24,7 @@
     android:clipChildren="false"
     android:clipToPadding="false"
     android:orientation="vertical"
-    android:background="@color/notification_guts_bg_color"
-    android:theme="@*android:style/Theme.DeviceDefault.Light">
+    android:background="@color/notification_guts_bg_color">
 
     <!-- Package Info -->
     <RelativeLayout
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index 7083269..e44fbcf 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -21,18 +21,5 @@
     android:layout_height="wrap_content"
     android:layout_weight="1"
     android:clipChildren="true"
-    android:clipToPadding="true"
-    android:paddingStart="@dimen/notification_side_paddings"
-    android:paddingEnd="@dimen/notification_side_paddings"
     android:paddingBottom="@dimen/qs_paged_tile_layout_padding_bottom">
-
-
-    <FrameLayout
-        android:id="@+id/page_decor"
-        android:layout_width="wrap_content"
-        android:layout_height="48dp"
-        android:layout_gravity="bottom">
-
-    </FrameLayout>
-
 </com.android.systemui.qs.PagedTileLayout>
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index f0436de..d033057 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -49,11 +49,6 @@
         android:paddingEnd="@dimen/status_bar_padding_end"
         android:orientation="horizontal"
         >
-        <ViewStub
-            android:id="@+id/operator_name"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout="@layout/operator_name" />
         <FrameLayout
             android:layout_height="match_parent"
             android:layout_width="0dp"
@@ -70,6 +65,12 @@
                 android:layout_width="match_parent"
                 android:clipChildren="false"
             >
+                <ViewStub
+                    android:id="@+id/operator_name"
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    android:layout="@layout/operator_name" />
+
                 <com.android.systemui.statusbar.policy.Clock
                     android:id="@+id/clock"
                     android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e1c71fa..42e19aa 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -761,6 +761,8 @@
     <string name="quick_settings_cast_device_default_description">Ready to cast</string>
     <!-- QuickSettings: Cast detail panel, text when there are no items [CHAR LIMIT=NONE] -->
     <string name="quick_settings_cast_detail_empty_text">No devices available</string>
+    <!-- QuickSettings: Cast unavailable, text when not connected to WiFi [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_cast_no_wifi">Wi\u2011Fi not connected</string>
     <!-- QuickSettings: Brightness dialog title [CHAR LIMIT=NONE] -->
     <string name="quick_settings_brightness_dialog_title">Brightness</string>
     <!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
@@ -1999,6 +2001,9 @@
     <!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_open_details">Open details.</string>
 
+    <!-- accessibility label for quick settings items that are currently disabled. Must have a reason [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_not_available">Unvailable due to <xliff:g name="reason" id="reason" example="Wifi not available">%s</xliff:g></string>
+
     <!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_open_settings">Open <xliff:g name="page" example="Bluetooth">%s</xliff:g> settings.</string>
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java
index c6a086d..c3815e4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInitializer.java
@@ -14,7 +14,6 @@
 
 package com.android.systemui.shared.plugins;
 
-import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Looper;
 
@@ -26,11 +25,16 @@
     Looper getBgLooper();
 
     /**
-     * This Runnable is run on the bg looper during initialization of {@link PluginManagerImpl}.
+     * Called from the bg looper during initialization of {@link PluginManagerImpl}.
      */
-    @Nullable Runnable getBgInitCallback();
+    void onPluginManagerInit();
 
     String[] getWhitelistedPlugins(Context context);
 
     PluginEnabler getPluginEnabler(Context context);
+
+    /**
+     * Called from {@link PluginManagerImpl#handleWtfs()}.
+     */
+    void handleWtfs();
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index a54e08e..87f2934 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -74,11 +74,11 @@
     private final boolean isDebuggable;
     private final PluginPrefs mPluginPrefs;
     private final PluginEnabler mPluginEnabler;
+    private final PluginInitializer mPluginInitializer;
     private ClassLoaderFilter mParentClassLoader;
     private boolean mListening;
     private boolean mHasOneShot;
     private Looper mLooper;
-    private boolean mWtfsSet;
 
     public PluginManagerImpl(Context context, PluginInitializer initializer) {
         this(context, new PluginInstanceManagerFactory(), Build.IS_DEBUGGABLE,
@@ -87,7 +87,7 @@
 
     @VisibleForTesting
     PluginManagerImpl(Context context, PluginInstanceManagerFactory factory, boolean debuggable,
-            UncaughtExceptionHandler defaultHandler, PluginInitializer initializer) {
+            UncaughtExceptionHandler defaultHandler, final PluginInitializer initializer) {
         mContext = context;
         mFactory = factory;
         mLooper = initializer.getBgLooper();
@@ -95,15 +95,18 @@
         mWhitelistedPlugins.addAll(Arrays.asList(initializer.getWhitelistedPlugins(mContext)));
         mPluginPrefs = new PluginPrefs(mContext);
         mPluginEnabler = initializer.getPluginEnabler(mContext);
+        mPluginInitializer = initializer;
 
         PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
                 defaultHandler);
         Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler);
 
-        Runnable bgRunnable = initializer.getBgInitCallback();
-        if (bgRunnable != null) {
-            new Handler(mLooper).post(bgRunnable);
-        }
+        new Handler(mLooper).post(new Runnable() {
+            @Override
+            public void run() {
+                initializer.onPluginManagerInit();
+            }
+        });
     }
 
     public String[] getWhitelistedPlugins() {
@@ -299,16 +302,7 @@
     }
 
     public void handleWtfs() {
-        if (!mWtfsSet) {
-            mWtfsSet = true;
-            Log.setWtfHandler(new Log.TerribleFailureHandler() {
-                @Override
-                public void onTerribleFailure(String tag, Log.TerribleFailure what,
-                        boolean system) {
-                    throw new CrashWhilePluginActiveException(what);
-                }
-            });
-        }
+        mPluginInitializer.handleWtfs();
     }
 
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -391,7 +385,7 @@
         }
     }
 
-    private class CrashWhilePluginActiveException extends RuntimeException {
+    public static class CrashWhilePluginActiveException extends RuntimeException {
         public CrashWhilePluginActiveException(Throwable throwable) {
             super(throwable);
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 2daa33b..112e067 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -373,11 +373,11 @@
             mPendingLockCheck.cancel(false);
             mPendingLockCheck = null;
         }
+        displayDefaultSecurityMessage();
     }
 
     @Override
     public void onResume(int reason) {
-        displayDefaultSecurityMessage();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index fe1fe1a..2c821b2 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -178,7 +178,8 @@
                 getDependency(ActivityStarter.class));
 
         mProviders.put(AsyncSensorManager.class, () ->
-                new AsyncSensorManager(mContext.getSystemService(SensorManager.class)));
+                new AsyncSensorManager(mContext.getSystemService(SensorManager.class),
+                        getDependency(PluginManager.class)));
 
         mProviders.put(BluetoothController.class, () ->
                 new BluetoothControllerImpl(mContext, getDependency(BG_LOOPER)));
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 4d24d82..3007b6e 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -736,14 +736,19 @@
             switch (gravity) {
                 case Gravity.TOP:
                     out.set(displayCutout.getBoundingRectTop());
+                    break;
                 case Gravity.LEFT:
                     out.set(displayCutout.getBoundingRectLeft());
+                    break;
                 case Gravity.BOTTOM:
                     out.set(displayCutout.getBoundingRectBottom());
+                    break;
                 case Gravity.RIGHT:
                     out.set(displayCutout.getBoundingRectRight());
+                    break;
+                default:
+                    out.setEmpty();
             }
-            out.setEmpty();
         }
 
         private void localBounds(Rect out) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index c90861e..7d77929 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -200,7 +200,9 @@
         mLastState = STATE_NONE;
         updateState(STATE_AUTHENTICATING);
 
-        title.setText(mBundle.getCharSequence(BiometricPrompt.KEY_TITLE));
+        CharSequence titleText = mBundle.getCharSequence(BiometricPrompt.KEY_TITLE);
+
+        title.setText(titleText);
         title.setSelected(true);
 
         positive.setVisibility(View.INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 7013947..77f7ad4f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.doze;
 
+import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
+
 import android.annotation.AnyThread;
 import android.app.ActivityManager;
 import android.app.AlarmManager;
@@ -39,8 +41,10 @@
 import com.android.internal.hardware.AmbientDisplayConfiguration;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.systemui.plugins.SensorManagerPlugin;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.AlarmTimeout;
+import com.android.systemui.util.AsyncSensorManager;
 import com.android.systemui.util.wakelock.WakeLock;
 
 import java.io.PrintWriter;
@@ -112,8 +116,8 @@
                         DozeLog.PULSE_REASON_SENSOR_LONG_PRESS,
                         true /* reports touch coordinates */,
                         true /* touchscreen */),
-                new TriggerSensor(
-                        findSensorWithType(config.wakeLockScreenSensorType()),
+                new PluginTriggerSensor(
+                        new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN),
                         Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
                         true /* configured */,
                         DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
@@ -375,7 +379,7 @@
             mHandler.post(mWakeLock.wrap(() -> {
                 if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event));
                 boolean sensorPerformsProxCheck = false;
-                if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
+                if (mSensor != null && mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
                     int subType = (int) event.values[0];
                     MetricsLogger.action(
                             mContext, MetricsProto.MetricsEvent.ACTION_AMBIENT_GESTURE,
@@ -418,6 +422,49 @@
         }
     }
 
+    /**
+     * A Sensor that is injected via plugin.
+     */
+    private class PluginTriggerSensor extends TriggerSensor {
+
+        private final SensorManagerPlugin.Sensor mPluginSensor;
+        private final SensorManagerPlugin.TriggerEventListener mTriggerEventListener = (event) -> {
+            onTrigger(null);
+        };
+
+        PluginTriggerSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
+                int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) {
+            super(null, setting, configured, pulseReason, reportsTouchCoordinates,
+                    requiresTouchscreen);
+            mPluginSensor = sensor;
+        }
+
+        @Override
+        public void updateListener() {
+            if (!mConfigured) return;
+            AsyncSensorManager asyncSensorManager = (AsyncSensorManager) mSensorManager;
+            if (mRequested && !mDisabled && enabledBySetting() && !mRegistered) {
+                asyncSensorManager.requestPluginTriggerSensor(mPluginSensor, mTriggerEventListener);
+                mRegistered = true;
+                if (DEBUG) Log.d(TAG, "requestPluginTriggerSensor");
+            } else if (mRegistered) {
+                asyncSensorManager.cancelPluginTriggerSensor(mPluginSensor, mTriggerEventListener);
+                mRegistered = false;
+                if (DEBUG) Log.d(TAG, "cancelPluginTriggerSensor");
+            }
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder("{mRegistered=").append(mRegistered)
+                    .append(", mRequested=").append(mRequested)
+                    .append(", mDisabled=").append(mDisabled)
+                    .append(", mConfigured=").append(mConfigured)
+                    .append(", mSensor=").append(mPluginSensor).append("}").toString();
+        }
+
+    }
+
     private class WakeScreenSensor extends TriggerSensor {
 
         WakeScreenSensor() {
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
index ac0a226..774567e 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInitializerImpl.java
@@ -16,29 +16,29 @@
 
 import android.content.Context;
 import android.os.Looper;
+import android.util.Log;
 
 import com.android.systemui.Dependency;
+import com.android.systemui.R;
 import com.android.systemui.shared.plugins.PluginEnabler;
 import com.android.systemui.shared.plugins.PluginInitializer;
-import com.android.systemui.R;
+import com.android.systemui.shared.plugins.PluginManagerImpl;
 
 public class PluginInitializerImpl implements PluginInitializer {
+
+    private boolean mWtfsSet;
+
     @Override
     public Looper getBgLooper() {
         return Dependency.get(Dependency.BG_LOOPER);
     }
 
     @Override
-    public Runnable getBgInitCallback() {
-        return new Runnable() {
-            @Override
-            public void run() {
-                // Plugin dependencies that don't have another good home can go here, but
-                // dependencies that have better places to init can happen elsewhere.
-                Dependency.get(PluginDependencyProvider.class)
-                        .allowPluginDependency(ActivityStarter.class);
-            }
-        };
+    public void onPluginManagerInit() {
+        // Plugin dependencies that don't have another good home can go here, but
+        // dependencies that have better places to init can happen elsewhere.
+        Dependency.get(PluginDependencyProvider.class)
+                .allowPluginDependency(ActivityStarter.class);
     }
 
     @Override
@@ -49,4 +49,18 @@
     public PluginEnabler getPluginEnabler(Context context) {
         return new PluginEnablerImpl(context);
     }
+
+    @Override
+    public void handleWtfs() {
+        if (!mWtfsSet) {
+            mWtfsSet = true;
+            Log.setWtfHandler(new Log.TerribleFailureHandler() {
+                @Override
+                public void onTerribleFailure(String tag, Log.TerribleFailure what,
+                        boolean system) {
+                    throw new PluginManagerImpl.CrashWhilePluginActiveException(what);
+                }
+            });
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index c398a4a..76dfddb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -8,6 +8,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -60,6 +61,7 @@
     private int mPageToRestore = -1;
     private int mLayoutOrientation;
     private int mLayoutDirection;
+    private int mHorizontalClipBound;
 
     public PagedTileLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -260,8 +262,8 @@
         // Update bottom padding, useful for removing extra space once the panel page indicator is
         // hidden.
         Resources res = getContext().getResources();
-        final int sidePadding = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
-        setPadding(sidePadding, 0, sidePadding,
+        mHorizontalClipBound = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
+        setPadding(0, 0, 0,
                 getContext().getResources().getDimensionPixelSize(
                         R.dimen.qs_paged_tile_layout_padding_bottom));
         boolean changed = false;
@@ -276,6 +278,13 @@
     }
 
     @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        Rect clipBounds = new Rect(mHorizontalClipBound, 0, (r-l) - mHorizontalClipBound, b - t);
+        setClipBounds(clipBounds);
+    }
+
+    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 
         final int nTiles = mTiles.size();
@@ -412,6 +421,14 @@
         public int maxTiles() {
             return mColumns * mRows;
         }
+
+        @Override
+        public boolean updateResources() {
+            final int sidePadding = getContext().getResources().getDimensionPixelSize(
+                    R.dimen.notification_side_paddings);
+            setPadding(sidePadding, 0, sidePadding, 0);
+            return super.updateResources();
+        }
     }
 
     private final PagerAdapter mAdapter = new PagerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index e884302..1dd729d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -104,11 +104,13 @@
         // container is measured. Any change in the tiles, should trigger a remeasure.
         final int numTiles = mRecords.size();
         final int width = MeasureSpec.getSize(widthMeasureSpec);
+        final int availableWidth = width - getPaddingStart() - getPaddingEnd();
         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
         if (heightMode == MeasureSpec.UNSPECIFIED) {
             mRows = (numTiles + mColumns - 1) / mColumns;
         }
-        mCellWidth = (width - mSidePadding * 2 - (mCellMarginHorizontal * mColumns)) / mColumns;
+        mCellWidth =
+                (availableWidth - mSidePadding * 2 - (mCellMarginHorizontal * mColumns)) / mColumns;
 
         // Measure each QS tile.
         View previousView = this;
@@ -124,7 +126,7 @@
                 (mRows != 0 ? (mCellMarginTop - mCellMarginVertical) : 0);
         if (height < 0) height = 0;
 
-        setMeasuredDimension(width, height);
+        setMeasuredDimension(width + getPaddingStart() + getPaddingEnd(), height);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index ed78048..921db69 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -46,6 +46,7 @@
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.NetworkController;
 
 import java.util.LinkedHashMap;
 import java.util.Set;
@@ -58,16 +59,18 @@
     private final CastController mController;
     private final CastDetailAdapter mDetailAdapter;
     private final KeyguardMonitor mKeyguard;
+    private final NetworkController mNetworkController;
     private final Callback mCallback = new Callback();
     private final ActivityStarter mActivityStarter;
     private Dialog mDialog;
-    private boolean mRegistered;
+    private boolean mWifiConnected;
 
     public CastTile(QSHost host) {
         super(host);
         mController = Dependency.get(CastController.class);
         mDetailAdapter = new CastDetailAdapter();
         mKeyguard = Dependency.get(KeyguardMonitor.class);
+        mNetworkController = Dependency.get(NetworkController.class);
         mActivityStarter = Dependency.get(ActivityStarter.class);
     }
 
@@ -87,10 +90,12 @@
         if (listening) {
             mController.addCallback(mCallback);
             mKeyguard.addCallback(mCallback);
+            mNetworkController.addCallback(mSignalCallback);
         } else {
             mController.setDiscovering(false);
             mController.removeCallback(mCallback);
             mKeyguard.removeCallback(mCallback);
+            mNetworkController.removeCallback(mSignalCallback);
         }
     }
 
@@ -112,6 +117,9 @@
 
     @Override
     protected void handleClick() {
+        if (getState().state == Tile.STATE_UNAVAILABLE) {
+            return;
+        }
         if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) {
             mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
                 showDetail(true);
@@ -164,13 +172,22 @@
         if (!state.value && connecting) {
             state.label = mContext.getString(R.string.quick_settings_connecting);
         }
-        state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on
                 : R.drawable.ic_qs_cast_off);
+        if (mWifiConnected) {
+            state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+            state.secondaryLabel = "";
+            state.contentDescription = state.contentDescription + ","
+                    + mContext.getString(R.string.accessibility_quick_settings_open_details);
+            state.expandedAccessibilityClassName = Button.class.getName();
+        } else {
+            state.state = Tile.STATE_UNAVAILABLE;
+            String noWifi = mContext.getString(R.string.quick_settings_cast_no_wifi);
+            state.secondaryLabel = noWifi;
+            state.contentDescription = state.contentDescription + ", " + mContext.getString(
+                    R.string.accessibility_quick_settings_not_available, noWifi);
+        }
         mDetailAdapter.updateItems(devices);
-        state.expandedAccessibilityClassName = Button.class.getName();
-        state.contentDescription = state.contentDescription + ","
-                + mContext.getString(R.string.accessibility_quick_settings_open_details);
     }
 
     @Override
@@ -192,6 +209,22 @@
                 : mContext.getString(R.string.quick_settings_cast_device_default_name);
     }
 
+    private final NetworkController.SignalCallback mSignalCallback =
+            new NetworkController.SignalCallback() {
+                @Override
+                public void setWifiIndicators(boolean enabled,
+                        NetworkController.IconState statusIcon,
+                        NetworkController.IconState qsIcon, boolean activityIn, boolean activityOut,
+                        String description, boolean isTransient, String statusLabel) {
+                    // statusIcon.visible has the connected status information
+                    boolean enabledAndConnected = enabled && qsIcon.visible;
+                    if (enabledAndConnected != mWifiConnected) {
+                        mWifiConnected = enabledAndConnected;
+                        refreshState();
+                    }
+                }
+            };
+
     private final class Callback implements CastController.Callback, KeyguardMonitor.Callback {
         @Override
         public void onCastDevicesChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 9d773ed..18151d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -54,10 +54,10 @@
     public static final float MAX_ICON_SCALE_AMOUNT = 1.5f;
     public static final float MIN_ICON_SCALE_AMOUNT = 0.8f;
 
+    protected final int mDarkIconColor;
+    protected final int mNormalColor;
     private final int mMinBackgroundRadius;
     private final Paint mCirclePaint;
-    private final int mDarkIconColor;
-    private final int mNormalColor;
     private final ArgbEvaluator mColorInterpolator;
     private final FlingAnimationUtils mFlingAnimationUtils;
     private float mCircleRadius;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index d8f7b61..7fa0426 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -436,7 +436,9 @@
                         public boolean onPreDraw() {
                             boolean animatingY = ViewState.isAnimatingY(icon);
                             if (!animatingY) {
-                                observer.removeOnPreDrawListener(this);
+                                if (observer.isAlive()) {
+                                    observer.removeOnPreDrawListener(this);
+                                }
                                 icon.setTag(TAG_CONTINUOUS_CLIPPING, null);
                                 return true;
                             }
@@ -453,7 +455,9 @@
                 @Override
                 public void onViewDetachedFromWindow(View v) {
                     if (v == icon) {
-                        observer.removeOnPreDrawListener(predrawListener);
+                        if (observer.isAlive()) {
+                            observer.removeOnPreDrawListener(predrawListener);
+                        }
                         icon.setTag(TAG_CONTINUOUS_CLIPPING, null);
                     }
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 2450e44..24665ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -491,6 +491,10 @@
     @Override
     public void onStateChanged(int newState) {
         super.onStateChanged(newState);
+        if (mFullscreenUserSwitcher == null) {
+            return; // Not using the full screen user switcher.
+        }
+
         if (newState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
             if (!mFullscreenUserSwitcher.isVisible()) {
                 // Current execution path continues to set state after this, thus we deffer the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 4963a0c..4ef8dbb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -26,6 +26,7 @@
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.NotificationHeaderView;
 import android.view.View;
@@ -40,12 +41,12 @@
 import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.TransformableView;
-import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper;
+import com.android.systemui.statusbar.notification.NotificationData;
 import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.RemoteInputView;
@@ -1188,6 +1189,7 @@
         updateSingleLineView();
         updateAmbientSingleLineView();
     }
+
     private void updateSingleLineView() {
         if (mIsChildInGroup) {
             boolean isNewView = mSingleLineView == null;
@@ -1223,53 +1225,44 @@
             return;
         }
 
-        boolean enableSmartReplies = (mSmartReplyConstants.isEnabled()
+        Notification notification = entry.notification.getNotification();
+
+        Pair<RemoteInput, Notification.Action> remoteInputActionPair =
+                entry.notification.getNotification().findRemoteInputActionPair(false /*freeform */);
+        Pair<RemoteInput, Notification.Action> freeformRemoteInputActionPair =
+                notification.findRemoteInputActionPair(true /*freeform */);
+
+        boolean enableAppGeneratedSmartReplies = (mSmartReplyConstants.isEnabled()
                 && (!mSmartReplyConstants.requiresTargetingP()
-                    || entry.targetSdk >= Build.VERSION_CODES.P));
+                || entry.targetSdk >= Build.VERSION_CODES.P));
 
-        boolean hasRemoteInput = false;
         RemoteInput remoteInputWithChoices = null;
-        PendingIntent pendingIntentWithChoices = null;
+        PendingIntent pendingIntentWithChoices= null;
         CharSequence[] choices = null;
-
-        Notification.Action[] actions = entry.notification.getNotification().actions;
-        if (actions != null) {
-            for (Notification.Action a : actions) {
-                if (a.getRemoteInputs() == null) {
-                    continue;
-                }
-                for (RemoteInput ri : a.getRemoteInputs()) {
-                    boolean showRemoteInputView = ri.getAllowFreeFormInput();
-                    boolean showSmartReplyView = enableSmartReplies
-                            && (ArrayUtils.isEmpty(ri.getChoices())
-                            || (showRemoteInputView && !ArrayUtils.isEmpty(entry.smartReplies)));
-                    if (showRemoteInputView) {
-                        hasRemoteInput = true;
-                    }
-                    if (showSmartReplyView) {
-                        remoteInputWithChoices = ri;
-                        pendingIntentWithChoices = a.actionIntent;
-                        if (!ArrayUtils.isEmpty(ri.getChoices())) {
-                            choices = ri.getChoices();
-                        } else {
-                            choices = entry.smartReplies;
-                        }
-                    }
-                    if (showRemoteInputView || showSmartReplyView) {
-                        break;
-                    }
-                }
-            }
+        if (enableAppGeneratedSmartReplies
+                && remoteInputActionPair != null
+                && !ArrayUtils.isEmpty(remoteInputActionPair.first.getChoices())) {
+            // app generated smart replies
+            remoteInputWithChoices = remoteInputActionPair.first;
+            pendingIntentWithChoices = remoteInputActionPair.second.actionIntent;
+            choices = remoteInputActionPair.first.getChoices();
+        } else if (!ArrayUtils.isEmpty(entry.smartReplies)
+                && freeformRemoteInputActionPair != null
+                && freeformRemoteInputActionPair.second.getAllowGeneratedReplies()) {
+            // system generated smart replies
+            remoteInputWithChoices = freeformRemoteInputActionPair.first;
+            pendingIntentWithChoices = freeformRemoteInputActionPair.second.actionIntent;
+            choices = entry.smartReplies;
         }
 
-        applyRemoteInput(entry, hasRemoteInput);
+        applyRemoteInput(entry, freeformRemoteInputActionPair != null);
         applySmartReplyView(remoteInputWithChoices, pendingIntentWithChoices, entry, choices);
     }
 
-    private void applyRemoteInput(NotificationData.Entry entry, boolean hasRemoteInput) {
+    private void applyRemoteInput(NotificationData.Entry entry, boolean hasFreeformRemoteInput) {
         View bigContentView = mExpandedChild;
         if (bigContentView != null) {
-            mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput,
+            mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasFreeformRemoteInput,
                     mPreviousExpandedRemoteInputIntent, mCachedExpandedRemoteInput,
                     mExpandedWrapper);
         } else {
@@ -1284,7 +1277,8 @@
 
         View headsUpContentView = mHeadsUpChild;
         if (headsUpContentView != null) {
-            mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput,
+            mHeadsUpRemoteInput = applyRemoteInput(
+                    headsUpContentView, entry, hasFreeformRemoteInput,
                     mPreviousHeadsUpRemoteInputIntent, mCachedHeadsUpRemoteInput, mHeadsUpWrapper);
         } else {
             mHeadsUpRemoteInput = null;
@@ -1370,8 +1364,8 @@
             mExpandedSmartReplyView =
                     applySmartReplyView(mExpandedChild, remoteInput, pendingIntent, entry, choices);
             if (mExpandedSmartReplyView != null && remoteInput != null
-                    && remoteInput.getChoices() != null && remoteInput.getChoices().length > 0) {
-                mSmartReplyController.smartRepliesAdded(entry, remoteInput.getChoices().length);
+                    && choices != null && choices.length > 0) {
+                mSmartReplyController.smartRepliesAdded(entry, choices.length);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 9ddab7c..33ac390 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -4849,7 +4849,7 @@
             activatedChild.makeInactive(false /* animate */);
         }
         updateFooter();
-        updateChildren();
+        requestChildrenUpdate();
         onUpdateRowStates();
 
         mEntryManager.updateNotifications();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 9acaf21..c66bbb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -48,6 +48,7 @@
     private final NotificationStackScrollLayout mStackScroller;
     private final HeadsUpStatusBarView mHeadsUpStatusBarView;
     private final View mClockView;
+    private final View mOperatorNameView;
     private final DarkIconDispatcher mDarkIconDispatcher;
     private final NotificationPanelView mPanelView;
     private final Consumer<ExpandableNotificationRow>
@@ -65,8 +66,10 @@
     private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener =
             (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
                     -> updatePanelTranslation();
+    private boolean mAnimationsEnabled = true;
     Point mPoint;
 
+
     public HeadsUpAppearanceController(
             NotificationIconAreaController notificationIconAreaController,
             HeadsUpManagerPhone headsUpManager,
@@ -75,7 +78,8 @@
                 statusbarView.findViewById(R.id.heads_up_status_bar_view),
                 statusbarView.findViewById(R.id.notification_stack_scroller),
                 statusbarView.findViewById(R.id.notification_panel),
-                statusbarView.findViewById(R.id.clock));
+                statusbarView.findViewById(R.id.clock),
+                statusbarView.findViewById(R.id.operator_name_frame));
     }
 
     @VisibleForTesting
@@ -85,7 +89,8 @@
             HeadsUpStatusBarView headsUpStatusBarView,
             NotificationStackScrollLayout stackScroller,
             NotificationPanelView panelView,
-            View clockView) {
+            View clockView,
+            View operatorNameView) {
         mNotificationIconAreaController = notificationIconAreaController;
         mHeadsUpManager = headsUpManager;
         mHeadsUpManager.addListener(this);
@@ -101,6 +106,7 @@
         mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
         mStackScroller.setHeadsUpAppearanceController(this);
         mClockView = clockView;
+        mOperatorNameView = operatorNameView;
         mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
         mDarkIconDispatcher.addDarkReceiver(this);
 
@@ -230,20 +236,52 @@
             mShown = isShown;
             if (isShown) {
                 mHeadsUpStatusBarView.setVisibility(View.VISIBLE);
-                CrossFadeHelper.fadeIn(mHeadsUpStatusBarView, CONTENT_FADE_DURATION /* duration */,
-                        CONTENT_FADE_DELAY /* delay */);
-                CrossFadeHelper.fadeOut(mClockView, CONTENT_FADE_DURATION/* duration */,
-                        0 /* delay */, () -> mClockView.setVisibility(View.INVISIBLE));
+                show(mHeadsUpStatusBarView);
+                hide(mClockView, View.INVISIBLE);
+                if (mOperatorNameView != null) {
+                    hide(mOperatorNameView, View.INVISIBLE);
+                }
             } else {
-                CrossFadeHelper.fadeIn(mClockView, CONTENT_FADE_DURATION /* duration */,
-                        CONTENT_FADE_DELAY /* delay */);
-                CrossFadeHelper.fadeOut(mHeadsUpStatusBarView, CONTENT_FADE_DURATION/* duration */,
-                        0 /* delay */, () -> mHeadsUpStatusBarView.setVisibility(View.GONE));
-
+                show(mClockView);
+                if (mOperatorNameView != null) {
+                    show(mOperatorNameView);
+                }
+                hide(mHeadsUpStatusBarView, View.GONE);
             }
         }
     }
 
+    /**
+     * Hides the view and sets the state to endState when finished.
+     *
+     * @param view The view to hide.
+     * @param endState One of {@link View#INVISIBLE} or {@link View#GONE}.
+     * @see View#setVisibility(int)
+     *
+     */
+    private void hide(View view, int endState) {
+        if (mAnimationsEnabled) {
+            CrossFadeHelper.fadeOut(view, CONTENT_FADE_DURATION /* duration */,
+                    0 /* delay */, () -> view.setVisibility(endState));
+        } else {
+            view.setVisibility(endState);
+        }
+    }
+
+    private void show(View view) {
+        if (mAnimationsEnabled) {
+            CrossFadeHelper.fadeIn(view, CONTENT_FADE_DURATION /* duration */,
+                    CONTENT_FADE_DELAY /* delay */);
+        } else {
+            view.setVisibility(View.VISIBLE);
+        }
+    }
+
+    @VisibleForTesting
+    void setAnimationsEnabled(boolean enabled) {
+        mAnimationsEnabled = enabled;
+    }
+
     @VisibleForTesting
     public boolean isShown() {
         return mShown;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 538a260..ae1353d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -561,6 +561,7 @@
         }
         mDarkAmount = darkAmount;
         mIndicationArea.setAlpha(1f - darkAmount);
+        mLockIcon.setDarkAmount(darkAmount);
     }
 
     private static boolean isSuccessfulLaunch(int result) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 2a4595b..8ac8677 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -361,6 +361,8 @@
         } else if (fraction == EXPANSION_HIDDEN && oldExpansion != EXPANSION_HIDDEN) {
             onFullyHidden();
             mExpansionCallback.onFullyHidden();
+        } else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
+            mExpansionCallback.onStartingToHide();
         }
     }
 
@@ -481,6 +483,7 @@
 
     public interface BouncerExpansionCallback {
         void onFullyShown();
+        void onStartingToHide();
         void onFullyHidden();
     }
 }
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 7c84df9..e85ff8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -519,7 +519,14 @@
         mStatusIconContainer.setAlpha(alpha);
         mStatusIconContainer.setVisibility(visibility);
 
-        mSystemIconsContainer.setTranslationX(-mCurrentBurnInOffsetX * mDarkAmount);
+        float iconsX = -mCurrentBurnInOffsetX;
+        if (mMultiUserSwitch.getVisibility() == VISIBLE) {
+            // Squared alpha to add a nice easing curve and avoid overlap during animation.
+            mMultiUserAvatar.setAlpha(alpha * alpha);
+            iconsX += mMultiUserAvatar.getPaddingLeft() + mMultiUserAvatar.getWidth()
+                    + mMultiUserAvatar.getPaddingRight();
+        }
+        mSystemIconsContainer.setTranslationX(iconsX * mDarkAmount);
         mSystemIconsContainer.setTranslationY(mCurrentBurnInOffsetY * mDarkAmount);
         updateIconsAndTextColors();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 2edc294..d5067b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -18,13 +18,14 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
 import android.util.AttributeSet;
-import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
 
+import com.android.internal.graphics.ColorUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
@@ -58,6 +59,7 @@
     private int mDensity;
 
     private final Runnable mDrawOffTimeout = () -> update(true /* forceUpdate */);
+    private float mDarkAmount;
 
     public LockIcon(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -130,6 +132,7 @@
                     ? (AnimatedVectorDrawable) icon
                     : null;
             setImageDrawable(icon, false);
+            updateDarkTint();
             if (mHasFaceUnlockIcon) {
                 announceForAccessibility(getContext().getString(
                     R.string.accessibility_scanning_face));
@@ -259,4 +262,15 @@
             return STATE_LOCKED;
         }
     }
+
+    public void setDarkAmount(float darkAmount) {
+        mDarkAmount = darkAmount;
+        updateDarkTint();
+    }
+
+    private void updateDarkTint() {
+        Drawable drawable = getDrawable().mutate();
+        int color = ColorUtils.blendARGB(Color.TRANSPARENT, Color.WHITE, mDarkAmount);
+        drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
+    }
 }
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 0b5871e..6bccf31 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -641,9 +641,12 @@
     // Injected from StatusBar at creation.
     public void setCurrentSysuiVisibility(int systemUiVisibility) {
         mSystemUiVisibility = systemUiVisibility;
-        mNavigationBarMode = mStatusBar.computeBarMode(0, mSystemUiVisibility,
+        final int barMode = mStatusBar.computeBarMode(0, mSystemUiVisibility,
                 View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
                 View.NAVIGATION_BAR_TRANSPARENT);
+        if (barMode != -1) {
+            mNavigationBarMode = barMode;
+        }
         checkNavBarModes();
         mStatusBar.touchAutoHide();
         mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
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 a7c43cd..56bef2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -524,6 +524,7 @@
     private boolean mIsOccluded;
     private boolean mWereIconsJustHidden;
     private boolean mBouncerWasShowingWhenHidden;
+    private boolean mIsCollapsingToShowActivityOverLockscreen;
 
     // Notifies StatusBarKeyguardViewManager every time the keyguard transition is over,
     // this animation is tied to the scrim for historic reasons.
@@ -2232,7 +2233,11 @@
 
         runPostCollapseRunnables();
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
-        showBouncerIfKeyguard();
+        if (!mIsCollapsingToShowActivityOverLockscreen) {
+            showBouncerIfKeyguard();
+        } else if (DEBUG) {
+            Log.d(TAG, "Not showing bouncer due to activity showing over lockscreen");
+        }
         recomputeDisableFlags(mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
 
         // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
@@ -4745,7 +4750,11 @@
                 && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
                 mLockscreenUserManager.getCurrentUserId());
         final boolean wasOccluded = mIsOccluded;
-        dismissKeyguardThenExecute(() -> {
+        boolean showOverLockscreen = mStatusBarKeyguardViewManager.isShowing()
+                && PreviewInflater.wouldShowOverLockscreen(mContext,
+                intent.getIntent(),
+                mLockscreenUserManager.getCurrentUserId());
+        OnDismissAction postKeyguardAction = () -> {
             // TODO: Some of this code may be able to move to NotificationEntryManager.
             if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(notificationKey)) {
                 // Release the HUN notification to the shade.
@@ -4853,9 +4862,14 @@
                     // Automatically remove all notifications that we may have kept around longer
                     removeNotification(sbn);
                 }
+
+                mIsCollapsingToShowActivityOverLockscreen = false;
             };
 
-            if (mStatusBarKeyguardViewManager.isShowing()
+            if (showOverLockscreen) {
+                addPostCollapseAction(runnable);
+                collapsePanel(true /* animate */);
+            } else if (mStatusBarKeyguardViewManager.isShowing()
                     && mStatusBarKeyguardViewManager.isOccluded()) {
                 mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
                 collapsePanel(true /* animate */);
@@ -4864,7 +4878,13 @@
             }
 
             return !mNotificationPanel.isFullyCollapsed();
-        }, afterKeyguardGone);
+        };
+        if (showOverLockscreen) {
+            mIsCollapsingToShowActivityOverLockscreen = true;
+            postKeyguardAction.onDismiss();
+        } else {
+            dismissKeyguardThenExecute(postKeyguardAction, afterKeyguardGone);
+        }
     }
 
     private void collapseOnMainThread() {
@@ -4881,7 +4901,10 @@
 
     public void collapsePanel(boolean animate) {
         if (animate) {
-            collapsePanel();
+            boolean willCollapse = collapsePanel();
+            if (!willCollapse) {
+                runPostCollapseRunnables();
+            }
         } else if (!isPresenterFullyCollapsed()) {
             instantCollapseNotificationPanel();
             visibilityChanged(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 3db1456..ac3608b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -84,6 +84,11 @@
         }
 
         @Override
+        public void onStartingToHide() {
+            updateStates();
+        }
+
+        @Override
         public void onFullyHidden() {
             updateStates();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
index 687b83a..92034b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
@@ -146,6 +146,14 @@
                 == null;
     }
 
+    public static boolean wouldShowOverLockscreen(Context ctx, Intent intent, int currentUserId) {
+        ActivityInfo targetActivityInfo = getTargetActivityInfo(ctx, intent, currentUserId,
+                false /* onlyDirectBootAware */);
+        return targetActivityInfo != null
+                && (targetActivityInfo.flags & (ActivityInfo.FLAG_SHOW_WHEN_LOCKED
+                | ActivityInfo.FLAG_SHOW_FOR_ALL_USERS)) > 0;
+    }
+
     /**
      * @param onlyDirectBootAware a boolean indicating whether the matched activity packages must
      *                            be direct boot aware when in direct boot mode if false, all
diff --git a/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java b/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
index 5790ba3..0dd8937 100644
--- a/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
+++ b/packages/SystemUI/src/com/android/systemui/util/AsyncSensorManager.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.util;
 
+import android.content.Context;
 import android.hardware.HardwareBuffer;
 import android.hardware.Sensor;
 import android.hardware.SensorAdditionalInfo;
@@ -30,7 +31,11 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.SensorManagerPlugin;
+import com.android.systemui.shared.plugins.PluginManager;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -40,7 +45,8 @@
  * without blocking. Note that this means registering listeners now always appears successful even
  * if it is not.
  */
-public class AsyncSensorManager extends SensorManager {
+public class AsyncSensorManager extends SensorManager
+        implements PluginListener<SensorManagerPlugin> {
 
     private static final String TAG = "AsyncSensorManager";
 
@@ -48,12 +54,15 @@
     private final List<Sensor> mSensorCache;
     private final HandlerThread mHandlerThread = new HandlerThread("async_sensor");
     @VisibleForTesting final Handler mHandler;
+    private final List<SensorManagerPlugin> mPlugins;
 
-    public AsyncSensorManager(SensorManager inner) {
+    public AsyncSensorManager(SensorManager inner, PluginManager pluginManager) {
         mInner = inner;
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper());
         mSensorCache = mInner.getSensorList(Sensor.TYPE_ALL);
+        mPlugins = new ArrayList<>();
+        pluginManager.addPluginListener(this, SensorManagerPlugin.class, true /* allowMultiple */);
     }
 
     @Override
@@ -63,7 +72,7 @@
 
     @Override
     protected List<Sensor> getFullDynamicSensorList() {
-        return mInner.getDynamicSensorList(Sensor.TYPE_ALL);
+        return mInner.getSensorList(Sensor.TYPE_ALL);
     }
 
     @Override
@@ -132,6 +141,32 @@
         return true;
     }
 
+    /**
+     * Requests for all sensors that match the given type from all plugins.
+     * @param sensor
+     * @param listener
+     */
+    public void requestPluginTriggerSensor(SensorManagerPlugin.Sensor sensor,
+            SensorManagerPlugin.TriggerEventListener listener) {
+        if (mPlugins.isEmpty()) {
+            Log.w(TAG, "No plugins registered");
+        }
+        mHandler.post(() -> {
+            for (int i = 0; i < mPlugins.size(); i++) {
+                mPlugins.get(i).registerTriggerEvent(sensor, listener);
+            }
+        });
+    }
+
+    public void cancelPluginTriggerSensor(SensorManagerPlugin.Sensor sensor,
+            SensorManagerPlugin.TriggerEventListener listener) {
+        mHandler.post(() -> {
+            for (int i = 0; i < mPlugins.size(); i++) {
+                mPlugins.get(i).unregisterTriggerEvent(sensor, listener);
+            }
+        });
+    }
+
     @Override
     protected boolean initDataInjectionImpl(boolean enable) {
         throw new UnsupportedOperationException("not implemented");
@@ -159,4 +194,14 @@
             }
         });
     }
+
+    @Override
+    public void onPluginConnected(SensorManagerPlugin plugin, Context pluginContext) {
+        mPlugins.add(plugin);
+    }
+
+    @Override
+    public void onPluginDisconnected(SensorManagerPlugin plugin) {
+        mPlugins.remove(plugin);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt
index cfe9818..ab3a3e1 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt
@@ -46,9 +46,9 @@
     }
 
     @Test
-    fun onResume_clearsTextField() {
+    fun onPause_clearsTextField() {
         mSecurityMessage.setMessage("an old message")
-        mKeyguardPatternView.onResume(KeyguardSecurityView.SCREEN_ON)
+        mKeyguardPatternView.onPause()
         assertThat(mSecurityMessage.text).isEqualTo("")
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
new file mode 100644
index 0000000..d9412ec
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.qs.tiles;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.service.quicksettings.Tile;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.NetworkController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.HashSet;
+import java.util.Set;
+
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class CastTileTest extends SysuiTestCase {
+
+    @Mock
+    private CastController mController;
+    @Mock
+    private ActivityStarter mActivityStarter;
+    @Mock
+    private KeyguardMonitor mKeyguard;
+    @Mock
+    private NetworkController mNetworkController;
+    @Mock
+    private QSTileHost mHost;
+    @Mock
+    NetworkController.SignalCallback mCallback;
+
+    private TestableLooper mTestableLooper;
+    private CastTile mCastTile;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mTestableLooper = TestableLooper.get(this);
+
+        mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+        mController = mDependency.injectMockDependency(CastController.class);
+        mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
+        mKeyguard = mDependency.injectMockDependency(KeyguardMonitor.class);
+        mNetworkController = mDependency.injectMockDependency(NetworkController.class);
+
+        when(mHost.getContext()).thenReturn(mContext);
+
+        mCastTile = new CastTile(mHost);
+
+        // We are not setting the mocks to listening, so we trigger a first refresh state to
+        // set the initial state
+        mCastTile.refreshState();
+
+        mCastTile.handleSetListening(true);
+        ArgumentCaptor<NetworkController.SignalCallback> signalCallbackArgumentCaptor =
+                ArgumentCaptor.forClass(NetworkController.SignalCallback.class);
+        verify(mNetworkController).addCallback(signalCallbackArgumentCaptor.capture());
+        mCallback = signalCallbackArgumentCaptor.getValue();
+
+    }
+
+    @Test
+    public void testStateUnavailable_wifiDisabled() {
+        NetworkController.IconState qsIcon =
+                new NetworkController.IconState(false, 0, "");
+        mCallback.setWifiIndicators(false, mock(NetworkController.IconState.class),
+                qsIcon, false,false, "",
+                false, "");
+        mTestableLooper.processAllMessages();
+
+        assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
+    }
+
+    @Test
+    public void testStateUnavailable_wifiNotConnected() {
+        NetworkController.IconState qsIcon =
+                new NetworkController.IconState(false, 0, "");
+        mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+                qsIcon, false,false, "",
+                false, "");
+        mTestableLooper.processAllMessages();
+
+        assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
+    }
+
+    @Test
+    public void testStateActive_wifiEnabledAndCasting() {
+        CastController.CastDevice device = mock(CastController.CastDevice.class);
+        device.state = CastController.CastDevice.STATE_CONNECTED;
+        Set<CastController.CastDevice> devices = new HashSet<>();
+        devices.add(device);
+        when(mController.getCastDevices()).thenReturn(devices);
+
+        NetworkController.IconState qsIcon =
+                new NetworkController.IconState(true, 0, "");
+        mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+                qsIcon, false,false, "",
+                false, "");
+        mTestableLooper.processAllMessages();
+
+        assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state);
+    }
+
+    @Test
+    public void testStateInactive_wifiEnabledNotCasting() {
+        NetworkController.IconState qsIcon =
+                new NetworkController.IconState(true, 0, "");
+        mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+                qsIcon, false,false, "",
+                false, "");
+        mTestableLooper.processAllMessages();
+
+        assertEquals(Tile.STATE_INACTIVE, mCastTile.getState().state);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index a4004ae..10b0d83 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -54,6 +54,7 @@
     private ExpandableNotificationRow mFirst;
     private HeadsUpStatusBarView mHeadsUpStatusBarView;
     private HeadsUpManagerPhone mHeadsUpManager;
+    private View mOperatorNameView;
 
     @Before
     public void setUp() throws Exception {
@@ -63,13 +64,15 @@
         mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
                 mock(TextView.class));
         mHeadsUpManager = mock(HeadsUpManagerPhone.class);
+        mOperatorNameView = new View(mContext);
         mHeadsUpAppearanceController = new HeadsUpAppearanceController(
                 mock(NotificationIconAreaController.class),
                 mHeadsUpManager,
                 mHeadsUpStatusBarView,
                 mStackScroller,
                 mPanelView,
-                new View(mContext));
+                new View(mContext),
+                mOperatorNameView);
         mHeadsUpAppearanceController.setExpandedHeight(0.0f, 0.0f);
     }
 
@@ -116,6 +119,22 @@
     }
 
     @Test
+    public void testOperatorNameViewUpdated() {
+        mHeadsUpAppearanceController.setAnimationsEnabled(false);
+
+        mFirst.setPinned(true);
+        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
+        when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry());
+        mHeadsUpAppearanceController.onHeadsUpPinned(mFirst);
+        Assert.assertEquals(View.INVISIBLE, mOperatorNameView.getVisibility());
+
+        mFirst.setPinned(false);
+        when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
+        mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst);
+        Assert.assertEquals(View.VISIBLE, mOperatorNameView.getVisibility());
+    }
+
+    @Test
     public void testHeaderReadFromOldController() {
         mHeadsUpAppearanceController.setExpandedHeight(1.0f, 1.0f);
 
@@ -125,6 +144,7 @@
                 mHeadsUpStatusBarView,
                 mStackScroller,
                 mPanelView,
+                new View(mContext),
                 new View(mContext));
         newController.readFrom(mHeadsUpAppearanceController);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index a7954f2..020682b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -170,13 +170,17 @@
         mBouncer.ensureView();
         mBouncer.setExpansion(0.5f);
 
-        mBouncer.setExpansion(1);
+        mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
         verify(mFalsingManager).onBouncerHidden();
         verify(mExpansionCallback).onFullyHidden();
 
-        mBouncer.setExpansion(0);
+        mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
         verify(mFalsingManager).onBouncerShown();
         verify(mExpansionCallback).onFullyShown();
+
+        verify(mExpansionCallback, never()).onStartingToHide();
+        mBouncer.setExpansion(0.9f);
+        verify(mExpansionCallback).onStartingToHide();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java
index 469bdc0..77df791 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/AsyncSensorManagerTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -28,6 +29,8 @@
 import android.testing.AndroidTestingRunner;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.SensorManagerPlugin;
+import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.utils.hardware.FakeSensorManager;
 
 import org.junit.Before;
@@ -42,9 +45,11 @@
     private FakeSensorManager mFakeSensorManager;
     private SensorEventListener mListener;
     private FakeSensorManager.MockProximitySensor mSensor;
+    private PluginManager mPluginManager;
 
     @Before
     public void setUp() throws Exception {
+        mPluginManager = mock(PluginManager.class);
         mFakeSensorManager = new FakeSensorManager(mContext);
         mAsyncSensorManager = new TestableAsyncSensorManager(mFakeSensorManager);
         mSensor = mFakeSensorManager.getMockProximitySensor();
@@ -86,9 +91,15 @@
         verifyNoMoreInteractions(mListener);
     }
 
+    @Test
+    public void registersPlugin_whenLoaded() {
+        verify(mPluginManager).addPluginListener(eq(mAsyncSensorManager),
+                eq(SensorManagerPlugin.class), eq(true) /* allowMultiple */);
+    }
+
     private class TestableAsyncSensorManager extends AsyncSensorManager {
         public TestableAsyncSensorManager(SensorManager sensorManager) {
-            super(sensorManager);
+            super(sensorManager, mPluginManager);
         }
 
         public void waitUntilRequestsCompleted() {
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 5e87707..d86de5d 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6549,6 +6549,21 @@
     // Subtype: The importance of a notification has been changed
     ADJUSTMENT_KEY_IMPORTANCE = 1580;
 
+    // OPEN: Settings > Network & internet > Mobile network > Choose network
+    // CATEGORY: SETTINGS
+    // OS: Q
+    MOBILE_NETWORK_SELECT = 1581;
+
+    // OPEN: Settings > Network & internet > Mobile network > Mobile Data > Dialog
+    // CATEGORY: SETTINGS
+    // OS: Q
+    MOBILE_DATA_DIALOG = 1582;
+
+    // OPEN: Settings > Network & internet > Mobile network > Data roaming > Dialog
+    // CATEGORY: SETTINGS
+    // OS: Q
+    MOBILE_ROAMING_DIALOG = 1583;
+
     // ---- End Q Constants, all Q constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 6918275..fbceade 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2630,7 +2630,7 @@
         final List<Integer> outsideWindowsIds;
         final List<RemoteAccessibilityConnection> connectionList = new ArrayList<>();
         synchronized (mLock) {
-            outsideWindowsIds = mSecurityPolicy.getWatchOutsideTouchWindowId(targetWindowId);
+            outsideWindowsIds = mSecurityPolicy.getWatchOutsideTouchWindowIdLocked(targetWindowId);
             for (int i = 0; i < outsideWindowsIds.size(); i++) {
                 connectionList.add(getConnectionLocked(outsideWindowsIds.get(i)));
             }
@@ -3684,13 +3684,13 @@
             return mWindowInfoById.get(windowId);
         }
 
-        private List<Integer> getWatchOutsideTouchWindowId(int targetWindowId) {
-            if (mWindowInfoById != null && mHasWatchOutsideTouchWindow) {
+        private List<Integer> getWatchOutsideTouchWindowIdLocked(int targetWindowId) {
+            final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId);
+            if (targetWindow != null && mWindowInfoById != null && mHasWatchOutsideTouchWindow) {
                 final List<Integer> outsideWindowsId = new ArrayList<>();
-                final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId);
                 for (int i = 0; i < mWindowInfoById.size(); i++) {
                     WindowInfo window = mWindowInfoById.valueAt(i);
-                    if (window.layer < targetWindow.layer
+                    if (window != null && window.layer < targetWindow.layer
                             && window.hasFlagWatchOutsideTouch) {
                         outsideWindowsId.add(mWindowInfoById.keyAt(i));
                     }
diff --git a/services/core/Android.bp b/services/core/Android.bp
index d9519e0..2fa2941 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -4,6 +4,7 @@
     aidl: {
         include_dirs: [
             "frameworks/native/aidl/binder",
+            "frameworks/native/cmds/dumpstate/binder",
             "system/core/storaged/binder",
             "system/netd/server/binder",
             "system/vold/binder",
@@ -11,6 +12,7 @@
     },
     srcs: [
         "java/**/*.java",
+        ":dumpstate_aidl",
         ":netd_aidl",
         ":netd_metrics_aidl",
         ":installd_aidl",
@@ -44,6 +46,7 @@
         "android.hardware.configstore-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
         "android.hidl.manager-V1.0-java",
+        "netd_aidl_interface-java",
     ],
 }
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5e8ffb7..4b77c69 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1798,7 +1798,8 @@
 
     private void sendStickyBroadcast(Intent intent) {
         synchronized (this) {
-            if (!mSystemReady) {
+            if (!mSystemReady
+                    && intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                 mInitialBroadcast = new Intent(intent);
             }
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -1847,8 +1848,6 @@
                 mInitialBroadcast = null;
             }
         }
-        // load the global proxy at startup
-        mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
 
         // Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
         // for user to unlock device too.
@@ -3089,7 +3088,7 @@
                     break;
                 }
                 case EVENT_APPLY_GLOBAL_HTTP_PROXY: {
-                    handleDeprecatedGlobalHttpProxy();
+                    mProxyTracker.loadDeprecatedGlobalHttpProxy();
                     break;
                 }
                 case EVENT_PROXY_HAS_CHANGED: {
@@ -3483,29 +3482,6 @@
         }
     }
 
-    private void handleDeprecatedGlobalHttpProxy() {
-        final String proxy = Settings.Global.getString(mContext.getContentResolver(),
-                Settings.Global.HTTP_PROXY);
-        if (!TextUtils.isEmpty(proxy)) {
-            String data[] = proxy.split(":");
-            if (data.length == 0) {
-                return;
-            }
-
-            final String proxyHost = data[0];
-            int proxyPort = 8080;
-            if (data.length > 1) {
-                try {
-                    proxyPort = Integer.parseInt(data[1]);
-                } catch (NumberFormatException e) {
-                    return;
-                }
-            }
-            final ProxyInfo p = new ProxyInfo(proxyHost, proxyPort, "");
-            setGlobalProxy(p);
-        }
-    }
-
     private static class SettingsObserver extends ContentObserver {
         final private HashMap<Uri, Integer> mUriEventMap;
         final private Context mContext;
@@ -5537,15 +5513,7 @@
 
             if (networkAgent.isVPN()) {
                 // Temporarily disable the default proxy (not global).
-                synchronized (mProxyTracker.mProxyLock) {
-                    if (!mProxyTracker.mDefaultProxyDisabled) {
-                        mProxyTracker.mDefaultProxyDisabled = true;
-                        if (mProxyTracker.mGlobalProxy == null
-                                && mProxyTracker.mDefaultProxy != null) {
-                            mProxyTracker.sendProxyBroadcast(null);
-                        }
-                    }
-                }
+                mProxyTracker.setDefaultProxyEnabled(false);
                 // TODO: support proxy per network.
             }
 
@@ -5567,15 +5535,7 @@
         } else if (state == NetworkInfo.State.DISCONNECTED) {
             networkAgent.asyncChannel.disconnect();
             if (networkAgent.isVPN()) {
-                synchronized (mProxyTracker.mProxyLock) {
-                    if (mProxyTracker.mDefaultProxyDisabled) {
-                        mProxyTracker.mDefaultProxyDisabled = false;
-                        if (mProxyTracker.mGlobalProxy == null
-                                && mProxyTracker.mDefaultProxy != null) {
-                            mProxyTracker.sendProxyBroadcast(mProxyTracker.mDefaultProxy);
-                        }
-                    }
-                }
+                mProxyTracker.setDefaultProxyEnabled(true);
                 updateUids(networkAgent, networkAgent.networkCapabilities, null);
             }
             disconnectAndDestroyNetwork(networkAgent);
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index 96ce6a4..6677541 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -109,14 +109,28 @@
                 "max_latency_micros",
                 "total_cpu_micros",
                 "max_cpu_micros",
+                "recorded_delay_message_count",
+                "total_delay_millis",
+                "max_delay_millis",
                 "exception_count"));
         pw.println(header);
         for (LooperStats.ExportedEntry entry : entries) {
-            pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", entry.workSourceUid,
-                    entry.threadName, entry.handlerClassName, entry.messageName,
-                    entry.isInteractive, entry.messageCount, entry.recordedMessageCount,
-                    entry.totalLatencyMicros, entry.maxLatencyMicros, entry.cpuUsageMicros,
-                    entry.maxCpuUsageMicros, entry.exceptionCount);
+            pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
+                    entry.workSourceUid,
+                    entry.threadName,
+                    entry.handlerClassName,
+                    entry.messageName,
+                    entry.isInteractive,
+                    entry.messageCount,
+                    entry.recordedMessageCount,
+                    entry.totalLatencyMicros,
+                    entry.maxLatencyMicros,
+                    entry.cpuUsageMicros,
+                    entry.maxCpuUsageMicros,
+                    entry.recordedDelayMessageCount,
+                    entry.delayMillis,
+                    entry.maxDelayMillis,
+                    entry.exceptionCount);
         }
     }
 
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index de930f7..cf39e95 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -57,6 +57,7 @@
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.INetd;
+import android.net.TetherStatsParcel;
 import android.net.INetworkManagementEventObserver;
 import android.net.ITetheringStatsProvider;
 import android.net.InterfaceConfiguration;
@@ -1844,31 +1845,30 @@
                 return new NetworkStats(SystemClock.elapsedRealtime(), 0);
             }
 
-            final PersistableBundle bundle;
+            final TetherStatsParcel[] tetherStatsVec;
             try {
-                bundle = mNetdService.tetherGetStats();
+                tetherStatsVec = mNetdService.tetherGetStats();
             } catch (RemoteException | ServiceSpecificException e) {
                 throw new IllegalStateException("problem parsing tethering stats: ", e);
             }
 
             final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(),
-                    bundle.size());
+                tetherStatsVec.length);
             final NetworkStats.Entry entry = new NetworkStats.Entry();
 
-            for (String iface : bundle.keySet()) {
-                long[] statsArray = bundle.getLongArray(iface);
+            for (TetherStatsParcel tetherStats : tetherStatsVec) {
                 try {
-                    entry.iface = iface;
+                    entry.iface = tetherStats.iface;
                     entry.uid = UID_TETHERING;
                     entry.set = SET_DEFAULT;
                     entry.tag = TAG_NONE;
-                    entry.rxBytes   = statsArray[INetd.TETHER_STATS_RX_BYTES];
-                    entry.rxPackets = statsArray[INetd.TETHER_STATS_RX_PACKETS];
-                    entry.txBytes   = statsArray[INetd.TETHER_STATS_TX_BYTES];
-                    entry.txPackets = statsArray[INetd.TETHER_STATS_TX_PACKETS];
+                    entry.rxBytes   = tetherStats.rxBytes;
+                    entry.rxPackets = tetherStats.rxPackets;
+                    entry.txBytes   = tetherStats.txBytes;
+                    entry.txPackets = tetherStats.txPackets;
                     stats.combineValues(entry);
                 } catch (ArrayIndexOutOfBoundsException e) {
-                    throw new IllegalStateException("invalid tethering stats for " + iface, e);
+                    throw new IllegalStateException("invalid tethering stats " + e);
                 }
             }
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 21f54dd..7c67596 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3754,7 +3754,7 @@
         }
 
         @Override
-        public void mountExternalStorageForApp(String packageName, int appId, String sharedUserId,
+        public void prepareSandboxForApp(String packageName, int appId, String sharedUserId,
                 int userId) {
             final String sandboxId;
             synchronized (mPackagesLock) {
@@ -3771,7 +3771,41 @@
             }
 
             try {
-                mVold.mountExternalStorageForApp(packageName, appId, sandboxId, userId);
+                mVold.prepareSandboxForApp(packageName, appId, sandboxId, userId);
+            } catch (Exception e) {
+                Slog.wtf(TAG, e);
+            }
+        }
+
+        @Override
+        public void destroySandboxForApp(String packageName, int userId) {
+            if (!ENABLE_ISOLATED_STORAGE) {
+                return;
+            }
+            final int appId;
+            final String sandboxId;
+            synchronized (mPackagesLock) {
+                final ArraySet<String> userPackages = getAvailablePackagesForUserPL(userId);
+                userPackages.remove(packageName);
+                appId = mAppIds.get(packageName);
+                sandboxId = mSandboxIds.get(appId);
+
+                // If the package is not uninstalled in any other users, remove appId and sandboxId
+                // corresponding to it from the internal state.
+                boolean installedInAnyUser = false;
+                for (int i = mPackages.size() - 1; i >= 0; --i) {
+                    if (mPackages.valueAt(i).contains(packageName)) {
+                        installedInAnyUser = true;
+                        break;
+                    }
+                }
+                if (!installedInAnyUser) {
+                    mAppIds.remove(packageName);
+                    mSandboxIds.remove(appId);
+                }
+            }
+            try {
+                mVold.destroySandboxForApp(packageName, appId, sandboxId, userId);
             } catch (Exception e) {
                 Slog.wtf(TAG, e);
             }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index fb8894b..591ec00 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -49,6 +49,7 @@
 import android.telephony.TelephonyManager;
 import android.telephony.VoLteServiceState;
 import android.util.LocalLog;
+import android.util.StatsLog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
@@ -1719,8 +1720,12 @@
         try {
             if (state == TelephonyManager.CALL_STATE_IDLE) {
                 mBatteryStats.notePhoneOff();
+                StatsLog.write(StatsLog.PHONE_STATE_CHANGED,
+                        StatsLog.PHONE_STATE_CHANGED__STATE__OFF);
             } else {
                 mBatteryStats.notePhoneOn();
+                StatsLog.write(StatsLog.PHONE_STATE_CHANGED,
+                        StatsLog.PHONE_STATE_CHANGED__STATE__ON);
             }
         } catch (RemoteException e) {
             /* The remote entity disappeared, we can safely ignore the exception. */
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index a392b51..9c60b8c 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -6155,7 +6155,12 @@
 
             final int uid;
             try {
-                uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+                long identityToken = clearCallingIdentity();
+                try {
+                    uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+                } finally {
+                    restoreCallingIdentity(identityToken);
+                }
             } catch (NameNotFoundException e) {
                 Slog.e(TAG, "Unknown package " + packageName);
                 return;
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index a648b09a..95a8e2a 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -1087,7 +1087,7 @@
         if (top == null) {
             return false;
         }
-        mSupervisor.moveFocusableActivityToTop(top, reason);
+        top.moveFocusableActivityToTop(reason);
         return true;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java b/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java
deleted file mode 100644
index f44ee7a..0000000
--- a/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.am;
-
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
-
-import com.android.server.am.LaunchParamsController.LaunchParams;
-import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
-
-/**
- * An implementation of {@link LaunchParamsModifier}, which applies the launch bounds specified
- * inside {@link ActivityOptions#getLaunchBounds()}.
- */
-public class ActivityLaunchParamsModifier implements LaunchParamsModifier {
-    private final ActivityStackSupervisor mSupervisor;
-
-    ActivityLaunchParamsModifier(ActivityStackSupervisor activityStackSupervisor) {
-        mSupervisor = activityStackSupervisor;
-    }
-
-    @Override
-    public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
-            ActivityRecord activity, ActivityRecord source, ActivityOptions options,
-            LaunchParams currentParams, LaunchParams outParams) {
-        // We only care about figuring out bounds for activities.
-        if (activity == null) {
-            return RESULT_SKIP;
-        }
-
-        // Activity must be resizeable in the specified task.
-        if (!(mSupervisor.canUseActivityOptionsLaunchBounds(options)
-                && (activity.isResizeable() || (task != null && task.isResizeable())))) {
-            return RESULT_SKIP;
-        }
-
-        final Rect bounds = options.getLaunchBounds();
-
-        // Bounds weren't valid.
-        if (bounds == null || bounds.isEmpty()) {
-            return RESULT_SKIP;
-        }
-
-        outParams.mBounds.set(bounds);
-
-        // When this is the most explicit position specification so we should not allow further
-        // modification of the position.
-        return RESULT_DONE;
-    }
-}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 37167c6..acf7a73 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10184,6 +10184,7 @@
         synchronized (this) {
             sb.append("Process: ").append(processName).append("\n");
             sb.append("PID: ").append(process.pid).append("\n");
+            sb.append("UID: ").append(process.uid).append("\n");
             int flags = process.info.flags;
             IPackageManager pm = AppGlobals.getPackageManager();
             sb.append("Flags: 0x").append(Integer.toHexString(flags)).append("\n");
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 18cdb05..7080e2b 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -110,7 +110,7 @@
  * data for Tron, logcat, event logs and {@link android.app.WaitResult}.
  *
  * Tests:
- * atest SystemMetricsFunctionalTests
+ * atest CtsActivityManagerDeviceTestCases:ActivityMetricsLoggerTests
  */
 class ActivityMetricsLogger {
 
@@ -351,18 +351,24 @@
                 + " processRunning=" + processRunning
                 + " processSwitch=" + processSwitch);
 
-        // If we are already in an existing transition, only update the activity name, but not the
-        // other attributes.
         final int windowingMode = launchedActivity != null
                 ? launchedActivity.getWindowingMode()
                 : WINDOWING_MODE_UNDEFINED;
-
+        final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
         if (mCurrentTransitionStartTime == INVALID_START_TIME) {
+            // No transition is active ignore this launch.
             return;
         }
 
-        final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
+        if (launchedActivity != null && launchedActivity.nowVisible) {
+            // Launched activity is already visible. We cannot measure windows drawn delay.
+            reset(true /* abort */, info);
+            return;
+        }
+
         if (launchedActivity != null && info != null) {
+            // If we are already in an existing transition, only update the activity name, but not
+            // the other attributes.
             info.launchedActivity = launchedActivity;
             return;
         }
@@ -371,7 +377,6 @@
                 mWindowingModeTransitionInfo.size() > 0 && info == null;
         if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch
                 || windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {
-
             // Failed to launch or it was not a process switch, so we don't care about the timing.
             reset(true /* abort */, info);
             return;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index fe10baf..6bdceb2 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -84,11 +84,13 @@
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
 
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SAVED_STATE;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
@@ -215,6 +217,7 @@
     private static final String TAG_STATES = TAG + POSTFIX_STATES;
     private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
     private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
+    private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
     // TODO(b/67864419): Remove once recents component is overridden
     private static final String LEGACY_RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
 
@@ -1348,6 +1351,42 @@
         return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
     }
 
+    /** Move activity with its stack to front and make the stack focused. */
+    boolean moveFocusableActivityToTop(String reason) {
+        if (!isFocusable()) {
+            if (DEBUG_FOCUS) {
+                Slog.d(TAG_FOCUS, "moveActivityStackToFront: unfocusable activity=" + this);
+            }
+            return false;
+        }
+
+        final TaskRecord task = getTask();
+        final ActivityStack stack = getStack();
+        if (stack == null) {
+            Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: activity="
+                    + this + " task=" + task);
+            return false;
+        }
+
+        if (mStackSupervisor.getTopResumedActivity() == this) {
+            if (DEBUG_FOCUS) {
+                Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this);
+            }
+            return false;
+        }
+
+        if (DEBUG_FOCUS) {
+            Slog.d(TAG_FOCUS, "moveActivityStackToFront: activity=" + this);
+        }
+
+        stack.moveToFront(reason, task);
+        // Report top activity change to tracking services and WM
+        if (mStackSupervisor.getTopResumedActivity() == this) {
+            // TODO(b/111361570): Support multiple focused apps in WM
+            service.setResumedActivityUncheckLocked(this, reason);
+        }
+        return true;
+    }
 
     /**
      * @return true if the activity contains windows that have
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6388423..864bf2d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -227,7 +227,7 @@
     }
 
     @Override
-    protected ConfigurationContainer getChildAt(int index) {
+    protected TaskRecord getChildAt(int index) {
         return mTaskHistory.get(index);
     }
 
@@ -3450,8 +3450,10 @@
         final String myReason = reason + " adjustFocus";
 
         if (next == r) {
-            mStackSupervisor.moveFocusableActivityToTop(mStackSupervisor.topRunningActivityLocked(),
-                    myReason);
+            final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
+            if (top != null) {
+                top.moveFocusableActivityToTop(myReason);
+            }
             return;
         }
 
@@ -4662,7 +4664,9 @@
 
             // Set focus to the top running activity of this stack.
             final ActivityRecord r = topRunningActivityLocked();
-            mStackSupervisor.moveFocusableActivityToTop(r, reason);
+            if (r != null) {
+                r.moveFocusableActivityToTop(reason);
+            }
 
             if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
             if (noAnimation) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 0477d73..8c8146c 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -53,8 +53,8 @@
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.Display.TYPE_VIRTUAL;
 import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
+
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
@@ -63,7 +63,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
@@ -99,6 +98,7 @@
 import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
 import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
 import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+
 import static java.lang.Integer.MAX_VALUE;
 
 import android.Manifest;
@@ -199,7 +199,6 @@
 public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener,
         RecentTasks.Callbacks, RootWindowContainerListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
-    private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
     private static final String TAG_IDLE = TAG + POSTFIX_IDLE;
     private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
@@ -783,7 +782,7 @@
 
         // Only resume home activity if isn't finishing.
         if (r != null && !r.finishing) {
-            moveFocusableActivityToTop(r, myReason);
+            r.moveFocusableActivityToTop(myReason);
             return resumeFocusedStacksTopActivitiesLocked(r.getStack(), prev, null);
         }
         return mService.startHomeActivityLocked(mCurrentUser, myReason, displayId);
@@ -3359,41 +3358,6 @@
         mService.getTaskChangeNotificationController().notifyActivityPinned(r);
     }
 
-    /** Move activity with its stack to front and make the stack focused. */
-    // TODO(b/111363427): Move this method to ActivityRecord.
-    boolean moveFocusableActivityToTop(ActivityRecord r, String reason) {
-        if (r == null || !r.isFocusable()) {
-            if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
-                    "moveActivityStackToFront: unfocusable r=" + r);
-            return false;
-        }
-
-        final TaskRecord task = r.getTask();
-        final ActivityStack stack = r.getStack();
-        if (stack == null) {
-            Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: r="
-                    + r + " task=" + task);
-            return false;
-        }
-
-        if (r == getTopResumedActivity()) {
-            if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
-                    "moveActivityStackToFront: already on top, r=" + r);
-            return false;
-        }
-
-        if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
-                "moveActivityStackToFront: r=" + r);
-
-        stack.moveToFront(reason, task);
-        // Report top activity change to tracking services and WM
-        if (r == getTopResumedActivity()) {
-            // TODO(b/111361570): Support multiple focused apps in WM
-            mService.setResumedActivityUncheckLocked(r, reason);
-        }
-        return true;
-    }
-
     ActivityRecord findTaskLocked(ActivityRecord r, int preferredDisplayId) {
         if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
         mTmpFindTaskResult.clear();
@@ -4456,10 +4420,6 @@
             if (!task.canBeLaunchedOnDisplay(actualDisplayId)) {
                 throw new IllegalStateException("Task resolved to incompatible display");
             }
-            // The task might have landed on a display different from requested.
-            // TODO(multi-display): Find proper stack for the task on the default display.
-            mService.setTaskWindowingMode(task.taskId,
-                    WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, true /* toTop */);
             if (preferredDisplayId != actualDisplayId) {
                 Slog.w(TAG, "Failed to put " + task + " on display " + preferredDisplayId);
                 // Display a warning toast that we failed to put a task on a secondary display.
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 2bd22e8..33f949f 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1477,7 +1477,7 @@
         if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                 && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
             newTask = true;
-            result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
+            result = setTaskFromReuseOrCreateNewTask(taskToAffiliate);
         } else if (mSourceRecord != null) {
             result = setTaskFromSourceRecord();
         } else if (mInTask != null) {
@@ -1606,13 +1606,18 @@
         mVoiceSession = voiceSession;
         mVoiceInteractor = voiceInteractor;
 
-        mPreferredDisplayId = getPreferedDisplayId(mSourceRecord, mStartActivity, options);
-
         mLaunchParams.reset();
 
         mSupervisor.getLaunchParamsController().calculate(inTask, null /*layout*/, r, sourceRecord,
                 options, mLaunchParams);
 
+        if (mLaunchParams.hasPreferredDisplay()) {
+            mPreferredDisplayId = mLaunchParams.mPreferredDisplayId;
+        } else {
+            mPreferredDisplayId = DEFAULT_DISPLAY;
+        }
+        ensureValidPreferredDisplayId(r);
+
         mLaunchMode = r.launchMode;
 
         mLaunchFlags = adjustLaunchFlagsToDocumentMode(
@@ -1704,6 +1709,24 @@
         mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
     }
 
+    /**
+     * Ensure preferred display ID matches the starting activity.
+     */
+    private void ensureValidPreferredDisplayId(ActivityRecord startingActivity) {
+        // Check if the Activity is a VR activity. If so, the activity should be launched in
+        // main display.
+        if (startingActivity != null && startingActivity.requestedVrComponent != null) {
+            mPreferredDisplayId = DEFAULT_DISPLAY;
+        }
+
+        // Get the virtual display ID from ActivityStackManagerService. If that's set we should
+        // always use that.
+        final int displayId = mService.mVr2dDisplayId;
+        if (displayId != INVALID_DISPLAY) {
+            mPreferredDisplayId = displayId;
+        }
+    }
+
     private void sendNewTaskResultRequestIfNeeded() {
         final ActivityStack sourceStack = mStartActivity.resultTo != null
                 ? mStartActivity.resultTo.getStack() : null;
@@ -1883,44 +1906,6 @@
     }
 
     /**
-     * Returns the ID of the display to use for a new activity. If the device is in VR mode,
-     * then return the Vr mode's virtual display ID. If not,  if the activity was started with
-     * a launchDisplayId, use that. Otherwise, if the source activity has a explicit display ID
-     * set, use that to launch the activity.
-     */
-    private int getPreferedDisplayId(
-            ActivityRecord sourceRecord, ActivityRecord startingActivity, ActivityOptions options) {
-        // Check if the Activity is a VR activity. If so, the activity should be launched in
-        // main display.
-        if (startingActivity != null && startingActivity.requestedVrComponent != null) {
-            return DEFAULT_DISPLAY;
-        }
-
-        // Get the virtual display id from ActivityManagerService.
-        int displayId = mService.mVr2dDisplayId;
-        if (displayId != INVALID_DISPLAY) {
-            if (DEBUG_STACK) {
-                Slog.d(TAG, "getSourceDisplayId :" + displayId);
-            }
-            return displayId;
-        }
-
-        // If the caller requested a display, prefer that display.
-        final int launchDisplayId =
-                (options != null) ? options.getLaunchDisplayId() : INVALID_DISPLAY;
-        if (launchDisplayId != INVALID_DISPLAY) {
-            return launchDisplayId;
-        }
-
-        displayId = sourceRecord != null ? sourceRecord.getDisplayId() : INVALID_DISPLAY;
-        // If the activity has a displayId set explicitly, launch it on the same displayId.
-        if (displayId != INVALID_DISPLAY) {
-            return displayId;
-        }
-        return DEFAULT_DISPLAY;
-    }
-
-    /**
      * Figure out which task and activity to bring to front when we have found an existing matching
      * activity record in history. May also clear the task if needed.
      * @param intentActivity Existing matching activity.
@@ -2125,8 +2110,7 @@
         mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
     }
 
-    private int setTaskFromReuseOrCreateNewTask(
-            TaskRecord taskToAffiliate, ActivityStack topStack) {
+    private int setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
         mTargetStack = computeStackFocus(mStartActivity, true, mLaunchFlags, mOptions);
 
         // Do no move the target stack to front yet, as we might bail if
@@ -2431,17 +2415,6 @@
             }
         }
         if (stack == null) {
-            // We first try to put the task in the first dynamic stack on home display.
-            final ActivityDisplay display = mSupervisor.getDefaultDisplay();
-            for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-                stack = display.getChildAt(stackNdx);
-                if (!stack.isOnHomeDisplay()) {
-                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                            "computeStackFocus: Setting focused stack=" + stack);
-                    return stack;
-                }
-            }
-            // If there is no suitable dynamic stack then we figure out which static stack to use.
             stack = mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP);
         }
         if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 8e3eeae..4dd5a99 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -1707,7 +1707,7 @@
                     return;
                 }
                 final ActivityRecord r = stack.topRunningActivityLocked();
-                if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedStack")) {
+                if (r != null && r.moveFocusableActivityToTop("setFocusedStack")) {
                     mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
                 }
             }
@@ -1728,7 +1728,7 @@
                     return;
                 }
                 final ActivityRecord r = task.topRunningActivityLocked();
-                if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedTask")) {
+                if (r != null && r.moveFocusableActivityToTop("setFocusedTask")) {
                     mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
                 }
             }
@@ -5554,7 +5554,7 @@
                     throw new IllegalArgumentException(
                             "setFocusedActivity: No activity record matching token=" + token);
                 }
-                if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedActivity")) {
+                if (r.moveFocusableActivityToTop("setFocusedActivity")) {
                     mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
                 }
             }
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 160c753..09c152e 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -55,6 +55,7 @@
         // add other system settings here...
 
         sGlobalSettingToTypeMap.put(Settings.Global.DEBUG_VIEW_ATTRIBUTES, int.class);
+        sGlobalSettingToTypeMap.put(Settings.Global.ANGLE_ENABLED_APP, String.class);
         // add other global settings here...
     }
 
diff --git a/services/core/java/com/android/server/am/LaunchParamsController.java b/services/core/java/com/android/server/am/LaunchParamsController.java
index 6415c3e..218d908 100644
--- a/services/core/java/com/android/server/am/LaunchParamsController.java
+++ b/services/core/java/com/android/server/am/LaunchParamsController.java
@@ -16,6 +16,13 @@
 
 package com.android.server.am;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
+
 import android.annotation.IntDef;
 import android.app.ActivityOptions;
 import android.content.pm.ActivityInfo.WindowLayout;
@@ -26,13 +33,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.view.Display.INVALID_DISPLAY;
-
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
-
 /**
  * {@link LaunchParamsController} calculates the {@link LaunchParams} by coordinating between
  * registered {@link LaunchParamsModifier}s.
@@ -58,11 +58,7 @@
      */
     void registerDefaultModifiers(ActivityStackSupervisor supervisor) {
         // {@link TaskLaunchParamsModifier} handles window layout preferences.
-        registerModifier(new TaskLaunchParamsModifier());
-
-        // {@link ActivityLaunchParamsModifier} is the most specific modifier and thus should be
-        // registered last (applied first) out of the defaults.
-        registerModifier(new ActivityLaunchParamsModifier(supervisor));
+        registerModifier(new TaskLaunchParamsModifier(supervisor));
     }
 
     /**
@@ -226,27 +222,41 @@
         @IntDef({RESULT_SKIP, RESULT_DONE, RESULT_CONTINUE})
         @interface Result {}
 
-        // Returned when the modifier does not want to influence the bounds calculation
+        /** Returned when the modifier does not want to influence the bounds calculation */
         int RESULT_SKIP = 0;
-        // Returned when the modifier has changed the bounds and would like its results to be the
-        // final bounds applied.
+        /**
+         * Returned when the modifier has changed the bounds and would like its results to be the
+         * final bounds applied.
+         */
         int RESULT_DONE = 1;
-        // Returned when the modifier has changed the bounds but is okay with other modifiers
-        // influencing the bounds.
+        /**
+         * Returned when the modifier has changed the bounds but is okay with other modifiers
+         * influencing the bounds.
+         */
         int RESULT_CONTINUE = 2;
 
         /**
-         * Called when asked to calculate {@link LaunchParams}.
-         * @param task            The {@link TaskRecord} currently being positioned.
-         * @param layout          The specified {@link WindowLayout}.
-         * @param activity        The {@link ActivityRecord} currently being positioned.
-         * @param source          The {@link ActivityRecord} activity was started from.
-         * @param options         The {@link ActivityOptions} specified for the activity.
-         * @param currentParams   The current {@link LaunchParams}. This can differ from the initial
-         *                        params as it represents the modified params up to this point.
-         * @param outParams       The resulting {@link LaunchParams} after all calculations.
-         * @return                A {@link Result} representing the result of the
-         *                        {@link LaunchParams} calculation.
+         * Returns the launch params that the provided activity launch params should be overridden
+         * to. {@link LaunchParamsModifier} can use this for various purposes, including: 1)
+         * Providing default bounds if the launch bounds have not been provided. 2) Repositioning
+         * the task so it doesn't get placed over an existing task. 3) Resizing the task so that its
+         * dimensions match the activity's requested orientation.
+         *
+         * @param task          Can be: 1) the target task in which the source activity wants to
+         *                      launch the target activity; 2) a newly created task that Android
+         *                      gives a chance to override its launching bounds; 3) {@code null} if
+         *                      this is called to override an activity's launching bounds.
+         * @param layout        Desired layout when activity is first launched.
+         * @param activity      Activity that is being started. This can be {@code null} on
+         *                      re-parenting an activity to a new task (e.g. for
+         *                      Picture-In-Picture). Tasks being created because an activity was
+         *                      launched should have this be non-null.
+         * @param source        the Activity that launched a new task. Could be {@code null}.
+         * @param options       {@link ActivityOptions} used to start the activity with.
+         * @param currentParams launching params after the process of last {@link
+         *                      LaunchParamsModifier}.
+         * @param outParams     the result params to be set.
+         * @return see {@link LaunchParamsModifier.Result}
          */
         @Result
         int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
diff --git a/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
index 92f1cc3..fd34d18 100644
--- a/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
@@ -16,304 +16,770 @@
 
 package com.android.server.am;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT;
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityOptions;
+import android.app.WindowConfiguration;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.graphics.Rect;
+import android.os.Build;
 import android.util.Slog;
 import android.view.Gravity;
-import com.android.internal.annotations.VisibleForTesting;
+
 import com.android.server.am.LaunchParamsController.LaunchParams;
 import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
- * Determines where a launching task should be positioned and sized on the display.
- *
- * The modifier is fairly simple. For the new task it tries default position based on the gravity
- * and compares corners of the task with corners of existing tasks. If some two pairs of corners are
- * sufficiently close enough, it shifts the bounds of the new task and tries again. When it exhausts
- * all possible shifts, it gives up and puts the task in the original position.
- *
- * Note that the only gravities of concern are the corners and the center.
+ * The class that defines the default launch params for tasks.
  */
 class TaskLaunchParamsModifier implements LaunchParamsModifier {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskLaunchParamsModifier" : TAG_AM;
+    private static final boolean DEBUG = false;
 
-    // Determines how close window frames/corners have to be to call them colliding.
-    private static final int BOUNDS_CONFLICT_MIN_DISTANCE = 4;
+    // A mask for SUPPORTS_SCREEN that indicates the activity supports resize.
+    private static final int SUPPORTS_SCREEN_RESIZEABLE_MASK =
+            ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
+                    | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS
+                    | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
+                    | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS
+                    | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
+                    | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
 
-    // Task will receive dimensions based on available dimensions divided by this.
-    private static final int WINDOW_SIZE_DENOMINATOR = 2;
+    // Screen size of Nexus 5x
+    private static final int DEFAULT_PORTRAIT_PHONE_WIDTH_DP = 412;
+    private static final int DEFAULT_PORTRAIT_PHONE_HEIGHT_DP = 732;
 
-    // Task will receive margins based on available dimensions divided by this.
-    private static final int MARGIN_SIZE_DENOMINATOR = 4;
+    // Allowance of size matching.
+    private static final int EPSILON = 2;
 
-    // If task bounds collide with some other, we will step and try again until we find a good
-    // position. The step will be determined by using dimensions and dividing it by this.
+    // Cascade window offset.
+    private static final int CASCADING_OFFSET_DP = 75;
+
+    // Threshold how close window corners have to be to call them colliding.
+    private static final int BOUNDS_CONFLICT_THRESHOLD = 4;
+
+    // Divide display size by this number to get each step to adjust bounds to avoid conflict.
     private static final int STEP_DENOMINATOR = 16;
 
     // We always want to step by at least this.
     private static final int MINIMAL_STEP = 1;
 
-    // Used to indicate if positioning algorithm is allowed to restart from the beginning, when it
-    // reaches the end of stack bounds.
-    private static final boolean ALLOW_RESTART = true;
+    private final ActivityStackSupervisor mSupervisor;
+    private final Rect mTmpBounds = new Rect();
+    private final int[] mTmpDirections = new int[2];
 
-    private static final int SHIFT_POLICY_DIAGONAL_DOWN = 1;
-    private static final int SHIFT_POLICY_HORIZONTAL_RIGHT = 2;
-    private static final int SHIFT_POLICY_HORIZONTAL_LEFT = 3;
+    private StringBuilder mLogBuilder;
 
-    private final Rect mAvailableRect = new Rect();
-    private final Rect mTmpProposal = new Rect();
-    private final Rect mTmpOriginal = new Rect();
+    TaskLaunchParamsModifier(ActivityStackSupervisor supervisor) {
+        mSupervisor = supervisor;
+    }
 
-    /**
-     * Tries to set task's bound in a way that it won't collide with any other task. By colliding
-     * we mean that two tasks have left-top corner very close to each other, so one might get
-     * obfuscated by the other one.
-     */
     @Override
     public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
                            ActivityRecord activity, ActivityRecord source, ActivityOptions options,
                            LaunchParams currentParams, LaunchParams outParams) {
-        // We can only apply positioning if we're in a freeform stack.
-        if (task == null || task.getStack() == null || !task.inFreeformWindowingMode()) {
-            return RESULT_SKIP;
+        initLogBuilder(task, activity);
+        final int result = calculate(task, layout, activity, source, options, currentParams,
+                outParams);
+        outputLog();
+        return result;
+    }
+
+    private int calculate(TaskRecord task, ActivityInfo.WindowLayout layout,
+            ActivityRecord activity, ActivityRecord source, ActivityOptions options,
+            LaunchParams currentParams, LaunchParams outParams) {
+        // STEP 1: Determine the display to launch the activity/task.
+        final int displayId = getPreferredLaunchDisplay(options, source, currentParams);
+        outParams.mPreferredDisplayId = displayId;
+        ActivityDisplay display = mSupervisor.getActivityDisplay(displayId);
+        if (DEBUG) {
+            appendLog("display-id=" + outParams.mPreferredDisplayId + " display-windowing-mode="
+                    + display.getWindowingMode());
         }
 
-        final ArrayList<TaskRecord> tasks = task.getStack().getAllTasks();
-
-        mAvailableRect.set(task.getParent().getBounds());
-
-        final Rect resultBounds = outParams.mBounds;
-
-        if (layout == null) {
-            positionCenter(tasks, mAvailableRect, getFreeformWidth(mAvailableRect),
-                    getFreeformHeight(mAvailableRect), resultBounds);
-            return RESULT_CONTINUE;
+        final ActivityRecord root;
+        if (task != null) {
+            root = (task.getRootActivity() == null ? activity : task.getRootActivity());
+        } else {
+            root = activity;
         }
-
-        int width = getFinalWidth(layout, mAvailableRect);
-        int height = getFinalHeight(layout, mAvailableRect);
-        int verticalGravity = layout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
-        int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
-        if (verticalGravity == Gravity.TOP) {
-            if (horizontalGravity == Gravity.RIGHT) {
-                positionTopRight(tasks, mAvailableRect, width, height, resultBounds);
+        // STEP 2: Resolve launch windowing mode.
+        // STEP 2.1: Determine if any parameter has specified initial bounds. That might be the
+        // launch bounds from activity options, or size/gravity passed in layout. It also treat the
+        // launch windowing mode in options as a suggestion for future resolution.
+        int launchMode = options != null ? options.getLaunchWindowingMode()
+                : WINDOWING_MODE_UNDEFINED;
+        // hasInitialBounds is set if either activity options or layout has specified bounds. If
+        // that's set we'll skip some adjustments later to avoid overriding the initial bounds.
+        boolean hasInitialBounds = false;
+        final boolean canApplyFreeformPolicy =
+                canApplyFreeformWindowPolicy(display, root, launchMode);
+        if (mSupervisor.canUseActivityOptionsLaunchBounds(options) && canApplyFreeformPolicy) {
+            hasInitialBounds = true;
+            launchMode = launchMode == WINDOWING_MODE_UNDEFINED
+                    ? WINDOWING_MODE_FREEFORM
+                    : launchMode;
+            outParams.mBounds.set(options.getLaunchBounds());
+            if (DEBUG) appendLog("activity-options-bounds=" + outParams.mBounds);
+        } else if (launchMode == WINDOWING_MODE_PINNED) {
+            // System controls PIP window's bounds, so don't apply launch bounds.
+            if (DEBUG) appendLog("empty-window-layout-for-pip");
+        } else if (launchMode == WINDOWING_MODE_FULLSCREEN) {
+            if (DEBUG) appendLog("activity-options-fullscreen=" + outParams.mBounds);
+        } else if (layout != null && canApplyFreeformPolicy) {
+            getLayoutBounds(display, root, layout, mTmpBounds);
+            if (!mTmpBounds.isEmpty()) {
+                launchMode = WINDOWING_MODE_FREEFORM;
+                outParams.mBounds.set(mTmpBounds);
+                hasInitialBounds = true;
+                if (DEBUG) appendLog("bounds-from-layout=" + outParams.mBounds);
             } else {
-                positionTopLeft(tasks, mAvailableRect, width, height, resultBounds);
+                if (DEBUG) appendLog("empty-window-layout");
             }
-        } else if (verticalGravity == Gravity.BOTTOM) {
-            if (horizontalGravity == Gravity.RIGHT) {
-                positionBottomRight(tasks, mAvailableRect, width, height, resultBounds);
-            } else {
-                positionBottomLeft(tasks, mAvailableRect, width, height, resultBounds);
+        }
+
+        // STEP 2.2: Check if previous modifier or the controller (referred as "callers" below) has
+        // some opinions on launch mode and launch bounds. If they have opinions and there is no
+        // initial bounds set in parameters. Note the check on display ID is also input param
+        // related because we always defer to callers' suggestion if there is no specific display ID
+        // in options or from source activity.
+        //
+        // If opinions from callers don't need any further resolution, we try to honor that as is as
+        // much as possible later.
+
+        // Flag to indicate if current param needs no further resolution. It's true it current
+        // param isn't freeform mode, or it already has launch bounds.
+        boolean fullyResolvedCurrentParam = false;
+        // We inherit launch params from previous modifiers or LaunchParamsController if options,
+        // layout and display conditions are not contradictory to their suggestions. It's important
+        // to carry over their values because LaunchParamsController doesn't automatically do that.
+        if (!currentParams.isEmpty() && !hasInitialBounds
+                && (!currentParams.hasPreferredDisplay()
+                    || displayId == currentParams.mPreferredDisplayId)) {
+            if (currentParams.hasWindowingMode()) {
+                launchMode = currentParams.mWindowingMode;
+                fullyResolvedCurrentParam = (launchMode != WINDOWING_MODE_FREEFORM);
+                if (DEBUG) {
+                    appendLog("inherit-" + WindowConfiguration.windowingModeToString(launchMode));
+                }
+            }
+
+            if (!currentParams.mBounds.isEmpty()) {
+                outParams.mBounds.set(currentParams.mBounds);
+                fullyResolvedCurrentParam = true;
+                if (DEBUG) appendLog("inherit-bounds=" + outParams.mBounds);
+            }
+        }
+
+        // STEP 2.3: Adjust launch parameters as needed for freeform display. We enforce the policy
+        // that legacy (pre-D) apps and those apps that can't handle multiple screen density well
+        // are forced to be maximized. The rest of this step is to define the default policy when
+        // there is no initial bounds or a fully resolved current params from callers. Right now we
+        // launch all possible tasks/activities that can handle freeform into freeform mode.
+        if (display.inFreeformWindowingMode()) {
+            if (launchMode == WINDOWING_MODE_PINNED) {
+                if (DEBUG) appendLog("picture-in-picture");
+            } else if (isTaskForcedMaximized(root)) {
+                // We're launching an activity that probably can't handle resizing nicely, so force
+                // it to be maximized even someone suggests launching it in freeform using launch
+                // options.
+                launchMode = WINDOWING_MODE_FULLSCREEN;
+                outParams.mBounds.setEmpty();
+                if (DEBUG) appendLog("forced-maximize");
+            } else if (fullyResolvedCurrentParam) {
+                // Don't adjust launch mode if that's inherited, except when we're launching an
+                // activity that should be forced to maximize.
+                if (DEBUG) appendLog("skip-adjustment-fully-resolved-params");
+            } else if (launchMode != WINDOWING_MODE_FREEFORM
+                    && (isNOrGreater(root) || isPreNResizeable(root))) {
+                // We're launching a pre-N and post-D activity that supports resizing, or a post-N
+                // activity. They can handle freeform nicely so launch them in freeform.
+                // Use undefined because we know we're in a freeform display.
+                launchMode = WINDOWING_MODE_UNDEFINED;
+                if (DEBUG) appendLog("should-be-freeform");
             }
         } else {
-            // Some fancy gravity setting that we don't support yet. We just put the activity in the
-            // center.
-            Slog.w(TAG, "Received unsupported gravity: " + layout.gravity
-                    + ", positioning in the center instead.");
-            positionCenter(tasks, mAvailableRect, width, height, resultBounds);
+            if (DEBUG) appendLog("non-freeform-display");
+        }
+        // If launch mode matches display windowing mode, let it inherit from display.
+        outParams.mWindowingMode = launchMode == display.getWindowingMode()
+                ? WINDOWING_MODE_UNDEFINED : launchMode;
+
+        // STEP 3: Determine final launch bounds based on resolved windowing mode and activity
+        // requested orientation. We set bounds to empty for fullscreen mode and keep bounds as is
+        // for all other windowing modes that's not freeform mode. One can read comments in
+        // relevant methods to further understand this step.
+        //
+        // We skip making adjustments if the params are fully resolved from previous results and
+        // trust that they are valid.
+        if (!fullyResolvedCurrentParam) {
+            final int resolvedMode = (launchMode != WINDOWING_MODE_UNDEFINED) ? launchMode
+                    : display.getWindowingMode();
+            if (source != null && source.inFreeformWindowingMode()
+                    && resolvedMode == WINDOWING_MODE_FREEFORM
+                    && outParams.mBounds.isEmpty()
+                    && source.getDisplayId() == display.mDisplayId) {
+                // Set bounds to be not very far from source activity.
+                cascadeBounds(source.getBounds(), display, outParams.mBounds);
+            }
+            getTaskBounds(root, display, layout, resolvedMode, hasInitialBounds, outParams.mBounds);
         }
 
         return RESULT_CONTINUE;
     }
 
-    @VisibleForTesting
-    static int getFreeformStartLeft(Rect bounds) {
-        return bounds.left + bounds.width() / MARGIN_SIZE_DENOMINATOR;
-    }
-
-    @VisibleForTesting
-    static int getFreeformStartTop(Rect bounds) {
-        return bounds.top + bounds.height() / MARGIN_SIZE_DENOMINATOR;
-    }
-
-    @VisibleForTesting
-    static int getFreeformWidth(Rect bounds) {
-        return bounds.width() / WINDOW_SIZE_DENOMINATOR;
-    }
-
-    @VisibleForTesting
-    static int getFreeformHeight(Rect bounds) {
-        return bounds.height() / WINDOW_SIZE_DENOMINATOR;
-    }
-
-    @VisibleForTesting
-    static int getHorizontalStep(Rect bounds) {
-        return Math.max(bounds.width() / STEP_DENOMINATOR, MINIMAL_STEP);
-    }
-
-    @VisibleForTesting
-    static int getVerticalStep(Rect bounds) {
-        return Math.max(bounds.height() / STEP_DENOMINATOR, MINIMAL_STEP);
-    }
-
-
-
-    private int getFinalWidth(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
-        int width = getFreeformWidth(availableRect);
-        if (windowLayout.width > 0) {
-            width = windowLayout.width;
+    private int getPreferredLaunchDisplay(@Nullable ActivityOptions options,
+            ActivityRecord source, LaunchParams currentParams) {
+        int displayId = INVALID_DISPLAY;
+        final int optionLaunchId = options != null ? options.getLaunchDisplayId() : INVALID_DISPLAY;
+        if (optionLaunchId != INVALID_DISPLAY) {
+            if (DEBUG) appendLog("display-from-option=" + optionLaunchId);
+            displayId = optionLaunchId;
         }
-        if (windowLayout.widthFraction > 0) {
-            width = (int) (availableRect.width() * windowLayout.widthFraction);
+
+        if (displayId == INVALID_DISPLAY && source != null) {
+            final int sourceDisplayId = source.getDisplayId();
+            if (DEBUG) appendLog("display-from-source=" + sourceDisplayId);
+            displayId = sourceDisplayId;
         }
-        return width;
-    }
 
-    private int getFinalHeight(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
-        int height = getFreeformHeight(availableRect);
-        if (windowLayout.height > 0) {
-            height = windowLayout.height;
+        if (displayId != INVALID_DISPLAY && mSupervisor.getActivityDisplay(displayId) == null) {
+            displayId = INVALID_DISPLAY;
         }
-        if (windowLayout.heightFraction > 0) {
-            height = (int) (availableRect.height() * windowLayout.heightFraction);
+        displayId = (displayId == INVALID_DISPLAY) ? currentParams.mPreferredDisplayId : displayId;
+
+        displayId = (displayId == INVALID_DISPLAY) ? DEFAULT_DISPLAY : displayId;
+
+        return displayId;
+    }
+
+    private boolean canApplyFreeformWindowPolicy(@NonNull ActivityDisplay display,
+            @NonNull ActivityRecord root, int launchMode) {
+        return display.inFreeformWindowingMode() || launchMode == WINDOWING_MODE_FREEFORM
+                || root.isResizeable();
+    }
+
+    private void getLayoutBounds(@NonNull ActivityDisplay display, @NonNull ActivityRecord root,
+            @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect outBounds) {
+        final int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+        final int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+        if (!windowLayout.hasSpecifiedSize() && verticalGravity == 0 && horizontalGravity == 0) {
+            outBounds.setEmpty();
+            return;
         }
-        return height;
-    }
 
-    private void positionBottomLeft(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
-            int height, Rect result) {
-        mTmpProposal.set(availableRect.left, availableRect.bottom - height,
-                availableRect.left + width, availableRect.bottom);
-        position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT,
-                result);
-    }
+        final Rect bounds = display.getBounds();
+        final int defaultWidth = bounds.width();
+        final int defaultHeight = bounds.height();
 
-    private void positionBottomRight(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
-            int height, Rect result) {
-        mTmpProposal.set(availableRect.right - width, availableRect.bottom - height,
-                availableRect.right, availableRect.bottom);
-        position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT,
-                result);
-    }
-
-    private void positionTopLeft(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
-            int height, Rect result) {
-        mTmpProposal.set(availableRect.left, availableRect.top,
-                availableRect.left + width, availableRect.top + height);
-        position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT,
-                result);
-    }
-
-    private void positionTopRight(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
-            int height, Rect result) {
-        mTmpProposal.set(availableRect.right - width, availableRect.top,
-                availableRect.right, availableRect.top + height);
-        position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT,
-                result);
-    }
-
-    private void positionCenter(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
-            int height, Rect result) {
-        final int defaultFreeformLeft = getFreeformStartLeft(availableRect);
-        final int defaultFreeformTop = getFreeformStartTop(availableRect);
-        mTmpProposal.set(defaultFreeformLeft, defaultFreeformTop,
-                defaultFreeformLeft + width, defaultFreeformTop + height);
-        position(tasks, availableRect, mTmpProposal, ALLOW_RESTART, SHIFT_POLICY_DIAGONAL_DOWN,
-                result);
-    }
-
-    private void position(ArrayList<TaskRecord> tasks, Rect availableRect,
-            Rect proposal, boolean allowRestart, int shiftPolicy, Rect result) {
-        mTmpOriginal.set(proposal);
-        boolean restarted = false;
-        while (boundsConflict(proposal, tasks)) {
-            // Unfortunately there is already a task at that spot, so we need to look for some
-            // other place.
-            shiftStartingPoint(proposal, availableRect, shiftPolicy);
-            if (shiftedTooFar(proposal, availableRect, shiftPolicy)) {
-                // We don't want the task to go outside of the stack, because it won't look
-                // nice. Depending on the starting point we either restart, or immediately give up.
-                if (!allowRestart) {
-                    proposal.set(mTmpOriginal);
-                    break;
-                }
-                // We must have started not from the top. Let's restart from there because there
-                // might be some space there.
-                proposal.set(availableRect.left, availableRect.top,
-                        availableRect.left + proposal.width(),
-                        availableRect.top + proposal.height());
-                restarted = true;
+        int width;
+        int height;
+        if (!windowLayout.hasSpecifiedSize()) {
+            outBounds.setEmpty();
+            getTaskBounds(root, display, windowLayout, WINDOWING_MODE_FREEFORM,
+                    /* hasInitialBounds */ false, outBounds);
+            width = outBounds.width();
+            height = outBounds.height();
+        } else {
+            width = defaultWidth;
+            if (windowLayout.width > 0 && windowLayout.width < defaultWidth) {
+                width = windowLayout.width;
+            } else if (windowLayout.widthFraction > 0 && windowLayout.widthFraction < 1.0f) {
+                width = (int) (width * windowLayout.widthFraction);
             }
-            if (restarted && (proposal.left > getFreeformStartLeft(availableRect)
-                    || proposal.top > getFreeformStartTop(availableRect))) {
-                // If we restarted and crossed the initial position, let's not struggle anymore.
-                // The user already must have ton of tasks visible, we can just smack the new
-                // one in the center.
-                proposal.set(mTmpOriginal);
-                break;
+
+            height = defaultHeight;
+            if (windowLayout.height > 0 && windowLayout.height < defaultHeight) {
+                height = windowLayout.height;
+            } else if (windowLayout.heightFraction > 0 && windowLayout.heightFraction < 1.0f) {
+                height = (int) (height * windowLayout.heightFraction);
             }
         }
-        result.set(proposal);
-    }
 
-    private boolean shiftedTooFar(Rect start, Rect availableRect, int shiftPolicy) {
-        switch (shiftPolicy) {
-            case SHIFT_POLICY_HORIZONTAL_LEFT:
-                return start.left < availableRect.left;
-            case SHIFT_POLICY_HORIZONTAL_RIGHT:
-                return start.right > availableRect.right;
-            default: // SHIFT_POLICY_DIAGONAL_DOWN
-                return start.right > availableRect.right || start.bottom > availableRect.bottom;
+        final float fractionOfHorizontalOffset;
+        switch (horizontalGravity) {
+            case Gravity.LEFT:
+                fractionOfHorizontalOffset = 0f;
+                break;
+            case Gravity.RIGHT:
+                fractionOfHorizontalOffset = 1f;
+                break;
+            default:
+                fractionOfHorizontalOffset = 0.5f;
         }
-    }
 
-    private void shiftStartingPoint(Rect posposal, Rect availableRect, int shiftPolicy) {
-        final int defaultFreeformStepHorizontal = getHorizontalStep(availableRect);
-        final int defaultFreeformStepVertical = getVerticalStep(availableRect);
-
-        switch (shiftPolicy) {
-            case SHIFT_POLICY_HORIZONTAL_LEFT:
-                posposal.offset(-defaultFreeformStepHorizontal, 0);
+        final float fractionOfVerticalOffset;
+        switch (verticalGravity) {
+            case Gravity.TOP:
+                fractionOfVerticalOffset = 0f;
                 break;
-            case SHIFT_POLICY_HORIZONTAL_RIGHT:
-                posposal.offset(defaultFreeformStepHorizontal, 0);
+            case Gravity.BOTTOM:
+                fractionOfVerticalOffset = 1f;
                 break;
-            default: // SHIFT_POLICY_DIAGONAL_DOWN:
-                posposal.offset(defaultFreeformStepHorizontal, defaultFreeformStepVertical);
-                break;
+            default:
+                fractionOfVerticalOffset = 0.5f;
         }
+
+        outBounds.set(0, 0, width, height);
+        final int xOffset = (int) (fractionOfHorizontalOffset * (defaultWidth - width));
+        final int yOffset = (int) (fractionOfVerticalOffset * (defaultHeight - height));
+        outBounds.offset(xOffset, yOffset);
     }
 
-    private static boolean boundsConflict(Rect proposal, ArrayList<TaskRecord> tasks) {
-        for (int i = tasks.size() - 1; i >= 0; i--) {
-            final TaskRecord task = tasks.get(i);
-            if (!task.mActivities.isEmpty() && !task.matchParentBounds()) {
-                final Rect bounds = task.getOverrideBounds();
-                if (closeLeftTopCorner(proposal, bounds) || closeRightTopCorner(proposal, bounds)
-                        || closeLeftBottomCorner(proposal, bounds)
-                        || closeRightBottomCorner(proposal, bounds)) {
-                    return true;
-                }
+    /**
+     * Returns if task is forced to maximize.
+     *
+     * There are several cases where we force a task to maximize:
+     * 1) Root activity is targeting pre-Donut, which by default can't handle multiple screen
+     *    densities, so resizing will likely cause issues;
+     * 2) Root activity doesn't declare any flag that it supports any screen density, so resizing
+     *    may also cause issues;
+     * 3) Root activity is not resizeable, for which we shouldn't allow user resize it.
+     *
+     * @param root the root activity to check against.
+     * @return {@code true} if it should be forced to maximize; {@code false} otherwise.
+     */
+    private boolean isTaskForcedMaximized(@NonNull ActivityRecord root) {
+        if (root.appInfo.targetSdkVersion < Build.VERSION_CODES.DONUT
+                || (root.appInfo.flags & SUPPORTS_SCREEN_RESIZEABLE_MASK) == 0) {
+            return true;
+        }
+
+        return !root.isResizeable();
+    }
+
+    private boolean isNOrGreater(@NonNull ActivityRecord root) {
+        return root.appInfo.targetSdkVersion >= Build.VERSION_CODES.N;
+    }
+
+    /**
+     * Resolves activity requested orientation to 4 categories:
+     * 1) {@link ActivityInfo#SCREEN_ORIENTATION_LOCKED} indicating app wants to lock down
+     *    orientation;
+     * 2) {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE} indicating app wants to be in landscape;
+     * 3) {@link ActivityInfo#SCREEN_ORIENTATION_PORTRAIT} indicating app wants to be in portrait;
+     * 4) {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} indicating app can handle any
+     *    orientation.
+     *
+     * @param activity the activity to check
+     * @return corresponding resolved orientation value.
+     */
+    private int resolveOrientation(@NonNull ActivityRecord activity) {
+        int orientation = activity.info.screenOrientation;
+        switch (orientation) {
+            case SCREEN_ORIENTATION_NOSENSOR:
+            case SCREEN_ORIENTATION_LOCKED:
+                orientation = SCREEN_ORIENTATION_LOCKED;
+                break;
+            case SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
+            case SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
+            case SCREEN_ORIENTATION_USER_LANDSCAPE:
+            case SCREEN_ORIENTATION_LANDSCAPE:
+                if (DEBUG) appendLog("activity-requested-landscape");
+                orientation = SCREEN_ORIENTATION_LANDSCAPE;
+                break;
+            case SCREEN_ORIENTATION_SENSOR_PORTRAIT:
+            case SCREEN_ORIENTATION_REVERSE_PORTRAIT:
+            case SCREEN_ORIENTATION_USER_PORTRAIT:
+            case SCREEN_ORIENTATION_PORTRAIT:
+                if (DEBUG) appendLog("activity-requested-portrait");
+                orientation = SCREEN_ORIENTATION_PORTRAIT;
+                break;
+            default:
+                orientation = SCREEN_ORIENTATION_UNSPECIFIED;
+        }
+
+        return orientation;
+    }
+
+    private boolean isPreNResizeable(ActivityRecord root) {
+        return root.appInfo.targetSdkVersion < Build.VERSION_CODES.N && root.isResizeable();
+    }
+
+    private void cascadeBounds(@NonNull Rect srcBounds, @NonNull ActivityDisplay display,
+            @NonNull Rect outBounds) {
+        outBounds.set(srcBounds);
+        float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
+        final int defaultOffset = (int) (CASCADING_OFFSET_DP * density + 0.5f);
+
+        display.getBounds(mTmpBounds);
+        final int dx = Math.min(defaultOffset, Math.max(0, mTmpBounds.right - srcBounds.right));
+        final int dy = Math.min(defaultOffset, Math.max(0, mTmpBounds.bottom - srcBounds.bottom));
+        outBounds.offset(dx, dy);
+    }
+
+    private void getTaskBounds(@NonNull ActivityRecord root, @NonNull ActivityDisplay display,
+            @NonNull ActivityInfo.WindowLayout layout, int resolvedMode, boolean hasInitialBounds,
+            @NonNull Rect inOutBounds) {
+        if (resolvedMode == WINDOWING_MODE_FULLSCREEN) {
+            // We don't handle letterboxing here. Letterboxing will be handled by valid checks
+            // later.
+            inOutBounds.setEmpty();
+            if (DEBUG) appendLog("maximized-bounds");
+            return;
+        }
+
+        if (resolvedMode != WINDOWING_MODE_FREEFORM) {
+            // We don't apply freeform bounds adjustment to other windowing modes.
+            if (DEBUG) {
+                appendLog("skip-bounds-" + WindowConfiguration.windowingModeToString(resolvedMode));
+            }
+            return;
+        }
+
+        final int orientation = resolveOrientation(root, display, inOutBounds);
+        if (orientation != SCREEN_ORIENTATION_PORTRAIT
+                && orientation != SCREEN_ORIENTATION_LANDSCAPE) {
+            throw new IllegalStateException(
+                    "Orientation must be one of portrait or landscape, but it's "
+                    + ActivityInfo.screenOrientationToString(orientation));
+        }
+
+        // First we get the default size we want.
+        getDefaultFreeformSize(display, layout, orientation, mTmpBounds);
+        if (hasInitialBounds || sizeMatches(inOutBounds, mTmpBounds)) {
+            // We're here because either input parameters specified initial bounds, or the suggested
+            // bounds have the same size of the default freeform size. We should use the suggested
+            // bounds if possible -- so if app can handle the orientation we just use it, and if not
+            // we transpose the suggested bounds in-place.
+            if (orientation == orientationFromBounds(inOutBounds)) {
+                if (DEBUG) appendLog("freeform-size-orientation-match=" + inOutBounds);
+            } else {
+                // Meh, orientation doesn't match. Let's rotate inOutBounds in-place.
+                centerBounds(display, inOutBounds.height(), inOutBounds.width(), inOutBounds);
+                if (DEBUG) appendLog("freeform-orientation-mismatch=" + inOutBounds);
+            }
+        } else {
+            // We are here either because there is no suggested bounds, or the suggested bounds is
+            // a cascade from source activity. We should use the default freeform size and center it
+            // to the center of suggested bounds (or the display if no suggested bounds). The
+            // default size might be too big to center to source activity bounds in display, so we
+            // may need to move it back to the display.
+            centerBounds(display, mTmpBounds.width(), mTmpBounds.height(), inOutBounds);
+            adjustBoundsToFitInDisplay(display, inOutBounds);
+            if (DEBUG) appendLog("freeform-size-mismatch=" + inOutBounds);
+        }
+
+        // Lastly we adjust bounds to avoid conflicts with other tasks as much as possible.
+        adjustBoundsToAvoidConflict(display, inOutBounds);
+    }
+
+    private int resolveOrientation(@NonNull ActivityRecord root, @NonNull ActivityDisplay display,
+            @NonNull Rect bounds) {
+        int orientation = resolveOrientation(root);
+
+        if (orientation == SCREEN_ORIENTATION_LOCKED) {
+            orientation = bounds.isEmpty() ? display.getConfiguration().orientation
+                    : orientationFromBounds(bounds);
+            if (DEBUG) {
+                appendLog(bounds.isEmpty() ? "locked-orientation-from-display=" + orientation
+                        : "locked-orientation-from-bounds=" + bounds);
             }
         }
+
+        if (orientation == SCREEN_ORIENTATION_UNSPECIFIED) {
+            orientation = bounds.isEmpty() ? SCREEN_ORIENTATION_PORTRAIT
+                    : orientationFromBounds(bounds);
+            if (DEBUG) {
+                appendLog(bounds.isEmpty() ? "default-portrait"
+                        : "orientation-from-bounds=" + bounds);
+            }
+        }
+
+        return orientation;
+    }
+
+    private void getDefaultFreeformSize(@NonNull ActivityDisplay display,
+            @NonNull ActivityInfo.WindowLayout layout, int orientation, @NonNull Rect bounds) {
+        // Default size, which is letterboxing/pillarboxing in display. That's to say the large
+        // dimension of default size is the small dimension of display size, and the small dimension
+        // of default size is calculated to keep the same aspect ratio as the display's.
+        Rect displayBounds = display.getBounds();
+        final int portraitHeight = Math.min(displayBounds.width(), displayBounds.height());
+        final int otherDimension = Math.max(displayBounds.width(), displayBounds.height());
+        final int portraitWidth = (portraitHeight * portraitHeight) / otherDimension;
+        final int defaultWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? portraitHeight
+                : portraitWidth;
+        final int defaultHeight = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? portraitWidth
+                : portraitHeight;
+
+        // Get window size based on Nexus 5x screen, we assume that this is enough to show content
+        // of activities.
+        final float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
+        final int phonePortraitWidth = (int) (DEFAULT_PORTRAIT_PHONE_WIDTH_DP * density + 0.5f);
+        final int phonePortraitHeight = (int) (DEFAULT_PORTRAIT_PHONE_HEIGHT_DP * density + 0.5f);
+        final int phoneWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? phonePortraitHeight
+                : phonePortraitWidth;
+        final int phoneHeight = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? phonePortraitWidth
+                : phonePortraitHeight;
+
+        // Minimum layout requirements.
+        final int layoutMinWidth = (layout == null) ? -1 : layout.minWidth;
+        final int layoutMinHeight = (layout == null) ? -1 : layout.minHeight;
+
+        // Final result.
+        final int width = Math.min(defaultWidth, Math.max(phoneWidth, layoutMinWidth));
+        final int height = Math.min(defaultHeight, Math.max(phoneHeight, layoutMinHeight));
+
+        bounds.set(0, 0, width, height);
+    }
+
+    /**
+     * Gets centered bounds of width x height. If inOutBounds is not empty, the result bounds
+     * centers at its center or display's center if inOutBounds is empty.
+     */
+    private void centerBounds(@NonNull ActivityDisplay display, int width, int height,
+            @NonNull Rect inOutBounds) {
+        if (inOutBounds.isEmpty()) {
+            display.getBounds(inOutBounds);
+        }
+        final int left = inOutBounds.centerX() - width / 2;
+        final int top = inOutBounds.centerY() - height / 2;
+        inOutBounds.set(left, top, left + width, top + height);
+    }
+
+    private void adjustBoundsToFitInDisplay(@NonNull ActivityDisplay display,
+            @NonNull Rect inOutBounds) {
+        final Rect displayBounds = display.getBounds();
+
+        if (displayBounds.width() < inOutBounds.width()
+                || displayBounds.height() < inOutBounds.height()) {
+            // There is no way for us to fit the bounds in the display without changing width
+            // or height. Don't even try it.
+            return;
+        }
+
+        final int dx;
+        if (inOutBounds.right > displayBounds.right) {
+            // Right edge is out of display.
+            dx = displayBounds.right - inOutBounds.right;
+        } else if (inOutBounds.left < displayBounds.left) {
+            // Left edge is out of display.
+            dx = displayBounds.left - inOutBounds.left;
+        } else {
+            // Vertical edges are all in display.
+            dx = 0;
+        }
+
+        final int dy;
+        if (inOutBounds.top < displayBounds.top) {
+            // Top edge is out of display.
+            dy = displayBounds.top - inOutBounds.top;
+        } else if (inOutBounds.bottom > displayBounds.bottom) {
+            // Bottom edge is out of display.
+            dy = displayBounds.bottom - inOutBounds.bottom;
+        } else {
+            // Horizontal edges are all in display.
+            dy = 0;
+        }
+        inOutBounds.offset(dx, dy);
+    }
+
+    /**
+     * Adjusts input bounds to avoid conflict with existing tasks in the display.
+     *
+     * If the input bounds conflict with existing tasks, this method scans the bounds in a series of
+     * directions to find a location where the we can put the bounds in display without conflict
+     * with any other tasks.
+     *
+     * It doesn't try to adjust bounds that's not fully in the given display.
+     *
+     * @param display the display which tasks are to check
+     * @param inOutBounds the bounds used to input initial bounds and output result bounds
+     */
+    private void adjustBoundsToAvoidConflict(@NonNull ActivityDisplay display,
+            @NonNull Rect inOutBounds) {
+        final Rect displayBounds = display.getBounds();
+        if (!displayBounds.contains(inOutBounds)) {
+            // The initial bounds are already out of display. The scanning algorithm below doesn't
+            // work so well with them.
+            return;
+        }
+
+        final List<TaskRecord> tasksToCheck = new ArrayList<>();
+        for (int i = 0; i < display.getChildCount(); ++i) {
+            ActivityStack<?> stack = display.getChildAt(i);
+            if (!stack.inFreeformWindowingMode()) {
+                continue;
+            }
+
+            for (int j = 0; j < stack.getChildCount(); ++j) {
+                tasksToCheck.add(stack.getChildAt(j));
+            }
+        }
+
+        if (!boundsConflict(tasksToCheck, inOutBounds)) {
+            // Current proposal doesn't conflict with any task. Early return to avoid unnecessary
+            // calculation.
+            return;
+        }
+
+        calculateCandidateShiftDirections(displayBounds, inOutBounds);
+        for (int direction : mTmpDirections) {
+            if (direction == Gravity.NO_GRAVITY) {
+                // We exhausted candidate directions, give up.
+                break;
+            }
+
+            mTmpBounds.set(inOutBounds);
+            while (boundsConflict(tasksToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) {
+                shiftBounds(direction, displayBounds, mTmpBounds);
+            }
+
+            if (!boundsConflict(tasksToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) {
+                // Found a candidate. Just use this.
+                inOutBounds.set(mTmpBounds);
+                if (DEBUG) appendLog("avoid-bounds-conflict=" + inOutBounds);
+                return;
+            }
+
+            // Didn't find a conflict free bounds here. Try the next candidate direction.
+        }
+
+        // We failed to find a conflict free location. Just keep the original result.
+    }
+
+    /**
+     * Determines scanning directions and their priorities to avoid bounds conflict.
+     *
+     * @param availableBounds bounds that the result must be in
+     * @param initialBounds initial bounds when start scanning
+     */
+    private void calculateCandidateShiftDirections(@NonNull Rect availableBounds,
+            @NonNull Rect initialBounds) {
+        for (int i = 0; i < mTmpDirections.length; ++i) {
+            mTmpDirections[i] = Gravity.NO_GRAVITY;
+        }
+
+        final int oneThirdWidth = (2 * availableBounds.left + availableBounds.right) / 3;
+        final int twoThirdWidth = (availableBounds.left + 2 * availableBounds.right) / 3;
+        final int centerX = initialBounds.centerX();
+        if (centerX < oneThirdWidth) {
+            // Too close to left, just scan to the right.
+            mTmpDirections[0] = Gravity.RIGHT;
+            return;
+        } else if (centerX > twoThirdWidth) {
+            // Too close to right, just scan to the left.
+            mTmpDirections[0] = Gravity.LEFT;
+            return;
+        }
+
+        final int oneThirdHeight = (2 * availableBounds.top + availableBounds.bottom) / 3;
+        final int twoThirdHeight = (availableBounds.top + 2 * availableBounds.bottom) / 3;
+        final int centerY = initialBounds.centerY();
+        if (centerY < oneThirdHeight || centerY > twoThirdHeight) {
+            // Too close to top or bottom boundary and we're in the middle horizontally, scan
+            // horizontally in both directions.
+            mTmpDirections[0] = Gravity.RIGHT;
+            mTmpDirections[1] = Gravity.LEFT;
+            return;
+        }
+
+        // We're in the center region both horizontally and vertically. Scan in both directions of
+        // primary diagonal.
+        mTmpDirections[0] = Gravity.BOTTOM | Gravity.RIGHT;
+        mTmpDirections[1] = Gravity.TOP | Gravity.LEFT;
+    }
+
+    private boolean boundsConflict(@NonNull List<TaskRecord> tasks, @NonNull Rect bounds) {
+        for (TaskRecord task : tasks) {
+            final Rect taskBounds = task.getBounds();
+            final boolean leftClose = Math.abs(taskBounds.left - bounds.left)
+                    < BOUNDS_CONFLICT_THRESHOLD;
+            final boolean topClose = Math.abs(taskBounds.top - bounds.top)
+                    < BOUNDS_CONFLICT_THRESHOLD;
+            final boolean rightClose = Math.abs(taskBounds.right - bounds.right)
+                    < BOUNDS_CONFLICT_THRESHOLD;
+            final boolean bottomClose = Math.abs(taskBounds.bottom - bounds.bottom)
+                    < BOUNDS_CONFLICT_THRESHOLD;
+
+            if ((leftClose && topClose) || (leftClose && bottomClose) || (rightClose && topClose)
+                    || (rightClose && bottomClose)) {
+                return true;
+            }
+        }
+
         return false;
     }
 
-    private static final boolean closeLeftTopCorner(Rect first, Rect second) {
-        return Math.abs(first.left - second.left) < BOUNDS_CONFLICT_MIN_DISTANCE
-                && Math.abs(first.top - second.top) < BOUNDS_CONFLICT_MIN_DISTANCE;
+    private void shiftBounds(int direction, @NonNull Rect availableRect,
+            @NonNull Rect inOutBounds) {
+        final int horizontalOffset;
+        switch (direction & Gravity.HORIZONTAL_GRAVITY_MASK) {
+            case Gravity.LEFT:
+                horizontalOffset = -Math.max(MINIMAL_STEP,
+                        availableRect.width() / STEP_DENOMINATOR);
+                break;
+            case Gravity.RIGHT:
+                horizontalOffset = Math.max(MINIMAL_STEP, availableRect.width() / STEP_DENOMINATOR);
+                break;
+            default:
+                horizontalOffset = 0;
+        }
+
+        final int verticalOffset;
+        switch (direction & Gravity.VERTICAL_GRAVITY_MASK) {
+            case Gravity.TOP:
+                verticalOffset = -Math.max(MINIMAL_STEP, availableRect.height() / STEP_DENOMINATOR);
+                break;
+            case Gravity.BOTTOM:
+                verticalOffset = Math.max(MINIMAL_STEP, availableRect.height() / STEP_DENOMINATOR);
+                break;
+            default:
+                verticalOffset = 0;
+        }
+
+        inOutBounds.offset(horizontalOffset, verticalOffset);
     }
 
-    private static final boolean closeRightTopCorner(Rect first, Rect second) {
-        return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
-                && Math.abs(first.top - second.top) < BOUNDS_CONFLICT_MIN_DISTANCE;
+    private void initLogBuilder(TaskRecord task, ActivityRecord activity) {
+        if (DEBUG) {
+            mLogBuilder = new StringBuilder("TaskLaunchParamsModifier:task=" + task
+                    + " activity=" + activity);
+        }
     }
 
-    private static final boolean closeLeftBottomCorner(Rect first, Rect second) {
-        return Math.abs(first.left - second.left) < BOUNDS_CONFLICT_MIN_DISTANCE
-                && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
+    private void appendLog(String log) {
+        if (DEBUG) mLogBuilder.append(" ").append(log);
     }
 
-    private static final boolean closeRightBottomCorner(Rect first, Rect second) {
-        return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
-                && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
+    private void outputLog() {
+        if (DEBUG) Slog.d(TAG, mLogBuilder.toString());
+    }
+
+    private static int orientationFromBounds(Rect bounds) {
+        return bounds.width() > bounds.height() ? SCREEN_ORIENTATION_LANDSCAPE
+                : SCREEN_ORIENTATION_PORTRAIT;
+    }
+
+    private static boolean sizeMatches(Rect left, Rect right) {
+        return (Math.abs(right.width() - left.width()) < EPSILON)
+                && (Math.abs(right.height() - left.height()) < EPSILON);
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index bdbb0a4..61836fdd 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -27,6 +27,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.security.KeyStore;
+import android.text.TextUtils;
 import android.util.Slog;
 
 import com.android.internal.statusbar.IStatusBarService;
@@ -205,6 +206,16 @@
         return super.onError(deviceId, error, vendorCode);
     }
 
+    public void setTitleIfEmpty(CharSequence title) {
+        if (TextUtils.isEmpty(mBundle.getCharSequence(BiometricPrompt.KEY_TITLE))) {
+            mBundle.putCharSequence(BiometricPrompt.KEY_TITLE, title);
+        }
+    }
+
+    public boolean isBiometricPrompt() {
+        return mBundle != null;
+    }
+
     private void notifyClientAuthenticationSucceeded(BiometricAuthenticator.Identifier identifier)
             throws RemoteException {
         final BiometricServiceBase.ServiceListener listener = getListener();
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 3d2f567..b80dca6 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -29,6 +29,7 @@
 import android.database.ContentObserver;
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricPrompt;
 import android.hardware.biometrics.BiometricSourceType;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
 import android.hardware.biometrics.IBiometricPromptReceiver;
@@ -239,7 +240,7 @@
      * should not carry any state. The reality is we need to keep a tiny amount of state so that
      * cancelAuthentication() can go to the right place.
      */
-    private final class BiometricPromptServiceWrapper extends IBiometricService.Stub {
+    private final class BiometricServiceWrapper extends IBiometricService.Stub {
 
         @Override // Binder call
         public void authenticate(IBinder token, long sessionId, int userId,
@@ -255,6 +256,12 @@
                 return;
             }
 
+            // Check the usage of this in system server. Need to remove this check if it becomes
+            // a public API.
+            if (bundle.getBoolean(BiometricPrompt.KEY_USE_DEFAULT_TITLE, false)) {
+                checkInternalPermission();
+            }
+
             final int callingUid = Binder.getCallingUid();
             final int callingPid = Binder.getCallingPid();
             final int callingUserId = UserHandle.getCallingUserId();
@@ -363,7 +370,7 @@
             return error;
         }
 
-        @Override
+        @Override // Binder call
         public void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback)
                 throws RemoteException {
             checkInternalPermission();
@@ -375,6 +382,19 @@
                 Slog.w(TAG, "Remote exception", e);
             }
         }
+
+        @Override // Binder call
+        public void setActiveUser(int userId) {
+            checkInternalPermission();
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                for (int i = 0; i < mAuthenticators.size(); i++) {
+                    mAuthenticators.get(i).getAuthenticator().setActiveUser(userId);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
     }
 
     private void checkAppOp(String opPackageName, int callingUid) {
@@ -387,7 +407,7 @@
 
     private void checkInternalPermission() {
         getContext().enforceCallingPermission(USE_BIOMETRIC_INTERNAL,
-                "Must have MANAGE_BIOMETRIC permission");
+                "Must have USE_BIOMETRIC_INTERNAL permission");
     }
 
     private void checkPermission() {
@@ -455,7 +475,7 @@
             }
         }
 
-        publishBinderService(Context.BIOMETRIC_SERVICE, new BiometricPromptServiceWrapper());
+        publishBinderService(Context.BIOMETRIC_SERVICE, new BiometricServiceWrapper());
     }
 
     /**
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 71bf560..74d742a 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -16,6 +16,7 @@
 
 package com.android.server.biometrics;
 
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
 
 import android.app.ActivityManager;
@@ -55,6 +56,7 @@
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 
+import com.android.internal.R;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.server.SystemService;
@@ -704,6 +706,30 @@
         }
 
         mHandler.post(() -> {
+            if (client.isBiometricPrompt()) {
+                try {
+                    final List<ActivityManager.RunningAppProcessInfo> procs =
+                            ActivityManager.getService().getRunningAppProcesses();
+                    for (int i = 0; i < procs.size(); i++) {
+                        final ActivityManager.RunningAppProcessInfo info = procs.get(i);
+                        if (info.uid == callingUid && info.importance == IMPORTANCE_FOREGROUND) {
+                            PackageManager pm = getContext().getPackageManager();
+                            final CharSequence label = pm.getApplicationLabel(
+                                    pm.getApplicationInfo(info.processName,
+                                            PackageManager.GET_META_DATA));
+                            final String title = getContext()
+                                    .getString(R.string.biometric_dialog_default_title, label);
+                            client.setTitleIfEmpty(title);
+                            break;
+                        }
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(getTag(), "Unable to get application name", e);
+                } catch (PackageManager.NameNotFoundException e) {
+                    Slog.e(getTag(), "Unable to get application name", e);
+                }
+            }
+
             mMetricsLogger.histogram(getMetrics().tagAuthToken(), opId != 0L ? 1 : 0);
 
             // Get performance stats object for this user.
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index ca9b256..30659c1 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -1031,6 +1031,11 @@
                 result.isPortal() /* isCaptivePortal */,
                 startTime, endTime);
 
+        log("isCaptivePortal: isSuccessful()=" + result.isSuccessful() +
+                " isPortal()=" + result.isPortal() +
+                " RedirectUrl=" + result.redirectUrl +
+                " StartTime=" + startTime + " EndTime=" + endTime);
+
         return result;
     }
 
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index b7bbd42..47e85b5 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -16,6 +16,12 @@
 
 package com.android.server.connectivity;
 
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_HOST;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PAC;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PORT;
+import static android.provider.Settings.Global.HTTP_PROXY;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentResolver;
@@ -47,16 +53,14 @@
     @NonNull
     private final Context mContext;
 
-    // TODO : make this private and import as much managing logic from ConnectivityService as
-    // possible
     @NonNull
-    public final Object mProxyLock = new Object();
+    private final Object mProxyLock = new Object();
     // The global proxy is the proxy that is set device-wide, overriding any network-specific
     // proxy. Note however that proxies are hints ; the system does not enforce their use. Hence
     // this value is only for querying.
     @Nullable
     @GuardedBy("mProxyLock")
-    public ProxyInfo mGlobalProxy = null;
+    private ProxyInfo mGlobalProxy = null;
     // The default proxy is the proxy that applies to no particular network if the global proxy
     // is not set. Individual networks have their own settings that override this. This member
     // is set through setDefaultProxy, which is called when the default network changes proxies
@@ -64,10 +68,10 @@
     // when PacManager resolves the proxy.
     @Nullable
     @GuardedBy("mProxyLock")
-    public volatile ProxyInfo mDefaultProxy = null;
-    // Whether the default proxy is disabled. TODO : make this mDefaultProxyEnabled
+    private volatile ProxyInfo mDefaultProxy = null;
+    // Whether the default proxy is enabled.
     @GuardedBy("mProxyLock")
-    public boolean mDefaultProxyDisabled = false;
+    private boolean mDefaultProxyEnabled = true;
 
     // The object responsible for Proxy Auto Configuration (PAC).
     @NonNull
@@ -85,7 +89,7 @@
     @Nullable
     private static ProxyInfo canonicalizeProxyInfo(@Nullable final ProxyInfo proxy) {
         if (proxy != null && TextUtils.isEmpty(proxy.getHost())
-                && (proxy.getPacFileUrl() == null || Uri.EMPTY.equals(proxy.getPacFileUrl()))) {
+                && Uri.EMPTY.equals(proxy.getPacFileUrl())) {
             return null;
         }
         return proxy;
@@ -123,7 +127,7 @@
         // This information is already available as a world read/writable jvm property.
         synchronized (mProxyLock) {
             final ProxyInfo ret = mGlobalProxy;
-            if ((ret == null) && !mDefaultProxyDisabled) return mDefaultProxy;
+            if ((ret == null) && mDefaultProxyEnabled) return mDefaultProxy;
             return ret;
         }
     }
@@ -146,11 +150,10 @@
      */
     public void loadGlobalProxy() {
         ContentResolver res = mContext.getContentResolver();
-        String host = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST);
-        int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0);
-        String exclList = Settings.Global.getString(res,
-                Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
-        String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC);
+        String host = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_HOST);
+        int port = Settings.Global.getInt(res, GLOBAL_HTTP_PROXY_PORT, 0);
+        String exclList = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
+        String pacFileUrl = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_PAC);
         if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
             ProxyInfo proxyProperties;
             if (!TextUtils.isEmpty(pacFileUrl)) {
@@ -167,10 +170,36 @@
                 mGlobalProxy = proxyProperties;
             }
         }
+        loadDeprecatedGlobalHttpProxy();
         // TODO : shouldn't this function call mPacManager.setCurrentProxyScriptUrl ?
     }
 
     /**
+     * Read the global proxy from the deprecated Settings.Global.HTTP_PROXY setting and apply it.
+     */
+    public void loadDeprecatedGlobalHttpProxy() {
+        final String proxy = Settings.Global.getString(mContext.getContentResolver(), HTTP_PROXY);
+        if (!TextUtils.isEmpty(proxy)) {
+            String data[] = proxy.split(":");
+            if (data.length == 0) {
+                return;
+            }
+
+            final String proxyHost = data[0];
+            int proxyPort = 8080;
+            if (data.length > 1) {
+                try {
+                    proxyPort = Integer.parseInt(data[1]);
+                } catch (NumberFormatException e) {
+                    return;
+                }
+            }
+            final ProxyInfo p = new ProxyInfo(proxyHost, proxyPort, "");
+            setGlobalProxy(p);
+        }
+    }
+
+    /**
      * Sends the system broadcast informing apps about a new proxy configuration.
      *
      * Confusingly this method also sets the PAC file URL. TODO : separate this, it has nothing
@@ -232,11 +261,10 @@
             final ContentResolver res = mContext.getContentResolver();
             final long token = Binder.clearCallingIdentity();
             try {
-                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
-                Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
-                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
-                        exclList);
-                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
+                Settings.Global.putString(res, GLOBAL_HTTP_PROXY_HOST, host);
+                Settings.Global.putInt(res, GLOBAL_HTTP_PROXY_PORT, port);
+                Settings.Global.putString(res, GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclList);
+                Settings.Global.putString(res, GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -253,10 +281,7 @@
      */
     public void setDefaultProxy(@Nullable ProxyInfo proxyInfo) {
         synchronized (mProxyLock) {
-            if (mDefaultProxy != null && mDefaultProxy.equals(proxyInfo)) {
-                return;
-            }
-            if (mDefaultProxy == proxyInfo) return; // catches repeated nulls
+            if (Objects.equals(mDefaultProxy, proxyInfo)) return;
             if (proxyInfo != null &&  !proxyInfo.isValid()) {
                 if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
                 return;
@@ -277,9 +302,27 @@
             mDefaultProxy = proxyInfo;
 
             if (mGlobalProxy != null) return;
-            if (!mDefaultProxyDisabled) {
+            if (mDefaultProxyEnabled) {
                 sendProxyBroadcast(proxyInfo);
             }
         }
     }
+
+    /**
+     * Enable or disable the default proxy.
+     *
+     * This sets the flag for enabling/disabling the default proxy and sends the broadcast
+     * if applicable.
+     * @param enabled whether the default proxy should be enabled.
+     */
+    public void setDefaultProxyEnabled(final boolean enabled) {
+        synchronized (mProxyLock) {
+            if (mDefaultProxyEnabled != enabled) {
+                mDefaultProxyEnabled = enabled;
+                if (mGlobalProxy == null && mDefaultProxy != null) {
+                    sendProxyBroadcast(enabled ? mDefaultProxy : null);
+                }
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 71c419f..a9b0d5c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -421,7 +421,6 @@
         final IInputContext inputContext;
         final int uid;
         final int pid;
-        final int selfReportedDisplayId;
         final InputBinding binding;
         final ClientDeathRecipient clientDeathRecipient;
 
@@ -431,18 +430,16 @@
         @Override
         public String toString() {
             return "ClientState{" + Integer.toHexString(
-                    System.identityHashCode(this)) + " uid=" + uid
-                    + " pid=" + pid + " displayId=" + selfReportedDisplayId + "}";
+                    System.identityHashCode(this)) + " uid " + uid
+                    + " pid " + pid + "}";
         }
 
         ClientState(IInputMethodClient _client, IInputContext _inputContext,
-                int _uid, int _pid, int _selfReportedDisplayId,
-                ClientDeathRecipient _clientDeathRecipient) {
+                int _uid, int _pid, ClientDeathRecipient _clientDeathRecipient) {
             client = _client;
             inputContext = _inputContext;
             uid = _uid;
             pid = _pid;
-            selfReportedDisplayId = _selfReportedDisplayId;
             binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
             clientDeathRecipient = _clientDeathRecipient;
         }
@@ -1748,21 +1745,15 @@
      *               process
      * @param inputContext communication channel for the dummy
      *                     {@link android.view.inputmethod.InputConnection}
-     * @param selfReportedDisplayId self-reported display ID to which the client is associated.
-     *                              Whether the client is still allowed to access to this display
-     *                              or not needs to be evaluated every time the client interacts
-     *                              with the display
      */
     @Override
-    public void addClient(IInputMethodClient client, IInputContext inputContext,
-            int selfReportedDisplayId) {
+    public void addClient(IInputMethodClient client, IInputContext inputContext) {
         final int callerUid = Binder.getCallingUid();
         final int callerPid = Binder.getCallingPid();
         synchronized (mMethodMap) {
             // TODO: Optimize this linear search.
             for (ClientState state : mClients.values()) {
-                if (state.uid == callerUid && state.pid == callerPid
-                        && state.selfReportedDisplayId == selfReportedDisplayId) {
+                if (state.uid == callerUid && state.pid == callerPid) {
                     throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
                             + " is already registered");
                 }
@@ -1773,25 +1764,11 @@
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
-            // We cannot fully avoid race conditions where the client UID already lost the access to
-            // the given self-reported display ID, even if the client is not maliciously reporting
-            // a fake display ID. Unconditionally returning SecurityException just because the
-            // client doesn't pass display ID verification can cause many test failures hence not an
-            // option right now.  At the same time
-            //    context.getSystemService(InputMethodManager.class)
-            // is expected to return a valid non-null instance at any time if we do not choose to
-            // have the client crash.  Thus we do not verify the display ID at all here.  Instead we
-            // later check the display ID every time the client needs to interact with the specified
-            // display.
-            mClients.put(client.asBinder(), new ClientState(client, inputContext, callerUid,
-                    callerPid, selfReportedDisplayId, deathRecipient));
+            mClients.put(client.asBinder(),
+                    new ClientState(client, inputContext, callerUid, callerPid, deathRecipient));
         }
     }
 
-    private boolean verifyDisplayId(ClientState cs) {
-        return mWindowManagerInternal.isUidAllowedOnDisplay(cs.selfReportedDisplayId, cs.uid);
-    }
-
     void removeClient(IInputMethodClient client) {
         synchronized (mMethodMap) {
             ClientState cs = mClients.remove(client.asBinder());
@@ -1941,9 +1918,8 @@
         mCurAttribute = attribute;
 
         // Check if the input method is changing.
-        // We expect the caller has already verified that the client is allowed to access this
-        // display ID.
-        final int displayId = mCurFocusedWindowClient.selfReportedDisplayId;
+        final int displayId = mWindowManagerInternal.getDisplayIdForWindow(
+                mCurFocusedWindow);
         if (mCurId != null && mCurId.equals(mCurMethodId) && displayId == mCurTokenDisplayId) {
             if (cs.curSession != null) {
                 // Fast case: if we are already connected to the input method,
@@ -2008,11 +1984,7 @@
                 com.android.internal.R.string.input_method_binding_label);
         mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
                 mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
-        if (!verifyDisplayId(mCurFocusedWindowClient)) {
-            // Wait, the client no longer has access to the display.
-            return InputBindResult.INVALID_DISPLAY_ID;
-        }
-        final int displayId = mCurFocusedWindowClient.selfReportedDisplayId;
+        final int displayId = mWindowManagerInternal.getDisplayIdForWindow(mCurFocusedWindow);
         mCurTokenDisplayId = (displayId != INVALID_DISPLAY) ? displayId : DEFAULT_DISPLAY;
 
         if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
@@ -2612,8 +2584,7 @@
                     if (cs == null) {
                         throw new IllegalArgumentException("unknown client " + client.asBinder());
                     }
-                    if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
-                            cs.selfReportedDisplayId)) {
+                    if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid)) {
                         Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
                         return false;
                     }
@@ -2697,8 +2668,7 @@
                     if (cs == null) {
                         throw new IllegalArgumentException("unknown client " + client.asBinder());
                     }
-                    if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
-                            cs.selfReportedDisplayId)) {
+                    if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid)) {
                         if (DEBUG) {
                             Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
                         }
@@ -2797,8 +2767,6 @@
         InputBindResult res = null;
         long ident = Binder.clearCallingIdentity();
         try {
-            final int windowDisplayId =
-                    mWindowManagerInternal.getDisplayIdForWindow(windowToken);
             synchronized (mMethodMap) {
                 if (DEBUG) Slog.v(TAG, "startInputOrWindowGainedFocusInternal: reason="
                         + InputMethodClient.getStartInputReason(startInputReason)
@@ -2817,15 +2785,8 @@
                     throw new IllegalArgumentException("unknown client "
                             + client.asBinder());
                 }
-                if (cs.selfReportedDisplayId != windowDisplayId) {
-                    Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch."
-                            + " from client:" + cs.selfReportedDisplayId
-                            + " from window:" + windowDisplayId);
-                    return InputBindResult.DISPLAY_ID_MISMATCH;
-                }
 
-                if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
-                        cs.selfReportedDisplayId)) {
+                if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid)) {
                     // Check with the window manager to make sure this client actually
                     // has a window with focus.  If not, reject.  This is thread safe
                     // because if the focus changes some time before or after, the
@@ -2897,9 +2858,9 @@
                                 // If focused display changed, we should unbind current method
                                 // to make app window in previous display relayout after Ime
                                 // window token removed.
-                                // Note that we can trust client's display ID as long as it matches
-                                // to the display ID obtained from the window.
-                                if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
+                                final int newFocusDisplayId =
+                                        mWindowManagerInternal.getDisplayIdForWindow(windowToken);
+                                if (newFocusDisplayId != mCurTokenDisplayId) {
                                     unbindCurrentMethodLocked();
                                 }
                             }
@@ -2997,7 +2958,6 @@
     }
 
     private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
-        // TODO(yukawa): multi-display support.
         final int uid = Binder.getCallingUid();
         if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
             return true;
@@ -3074,7 +3034,6 @@
     @Override
     public void showInputMethodAndSubtypeEnablerFromClient(
             IInputMethodClient client, String inputMethodId) {
-        // TODO(yukawa): Should we verify the display ID?
         if (!calledFromValidUser()) {
             return;
         }
@@ -3270,7 +3229,6 @@
      */
     @Override
     public int getInputMethodWindowVisibleHeight() {
-        // TODO(yukawa): Should we verify the display ID?
         return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
     }
 
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 389782a..dd993b8 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -877,14 +877,17 @@
             // This may throw a SecurityException.
             jobStatus.prepareLocked(ActivityManager.getService());
 
-            if (toCancel != null) {
-                cancelJobImplLocked(toCancel, jobStatus, "job rescheduled by app");
-            }
             if (work != null) {
                 // If work has been supplied, enqueue it into the new job.
                 jobStatus.enqueueWorkLocked(ActivityManager.getService(), work);
             }
-            startTrackingJobLocked(jobStatus, toCancel);
+
+            if (toCancel != null) {
+                // Implicitly replaces the existing job record with the new instance
+                cancelJobImplLocked(toCancel, jobStatus, "job rescheduled by app");
+            } else {
+                startTrackingJobLocked(jobStatus, null);
+            }
             StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_STATE_CHANGED,
                     uId, null, jobStatus.getBatteryName(),
                     StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED,
@@ -1013,6 +1016,12 @@
         }
     }
 
+    /**
+     * Cancel the given job, stopping it if it's currently executing.  If {@code incomingJob}
+     * is null, the cancelled job is removed outright from the system.  If
+     * {@code incomingJob} is non-null, it replaces {@code cancelled} in the store of
+     * currently scheduled jobs.
+     */
     private void cancelJobImplLocked(JobStatus cancelled, JobStatus incomingJob, String reason) {
         if (DEBUG) Slog.d(TAG, "CANCEL: " + cancelled.toShortString());
         cancelled.unprepareLocked(ActivityManager.getService());
@@ -1023,6 +1032,11 @@
         }
         // Cancel if running.
         stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED, reason);
+        // If this is a replacement, bring in the new version of the job
+        if (incomingJob != null) {
+            if (DEBUG) Slog.i(TAG, "Tracking replacement job " + incomingJob.toShortString());
+            startTrackingJobLocked(incomingJob, cancelled);
+        }
         reportActiveLocked();
     }
 
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java
index 9640e04..b29b7cf 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java
@@ -76,6 +76,13 @@
      */
     private final AtomicBoolean mConnectionOpen = new AtomicBoolean(true);
 
+    /*
+     * Internal interface used to invoke client callbacks.
+     */
+    private interface CallbackConsumer {
+        void accept(IContextHubClientCallback callback) throws RemoteException;
+    }
+
     /* package */ ContextHubClientBroker(
             Context context, IContexthub contextHubProxy, ContextHubClientManager clientManager,
             int contextHubId, short hostEndPointId, IContextHubClientCallback callback) {
@@ -140,12 +147,9 @@
     /**
      * Invoked when the underlying binder of this broker has died at the client process.
      */
+    @Override
     public void binderDied() {
-        try {
-            IContextHubClient.Stub.asInterface(this).close();
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException while closing client on death", e);
-        }
+        close();
     }
 
     /**
@@ -168,14 +172,7 @@
      * @param message the message that came from a nanoapp
      */
     /* package */ void sendMessageToClient(NanoAppMessage message) {
-        if (mConnectionOpen.get()) {
-            try {
-                mCallbackInterface.onMessageFromNanoApp(message);
-            } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException while sending message to client (host endpoint ID = "
-                        + mHostEndPointId + ")", e);
-            }
-        }
+        invokeCallbackConcurrent(callback -> callback.onMessageFromNanoApp(message));
     }
 
     /**
@@ -184,14 +181,7 @@
      * @param nanoAppId the ID of the nanoapp that was loaded.
      */
     /* package */ void onNanoAppLoaded(long nanoAppId) {
-        if (mConnectionOpen.get()) {
-            try {
-                mCallbackInterface.onNanoAppLoaded(nanoAppId);
-            } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException while calling onNanoAppLoaded on client"
-                        + " (host endpoint ID = " + mHostEndPointId + ")", e);
-            }
-        }
+        invokeCallbackConcurrent(callback -> callback.onNanoAppLoaded(nanoAppId));
     }
 
     /**
@@ -200,28 +190,14 @@
      * @param nanoAppId the ID of the nanoapp that was unloaded.
      */
     /* package */ void onNanoAppUnloaded(long nanoAppId) {
-        if (mConnectionOpen.get()) {
-            try {
-                mCallbackInterface.onNanoAppUnloaded(nanoAppId);
-            } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException while calling onNanoAppUnloaded on client"
-                        + " (host endpoint ID = " + mHostEndPointId + ")", e);
-            }
-        }
+        invokeCallbackConcurrent(callback -> callback.onNanoAppUnloaded(nanoAppId));
     }
 
     /**
      * Notifies the client of a hub reset event if the connection is open.
      */
     /* package */ void onHubReset() {
-        if (mConnectionOpen.get()) {
-            try {
-                mCallbackInterface.onHubReset();
-            } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException while calling onHubReset on client" +
-                        " (host endpoint ID = " + mHostEndPointId + ")", e);
-            }
-        }
+        invokeCallbackConcurrent(callback -> callback.onHubReset());
     }
 
     /**
@@ -231,12 +207,21 @@
      * @param abortCode the nanoapp specific abort code
      */
     /* package */ void onNanoAppAborted(long nanoAppId, int abortCode) {
+        invokeCallbackConcurrent(callback -> callback.onNanoAppAborted(nanoAppId, abortCode));
+    }
+
+    /**
+     * Helper function to invoke a specified client callback, if the connection is open.
+     *
+     * @param consumer the consumer specifying the callback to invoke
+     */
+    private void invokeCallbackConcurrent(CallbackConsumer consumer) {
         if (mConnectionOpen.get()) {
             try {
-                mCallbackInterface.onNanoAppAborted(nanoAppId, abortCode);
+                consumer.accept(mCallbackInterface);
             } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException while calling onNanoAppAborted on client"
-                        + " (host endpoint ID = " + mHostEndPointId + ")", e);
+                Log.e(TAG, "RemoteException while invoking client callback (host endpoint ID = "
+                        + mHostEndPointId + ")", e);
             }
         }
     }
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 31cf9e3..53d54ba 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -254,6 +254,9 @@
     private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000;
     // Default update duration in milliseconds for REQUEST_LOCATION.
     private static final long LOCATION_UPDATE_DURATION_MILLIS = 10 * 1000;
+    // Default time limit in milliseconds for the ConnectivityManager to find a suitable
+    // network with SUPL connectivity or report an error.
+    private static final int SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS = 10 * 1000;
 
     /** simpler wrapper for ProviderRequest + Worksource */
     private static class GpsRequest {
@@ -539,14 +542,23 @@
             new ConnectivityManager.NetworkCallback() {
                 @Override
                 public void onAvailable(Network network) {
+                    if (DEBUG) Log.d(TAG, "SUPL network connection available.");
                     // Specific to a change to a SUPL enabled network becoming ready
                     sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
                 }
 
                 @Override
                 public void onLost(Network network) {
+                    Log.i(TAG, "SUPL network connection lost.");
                     releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
                 }
+
+                @Override
+                public void onUnavailable() {
+                    Log.i(TAG, "SUPL network connection request timed out.");
+                    // Could not setup the connection to the network in the specified time duration.
+                    releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
+                }
             };
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -953,7 +965,8 @@
         NetworkRequest request = requestBuilder.build();
         mConnMgr.requestNetwork(
                 request,
-                mSuplConnectivityCallback);
+                mSuplConnectivityCallback,
+                SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS);
     }
 
     private void handleReleaseSuplConnection(int agpsDataConnStatus) {
@@ -2796,4 +2809,3 @@
 
     private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);
 }
-
diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java
index 4001b90..3829b65 100644
--- a/services/core/java/com/android/server/notification/CalendarTracker.java
+++ b/services/core/java/com/android/server/notification/CalendarTracker.java
@@ -22,7 +22,6 @@
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.net.Uri;
-import android.provider.BaseColumns;
 import android.provider.CalendarContract.Attendees;
 import android.provider.CalendarContract.Calendars;
 import android.provider.CalendarContract.Events;
@@ -89,13 +88,13 @@
         pw.print(prefix); pw.print("u="); pw.println(mUserContext.getUserId());
     }
 
-    private ArraySet<Long> getPrimaryCalendars() {
+    private ArraySet<Long> getCalendarsWithAccess() {
         final long start = System.currentTimeMillis();
         final ArraySet<Long> rt = new ArraySet<>();
-        final String primary = "\"primary\"";
-        final String[] projection = { Calendars._ID,
-                "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + primary };
-        final String selection = primary + " = 1";
+        final String[] projection = { Calendars._ID };
+        final String selection = Calendars.CALENDAR_ACCESS_LEVEL + " >= "
+                + Calendars.CAL_ACCESS_CONTRIBUTOR
+                + " AND " + Calendars.SYNC_EVENTS + " = 1";
         Cursor cursor = null;
         try {
             cursor = mUserContext.getContentResolver().query(Calendars.CONTENT_URI, projection,
@@ -108,7 +107,9 @@
                 cursor.close();
             }
         }
-        if (DEBUG) Log.d(TAG, "getPrimaryCalendars took " + (System.currentTimeMillis() - start));
+        if (DEBUG) {
+            Log.d(TAG, "getCalendarsWithAccess took " + (System.currentTimeMillis() - start));
+        }
         return rt;
     }
 
@@ -122,7 +123,7 @@
         final CheckEventResult result = new CheckEventResult();
         result.recheckAt = time + EVENT_CHECK_LOOKAHEAD;
         try {
-            final ArraySet<Long> primaryCalendars = getPrimaryCalendars();
+            final ArraySet<Long> calendars = getCalendarsWithAccess();
             while (cursor != null && cursor.moveToNext()) {
                 final long begin = cursor.getLong(0);
                 final long end = cursor.getLong(1);
@@ -133,17 +134,19 @@
                 final String owner = cursor.getString(6);
                 final long calendarId = cursor.getLong(7);
                 final int availability = cursor.getInt(8);
-                final boolean calendarPrimary = primaryCalendars.contains(calendarId);
-                if (DEBUG) Log.d(TAG, String.format(
-                        "%s %s-%s v=%s a=%s eid=%s n=%s o=%s cid=%s p=%s",
-                        title,
-                        new Date(begin), new Date(end), calendarVisible,
-                        availabilityToString(availability), eventId, name, owner, calendarId,
-                        calendarPrimary));
+                final boolean canAccessCal = calendars.contains(calendarId);
+                if (DEBUG) {
+                    Log.d(TAG, String.format("title=%s time=%s-%s vis=%s availability=%s "
+                                    + "eventId=%s name=%s owner=%s calId=%s canAccessCal=%s",
+                            title, new Date(begin), new Date(end), calendarVisible,
+                            availabilityToString(availability), eventId, name, owner, calendarId,
+                            canAccessCal));
+                }
                 final boolean meetsTime = time >= begin && time < end;
-                final boolean meetsCalendar = calendarVisible && calendarPrimary
-                        && (filter.calendar == null || Objects.equals(filter.calendar, owner)
-                        || Objects.equals(filter.calendar, name));
+                final boolean meetsCalendar = calendarVisible && canAccessCal
+                        && ((filter.calName == null && filter.calendarId == null)
+                        || (Objects.equals(filter.calendarId, calendarId))
+                        || Objects.equals(filter.calName, name));
                 final boolean meetsAvailability = availability != Instances.AVAILABILITY_FREE;
                 if (meetsCalendar && meetsAvailability) {
                     if (DEBUG) Log.d(TAG, "  MEETS CALENDAR & AVAILABILITY");
diff --git a/services/core/java/com/android/server/notification/EventConditionProvider.java b/services/core/java/com/android/server/notification/EventConditionProvider.java
index 5bc9b1c..a4a94c2 100644
--- a/services/core/java/com/android/server/notification/EventConditionProvider.java
+++ b/services/core/java/com/android/server/notification/EventConditionProvider.java
@@ -27,7 +27,6 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.Looper;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -221,7 +220,7 @@
                     continue;
                 }
                 CheckEventResult result = null;
-                if (event.calendar == null) { // any calendar
+                if (event.calName == null) { // any calendar
                     // event could exist on any tracker
                     for (int i = 0; i < mTrackers.size(); i++) {
                         final CalendarTracker tracker = mTrackers.valueAt(i);
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index d326c22..6187583 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -696,7 +696,7 @@
             for (int i = 0; i < userIds.size(); i++) {
                 final int userId = userIds.get(i);
                 if (enabled) {
-                    if (isPackageOrComponentAllowed(component.toString(), userId)
+                    if (isPackageOrComponentAllowed(component.flattenToString(), userId)
                             || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
                         registerServiceLocked(component, userId);
                     } else {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f9d49d7..506cc44 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4282,14 +4282,16 @@
     }
 
     private void doChannelWarningToast(CharSequence toastText) {
-        final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
-        final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
-                Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
-        if (warningEnabled) {
-            Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
-                    Toast.LENGTH_SHORT);
-            toast.show();
-        }
+        Binder.withCleanCallingIdentity(() -> {
+            final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
+            final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
+                    Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
+            if (warningEnabled) {
+                Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
+                        Toast.LENGTH_SHORT);
+                toast.show();
+            }
+        });
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index fbb42ea..65ec580 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -662,10 +662,6 @@
 
     public void setContactAffinity(float contactAffinity) {
         mContactAffinity = contactAffinity;
-        if (mImportance < IMPORTANCE_DEFAULT &&
-                mContactAffinity > ValidateNotificationPeople.VALID_CONTACT) {
-            setSystemImportance(IMPORTANCE_DEFAULT);
-        }
     }
 
     public float getContactAffinity() {
diff --git a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
index 5f08257..9c1ac34 100644
--- a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
+++ b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
@@ -16,18 +16,15 @@
 
 package com.android.server.os;
 
-import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Binder;
 import android.os.Build;
 import android.os.IDeviceIdentifiersPolicyService;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemProperties;
-import android.os.UserHandle;
+
+import com.android.internal.telephony.TelephonyPermissions;
 import com.android.server.SystemService;
 
 /**
@@ -54,15 +51,22 @@
 
         @Override
         public @Nullable String getSerial() throws RemoteException {
-            if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID
-                    && mContext.checkCallingOrSelfPermission(
-                            Manifest.permission.READ_PHONE_STATE)
-                                    != PackageManager.PERMISSION_GRANTED
-                    && mContext.checkCallingOrSelfPermission(
-                            Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-                                    != PackageManager.PERMISSION_GRANTED) {
-                throw new SecurityException("getSerial requires READ_PHONE_STATE"
-                        + " or READ_PRIVILEGED_PHONE_STATE permission");
+            // Since this invocation is on the server side a null value is used for the
+            // callingPackage as the server's package name (typically android) should not be used
+            // for any device / profile owner checks. The majority of requests for the serial number
+            // should use the getSerialForPackage method with the calling package specified.
+            if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
+                    /* callingPackage */ null, "getSerial")) {
+                return Build.UNKNOWN;
+            }
+            return SystemProperties.get("ro.serialno", Build.UNKNOWN);
+        }
+
+        @Override
+        public @Nullable String getSerialForPackage(String callingPackage) throws RemoteException {
+            if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
+                    callingPackage, "getSerial")) {
+                return Build.UNKNOWN;
             }
             return SystemProperties.get("ro.serialno", Build.UNKNOWN);
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 329b1da..9108603 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -940,6 +940,7 @@
     private UserManagerInternal mUserManagerInternal;
     private ActivityManagerInternal mActivityManagerInternal;
     private ActivityTaskManagerInternal mActivityTaskManagerInternal;
+    private StorageManagerInternal mStorageManagerInternal;
 
     private DeviceIdleController.LocalService mDeviceIdleController;
 
@@ -2919,7 +2920,7 @@
                 for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
                     final PermissionManager.SplitPermissionInfo splitPerm =
                             splitPermissions.get(splitPermNum);
-                    final String rootPerm = splitPerm.getRootPermission();
+                    final String rootPerm = splitPerm.getSplitPermission();
 
                     if (preUpgradeSdkVersion >= splitPerm.getTargetSdk()) {
                         continue;
@@ -2941,11 +2942,11 @@
                             continue;
                         }
 
-                        final String[] newPerms = splitPerm.getNewPermissions();
+                        final List<String> newPerms = splitPerm.getNewPermissions();
 
-                        final int numNewPerms = newPerms.length;
+                        final int numNewPerms = newPerms.size();
                         for (int newPermNum = 0; newPermNum < numNewPerms; newPermNum++) {
-                            final String newPerm = newPerms[newPermNum];
+                            final String newPerm = newPerms.get(newPermNum);
                             if (checkPermission(newPerm, pkgName, userId) == PERMISSION_GRANTED) {
                                 continue;
                             }
@@ -4598,6 +4599,13 @@
         return mDeviceIdleController;
     }
 
+    private StorageManagerInternal getStorageManagerInternal() {
+        if (mStorageManagerInternal == null) {
+            mStorageManagerInternal = LocalServices.getService(StorageManagerInternal.class);
+        }
+        return mStorageManagerInternal;
+    }
+
     /**
      * Update given flags when being used to request {@link PackageInfo}.
      */
@@ -9505,6 +9513,30 @@
             } catch (InstallerException e) {
                 Slog.w(TAG, String.valueOf(e));
             }
+            // If this package doesn't have a sharedUserId or there are no other packages
+            // present with same sharedUserId, then delete the sandbox data too.
+            try {
+                final SharedUserSetting sharedUserSetting = mSettings.getSharedUserLPw(
+                        pkg.mSharedUserId, 0 /* pkgFlags */,
+                        0 /* pkgPrivateFlags */, false /* create */);
+                boolean deleteSandboxData = true;
+                if (sharedUserSetting != null && sharedUserSetting.packages != null) {
+                    for (int i = sharedUserSetting.packages.size() - 1; i >= 0; --i) {
+                        final PackageSetting packageSetting = sharedUserSetting.packages.valueAt(i);
+                        if (!packageSetting.name.equals(pkg.packageName)
+                                && packageSetting.readUserState(realUserId).isAvailable(
+                                        MATCH_UNINSTALLED_PACKAGES)) {
+                            deleteSandboxData = false;
+                            break;
+                        }
+                    }
+                }
+                if (deleteSandboxData) {
+                    getStorageManagerInternal().destroySandboxForApp(pkg.packageName, realUserId);
+                }
+            } catch (PackageManagerException e) {
+                // Should not happen
+            }
             mDexManager.notifyPackageDataDestroyed(pkg.packageName, userId);
         }
     }
@@ -19820,9 +19852,7 @@
         mDexManager.systemReady();
         mPackageDexOptimizer.systemReady();
 
-        StorageManagerInternal storageManagerInternal = LocalServices.getService(
-                StorageManagerInternal.class);
-        storageManagerInternal.addExternalStoragePolicy(
+        getStorageManagerInternal().addExternalStoragePolicy(
                 new StorageManagerInternal.ExternalStorageMountPolicy() {
             @Override
             public int getMountMode(int uid, String packageName) {
@@ -21215,10 +21245,8 @@
         }
 
         prepareAppDataContentsLeafLIF(pkg, userId, flags);
-        final StorageManagerInternal storageManagerInternal
-                = LocalServices.getService(StorageManagerInternal.class);
-        if (storageManagerInternal != null) {
-            storageManagerInternal.mountExternalStorageForApp(
+        if (getStorageManagerInternal() != null) {
+            getStorageManagerInternal().prepareSandboxForApp(
                     pkg.packageName, appId, pkg.mSharedUserId, userId);
         }
     }
diff --git a/services/core/java/com/android/server/pm/dex/TEST_MAPPING b/services/core/java/com/android/server/pm/dex/TEST_MAPPING
index ad52559..c93af2a 100644
--- a/services/core/java/com/android/server/pm/dex/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/dex/TEST_MAPPING
@@ -1,19 +1,12 @@
 {
   "presubmit": [
     {
-      "name": "DexLoggerTests"
-    },
-    {
-      "name": "DexManagerTests"
-    },
-    {
-      "name": "DexoptOptionsTests"
-    },
-    {
-      "name": "DexoptUtilsTest"
-    },
-    {
-      "name": "PackageDexUsageTests"
+      "name": "FrameworksServicesTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.pm.dex"
+        }
+      ]
     },
     {
       "name": "DexLoggerIntegrationTests"
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 6f644dd..0a93653 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1033,8 +1033,8 @@
 
             if (applicationInfo != null
                     && applicationInfo.targetSdkVersion < splitPerm.getTargetSdk()
-                    && permissionsWithoutSplits.contains(splitPerm.getRootPermission())) {
-                Collections.addAll(permissions, splitPerm.getNewPermissions());
+                    && permissionsWithoutSplits.contains(splitPerm.getSplitPermission())) {
+                permissions.addAll(splitPerm.getNewPermissions());
             }
         }
 
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 1cba1c7..a55b49f 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -95,10 +95,22 @@
         mIsShowing = showing;
 
         mCallback.onShowingChanged();
-        try {
-            mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Error informing keystore of screen lock", e);
+        int retry = 2;
+        while (retry > 0) {
+            try {
+                mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
+                break;
+            } catch (RemoteException e) {
+                if (retry == 2) {
+                    Slog.w(TAG, "Error informing keystore of screen lock. Keystore may have died"
+                            + " -> refreshing service token and retrying");
+                    mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
+                            .getService("android.security.keystore"));
+                } else {
+                    Slog.e(TAG, "Error informing keystore of screen lock after retrying once", e);
+                }
+                --retry;
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6f728fc..642f5781 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -92,7 +92,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
@@ -119,7 +118,6 @@
 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
-import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
 
 import android.annotation.CallSuper;
 import android.annotation.NonNull;
@@ -2065,9 +2063,25 @@
         layoutAndAssignWindowLayersIfNeeded();
     }
 
-    int taskIdFromPoint(int x, int y) {
+    /**
+     * Used to obtain task ID when user taps on coordinate (x, y) in this display, and outside
+     * current task in focus.
+     *
+     * This returns the task ID of the foremost task at (x, y) if the task is not home. Otherwise it
+     * returns -1.
+     *
+     * @param x horizontal coordinate of the tap position
+     * @param y vertical coordinate of the tap position
+     * @return the task ID if a non-home task is found; -1 if not
+     */
+    int taskForTapOutside(int x, int y) {
         for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
             final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
+            if (stack.isActivityTypeHome()) {
+                // We skip not only home stack, but also everything behind home because user can't
+                // see them.
+                break;
+            }
             final int taskId = stack.taskIdFromPoint(x, y);
             if (taskId != -1) {
                 return taskId;
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 278d2b8..b64d4f8 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -582,6 +582,9 @@
         pw.print(prefix + "  defaultBounds=");
         getDefaultBounds(INVALID_SNAP_FRACTION).printShortString(pw);
         pw.println();
+        pw.println(prefix + "  mDefaultMinSize=" + mDefaultMinSize);
+        pw.println(prefix + "  mDefaultStackGravity=" + mDefaultStackGravity);
+        pw.println(prefix + "  mDefaultAspectRatio=" + mDefaultAspectRatio);
         mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
         pw.print(prefix + "  movementBounds="); getMovementBounds(mTmpRect).printShortString(pw);
         pw.println();
@@ -591,6 +594,9 @@
         pw.println(prefix + "  mShelfHeight=" + mShelfHeight);
         pw.println(prefix + "  mReentrySnapFraction=" + mReentrySnapFraction);
         pw.println(prefix + "  mIsMinimized=" + mIsMinimized);
+        pw.println(prefix + "  mAspectRatio=" + mAspectRatio);
+        pw.println(prefix + "  mMinAspectRatio=" + mMinAspectRatio);
+        pw.println(prefix + "  mMaxAspectRatio=" + mMaxAspectRatio);
         if (mActions.isEmpty()) {
             pw.println(prefix + "  mActions=[]");
         } else {
@@ -602,7 +608,7 @@
             }
             pw.println(prefix + "  ]");
         }
-        pw.println(prefix + " mDisplayInfo=" + mDisplayInfo);
+        pw.println(prefix + "  mDisplayInfo=" + mDisplayInfo);
     }
 
     void writeToProto(ProtoOutputStream proto, long fieldId) {
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index b7e37b2..25148d1 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -88,7 +88,7 @@
                     }
                     taskId = task.mTaskId;
                 } else {
-                    taskId = displayContent.taskIdFromPoint(x, y);
+                    taskId = displayContent.taskForTapOutside(x, y);
                 }
             }
             if (taskId >= 0) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index b096bf2..5410676 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -430,25 +430,14 @@
     public abstract boolean isUidFocused(int uid);
 
     /**
-     * Checks whether the specified IME client has IME focus or not.
+     * Checks whether the specified process has IME focus or not.
      *
      * @param uid UID of the process to be queried
      * @param pid PID of the process to be queried
-     * @param displayId Display ID reported from the client. Note that this method also verifies
-     *                  whether the specified process is allowed to access to this display or not
-     * @return {@code true} if the IME client specified with {@code uid}, {@code pid}, and
-     *         {@code displayId} has IME focus
+     * @return {@code true} if a process that is identified by {@code uid} and {@code pid} has IME
+     *         focus
      */
-    public abstract boolean isInputMethodClientFocus(int uid, int pid, int displayId);
-
-    /**
-     * Checks whether the given {@code uid} is allowed to use the given {@code displayId} or not.
-     *
-     * @param displayId Display ID to be checked
-     * @param uid UID to be checked.
-     * @return {@code true} if the given {@code uid} is allowed to use the given {@code displayId}
-     */
-    public abstract boolean isUidAllowedOnDisplay(int displayId, int uid);
+    public abstract boolean isInputMethodClientFocus(int uid, int pid);
 
     /**
      * Return the display Id for given window.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e153a1d..10ba63e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7201,20 +7201,16 @@
         }
 
         @Override
-        public boolean isInputMethodClientFocus(int uid, int pid, int displayId) {
-            if (displayId == Display.INVALID_DISPLAY) {
-                return false;
-            }
+        public boolean isInputMethodClientFocus(int uid, int pid) {
             synchronized (mWindowMap) {
-                final DisplayContent displayContent = mRoot.getTopFocusedDisplayContent();
-                if (displayContent == null
-                        || displayContent.getDisplayId() != displayId
-                        || !displayContent.hasAccess(uid)) {
-                    return false;
+                // Check all displays if any input method window has focus.
+                for (int i = mRoot.mChildren.size() - 1; i >= 0; --i) {
+                    final DisplayContent displayContent = mRoot.mChildren.get(i);
+                    if (displayContent.isInputMethodClientFocus(uid, pid)) {
+                        return true;
+                    }
                 }
-                if (displayContent.isInputMethodClientFocus(uid, pid)) {
-                    return true;
-                }
+
                 // Okay, how about this...  what is the current focus?
                 // It seems in some cases we may not have moved the IM
                 // target window, such as when it was in a pop-up window,
@@ -7223,7 +7219,7 @@
                 // press home.  Sometimes the IME won't go down.)
                 // Would be nice to fix this more correctly, but it's
                 // way at the end of a release, and this should be good enough.
-                final WindowState currentFocus = displayContent.mCurrentFocus;
+                final WindowState currentFocus = mRoot.getTopFocusedDisplayContent().mCurrentFocus;
                 if (currentFocus != null && currentFocus.mSession.mUid == uid
                         && currentFocus.mSession.mPid == pid) {
                     return true;
@@ -7233,20 +7229,6 @@
         }
 
         @Override
-        public boolean isUidAllowedOnDisplay(int displayId, int uid) {
-            if (displayId == Display.DEFAULT_DISPLAY) {
-                return true;
-            }
-            if (displayId == Display.INVALID_DISPLAY) {
-                return false;
-            }
-            synchronized (mWindowMap) {
-                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
-                return displayContent != null && displayContent.hasAccess(uid);
-            }
-        }
-
-        @Override
         public int getDisplayIdForWindow(IBinder windowToken) {
             synchronized (mWindowMap) {
                 final WindowState window = mWindowMap.get(windowToken);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 66cf48c..4350596 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -66,4 +66,9 @@
     public long forceSecurityLogs() {
         return 0;
     }
+
+    @Override
+    public boolean checkDeviceIdentifierAccess(String packageName, int userHandle) {
+        return false;
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index eeb4ad3..913b844 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7861,6 +7861,21 @@
         return getApplicationLabel(profileOwner.getPackageName(), userHandle);
     }
 
+    @Override
+    public boolean checkDeviceIdentifierAccess(String packageName, int userHandle) {
+        // Allow access to the device owner.
+        ComponentName deviceOwner = getDeviceOwnerComponent(true);
+        if (deviceOwner != null && deviceOwner.getPackageName().equals(packageName)) {
+            return true;
+        }
+        // Allow access to the profile owner for the specified user.
+        ComponentName profileOwner = getProfileOwnerAsUser(userHandle);
+        if (profileOwner != null && profileOwner.getPackageName().equals(packageName)) {
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Canonical name for a given package.
      */
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b8241d0..bbc4f44 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -359,7 +359,7 @@
             // The system server should never make non-oneway calls
             Binder.setWarnOnBlocking(true);
             // The system server should always load safe labels
-            PackageItemInfo.setForceSafeLabels(true);
+            PackageItemInfo.forceSafeLabels();
 
             // Default to FULL within the system server.
             SQLiteGlobal.sDefaultSyncMode = SQLiteGlobal.SYNC_MODE_FULL;
@@ -468,6 +468,12 @@
             }
         }
 
+        // Diagnostic to ensure that the system is in a base healthy state. Done here as a common
+        // non-zygote process.
+        if (!VMRuntime.hasBootImageSpaces()) {
+            Slog.wtf(TAG, "Runtime is not running with a boot image!");
+        }
+
         // Loop forever.
         Looper.loop();
         throw new RuntimeException("Main thread loop unexpectedly exited");
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index 9d686ef..d197d01 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -28,7 +28,6 @@
 import android.net.util.InterfaceParams;
 import android.system.ErrnoException;
 import android.system.Os;
-import android.system.StructGroupReq;
 import android.system.StructTimeval;
 import android.util.Log;
 
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
deleted file mode 100644
index 9de64f2..0000000
--- a/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.am;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.am.LaunchParamsController.LaunchParams;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for exercising resizing bounds due to activity options.
- *
- * Build/Install/Run:
- *  atest FrameworksServicesTests:ActivityLaunchParamsModifierTests
- */
-@MediumTest
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class ActivityLaunchParamsModifierTests extends ActivityTestsBase {
-    private ActivityLaunchParamsModifier mModifier;
-    private ActivityTaskManagerService mService;
-    private ActivityStack mStack;
-    private TaskRecord mTask;
-    private ActivityRecord mActivity;
-
-    private LaunchParams mCurrent;
-    private LaunchParams mResult;
-
-    @Before
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        mService = createActivityTaskManagerService();
-        mModifier = new ActivityLaunchParamsModifier(mService.mStackSupervisor);
-        mCurrent = new LaunchParams();
-        mResult = new LaunchParams();
-
-
-        mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
-                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
-        mActivity = new ActivityBuilder(mService).setTask(mTask).build();
-    }
-
-
-    @Test
-    public void testSkippedInvocations() throws Exception {
-        // No specified activity should be ignored
-        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
-                null /*activity*/, null /*source*/, null /*options*/, mCurrent, mResult));
-
-        // No specified activity options should be ignored
-        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
-                mActivity, null /*source*/, null /*options*/, mCurrent, mResult));
-
-        // launch bounds specified should be ignored.
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
-                mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
-        // Non-resizeable records should be ignored
-        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-        assertFalse(mActivity.isResizeable());
-        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
-                mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
-        // make record resizeable
-        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
-        assertTrue(mActivity.isResizeable());
-
-        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
-                mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
-        // Does not support freeform
-        mService.mSupportsFreeformWindowManagement = false;
-        assertFalse(mService.mStackSupervisor.canUseActivityOptionsLaunchBounds(options));
-        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
-                mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
-        mService.mSupportsFreeformWindowManagement = true;
-        options.setLaunchBounds(new Rect());
-        assertTrue(mService.mStackSupervisor.canUseActivityOptionsLaunchBounds(options));
-
-        // Invalid bounds
-        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
-                mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-        options.setLaunchBounds(new Rect(0, 0, -1, -1));
-        assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
-                mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
-        // Valid bounds should cause the positioner to be applied.
-        options.setLaunchBounds(new Rect(0, 0, 100, 100));
-        assertEquals(RESULT_DONE, mModifier.onCalculate(null /*task*/, null /*layout*/,
-                mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-    }
-
-    @Test
-    public void testBoundsExtraction() throws Exception {
-        // Make activity resizeable and enable freeform mode.
-        mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
-        mService.mSupportsFreeformWindowManagement = true;
-
-        ActivityOptions options = ActivityOptions.makeBasic();
-        final Rect proposedBounds = new Rect(20, 30, 45, 40);
-        options.setLaunchBounds(proposedBounds);
-
-        assertEquals(RESULT_DONE, mModifier.onCalculate(null /*task*/, null /*layout*/,
-                mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-        assertEquals(mResult.mBounds, proposedBounds);
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
index f5b8f78..0d1302f 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
@@ -11,239 +11,1098 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 package com.android.server.am;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
 
-import android.content.pm.ActivityInfo.WindowLayout;
+import android.app.ActivityOptions;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.Build;
 import android.platform.test.annotations.Presubmit;
 import android.view.Gravity;
 
-import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.am.LaunchParamsController.LaunchParams;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Locale;
+
 /**
- * Tests for exercising resizing task bounds.
+ * Tests for default task bounds.
  *
  * Build/Install/Run:
  *  atest FrameworksServicesTests:TaskLaunchParamsModifierTests
  */
-@MediumTest
+@SmallTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
+@FlakyTest(detail = "Confirm stable in post-submit before removing")
 public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
-    private final static int STACK_WIDTH = 100;
-    private final static int STACK_HEIGHT = 200;
 
-    private final static Rect STACK_BOUNDS = new Rect(0, 0, STACK_WIDTH, STACK_HEIGHT);
+    private ActivityRecord mActivity;
 
-    private ActivityTaskManagerService mService;
-    private ActivityStack mStack;
-    private TaskRecord mTask;
+    private TaskLaunchParamsModifier mTarget;
 
-    private TaskLaunchParamsModifier mPositioner;
-
-    private LaunchParamsController.LaunchParams mCurrent;
-    private LaunchParamsController.LaunchParams mResult;
+    private LaunchParams mCurrent;
+    private LaunchParams mResult;
 
     @Before
     @Override
     public void setUp() throws Exception {
         super.setUp();
 
-        mService = createActivityTaskManagerService();
-        mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
-                WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        mStack.requestResize(STACK_BOUNDS);
+        setupActivityTaskManagerService();
+        mService.mSupportsFreeformWindowManagement = true;
+        when(mSupervisor.canUseActivityOptionsLaunchBounds(any())).thenCallRealMethod();
 
-        // We must create the task after resizing to make sure it does not inherit the stack
-        // dimensions on resize.
-        mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+        mActivity = new ActivityBuilder(mService).build();
+        mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
+        mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
 
-        mPositioner = new TaskLaunchParamsModifier();
+        mTarget = new TaskLaunchParamsModifier(mSupervisor);
 
-        mResult = new LaunchParamsController.LaunchParams();
-        mCurrent = new LaunchParamsController.LaunchParams();
+        mCurrent = new LaunchParams();
+        mCurrent.reset();
+        mResult = new LaunchParams();
+        mResult.reset();
     }
 
-    /**
-     * Ensures that the setup bounds are set as expected with the stack bounds set and the task
-     * bounds still {@code null}.
-     * @throws Exception
-     */
+    // =============================
+    // Display ID Related Tests
+    // =============================
     @Test
-    public void testInitialBounds() throws Exception {
-        assertEquals(mStack.getOverrideBounds(), STACK_BOUNDS);
-        assertEquals(mTask.getOverrideBounds(), new Rect());
+    public void testDefaultToPrimaryDisplay() {
+        createNewActivityDisplay(WINDOWING_MODE_FREEFORM);
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(DEFAULT_DISPLAY, mResult.mPreferredDisplayId);
     }
 
-    /**
-     * Ensures that a task positioned with no {@link WindowLayout} receives the default launch
-     * position.
-     * @throws Exception
-     */
     @Test
-    public void testLaunchNoWindowLayout() throws Exception {
-        assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask, null /*layout*/,
-                null /*record*/, null /*source*/, null /*options*/, mCurrent, mResult));
-        assertEquals(getDefaultBounds(Gravity.NO_GRAVITY), mResult.mBounds);
+    public void testUsesPreviousDisplayIdIfSet() {
+        createNewActivityDisplay(WINDOWING_MODE_FREEFORM);
+        final TestActivityDisplay display = createNewActivityDisplay(WINDOWING_MODE_FULLSCREEN);
+
+        mCurrent.mPreferredDisplayId = display.mDisplayId;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(display.mDisplayId, mResult.mPreferredDisplayId);
     }
 
-    /**
-     * Ensures that a task positioned with an empty {@link WindowLayout} receives the default launch
-     * position.
-     * @throws Exception
-     */
     @Test
-    public void testlaunchEmptyWindowLayout() throws Exception {
-        assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
-                new WindowLayout(0, 0, 0, 0, Gravity.NO_GRAVITY, 0, 0), null /*activity*/,
-                null /*source*/, null /*options*/, mCurrent, mResult));
-        assertEquals(mResult.mBounds, getDefaultBounds(Gravity.NO_GRAVITY));
+    public void testUsesSourcesDisplayIdIfSet() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+        final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FULLSCREEN);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        ActivityRecord source = createSourceActivity(fullscreenDisplay);
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, source, /* options */ null, mCurrent, mResult));
+
+        assertEquals(fullscreenDisplay.mDisplayId, mResult.mPreferredDisplayId);
     }
 
-    /**
-     * Ensures that a task positioned with a {@link WindowLayout} gravity specified is positioned
-     * according to specification.
-     * @throws Exception
-     */
     @Test
-    public void testlaunchWindowLayoutGravity() throws Exception {
-        // Unspecified gravity should be ignored
-        testGravity(Gravity.NO_GRAVITY);
+    public void testUsesOptionsDisplayIdIfSet() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+        final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FULLSCREEN);
 
-        // Unsupported gravity should be ignored
-        testGravity(Gravity.LEFT);
-        testGravity(Gravity.RIGHT);
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+        ActivityRecord source = createSourceActivity(freeformDisplay);
 
-        // Test defaults for vertical gravities
-        testGravity(Gravity.TOP);
-        testGravity(Gravity.BOTTOM);
+        ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(fullscreenDisplay.mDisplayId);
 
-        // Test corners
-        testGravity(Gravity.TOP | Gravity.LEFT);
-        testGravity(Gravity.TOP | Gravity.RIGHT);
-        testGravity(Gravity.BOTTOM | Gravity.LEFT);
-        testGravity(Gravity.BOTTOM | Gravity.RIGHT);
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, source, options, mCurrent, mResult));
+
+        assertEquals(fullscreenDisplay.mDisplayId, mResult.mPreferredDisplayId);
     }
 
-    private void testGravity(int gravity) {
-        try {
-            assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
-                    new WindowLayout(0, 0, 0, 0, gravity, 0, 0), null /*activity*/,
-                    null /*source*/, null /*options*/, mCurrent, mResult));
-            assertEquals(mResult.mBounds, getDefaultBounds(gravity));
-        } finally {
-            mCurrent.reset();
-            mResult.reset();
+    // =====================================
+    // Launch Windowing Mode Related Tests
+    // =====================================
+    @Test
+    public void testBoundsInOptionsInfersFreeformOnFreeformDisplay() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchBounds(new Rect(0, 0, 100, 100));
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
+    public void testBoundsInOptionsInfersFreeformWithResizeableActivity() {
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchBounds(new Rect(0, 0, 100, 100));
+
+        mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+                WINDOWING_MODE_FULLSCREEN);
+    }
+
+    @Test
+    public void testKeepsPictureInPictureLaunchModeInOptions() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_PINNED, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
+    public void testKeepsPictureInPictureLaunchModeWithBoundsInOptions() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
+        options.setLaunchBounds(new Rect(0, 0, 100, 100));
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_PINNED, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
+    public void testKeepsFullscreenLaunchModeInOptionsOnNonFreeformDisplay() {
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+        mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+                WINDOWING_MODE_FULLSCREEN);
+    }
+
+    @Test
+    public void testNonEmptyLayoutInfersFreeformOnFreeformDisplay() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setWidth(120).setHeight(80).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
+    public void testNonEmptyLayoutInfersFreeformWithEmptySize() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setGravity(Gravity.LEFT).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
+    public void testNonEmptyLayoutInfersFreeformWithResizeableActivity() {
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setWidth(120).setHeight(80).build();
+
+        mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+                WINDOWING_MODE_FULLSCREEN);
+    }
+
+    @Test
+    public void testRespectsFullyResolvedCurrentParam_Fullscreen() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+        mCurrent.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
+    public void testRespectsModeFromFullyResolvedCurrentParam_NonEmptyBounds() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+        mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+        mCurrent.mBounds.set(0, 0, 200, 100);
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
+    public void testForceMaximizesPreDApp() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+        options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+        mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+        mCurrent.mBounds.set(0, 0, 200, 100);
+
+        mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.CUPCAKE;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
+    public void testForceMaximizesAppWithoutMultipleDensitySupport() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+        options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+        mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+        mCurrent.mBounds.set(0, 0, 200, 100);
+
+        mActivity.appInfo.flags = 0;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
+    public void testForceMaximizesUnresizeableApp() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+        options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+        mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+        mCurrent.mBounds.set(0, 0, 200, 100);
+
+        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
+    public void testSkipsForceMaximizingAppsOnNonFreeformDisplay() {
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+        options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+        mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+        mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+        mCurrent.mBounds.set(0, 0, 200, 100);
+
+        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+                WINDOWING_MODE_FULLSCREEN);
+    }
+
+    @Test
+    public void testUsesFullscreenOnNonFreeformDisplay() {
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(DEFAULT_DISPLAY);
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+                WINDOWING_MODE_FULLSCREEN);
+    }
+
+    @Test
+    public void testUsesFreeformByDefaultForPostNApp() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
+    public void testUsesFreeformByDefaultForPreNResizeableAppWithoutOrientationRequest() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+        mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+                WINDOWING_MODE_FREEFORM);
+    }
+
+    @Test
+    public void testSkipsFreeformForPreNResizeableAppOnNonFullscreenDisplay() {
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(DEFAULT_DISPLAY);
+
+        mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+                WINDOWING_MODE_FULLSCREEN);
+    }
+
+    // ================================
+    // Launching Bounds Related Tests
+    // ===============================
+    @Test
+    public void testKeepsBoundsWithPictureInPictureLaunchModeInOptions() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
+
+        final Rect expected = new Rect(0, 0, 100, 100);
+        options.setLaunchBounds(expected);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquals(expected, mResult.mBounds);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_LeftGravity() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setGravity(Gravity.LEFT).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(0, mResult.mBounds.left);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopGravity() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setGravity(Gravity.TOP).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(0, mResult.mBounds.top);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopLeftGravity() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setGravity(Gravity.TOP | Gravity.LEFT).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(0, mResult.mBounds.left);
+        assertEquals(0, mResult.mBounds.top);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_RightGravity() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setGravity(Gravity.RIGHT).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(1920, mResult.mBounds.right);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomGravity() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setGravity(Gravity.BOTTOM).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(1080, mResult.mBounds.bottom);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomRightGravity() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setGravity(Gravity.BOTTOM | Gravity.RIGHT).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(1920, mResult.mBounds.right);
+        assertEquals(1080, mResult.mBounds.bottom);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsOnFreeformDisplay_CenterToDisplay() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setWidth(120).setHeight(80).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(new Rect(900, 500, 1020, 580), mResult.mBounds);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsOnFreeformDisplay_LeftGravity() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setWidth(120).setHeight(80).setGravity(Gravity.LEFT).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(new Rect(0, 500, 120, 580), mResult.mBounds);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopGravity() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setWidth(120).setHeight(80).setGravity(Gravity.TOP).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(new Rect(900, 0, 1020, 80), mResult.mBounds);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopLeftGravity() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setWidth(120).setHeight(80).setGravity(Gravity.TOP | Gravity.LEFT).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(new Rect(0, 0, 120, 80), mResult.mBounds);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightGravity() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setWidth(120).setHeight(80).setGravity(Gravity.RIGHT).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(new Rect(1800, 500, 1920, 580), mResult.mBounds);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsOnFreeformDisplay_BottomGravity() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setWidth(120).setHeight(80).setGravity(Gravity.BOTTOM).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(new Rect(900, 1000, 1020, 1080), mResult.mBounds);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightBottomGravity() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setWidth(120).setHeight(80).setGravity(Gravity.BOTTOM | Gravity.RIGHT).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(new Rect(1800, 1000, 1920, 1080), mResult.mBounds);
+    }
+
+    @Test
+    public void testNonEmptyLayoutFractionBoundsOnFreeformDisplay() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setWidthFraction(0.0625f).setHeightFraction(0.1f).build();
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(new Rect(900, 486, 1020, 594), mResult.mBounds);
+    }
+
+    @Test
+    public void testNonEmptyLayoutBoundsWithResizeableActivity() {
+        final ActivityDisplay display = mSupervisor.getActivityDisplay(DEFAULT_DISPLAY);
+        display.setBounds(new Rect(0, 0, 1920, 1080));
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setWidth(120).setHeight(80).build();
+
+        mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(new Rect(900, 500, 1020, 580), mResult.mBounds);
+    }
+
+    @Test
+    public void testRespectBoundsFromFullyResolvedCurrentParam_NonEmptyBounds() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+        mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+        mCurrent.mBounds.set(0, 0, 200, 100);
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+        assertEquals(new Rect(0, 0, 200, 100), mResult.mBounds);
+    }
+
+    @Test
+    public void testDefaultSizeSmallerThanBigScreen() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+        mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        final int resultWidth = mResult.mBounds.width();
+        final int displayWidth = freeformDisplay.getBounds().width();
+        assertTrue("Result width " + resultWidth + " is not smaller than " + displayWidth,
+                resultWidth < displayWidth);
+
+        final int resultHeight = mResult.mBounds.height();
+        final int displayHeight = freeformDisplay.getBounds().height();
+        assertTrue("Result width " + resultHeight + " is not smaller than "
+                        + displayHeight, resultHeight < displayHeight);
+    }
+
+    @Test
+    public void testDefaultFreeformSizeCenteredToDisplay() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+        mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        final Rect displayBounds = freeformDisplay.getBounds();
+        assertEquals("Distance to left and right should be equal.",
+                mResult.mBounds.left - displayBounds.left,
+                displayBounds.right - mResult.mBounds.right);
+        assertEquals("Distance to top and bottom should be equal.",
+                mResult.mBounds.top - displayBounds.top,
+                displayBounds.bottom - mResult.mBounds.bottom);
+    }
+
+    @Test
+    public void testCascadesToSourceSizeForFreeform() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+        final ActivityRecord source = createSourceActivity(freeformDisplay);
+        source.setBounds(0, 0, 412, 732);
+
+        mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, source, options, mCurrent, mResult));
+
+        final Rect displayBounds = freeformDisplay.getBounds();
+        assertTrue("Left bounds should be larger than 0.", mResult.mBounds.left > 0);
+        assertTrue("Top bounds should be larger than 0.", mResult.mBounds.top > 0);
+        assertTrue("Bounds should be centered at somewhere in the left half, but it's "
+                + "centerX is " + mResult.mBounds.centerX(),
+                mResult.mBounds.centerX() < displayBounds.centerX());
+        assertTrue("Bounds should be centered at somewhere in the top half, but it's "
+                        + "centerY is " + mResult.mBounds.centerY(),
+                mResult.mBounds.centerY() < displayBounds.centerY());
+    }
+
+    @Test
+    public void testAdjustBoundsToFitDisplay_TopLeftOutOfDisplay() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+        final ActivityRecord source = createSourceActivity(freeformDisplay);
+        source.setBounds(0, 0, 200, 400);
+
+        mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, source, options, mCurrent, mResult));
+
+        final Rect displayBounds = freeformDisplay.getBounds();
+        assertTrue("display bounds doesn't contain result. display bounds: "
+                + displayBounds + " result: " + mResult.mBounds,
+                displayBounds.contains(mResult.mBounds));
+    }
+
+    @Test
+    public void testAdjustBoundsToFitDisplay_BottomRightOutOfDisplay() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+        final ActivityRecord source = createSourceActivity(freeformDisplay);
+        source.setBounds(1720, 680, 1920, 1080);
+
+        mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, source, options, mCurrent, mResult));
+
+        final Rect displayBounds = freeformDisplay.getBounds();
+        assertTrue("display bounds doesn't contain result. display bounds: "
+                        + displayBounds + " result: " + mResult.mBounds,
+                displayBounds.contains(mResult.mBounds));
+    }
+
+    @Test
+    public void testAdjustBoundsToFitDisplay_LargerThanDisplay() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        Configuration overrideConfig = new Configuration();
+        overrideConfig.setTo(mSupervisor.getOverrideConfiguration());
+        overrideConfig.setLayoutDirection(new Locale("ar"));
+        mSupervisor.onConfigurationChanged(overrideConfig);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+        final ActivityRecord source = createSourceActivity(freeformDisplay);
+        source.setBounds(1720, 680, 1920, 1080);
+
+        mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, source, options, mCurrent, mResult));
+
+        final Rect displayBounds = freeformDisplay.getBounds();
+        assertTrue("display bounds doesn't contain result. display bounds: "
+                        + displayBounds + " result: " + mResult.mBounds,
+                displayBounds.contains(mResult.mBounds));
+    }
+
+    @Test
+    public void testRespectsLayoutMinDimensions() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+        final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+                .setMinWidth(500).setMinHeight(800).build();
+
+        mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+                /* source */ null, options, mCurrent, mResult));
+
+        assertEquals(500, mResult.mBounds.width());
+        assertEquals(800, mResult.mBounds.height());
+    }
+
+    @Test
+    public void testRotatesInPlaceInitialBoundsMismatchOrientation() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+        options.setLaunchBounds(new Rect(100, 100, 500, 300));
+
+        mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquals(new Rect(200, 0, 400, 400), mResult.mBounds);
+    }
+
+    @Test
+    public void testShiftsToRightForCloseToLeftBoundsWhenConflict() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        addFreeformTaskTo(freeformDisplay, new Rect(50, 50, 100, 150));
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+        options.setLaunchBounds(new Rect(50, 50, 500, 300));
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquals(new Rect(170, 50, 620, 300), mResult.mBounds);
+    }
+
+    @Test
+    public void testShiftsToLeftForCloseToRightBoundsWhenConflict() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        addFreeformTaskTo(freeformDisplay, new Rect(1720, 50, 1830, 150));
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+        options.setLaunchBounds(new Rect(1720, 50, 1850, 300));
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquals(new Rect(1600, 50, 1730, 300), mResult.mBounds);
+    }
+
+    @Test
+    public void testShiftsToRightFirstForHorizontallyCenteredAndCloseToTopWhenConflict() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        addFreeformTaskTo(freeformDisplay, new Rect(0, 0, 100, 300));
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+        options.setLaunchBounds(new Rect(0, 0, 1800, 200));
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquals(new Rect(120, 0, 1920, 200), mResult.mBounds);
+    }
+
+    @Test
+    public void testShiftsToLeftNoSpaceOnRightForHorizontallyCenteredAndCloseToTopWhenConflict() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 300));
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+        options.setLaunchBounds(new Rect(120, 0, 1860, 200));
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquals(new Rect(0, 0, 1740, 200), mResult.mBounds);
+    }
+
+    @Test
+    public void testShiftsToBottomRightFirstForCenteredBoundsWhenConflict() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 100));
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+        options.setLaunchBounds(new Rect(120, 0, 1800, 1013));
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquals(new Rect(240, 67, 1920, 1080), mResult.mBounds);
+    }
+
+    @Test
+    public void testShiftsToTopLeftIfNoSpaceOnBottomRightForCenteredBoundsWhenConflict() {
+        final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+                WINDOWING_MODE_FREEFORM);
+
+        addFreeformTaskTo(freeformDisplay, new Rect(120, 67, 240, 100));
+
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+        options.setLaunchBounds(new Rect(120, 67, 1800, 1020));
+
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+                mActivity, /* source */ null, options, mCurrent, mResult));
+
+        assertEquals(new Rect(0, 0, 1680,
+                953), mResult.mBounds);
+    }
+
+    private TestActivityDisplay createNewActivityDisplay(int windowingMode) {
+        final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+        display.setWindowingMode(windowingMode);
+        display.setBounds(/* left */ 0, /* top */ 0, /* right */ 1920, /* bottom */ 1080);
+        display.getConfiguration().densityDpi = DENSITY_DEFAULT;
+        return display;
+    }
+
+    private ActivityRecord createSourceActivity(TestActivityDisplay display) {
+        final TestActivityStack stack = display.createStack(display.getWindowingMode(),
+                ACTIVITY_TYPE_STANDARD, true);
+        return new ActivityBuilder(mService).setStack(stack).setCreateTask(true).build();
+    }
+
+    private void addFreeformTaskTo(TestActivityDisplay display, Rect bounds) {
+        final TestActivityStack stack = display.createStack(display.getWindowingMode(),
+                ACTIVITY_TYPE_STANDARD, true);
+        stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+        task.setBounds(bounds);
+    }
+
+    private void assertEquivalentWindowingMode(int expected, int actual, int parentWindowingMode) {
+        if (expected != parentWindowingMode) {
+            assertEquals(expected, actual);
+        } else {
+            assertEquals(WINDOWING_MODE_UNDEFINED, actual);
         }
     }
 
-    /**
-     * Ensures that a task which causes a conflict with another task when positioned is adjusted as
-     * expected.
-     * @throws Exception
-     */
-    @Test
-    public void testLaunchWindowCenterConflict() throws Exception {
-        testConflict(Gravity.NO_GRAVITY);
-        testConflict(Gravity.TOP);
-        testConflict(Gravity.BOTTOM);
-        testConflict(Gravity.TOP | Gravity.LEFT);
-        testConflict(Gravity.TOP | Gravity.RIGHT);
-        testConflict(Gravity.BOTTOM | Gravity.LEFT);
-        testConflict(Gravity.BOTTOM | Gravity.RIGHT);
-    }
+    private static class WindowLayoutBuilder {
+        private int mWidth = -1;
+        private int mHeight = -1;
+        private float mWidthFraction = -1f;
+        private float mHeightFraction = -1f;
+        private int mGravity = Gravity.NO_GRAVITY;
+        private int mMinWidth = -1;
+        private int mMinHeight = -1;
 
-    private void testConflict(int gravity) {
-        final WindowLayout layout = new WindowLayout(0, 0, 0, 0, gravity, 0, 0);
-
-        // layout first task
-        mService.mStackSupervisor.getLaunchParamsController().layoutTask(mTask, layout);
-
-        // Second task will be laid out on top of the first so starting bounds is the same.
-        final Rect expectedBounds = new Rect(mTask.getOverrideBounds());
-
-        ActivityRecord activity = null;
-        TaskRecord secondTask = null;
-
-        // wrap with try/finally to ensure cleanup of activity/stack.
-        try {
-            // empty tasks are ignored in conflicts
-            activity = new ActivityBuilder(mService).setTask(mTask).build();
-
-            // Create secondary task
-            secondTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
-
-            // layout second task
-            assertEquals(RESULT_CONTINUE,
-                    mPositioner.onCalculate(secondTask, layout, null /*activity*/,
-                            null /*source*/, null /*options*/, mCurrent, mResult));
-
-            if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)
-                    || (gravity & (Gravity.BOTTOM | Gravity.RIGHT))
-                    == (Gravity.BOTTOM | Gravity.RIGHT)) {
-                expectedBounds.offset(-TaskLaunchParamsModifier.getHorizontalStep(
-                        mStack.getOverrideBounds()), 0);
-            } else if ((gravity & Gravity.TOP) == Gravity.TOP
-                    || (gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
-                expectedBounds.offset(
-                        TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()), 0);
-            } else {
-                expectedBounds.offset(
-                        TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()),
-                        TaskLaunchParamsModifier.getVerticalStep(mStack.getOverrideBounds()));
-            }
-
-            assertEquals(mResult.mBounds, expectedBounds);
-        } finally {
-            // Remove task and activity to prevent influencing future tests
-            if (activity != null) {
-                mTask.removeActivity(activity);
-            }
-
-            if (secondTask != null) {
-                mStack.removeTask(secondTask, "cleanup", ActivityStack.REMOVE_TASK_MODE_DESTROYING);
-            }
-        }
-    }
-
-    private Rect getDefaultBounds(int gravity) {
-        final Rect bounds = new Rect();
-        bounds.set(mStack.getOverrideBounds());
-
-        final int verticalInset =
-                TaskLaunchParamsModifier.getFreeformStartTop(mStack.getOverrideBounds());
-        final int horizontalInset =
-                TaskLaunchParamsModifier.getFreeformStartLeft(mStack.getOverrideBounds());
-
-        bounds.inset(horizontalInset, verticalInset);
-
-        if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)) {
-            bounds.offsetTo(horizontalInset * 2, 0);
-        } else if ((gravity & Gravity.TOP) == Gravity.TOP) {
-            bounds.offsetTo(0, 0);
-        } else if ((gravity & (Gravity.BOTTOM | Gravity.RIGHT))
-                == (Gravity.BOTTOM | Gravity.RIGHT)) {
-            bounds.offsetTo(horizontalInset * 2, verticalInset * 2);
-        } else if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
-            bounds.offsetTo(0, verticalInset * 2);
+        private WindowLayoutBuilder setWidth(int width) {
+            mWidth = width;
+            return this;
         }
 
-        return bounds;
+        private WindowLayoutBuilder setHeight(int height) {
+            mHeight = height;
+            return this;
+        }
+
+        private WindowLayoutBuilder setWidthFraction(float widthFraction) {
+            mWidthFraction = widthFraction;
+            return this;
+        }
+
+        private WindowLayoutBuilder setHeightFraction(float heightFraction) {
+            mHeightFraction = heightFraction;
+            return this;
+        }
+
+        private WindowLayoutBuilder setGravity(int gravity) {
+            mGravity = gravity;
+            return this;
+        }
+
+        private WindowLayoutBuilder setMinWidth(int minWidth) {
+            mMinWidth = minWidth;
+            return this;
+        }
+
+        private WindowLayoutBuilder setMinHeight(int minHeight) {
+            mMinHeight = minHeight;
+            return this;
+        }
+
+        private ActivityInfo.WindowLayout build() {
+            return new ActivityInfo.WindowLayout(mWidth, mWidthFraction, mHeight, mHeightFraction,
+                    mGravity, mMinWidth, mMinHeight);
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
index 7125246..3c8b2a0 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
@@ -40,27 +40,25 @@
 import android.view.SurfaceSession;
 import android.view.View;
 
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.LocalServices;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import androidx.test.filters.SmallTest;
+
 /**
  * Tests for the {@link DragDropController} class.
  *
- * atest FrameworksServicesTests:com.android.server.wm.DragDropControllerTests
+ * Build/Install/Run:
+ *  atest FrameworksServicesTests:com.android.server.wm.DragDropControllerTests
  */
 @SmallTest
-@RunWith(AndroidJUnit4.class)
 @Presubmit
 public class DragDropControllerTests extends WindowTestsBase {
     private static final int TIMEOUT_MS = 3000;
@@ -109,6 +107,7 @@
         return window;
     }
 
+    @Override
     @Before
     public void setUp() throws Exception {
         final UserManagerInternal userManager = mock(UserManagerInternal.class);
@@ -127,6 +126,7 @@
         }
     }
 
+    @Override
     @After
     public void tearDown() throws Exception {
         LocalServices.removeServiceForTest(UserManagerInternal.class);
@@ -139,25 +139,25 @@
                 mTarget.cancelDragAndDrop(mToken);
             }
             latch = new CountDownLatch(1);
-            mTarget.setOnClosedCallbackLocked(() -> {
-                latch.countDown();
-            });
+            mTarget.setOnClosedCallbackLocked(latch::countDown);
         }
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+        super.tearDown();
     }
 
     @Test
-    public void testDragFlow() throws Exception {
+    public void testDragFlow() {
         dragFlow(0, ClipData.newPlainText("label", "Test"), 0, 0);
     }
 
     @Test
-    public void testPerformDrag_NullDataWithGrantUri() throws Exception {
+    public void testPerformDrag_NullDataWithGrantUri() {
         dragFlow(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0);
     }
 
     @Test
-    public void testPerformDrag_NullDataToOtherUser() throws Exception {
+    public void testPerformDrag_NullDataToOtherUser() {
         final WindowState otherUsersWindow =
                 createDropTargetWindow("Other user's window", 1 * UserHandle.PER_USER_RANGE);
         doReturn(otherUsersWindow).when(mDisplayContent).getTouchableWinAtPointLocked(10, 10);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index 6f4f173..33b137e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -29,14 +29,14 @@
 import android.graphics.Rect;
 import android.os.UserManager;
 
-import androidx.test.InstrumentationRegistry;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.BeforeClass;
 
 import java.io.File;
 
+import androidx.test.InstrumentationRegistry;
+
 /**
  * Base class for tests that use a {@link TaskSnapshotPersister}.
  */
@@ -54,9 +54,11 @@
         sFilesDir = InstrumentationRegistry.getContext().getFilesDir();
     }
 
+    @Override
     @Before
     public void setUp() throws Exception {
         super.setUp();
+
         final UserManager um = UserManager.get(InstrumentationRegistry.getContext());
         mTestUserId = um.getUserHandle();
         mPersister = new TaskSnapshotPersister(userId -> sFilesDir);
@@ -64,9 +66,12 @@
         mPersister.start();
     }
 
+    @Override
     @After
     public void tearDown() throws Exception {
         cleanDirectory();
+
+        super.tearDown();
     }
 
     private void cleanDirectory() {
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index ea44279..0e9a63c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -19,36 +19,37 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 
+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.assertTrue;
 
 import android.platform.test.annotations.Presubmit;
 
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import androidx.test.filters.SmallTest;
 
 /**
  * Tests for the {@link DisplayContent.TaskStackContainers} container in {@link DisplayContent}.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.wm.TaskStackContainersTests
+ *  atest FrameworksServicesTests:com.android.server.wm.TaskStackContainersTests
  */
 @SmallTest
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class TaskStackContainersTests extends WindowTestsBase {
 
     private TaskStack mPinnedStack;
 
+    @Override
     @Before
     public void setUp() throws Exception {
         super.setUp();
+
         mPinnedStack = createStackControllerOnStackOnDisplay(
                 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
         // Stack should contain visible app window to be considered visible.
@@ -60,13 +61,16 @@
         assertTrue(mPinnedStack.isVisible());
     }
 
+    @Override
     @After
     public void tearDown() throws Exception {
         mPinnedStack.removeImmediately();
+
+        super.tearDown();
     }
 
     @Test
-    public void testStackPositionChildAt() throws Exception {
+    public void testStackPositionChildAt() {
         // Test that always-on-top stack can't be moved to position other than top.
         final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
         final TaskStack stack2 = createTaskStackOnDisplay(mDisplayContent);
@@ -76,8 +80,8 @@
         final int stack1Pos = taskStackContainer.mChildren.indexOf(stack1);
         final int stack2Pos = taskStackContainer.mChildren.indexOf(stack2);
         final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedStack);
-        assertGreaterThan(pinnedStackPos, stack2Pos);
-        assertGreaterThan(stack2Pos, stack1Pos);
+        assertThat(pinnedStackPos).isGreaterThan(stack2Pos);
+        assertThat(stack2Pos).isGreaterThan(stack1Pos);
 
         taskStackContainer.positionChildAt(WindowContainer.POSITION_BOTTOM, mPinnedStack, false);
         assertEquals(taskStackContainer.mChildren.get(stack1Pos), stack1);
@@ -91,7 +95,7 @@
     }
 
     @Test
-    public void testStackPositionBelowPinnedStack() throws Exception {
+    public void testStackPositionBelowPinnedStack() {
         // Test that no stack can be above pinned stack.
         final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
 
@@ -99,7 +103,7 @@
 
         final int stackPos = taskStackContainer.mChildren.indexOf(stack1);
         final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedStack);
-        assertGreaterThan(pinnedStackPos, stackPos);
+        assertThat(pinnedStackPos).isGreaterThan(stackPos);
 
         taskStackContainer.positionChildAt(WindowContainer.POSITION_TOP, stack1, false);
         assertEquals(taskStackContainer.mChildren.get(stackPos), stack1);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 70e4ce4..cf67d78 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -48,18 +48,17 @@
 import android.view.IWindow;
 import android.view.WindowManager;
 
-import androidx.test.InstrumentationRegistry;
-
 import com.android.server.AttributeCache;
 
 import org.junit.After;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 
 import java.util.HashSet;
 import java.util.LinkedList;
 
+import androidx.test.InstrumentationRegistry;
+
 /**
  * Common base class for window manager unit test classes.
  *
@@ -194,14 +193,6 @@
         }
     }
 
-    /**
-     * @return A SurfaceBuilderFactory to inject in to the WindowManagerService during
-     *         set-up (or null).
-     */
-    SurfaceBuilderFactory getSurfaceBuilderFactory() {
-        return null;
-    }
-
     private WindowState createCommonWindow(WindowState parent, int type, String name) {
         synchronized (sWm.mWindowMap) {
             final WindowState win = createWindow(parent, type, name);
@@ -212,16 +203,6 @@
         }
     }
 
-    /** Asserts that the first entry is greater than the second entry. */
-    void assertGreaterThan(int first, int second) throws Exception {
-        Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
-    }
-
-    /** Asserts that the first entry is greater than the second entry. */
-    void assertLessThan(int first, int second) throws Exception {
-        Assert.assertTrue("Excepted " + first + " to be less than " + second, first < second);
-    }
-
     /**
      * Waits until the main handler for WM has processed all messages.
      */
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
index 8f9fb1b..a610e6e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -32,36 +32,35 @@
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import android.platform.test.annotations.Presubmit;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
 import org.junit.After;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.HashMap;
 import java.util.LinkedList;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
 /**
  * Tests for the {@link WindowLayersController} class.
  *
  * Build/Install/Run:
- *  bit FrameworksServicesTests:com.android.server.wm.ZOrderingTests
+ *  atest FrameworksServicesTests:com.android.server.wm.ZOrderingTests
  */
 @SmallTest
 @FlakyTest(bugId = 74078662)
 @Presubmit
-@RunWith(AndroidJUnit4.class)
 public class ZOrderingTests extends WindowTestsBase {
 
     private class LayerRecordingTransaction extends SurfaceControl.Transaction {
-        HashMap<SurfaceControl, Integer> mLayersForControl = new HashMap();
-        HashMap<SurfaceControl, SurfaceControl> mRelativeLayersForControl = new HashMap();
+        HashMap<SurfaceControl, Integer> mLayersForControl = new HashMap<>();
+        HashMap<SurfaceControl, SurfaceControl> mRelativeLayersForControl = new HashMap<>();
 
         @Override
         public SurfaceControl.Transaction setLayer(SurfaceControl sc, int layer) {
@@ -86,11 +85,11 @@
         private SurfaceControl getRelativeLayer(SurfaceControl sc) {
             return mRelativeLayersForControl.get(sc);
         }
-    };
+    }
 
     // We have WM use our Hierarchy recording subclass of SurfaceControl.Builder
     // such that we can keep track of the parents of Surfaces as they are constructed.
-    private HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap();
+    private HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap<>();
 
     private class HierarchyRecorder extends SurfaceControl.Builder {
         SurfaceControl mPendingParent;
@@ -109,13 +108,13 @@
             mPendingParent = null;
             return sc;
         }
-    };
+    }
 
     class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory {
         public SurfaceControl.Builder make(SurfaceSession s) {
             return new HierarchyRecorder(s);
         }
-    };
+    }
 
     private LayerRecordingTransaction mTransaction;
 
@@ -136,7 +135,7 @@
     }
 
     LinkedList<SurfaceControl> getAncestors(LayerRecordingTransaction t, SurfaceControl sc) {
-        LinkedList<SurfaceControl> p = new LinkedList();
+        LinkedList<SurfaceControl> p = new LinkedList<>();
         SurfaceControl current = sc;
         do {
             p.addLast(current);
@@ -153,7 +152,7 @@
 
 
     void assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left,
-            SurfaceControl right) throws Exception {
+            SurfaceControl right) {
         final LinkedList<SurfaceControl> leftParentChain = getAncestors(t, left);
         final LinkedList<SurfaceControl> rightParentChain = getAncestors(t, right);
 
@@ -168,16 +167,15 @@
         }
 
         if (rightTop == null) { // right is the parent of left.
-            assertGreaterThan(t.getLayer(leftTop), 0);
+            assertThat(t.getLayer(leftTop)).isGreaterThan(0);
         } else if (leftTop == null) { // left is the parent of right.
-            assertGreaterThan(0, t.getLayer(rightTop));
+            assertThat(t.getLayer(rightTop)).isLessThan(0);
         } else {
-            assertGreaterThan(t.getLayer(leftTop),
-                    t.getLayer(rightTop));
+            assertThat(t.getLayer(leftTop)).isGreaterThan(t.getLayer(rightTop));
         }
     }
 
-    void assertWindowHigher(WindowState left, WindowState right) throws Exception {
+    void assertWindowHigher(WindowState left, WindowState right) {
         assertZOrderGreaterThan(mTransaction, left.getSurfaceControl(), right.getSurfaceControl());
     }
 
@@ -186,7 +184,7 @@
     }
 
     @Test
-    public void testAssignWindowLayers_ForImeWithNoTarget() throws Exception {
+    public void testAssignWindowLayers_ForImeWithNoTarget() {
         sWm.mInputMethodTarget = null;
         mDisplayContent.assignChildLayers(mTransaction);
 
@@ -203,7 +201,7 @@
     }
 
     @Test
-    public void testAssignWindowLayers_ForImeWithAppTarget() throws Exception {
+    public void testAssignWindowLayers_ForImeWithAppTarget() {
         final WindowState imeAppTarget = createWindow("imeAppTarget");
         sWm.mInputMethodTarget = imeAppTarget;
 
@@ -222,7 +220,7 @@
     }
 
     @Test
-    public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() throws Exception {
+    public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() {
         final WindowState imeAppTarget = createWindow("imeAppTarget");
         final WindowState imeAppTargetChildAboveWindow = createWindow(imeAppTarget,
                 TYPE_APPLICATION_ATTACHED_DIALOG, imeAppTarget.mToken,
@@ -248,7 +246,7 @@
     }
 
     @Test
-    public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() throws Exception {
+    public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
         final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
         final WindowState imeAppTarget = createWindow("imeAppTarget");
         final WindowState appAboveImeTarget = createWindow("appAboveImeTarget");
@@ -271,7 +269,7 @@
     }
 
     @Test
-    public void testAssignWindowLayers_ForImeNonAppImeTarget() throws Exception {
+    public void testAssignWindowLayers_ForImeNonAppImeTarget() {
         final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
                 mDisplayContent, "imeSystemOverlayTarget",
                 true /* ownerCanAddInternalSystemWindow */);
@@ -298,7 +296,7 @@
     }
 
     @Test
-    public void testAssignWindowLayers_ForStatusBarImeTarget() throws Exception {
+    public void testAssignWindowLayers_ForStatusBarImeTarget() {
         sWm.mInputMethodTarget = mStatusBarWindow;
         mDisplayContent.assignChildLayers(mTransaction);
 
@@ -312,7 +310,7 @@
     }
 
     @Test
-    public void testStackLayers() throws Exception {
+    public void testStackLayers() {
         final WindowState anyWindow1 = createWindow("anyWindow");
         final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
                 ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
@@ -342,7 +340,7 @@
     }
 
     @Test
-    public void testAssignWindowLayers_ForSysUiPanels() throws Exception {
+    public void testAssignWindowLayers_ForSysUiPanels() {
         final WindowState navBarPanel =
                 createWindow(null, TYPE_NAVIGATION_BAR_PANEL, mDisplayContent, "NavBarPanel");
         final WindowState statusBarPanel =
@@ -359,7 +357,7 @@
     }
 
     @Test
-    public void testAssignWindowLayers_ForNegativelyZOrderedSubtype() throws Exception {
+    public void testAssignWindowLayers_ForNegativelyZOrderedSubtype() {
         // TODO(b/70040778): We should aim to eliminate the last user of TYPE_APPLICATION_MEDIA
         // then we can drop all negative layering on the windowing side.
 
@@ -376,7 +374,7 @@
     }
 
     @Test
-    public void testDockedDividerPosition() throws Exception {
+    public void testDockedDividerPosition() {
         final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
                 ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
                 "pinnedStackWindow");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 11b086c..1b59e75 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -32,6 +32,7 @@
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -54,7 +55,6 @@
 import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.Adjustment;
@@ -74,35 +74,31 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
-import java.util.Objects;
+import java.util.Arrays;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class NotificationRecordTest extends UiServiceTestCase {
 
     private final Context mMockContext = mock(Context.class);
-    @Mock PackageManager mPm;
+    @Mock private PackageManager mPm;
 
     private final String pkg = PKG_N_MR1;
     private final int uid = 9583;
-    private final String pkg2 = PKG_O;
-    private final int uid2 = 1111111;
     private final int id1 = 1;
-    private final int id2 = 2;
     private final String tag1 = "tag1";
-    private final String tag2 = "tag2";
     private final String channelId = "channel";
-    NotificationChannel channel =
+    private NotificationChannel channel =
             new NotificationChannel(channelId, "test", NotificationManager.IMPORTANCE_DEFAULT);
     private final String channelIdLong =
             "give_a_developer_a_string_argument_and_who_knows_what_they_will_pass_in_there";
-    final String groupId = "group";
-    final String groupIdOverride = "other_group";
+    private final String groupId = "group";
+    private final String groupIdOverride = "other_group";
     private final String groupIdLong =
             "0|com.foo.bar|g:content://com.foo.bar.ui/account%3A-0000000/account/";
-    NotificationChannel channelLongId =
+    private NotificationChannel channelLongId =
             new NotificationChannel(channelIdLong, "long", NotificationManager.IMPORTANCE_DEFAULT);
-    NotificationChannel defaultChannel =
+    private NotificationChannel defaultChannel =
             new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "test",
                     NotificationManager.IMPORTANCE_UNSPECIFIED);
     private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
@@ -185,7 +181,7 @@
     //
 
     @Test
-    public void testSound_default_preUpgradeUsesNotification() throws Exception {
+    public void testSound_default_preUpgradeUsesNotification() {
         defaultChannel.setSound(null, null);
         // pre upgrade, default sound.
         StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
@@ -198,7 +194,7 @@
     }
 
     @Test
-    public void testSound_custom_preUpgradeUsesNotification() throws Exception {
+    public void testSound_custom_preUpgradeUsesNotification() {
         defaultChannel.setSound(null, null);
         // pre upgrade, custom sound.
         StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
@@ -211,7 +207,7 @@
     }
 
     @Test
-    public void testSound_default_userLocked_preUpgrade() throws Exception {
+    public void testSound_default_userLocked_preUpgrade() {
         defaultChannel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
         // pre upgrade, default sound.
@@ -225,19 +221,19 @@
     }
 
     @Test
-    public void testSound_noSound_preUpgrade() throws Exception {
+    public void testSound_noSound_preUpgrade() {
         // pre upgrade, default sound.
         StatusBarNotification sbn = getNotification(PKG_N_MR1, false /* noisy */,
                 false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
 
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
-        assertEquals(null, record.getSound());
+        assertNull(record.getSound());
         assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, record.getAudioAttributes());
     }
 
     @Test
-    public void testSound_default_upgradeUsesChannel() throws Exception {
+    public void testSound_default_upgradeUsesChannel() {
         channel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
         // post upgrade, default sound.
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
@@ -250,7 +246,7 @@
     }
 
     @Test
-    public void testVibration_default_preUpgradeUsesNotification() throws Exception {
+    public void testVibration_default_preUpgradeUsesNotification() {
         defaultChannel.enableVibration(false);
         // pre upgrade, default vibration.
         StatusBarNotification sbn = getNotification(PKG_N_MR1, false /* noisy */,
@@ -262,7 +258,7 @@
     }
 
     @Test
-    public void testVibration_custom_preUpgradeUsesNotification() throws Exception {
+    public void testVibration_custom_preUpgradeUsesNotification() {
         defaultChannel.enableVibration(false);
         // pre upgrade, custom vibration.
         StatusBarNotification sbn = getNotification(PKG_N_MR1, false /* noisy */,
@@ -274,7 +270,7 @@
     }
 
     @Test
-    public void testVibration_custom_userLocked_preUpgrade() throws Exception {
+    public void testVibration_custom_userLocked_preUpgrade() {
         defaultChannel.enableVibration(true);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
         // pre upgrade, custom vibration.
@@ -283,11 +279,11 @@
                 false /* lights */, false /* defaultLights */, null /* group */);
 
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
-        assertTrue(!Objects.equals(CUSTOM_VIBRATION, record.getVibration()));
+        assertTrue(!Arrays.equals(CUSTOM_VIBRATION, record.getVibration()));
     }
 
     @Test
-    public void testVibration_custom_upgradeUsesChannel() throws Exception {
+    public void testVibration_custom_upgradeUsesChannel() {
         channel.enableVibration(true);
         // post upgrade, custom vibration.
         StatusBarNotification sbn = getNotification(PKG_O, false /* noisy */,
@@ -299,7 +295,7 @@
     }
 
     @Test
-    public void testImportance_preUpgrade() throws Exception {
+    public void testImportance_preUpgrade() {
         StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
@@ -308,7 +304,7 @@
     }
 
     @Test
-    public void testImportance_locked_preUpgrade() throws Exception {
+    public void testImportance_locked_preUpgrade() {
         defaultChannel.setImportance(IMPORTANCE_LOW);
         defaultChannel.lockFields(USER_LOCKED_IMPORTANCE);
         StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
@@ -320,7 +316,7 @@
     }
 
     @Test
-    public void testImportance_locked_unspecified_preUpgrade() throws Exception {
+    public void testImportance_locked_unspecified_preUpgrade() {
         defaultChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
         defaultChannel.lockFields(USER_LOCKED_IMPORTANCE);
         StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
@@ -332,7 +328,7 @@
     }
 
     @Test
-    public void testImportance_upgrade() throws Exception {
+    public void testImportance_upgrade() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
@@ -341,7 +337,7 @@
     }
 
     @Test
-    public void testLights_preUpgrade_noLight() throws Exception {
+    public void testLights_preUpgrade_noLight() {
         StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
@@ -351,7 +347,7 @@
 
 
     @Test
-    public void testLights_preUpgrade() throws Exception {
+    public void testLights_preUpgrade() {
         StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /* defaultLights */, null /* group */);
@@ -360,7 +356,7 @@
     }
 
     @Test
-    public void testLights_locked_preUpgrade() throws Exception {
+    public void testLights_locked_preUpgrade() {
         defaultChannel.enableLights(true);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
         StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */,
@@ -368,11 +364,11 @@
                 true /* lights */, false /* defaultLights */, null /* group */);
 
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
-        assertFalse(CUSTOM_LIGHT.equals(record.getLight()));
+        assertNotEquals(CUSTOM_LIGHT, record.getLight());
     }
 
     @Test
-    public void testLights_upgrade_defaultLights() throws Exception {
+    public void testLights_upgrade_defaultLights() {
         int defaultLightColor = mMockContext.getResources().getColor(
                 com.android.internal.R.color.config_defaultNotificationColor);
         int defaultLightOn = mMockContext.getResources().getInteger(
@@ -390,7 +386,7 @@
     }
 
     @Test
-    public void testLights_upgrade() throws Exception {
+    public void testLights_upgrade() {
         int defaultLightOn = mMockContext.getResources().getInteger(
                 com.android.internal.R.integer.config_defaultNotificationLedOn);
         int defaultLightOff = mMockContext.getResources().getInteger(
@@ -406,7 +402,7 @@
     }
 
     @Test
-    public void testLights_upgrade_noLight() throws Exception {
+    public void testLights_upgrade_noLight() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
@@ -415,7 +411,7 @@
     }
 
     @Test
-    public void testLogmakerShortChannel() throws Exception {
+    public void testLogmakerShortChannel() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, null /* group */);
@@ -428,7 +424,7 @@
     }
 
     @Test
-    public void testLogmakerLongChannel() throws Exception {
+    public void testLogmakerLongChannel() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
         true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
         false /* lights */, false /*defaultLights */, null /* group */);
@@ -439,7 +435,7 @@
     }
 
     @Test
-    public void testLogmakerNoGroup() throws Exception {
+    public void testLogmakerNoGroup() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */, null /* group */);
@@ -448,7 +444,7 @@
     }
 
     @Test
-    public void testLogmakerShortGroup() throws Exception {
+    public void testLogmakerShortGroup() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
@@ -458,7 +454,7 @@
     }
 
     @Test
-    public void testLogmakerLongGroup() throws Exception {
+    public void testLogmakerLongGroup() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupIdLong /* group */);
@@ -469,7 +465,7 @@
     }
 
     @Test
-    public void testLogmakerOverrideGroup() throws Exception {
+    public void testLogmakerOverrideGroup() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
@@ -485,7 +481,7 @@
     }
 
     @Test
-    public void testNotificationStats() throws Exception {
+    public void testNotificationStats() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
@@ -528,7 +524,7 @@
     }
 
     @Test
-    public void testUserSentiment() throws Exception {
+    public void testUserSentiment() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
@@ -546,7 +542,7 @@
     }
 
     @Test
-    public void testUserSentiment_appImportanceUpdatesSentiment() throws Exception {
+    public void testUserSentiment_appImportanceUpdatesSentiment() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
@@ -558,7 +554,7 @@
     }
 
     @Test
-    public void testUserSentiment_appImportanceBlocksNegativeSentimentUpdate() throws Exception {
+    public void testUserSentiment_appImportanceBlocksNegativeSentimentUpdate() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
@@ -574,7 +570,7 @@
     }
 
     @Test
-    public void testUserSentiment_userLocked() throws Exception {
+    public void testUserSentiment_userLocked() {
         channel.lockFields(USER_LOCKED_IMPORTANCE);
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
@@ -593,17 +589,17 @@
     }
 
     @Test
-    public void testAppImportance_returnsCorrectly() throws Exception {
+    public void testAppImportance_returnsCorrectly() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /* defaultLights */, groupId /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
 
         record.setIsAppImportanceLocked(true);
-        assertEquals(true, record.getIsAppImportanceLocked());
+        assertTrue(record.getIsAppImportanceLocked());
 
         record.setIsAppImportanceLocked(false);
-        assertEquals(false, record.getIsAppImportanceLocked());
+        assertFalse(record.getIsAppImportanceLocked());
     }
 
     @Test
@@ -613,10 +609,10 @@
                 false /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
 
-        assertEquals(false, record.isInterruptive());
+        assertFalse(record.isInterruptive());
 
         record.setTextChanged(true);
-        assertEquals(false, record.isInterruptive());
+        assertFalse(record.isInterruptive());
     }
 
     @Test
@@ -626,11 +622,11 @@
                 false /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
 
-        assertEquals(false, record.isInterruptive());
+        assertFalse(record.isInterruptive());
 
         record.setTextChanged(true);
         record.setSeen();
-        assertEquals(true, record.isInterruptive());
+        assertTrue(record.isInterruptive());
     }
 
     @Test
@@ -640,15 +636,15 @@
                 false /* lights */, false /* defaultLights */, null /* group */);
         NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
 
-        assertEquals(false, record.isInterruptive());
+        assertFalse(record.isInterruptive());
 
         record.setTextChanged(false);
         record.setSeen();
-        assertEquals(false, record.isInterruptive());
+        assertFalse(record.isInterruptive());
     }
 
     @Test
-    public void testCalculateGrantableUris_PappProvided() throws RemoteException {
+    public void testCalculateGrantableUris_PappProvided() {
         IActivityManager am = mock(IActivityManager.class);
         UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
         when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
@@ -671,7 +667,7 @@
     }
 
     @Test
-    public void testCalculateGrantableUris_PuserOverridden() throws RemoteException {
+    public void testCalculateGrantableUris_PuserOverridden() {
         IActivityManager am = mock(IActivityManager.class);
         UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
         when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
@@ -689,7 +685,7 @@
     }
 
     @Test
-    public void testCalculateGrantableUris_prePappProvided() throws RemoteException {
+    public void testCalculateGrantableUris_prePappProvided() {
         IActivityManager am = mock(IActivityManager.class);
         UriGrantsManagerInternal ugm = mock(UriGrantsManagerInternal.class);
         when(ugm.checkGrantUriPermission(anyInt(), eq(null), any(Uri.class),
@@ -790,4 +786,19 @@
 
         assertEquals(IMPORTANCE_LOW, record.getImportance());
     }
+
+    @Test
+    public void testSetContactAffinity() {
+        channel.setImportance(IMPORTANCE_LOW);
+        channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, groupId /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        record.setContactAffinity(1.0f);
+
+        assertEquals(1.0f, record.getContactAffinity());
+        assertEquals(IMPORTANCE_LOW, record.getImportance());
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
index 9db823c..55c16b3 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java
@@ -48,6 +48,7 @@
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.style.StyleSpan;
+import android.util.Pair;
 import android.widget.RemoteViews;
 
 import com.android.server.UiServiceTestCase;
@@ -541,5 +542,94 @@
 
         assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
     }
+
+    @Test
+    public void testFreeformRemoteInputActionPair_noRemoteInput() {
+        PendingIntent intent = mock(PendingIntent.class);
+        Icon icon = mock(Icon.class);
+        Notification notification = new Notification.Builder(mContext, "test")
+                .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent)
+                        .build())
+                .build();
+        assertNull(notification.findRemoteInputActionPair(false));
+    }
+
+    @Test
+    public void testFreeformRemoteInputActionPair_hasRemoteInput() {
+        PendingIntent intent = mock(PendingIntent.class);
+        Icon icon = mock(Icon.class);
+
+        RemoteInput remoteInput = new RemoteInput.Builder("a").build();
+
+        Notification.Action actionWithRemoteInput =
+                new Notification.Action.Builder(icon, "TEXT 1", intent)
+                        .addRemoteInput(remoteInput)
+                        .addRemoteInput(remoteInput)
+                        .build();
+
+        Notification.Action actionWithoutRemoteInput =
+                new Notification.Action.Builder(icon, "TEXT 2", intent)
+                        .build();
+
+        Notification notification = new Notification.Builder(mContext, "test")
+                .addAction(actionWithoutRemoteInput)
+                .addAction(actionWithRemoteInput)
+                .build();
+
+        Pair<RemoteInput, Notification.Action> remoteInputActionPair =
+                notification.findRemoteInputActionPair(false);
+
+        assertNotNull(remoteInputActionPair);
+        assertEquals(remoteInput, remoteInputActionPair.first);
+        assertEquals(actionWithRemoteInput, remoteInputActionPair.second);
+    }
+
+    @Test
+    public void testFreeformRemoteInputActionPair_requestFreeform_noFreeformRemoteInput() {
+        PendingIntent intent = mock(PendingIntent.class);
+        Icon icon = mock(Icon.class);
+        Notification notification = new Notification.Builder(mContext, "test")
+                .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent)
+                        .addRemoteInput(
+                                new RemoteInput.Builder("a")
+                                        .setAllowFreeFormInput(false).build())
+                        .build())
+                .build();
+        assertNull(notification.findRemoteInputActionPair(true));
+    }
+
+    @Test
+    public void testFreeformRemoteInputActionPair_requestFreeform_hasFreeformRemoteInput() {
+        PendingIntent intent = mock(PendingIntent.class);
+        Icon icon = mock(Icon.class);
+
+        RemoteInput remoteInput =
+                new RemoteInput.Builder("a").setAllowFreeFormInput(false).build();
+        RemoteInput freeformRemoteInput =
+                new RemoteInput.Builder("b").setAllowFreeFormInput(true).build();
+
+        Notification.Action actionWithFreeformRemoteInput =
+                new Notification.Action.Builder(icon, "TEXT 1", intent)
+                        .addRemoteInput(remoteInput)
+                        .addRemoteInput(freeformRemoteInput)
+                        .build();
+
+        Notification.Action actionWithoutFreeformRemoteInput =
+                new Notification.Action.Builder(icon, "TEXT 2", intent)
+                        .addRemoteInput(remoteInput)
+                        .build();
+
+        Notification notification = new Notification.Builder(mContext, "test")
+                .addAction(actionWithoutFreeformRemoteInput)
+                .addAction(actionWithFreeformRemoteInput)
+                .build();
+
+        Pair<RemoteInput, Notification.Action> remoteInputActionPair =
+                notification.findRemoteInputActionPair(true);
+
+        assertNotNull(remoteInputActionPair);
+        assertEquals(freeformRemoteInput, remoteInputActionPair.first);
+        assertEquals(actionWithFreeformRemoteInput, remoteInputActionPair.second);
+    }
 }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 100f9c6..9bd3f26 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -19,7 +19,9 @@
 import static junit.framework.Assert.assertEquals;
 
 import android.app.NotificationManager.Policy;
+import android.net.Uri;
 import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.EventInfo;
 import android.service.notification.ZenPolicy;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -112,6 +114,30 @@
         assertEquals(true, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
     }
 
+    @Test
+    public void testParseOldEvent() {
+        EventInfo oldEvent = new EventInfo();
+        oldEvent.userId = 1;
+        oldEvent.calName = "calName";
+        oldEvent.calendarId = null; // old events will have null ids
+
+        Uri conditionId = ZenModeConfig.toEventConditionId(oldEvent);
+        EventInfo eventParsed = ZenModeConfig.tryParseEventConditionId(conditionId);
+        assertEquals(oldEvent, eventParsed);
+    }
+
+    @Test
+    public void testParseNewEvent() {
+        EventInfo event = new EventInfo();
+        event.userId = 1;
+        event.calName = "calName";
+        event.calendarId = 12345L;
+
+        Uri conditionId = ZenModeConfig.toEventConditionId(event);
+        EventInfo eventParsed = ZenModeConfig.tryParseEventConditionId(conditionId);
+        assertEquals(event, eventParsed);
+    }
+
     private ZenModeConfig getMutedNotificationsConfig() {
         ZenModeConfig config = new ZenModeConfig();
         // Allow alarms, media, and system
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 8d6dccc..9918395 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -50,7 +50,6 @@
 import android.hidl.manager.V1_0.IServiceManager;
 import android.hidl.manager.V1_0.IServiceNotification;
 import android.os.BatteryManager;
-import android.os.Binder;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -1982,9 +1981,10 @@
      * opens the currently attached USB accessory.
      *
      * @param accessory accessory to be openened.
+     * @param uid Uid of the caller
      */
     public ParcelFileDescriptor openAccessory(UsbAccessory accessory,
-            UsbUserSettingsManager settings) {
+            UsbUserSettingsManager settings, int uid) {
         UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
         if (currentAccessory == null) {
             throw new IllegalArgumentException("no accessory attached");
@@ -1995,7 +1995,7 @@
                     + currentAccessory;
             throw new IllegalArgumentException(error);
         }
-        settings.checkPermission(accessory, Binder.getCallingUid());
+        settings.checkPermission(accessory, uid);
         return nativeOpenAccessory();
     }
 
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 4be70af..e0f3685 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -230,42 +230,29 @@
         }
     }
 
-    /**
-     * Check if the calling user is in the same profile group as the {@link #mCurrentUserId
-     * current user}.
-     *
-     * @return Iff the caller is in the current user's profile group
-     */
-    @GuardedBy("mLock")
-    private boolean isCallerInCurrentUserProfileGroupLocked() {
-        int userIdInt = UserHandle.getCallingUserId();
-
-        long ident = clearCallingIdentity();
-        try {
-            return mUserManager.isSameProfileGroup(userIdInt, mCurrentUserId);
-        } finally {
-            restoreCallingIdentity(ident);
-        }
-    }
-
     /* Opens the specified USB device (host mode) */
     @Override
     public ParcelFileDescriptor openDevice(String deviceName, String packageName) {
         ParcelFileDescriptor fd = null;
 
         if (mHostManager != null) {
-            synchronized (mLock) {
-                if (deviceName != null) {
-                    int userIdInt = UserHandle.getCallingUserId();
-                    boolean isCurrentUser = isCallerInCurrentUserProfileGroupLocked();
+            if (deviceName != null) {
+                int uid = Binder.getCallingUid();
+                int user = UserHandle.getUserId(uid);
 
-                    if (isCurrentUser) {
-                        fd = mHostManager.openDevice(deviceName, getSettingsForUser(userIdInt),
-                                packageName, Binder.getCallingUid());
-                    } else {
-                        Slog.w(TAG, "Cannot open " + deviceName + " for user " + userIdInt +
-                               " as user is not active.");
+                long ident = clearCallingIdentity();
+                try {
+                    synchronized (mLock) {
+                        if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) {
+                            fd = mHostManager.openDevice(deviceName, getSettingsForUser(user),
+                                    packageName, uid);
+                        } else {
+                            Slog.w(TAG, "Cannot open " + deviceName + " for user " + user
+                                    + " as user is not active.");
+                        }
                     }
+                } finally {
+                    restoreCallingIdentity(ident);
                 }
             }
         }
@@ -287,17 +274,22 @@
     @Override
     public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
         if (mDeviceManager != null) {
-            int userIdInt = UserHandle.getCallingUserId();
+            int uid = Binder.getCallingUid();
+            int user = UserHandle.getUserId(uid);
 
-            synchronized (mLock) {
-                boolean isCurrentUser = isCallerInCurrentUserProfileGroupLocked();
-
-                if (isCurrentUser) {
-                    return mDeviceManager.openAccessory(accessory, getSettingsForUser(userIdInt));
-                } else {
-                    Slog.w(TAG, "Cannot open " + accessory + " for user " + userIdInt +
-                            " as user is not active.");
+            long ident = clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) {
+                        return mDeviceManager.openAccessory(accessory, getSettingsForUser(user),
+                                uid);
+                    } else {
+                        Slog.w(TAG, "Cannot open " + accessory + " for user " + user
+                                + " as user is not active.");
+                    }
                 }
+            } finally {
+                restoreCallingIdentity(ident);
             }
         }
 
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 08bc9bc..daa09f5 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -397,7 +397,19 @@
         public static final int PROPERTY_WIFI = 0x00000008;
 
         /**
-         * Call is using high definition audio.
+         * When set, the UI should indicate to the user that a call is using high definition
+         * audio.
+         * <p>
+         * The underlying {@link ConnectionService} is responsible for reporting this
+         * property.  It is important to note that this property is not intended to report the
+         * actual audio codec being used for a Call, but whether the call should be indicated
+         * to the user as high definition.
+         * <p>
+         * The Android Telephony stack reports this property for calls based on a number
+         * of factors, including which audio codec is used and whether a call is using an HD
+         * codec end-to-end.  Some mobile operators choose to suppress display of an HD indication,
+         * and in these cases this property will not be set for a call even if the underlying audio
+         * codec is in fact "high definition".
          */
         public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
 
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 4846092..8454d12 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3289,7 +3289,6 @@
             values.put(CDMA_ERI_ICON_INDEX, state.getCdmaEriIconIndex());
             values.put(CDMA_ERI_ICON_MODE, state.getCdmaEriIconMode());
             values.put(IS_EMERGENCY_ONLY, state.isEmergencyOnly());
-            values.put(IS_DATA_ROAMING_FROM_REGISTRATION, state.getDataRoamingFromRegistration());
             values.put(IS_USING_CARRIER_AGGREGATION, state.isUsingCarrierAggregation());
             return values;
         }
diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java
index 79298fd..ac38efb 100644
--- a/telephony/java/android/telephony/NeighboringCellInfo.java
+++ b/telephony/java/android/telephony/NeighboringCellInfo.java
@@ -34,8 +34,8 @@
  * Received Signal Strength and Cell ID location.
  *
  * @deprecated This class should not be used by any app targeting
- *     {@link Build.VERSION_CODES.Q Android Q} or higher. Instead callers should use
- *     {@Link android.telephony.CellInfo CellInfo}.
+ *     {@link android.os.Build.VERSION_CODES#Q Android Q} or higher. Instead callers should use
+ *     {@link android.telephony.CellInfo CellInfo}.
  */
 @Deprecated
 public class NeighboringCellInfo implements Parcelable
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java
index c393155..b312f84 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -95,6 +95,13 @@
     @RegState
     private final int mRegState;
 
+    /**
+     * Save the {@link ServiceState.RoamingType roaming type}. it can be overridden roaming type
+     * from resource overlay or carrier config.
+     */
+    @ServiceState.RoamingType
+    private int mRoamingType;
+
     private final int mAccessNetworkTechnology;
 
     private final int mRejectCause;
@@ -140,6 +147,8 @@
         mDomain = domain;
         mTransportType = transportType;
         mRegState = regState;
+        mRoamingType = (regState == REG_STATE_ROAMING)
+                ? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING;
         mAccessNetworkTechnology = accessNetworkTechnology;
         mRejectCause = rejectCause;
         mAvailableServices = availableServices;
@@ -182,6 +191,7 @@
         mDomain = source.readInt();
         mTransportType = source.readInt();
         mRegState = source.readInt();
+        mRoamingType = source.readInt();
         mAccessNetworkTechnology = source.readInt();
         mRejectCause = source.readInt();
         mEmergencyOnly = source.readBoolean();
@@ -211,6 +221,31 @@
     }
 
     /**
+     * @return {@code true} if registered on roaming network, {@code false} otherwise.
+     */
+    public boolean isRoaming() {
+        return mRoamingType != ServiceState.ROAMING_TYPE_NOT_ROAMING;
+    }
+
+    /**
+     * Set {@link ServiceState.RoamingType roaming type}. This could override
+     * roaming type based on resource overlay or carrier config.
+     * @hide
+     */
+    public void setRoamingType(@ServiceState.RoamingType int roamingType) {
+        mRoamingType = roamingType;
+    }
+
+    /**
+     * @return {@link ServiceState.RoamingType roaming type}. This could return
+     * overridden roaming type based on resource overlay or carrier config.
+     * @hide
+     */
+    public @ServiceState.RoamingType int getRoamingType() {
+        return mRoamingType;
+    }
+
+    /**
      * @return Whether emergency is enabled.
      */
     public boolean isEmergencyEnabled() { return mEmergencyOnly; }
@@ -280,6 +315,7 @@
                 .append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS")
                 .append("transportType=").append(mTransportType)
                 .append(" regState=").append(regStateToString(mRegState))
+                .append(" roamingType=").append(mRoamingType)
                 .append(" accessNetworkTechnology=")
                 .append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology))
                 .append(" rejectCause=").append(mRejectCause)
@@ -293,9 +329,9 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mDomain, mTransportType, mRegState, mAccessNetworkTechnology,
-                mRejectCause, mEmergencyOnly, mAvailableServices, mCellIdentity,
-                mVoiceSpecificStates, mDataSpecificStates);
+        return Objects.hash(mDomain, mTransportType, mRegState, mRoamingType,
+                mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
+                mCellIdentity, mVoiceSpecificStates, mDataSpecificStates);
     }
 
     @Override
@@ -310,6 +346,7 @@
         return mDomain == other.mDomain
                 && mTransportType == other.mTransportType
                 && mRegState == other.mRegState
+                && mRoamingType == other.mRoamingType
                 && mAccessNetworkTechnology == other.mAccessNetworkTechnology
                 && mRejectCause == other.mRejectCause
                 && mEmergencyOnly == other.mEmergencyOnly
@@ -325,6 +362,7 @@
         dest.writeInt(mDomain);
         dest.writeInt(mTransportType);
         dest.writeInt(mRegState);
+        dest.writeInt(mRoamingType);
         dest.writeInt(mAccessNetworkTechnology);
         dest.writeInt(mRejectCause);
         dest.writeBoolean(mEmergencyOnly);
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 7469186..e0ec2c5 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -20,6 +20,7 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
+import android.content.Intent;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -57,7 +58,7 @@
      * Normal operation condition, the phone is registered
      * with an operator either in home network or in roaming.
      */
-    public static final int STATE_IN_SERVICE = 0;
+    public static final int STATE_IN_SERVICE = TelephonyProtoEnums.SERVICE_STATE_IN_SERVICE; // 0
 
     /**
      * Phone is not registered with any operator, the phone
@@ -65,17 +66,19 @@
      * searching to registration at all, or registration is denied, or radio
      * signal is not available.
      */
-    public static final int STATE_OUT_OF_SERVICE = 1;
+    public static final int STATE_OUT_OF_SERVICE =
+            TelephonyProtoEnums.SERVICE_STATE_OUT_OF_SERVICE;  // 1
 
     /**
      * The phone is registered and locked.  Only emergency numbers are allowed. {@more}
      */
-    public static final int STATE_EMERGENCY_ONLY = 2;
+    public static final int STATE_EMERGENCY_ONLY =
+            TelephonyProtoEnums.SERVICE_STATE_EMERGENCY_ONLY;  // 2
 
     /**
      * Radio of telephony is explicitly powered off.
      */
-    public static final int STATE_POWER_OFF = 3;
+    public static final int STATE_POWER_OFF = TelephonyProtoEnums.SERVICE_STATE_POWER_OFF;  // 3
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -198,6 +201,15 @@
     private int mVoiceRegState = STATE_OUT_OF_SERVICE;
     private int mDataRegState = STATE_OUT_OF_SERVICE;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "ROAMING_TYPE_" }, value = {
+            ROAMING_TYPE_NOT_ROAMING,
+            ROAMING_TYPE_UNKNOWN,
+            ROAMING_TYPE_DOMESTIC,
+            ROAMING_TYPE_INTERNATIONAL
+    })
+    public @interface RoamingType {}
     /**
      * Roaming type
      * HOME : in home network
@@ -228,8 +240,6 @@
      */
     public static final int UNKNOWN_ID = -1;
 
-    private int mVoiceRoamingType;
-    private int mDataRoamingType;
     private String mVoiceOperatorAlphaLong;
     private String mVoiceOperatorAlphaShort;
     private String mVoiceOperatorNumeric;
@@ -259,8 +269,6 @@
     @UnsupportedAppUsage
     private int mCdmaEriIconMode;
 
-    private boolean mIsDataRoamingFromRegistration;
-
     @UnsupportedAppUsage
     private boolean mIsUsingCarrierAggregation;
 
@@ -332,8 +340,6 @@
     protected void copyFrom(ServiceState s) {
         mVoiceRegState = s.mVoiceRegState;
         mDataRegState = s.mDataRegState;
-        mVoiceRoamingType = s.mVoiceRoamingType;
-        mDataRoamingType = s.mDataRoamingType;
         mVoiceOperatorAlphaLong = s.mVoiceOperatorAlphaLong;
         mVoiceOperatorAlphaShort = s.mVoiceOperatorAlphaShort;
         mVoiceOperatorNumeric = s.mVoiceOperatorNumeric;
@@ -351,7 +357,6 @@
         mCdmaEriIconIndex = s.mCdmaEriIconIndex;
         mCdmaEriIconMode = s.mCdmaEriIconMode;
         mIsEmergencyOnly = s.mIsEmergencyOnly;
-        mIsDataRoamingFromRegistration = s.mIsDataRoamingFromRegistration;
         mIsUsingCarrierAggregation = s.mIsUsingCarrierAggregation;
         mChannelNumber = s.mChannelNumber;
         mCellBandwidths = s.mCellBandwidths == null ? null :
@@ -367,8 +372,6 @@
     public ServiceState(Parcel in) {
         mVoiceRegState = in.readInt();
         mDataRegState = in.readInt();
-        mVoiceRoamingType = in.readInt();
-        mDataRoamingType = in.readInt();
         mVoiceOperatorAlphaLong = in.readString();
         mVoiceOperatorAlphaShort = in.readString();
         mVoiceOperatorNumeric = in.readString();
@@ -386,7 +389,6 @@
         mCdmaEriIconIndex = in.readInt();
         mCdmaEriIconMode = in.readInt();
         mIsEmergencyOnly = in.readInt() != 0;
-        mIsDataRoamingFromRegistration = in.readInt() != 0;
         mIsUsingCarrierAggregation = in.readInt() != 0;
         mLteEarfcnRsrpBoost = in.readInt();
         mNetworkRegistrationStates = new ArrayList<>();
@@ -398,8 +400,6 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mVoiceRegState);
         out.writeInt(mDataRegState);
-        out.writeInt(mVoiceRoamingType);
-        out.writeInt(mDataRoamingType);
         out.writeString(mVoiceOperatorAlphaLong);
         out.writeString(mVoiceOperatorAlphaShort);
         out.writeString(mVoiceOperatorNumeric);
@@ -417,7 +417,6 @@
         out.writeInt(mCdmaEriIconIndex);
         out.writeInt(mCdmaEriIconMode);
         out.writeInt(mIsEmergencyOnly ? 1 : 0);
-        out.writeInt(mIsDataRoamingFromRegistration ? 1 : 0);
         out.writeInt(mIsUsingCarrierAggregation ? 1 : 0);
         out.writeInt(mLteEarfcnRsrpBoost);
         out.writeList(mNetworkRegistrationStates);
@@ -535,17 +534,21 @@
      */
     @UnsupportedAppUsage
     public boolean getVoiceRoaming() {
-        return mVoiceRoamingType != ROAMING_TYPE_NOT_ROAMING;
+        return getVoiceRoamingType() != ROAMING_TYPE_NOT_ROAMING;
     }
-
     /**
      * Get current voice network roaming type
      * @return roaming type
      * @hide
      */
     @UnsupportedAppUsage
-    public int getVoiceRoamingType() {
-        return mVoiceRoamingType;
+    public @RoamingType int getVoiceRoamingType() {
+        final NetworkRegistrationState regState = getNetworkRegistrationState(
+                NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+        if (regState != null) {
+            return regState.getRoamingType();
+        }
+        return ROAMING_TYPE_NOT_ROAMING;
     }
 
     /**
@@ -555,19 +558,7 @@
      */
     @UnsupportedAppUsage
     public boolean getDataRoaming() {
-        return mDataRoamingType != ROAMING_TYPE_NOT_ROAMING;
-    }
-
-    /**
-     * Set whether data network registration state is roaming
-     *
-     * This should only be set to the roaming value received
-     * once the data registration phase has completed.
-     * @hide
-     */
-    @UnsupportedAppUsage
-    public void setDataRoamingFromRegistration(boolean dataRoaming) {
-        mIsDataRoamingFromRegistration = dataRoaming;
+        return getDataRoamingType() != ROAMING_TYPE_NOT_ROAMING;
     }
 
     /**
@@ -576,7 +567,12 @@
      * @hide
      */
     public boolean getDataRoamingFromRegistration() {
-        return mIsDataRoamingFromRegistration;
+        final NetworkRegistrationState regState = getNetworkRegistrationState(
+                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+        if (regState != null) {
+            return (regState.getRegState() == NetworkRegistrationState.REG_STATE_ROAMING);
+        }
+        return false;
     }
 
     /**
@@ -585,8 +581,13 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public int getDataRoamingType() {
-        return mDataRoamingType;
+    public @RoamingType int getDataRoamingType() {
+        final NetworkRegistrationState regState = getNetworkRegistrationState(
+                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+        if (regState != null) {
+            return regState.getRoamingType();
+        }
+        return ROAMING_TYPE_NOT_ROAMING;
     }
 
     /**
@@ -759,8 +760,6 @@
         return Objects.hash(
                 mVoiceRegState,
                 mDataRegState,
-                mVoiceRoamingType,
-                mDataRoamingType,
                 mChannelNumber,
                 mCellBandwidths,
                 mVoiceOperatorAlphaLong,
@@ -780,7 +779,6 @@
                 mCdmaEriIconIndex,
                 mCdmaEriIconMode,
                 mIsEmergencyOnly,
-                mIsDataRoamingFromRegistration,
                 mIsUsingCarrierAggregation,
                 mLteEarfcnRsrpBoost,
                 mNetworkRegistrationStates);
@@ -794,8 +792,6 @@
         return (mVoiceRegState == s.mVoiceRegState
                 && mDataRegState == s.mDataRegState
                 && mIsManualNetworkSelection == s.mIsManualNetworkSelection
-                && mVoiceRoamingType == s.mVoiceRoamingType
-                && mDataRoamingType == s.mDataRoamingType
                 && mChannelNumber == s.mChannelNumber
                 && Arrays.equals(mCellBandwidths, s.mCellBandwidths)
                 && equalsHandlesNulls(mVoiceOperatorAlphaLong, s.mVoiceOperatorAlphaLong)
@@ -813,7 +809,6 @@
                 && equalsHandlesNulls(mCdmaDefaultRoamingIndicator,
                         s.mCdmaDefaultRoamingIndicator)
                 && mIsEmergencyOnly == s.mIsEmergencyOnly
-                && mIsDataRoamingFromRegistration == s.mIsDataRoamingFromRegistration
                 && mIsUsingCarrierAggregation == s.mIsUsingCarrierAggregation)
                 && (mNetworkRegistrationStates == null ? s.mNetworkRegistrationStates == null :
                         s.mNetworkRegistrationStates != null &&
@@ -933,8 +928,6 @@
             .append(", mChannelNumber=").append(mChannelNumber)
             .append(", duplexMode()=").append(getDuplexMode())
             .append(", mCellBandwidths=").append(Arrays.toString(mCellBandwidths))
-            .append(", mVoiceRoamingType=").append(getRoamingLogString(mVoiceRoamingType))
-            .append(", mDataRoamingType=").append(getRoamingLogString(mDataRoamingType))
             .append(", mVoiceOperatorAlphaLong=").append(mVoiceOperatorAlphaLong)
             .append(", mVoiceOperatorAlphaShort=").append(mVoiceOperatorAlphaShort)
             .append(", mDataOperatorAlphaLong=").append(mDataOperatorAlphaLong)
@@ -951,7 +944,6 @@
             .append(", mCdmaRoamingIndicator=").append(mCdmaRoamingIndicator)
             .append(", mCdmaDefaultRoamingIndicator=").append(mCdmaDefaultRoamingIndicator)
             .append(", mIsEmergencyOnly=").append(mIsEmergencyOnly)
-            .append(", mIsDataRoamingFromRegistration=").append(mIsDataRoamingFromRegistration)
             .append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
             .append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
             .append(", mNetworkRegistrationStates=").append(mNetworkRegistrationStates)
@@ -962,8 +954,6 @@
         if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setNullState=" + state);
         mVoiceRegState = state;
         mDataRegState = state;
-        mVoiceRoamingType = ROAMING_TYPE_NOT_ROAMING;
-        mDataRoamingType = ROAMING_TYPE_NOT_ROAMING;
         mChannelNumber = -1;
         mCellBandwidths = new int[0];
         mVoiceOperatorAlphaLong = null;
@@ -983,7 +973,6 @@
         mCdmaEriIconIndex = -1;
         mCdmaEriIconMode = -1;
         mIsEmergencyOnly = false;
-        mIsDataRoamingFromRegistration = false;
         mIsUsingCarrierAggregation = false;
         mLteEarfcnRsrpBoost = 0;
         mNetworkRegistrationStates = new ArrayList<>();
@@ -1029,32 +1018,50 @@
     }
 
     public void setRoaming(boolean roaming) {
-        mVoiceRoamingType = (roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
-        mDataRoamingType = mVoiceRoamingType;
+        setVoiceRoaming(roaming);
+        setDataRoaming(roaming);
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public void setVoiceRoaming(boolean roaming) {
-        mVoiceRoamingType = (roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
+        setVoiceRoamingType(roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
     }
 
     /** @hide */
     @UnsupportedAppUsage
-    public void setVoiceRoamingType(int type) {
-        mVoiceRoamingType = type;
+    public void setVoiceRoamingType(@RoamingType int type) {
+        NetworkRegistrationState regState = getNetworkRegistrationState(
+                NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+        if (regState == null) {
+            regState = new NetworkRegistrationState(
+                    NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN,
+                    ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
+                    false, null, null);
+            addNetworkRegistrationState(regState);
+        }
+        regState.setRoamingType(type);
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public void setDataRoaming(boolean dataRoaming) {
-        mDataRoamingType = (dataRoaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
+        setDataRoamingType(dataRoaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
     }
 
     /** @hide */
     @UnsupportedAppUsage
-    public void setDataRoamingType(int type) {
-        mDataRoamingType = type;
+    public void setDataRoamingType(@RoamingType int type) {
+        NetworkRegistrationState regState = getNetworkRegistrationState(
+                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+        if (regState == null) {
+            regState = new NetworkRegistrationState(
+                    NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN,
+                    ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
+                    false, null, null);
+            addNetworkRegistrationState(regState);
+        }
+        regState.setRoamingType(type);
     }
 
     /**
@@ -1166,30 +1173,10 @@
      */
     @UnsupportedAppUsage
     private void setFromNotifierBundle(Bundle m) {
-        mVoiceRegState = m.getInt("voiceRegState");
-        mDataRegState = m.getInt("dataRegState");
-        mVoiceRoamingType = m.getInt("voiceRoamingType");
-        mDataRoamingType = m.getInt("dataRoamingType");
-        mVoiceOperatorAlphaLong = m.getString("operator-alpha-long");
-        mVoiceOperatorAlphaShort = m.getString("operator-alpha-short");
-        mVoiceOperatorNumeric = m.getString("operator-numeric");
-        mDataOperatorAlphaLong = m.getString("data-operator-alpha-long");
-        mDataOperatorAlphaShort = m.getString("data-operator-alpha-short");
-        mDataOperatorNumeric = m.getString("data-operator-numeric");
-        mIsManualNetworkSelection = m.getBoolean("manual");
-        mRilVoiceRadioTechnology = m.getInt("radioTechnology");
-        mRilDataRadioTechnology = m.getInt("dataRadioTechnology");
-        mCssIndicator = m.getBoolean("cssIndicator");
-        mNetworkId = m.getInt("networkId");
-        mSystemId = m.getInt("systemId");
-        mCdmaRoamingIndicator = m.getInt("cdmaRoamingIndicator");
-        mCdmaDefaultRoamingIndicator = m.getInt("cdmaDefaultRoamingIndicator");
-        mIsEmergencyOnly = m.getBoolean("emergencyOnly");
-        mIsDataRoamingFromRegistration = m.getBoolean("isDataRoamingFromRegistration");
-        mIsUsingCarrierAggregation = m.getBoolean("isUsingCarrierAggregation");
-        mLteEarfcnRsrpBoost = m.getInt("LteEarfcnRsrpBoost");
-        mChannelNumber = m.getInt("ChannelNumber");
-        mCellBandwidths = m.getIntArray("CellBandwidths");
+        ServiceState ssFromBundle = m.getParcelable(Intent.EXTRA_SERVICE_STATE);
+        if (ssFromBundle != null) {
+            copyFrom(ssFromBundle);
+        }
     }
 
     /**
@@ -1200,10 +1187,13 @@
      */
     @UnsupportedAppUsage
     public void fillInNotifierBundle(Bundle m) {
+        m.putParcelable(Intent.EXTRA_SERVICE_STATE, this);
+        // serviceState already consists of below entries.
+        // for backward compatibility, we continue fill in below entries.
         m.putInt("voiceRegState", mVoiceRegState);
         m.putInt("dataRegState", mDataRegState);
-        m.putInt("voiceRoamingType", mVoiceRoamingType);
-        m.putInt("dataRoamingType", mDataRoamingType);
+        m.putInt("dataRoamingType", getDataRoamingType());
+        m.putInt("voiceRoamingType", getVoiceRoamingType());
         m.putString("operator-alpha-long", mVoiceOperatorAlphaLong);
         m.putString("operator-alpha-short", mVoiceOperatorAlphaShort);
         m.putString("operator-numeric", mVoiceOperatorNumeric);
@@ -1219,7 +1209,7 @@
         m.putInt("cdmaRoamingIndicator", mCdmaRoamingIndicator);
         m.putInt("cdmaDefaultRoamingIndicator", mCdmaDefaultRoamingIndicator);
         m.putBoolean("emergencyOnly", mIsEmergencyOnly);
-        m.putBoolean("isDataRoamingFromRegistration", mIsDataRoamingFromRegistration);
+        m.putBoolean("isDataRoamingFromRegistration", getDataRoamingFromRegistration());
         m.putBoolean("isUsingCarrierAggregation", mIsUsingCarrierAggregation);
         m.putInt("LteEarfcnRsrpBoost", mLteEarfcnRsrpBoost);
         m.putInt("ChannelNumber", mChannelNumber);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 96069ac..f850693 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -32,12 +32,14 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.BroadcastOptions;
 import android.app.PendingIntent;
+import android.app.job.JobService;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.database.ContentObserver;
 import android.net.INetworkPolicyManager;
 import android.net.NetworkCapabilities;
 import android.net.Uri;
@@ -86,8 +88,9 @@
     /** @hide */
     public static final int INVALID_PHONE_INDEX = -1;
 
-    /** Indicates invalid sim slot. This can be returned by {@link #getSlotIndex(int)}. */
-    public static final int INVALID_SIM_SLOT_INDEX = -2;
+    /** An invalid slot identifier */
+    /** @hide */
+    public static final int INVALID_SIM_SLOT_INDEX = -1;
 
     /** Indicates the default subscription ID in Telephony. */
     public static final int DEFAULT_SUBSCRIPTION_ID = Integer.MAX_VALUE;
@@ -115,6 +118,52 @@
     @UnsupportedAppUsage
     public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
 
+
+    /**
+     * Generates a content {@link Uri} used to receive updates on simInfo change
+     * on the given subscriptionId
+     * @param subscriptionId the subscriptionId to receive updates on
+     * @return the Uri used to observe carrier identity changes
+     * @hide
+     */
+    public static Uri getUriForSubscriptionId(int subscriptionId) {
+        return Uri.withAppendedPath(CONTENT_URI, String.valueOf(subscriptionId));
+    }
+
+    /**
+     * A content {@link Uri} used to receive updates on wfc enabled user setting.
+     * <p>
+     * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+     * subscription wfc enabled {@link SubscriptionManager#WFC_IMS_ENABLED}
+     * while your app is running. You can also use a {@link JobService} to ensure your app
+     * is notified of changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+     * updates to the {@link Uri}.
+     * To be notified of changes to a specific subId, append subId to the URI
+     * {@link Uri#withAppendedPath(Uri, String)}.
+     * @hide
+     */
+    @SystemApi
+    public static final Uri WFC_ENABLED_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "wfc");
+
+    /**
+     * A content {@link Uri} used to receive updates on enhanced 4g user setting.
+     * <p>
+     * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+     * subscription enhanced 4G enabled {@link SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+     * while your app is running. You can also use a {@link JobService} to ensure your app
+     * is notified of changes to the {@link Uri} even when it is not running.
+     * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+     * updates to the {@link Uri}.
+     * To be notified of changes to a specific subId, append subId to the URI
+     * {@link Uri#withAppendedPath(Uri, String)}.
+     * @hide
+     */
+    @SystemApi
+    public static final Uri ENHANCED_4G_ENABLED_CONTENT_URI = Uri.withAppendedPath(
+            CONTENT_URI, "enhanced_4g");
+
+
     /**
      * TelephonyProvider unique key column name is the subscription id.
      * <P>Type: TEXT (String)</P>
@@ -136,8 +185,9 @@
     /** @hide */
     public static final String SIM_SLOT_INDEX = "sim_id";
 
-    /** Indicates SIM is not inserted. This can be returned by {@link #getSlotIndex(int)}. */
-    public static final int SIM_NOT_INSERTED = -3;
+    /** SIM is not inserted */
+    /** @hide */
+    public static final int SIM_NOT_INSERTED = -1;
 
     /**
      * TelephonyProvider column name for user displayed name.
@@ -1260,22 +1310,16 @@
 
     /**
      * Get slotIndex associated with the subscription.
-     *
-     * @param subscriptionId the unique SubscriptionInfo index in database
-     * @return slotIndex as a positive integer or a negative value,
-     * <ol>
-     * <li>{@link #INVALID_SUBSCRIPTION_ID} if the supplied subscriptionId is invalid </li>
-     * <li>{@link #SIM_NOT_INSERTED} if sim is not inserted </li>
-     * <li>{@link #INVALID_SIM_SLOT_INDEX} if the supplied subscriptionId doesn't have an
-     *     associated slot index </li>
-     * </ol>
+     * @return slotIndex as a positive integer or a negative value if an error either
+     * SIM_NOT_INSERTED or < 0 if an invalid slot index
+     * @hide
      */
-    public static int getSlotIndex(int subscriptionId) {
-        if (!isValidSubscriptionId(subscriptionId)) {
+    @UnsupportedAppUsage
+    public static int getSlotIndex(int subId) {
+        if (!isValidSubscriptionId(subId)) {
             if (DBG) {
-                logd("[getSlotIndex]- supplied subscriptionId is invalid. ");
+                logd("[getSlotIndex]- fail");
             }
-            return INVALID_SUBSCRIPTION_ID;
         }
 
         int result = INVALID_SIM_SLOT_INDEX;
@@ -1283,7 +1327,7 @@
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                result = iSub.getSlotIndex(subscriptionId);
+                result = iSub.getSlotIndex(subId);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1607,7 +1651,7 @@
      * Check if the subscription ID is usable.
      *
      * A usable subscription ID has a valid value except some special values such as
-     * {@link DEFAULT_SUBSCRIPTION_ID}. It can be used for subscription functions.
+     * {@link #DEFAULT_SUBSCRIPTION_ID}. It can be used for subscription functions.
      *
      * @param subscriptionId the subscription ID
      * @return {@code true} if the subscription ID is usable; {@code false} otherwise.
@@ -2189,9 +2233,10 @@
      *  Provide all available user downloaded profiles on phone which are used only for
      *  opportunistic data.
      *  @param slotIndex slot on which the profiles are queried from.
+     *  @return the list of opportunistic subscription info. If none exists, an empty list. 
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    public List<SubscriptionInfo> getOpportunisticSubscriptions(int slotIndex) {
+    public @NonNull List<SubscriptionInfo> getOpportunisticSubscriptions(int slotIndex) {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         List<SubscriptionInfo> subInfoList = null;
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 52c8f5a..fca14c8 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -60,6 +60,7 @@
 import android.telephony.ims.aidl.IImsRcsFeature;
 import android.telephony.ims.aidl.IImsRegistration;
 import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.ims.internal.IImsServiceFeatureCallback;
@@ -1266,15 +1267,18 @@
      * Returns the unique device ID, for example, the IMEI for GSM and the MEID
      * or ESN for CDMA phones. Return null if device ID is not available.
      *
-     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
-     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+     * device or profile owner. The profile owner is an app that owns a managed profile on the
+     * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+     * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+     * release.
      *
      * @deprecated Use (@link getImei} which returns IMEI for GSM or (@link getMeid} which returns
      * MEID for CDMA.
      */
     @Deprecated
-    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @SuppressAutoDoc // No support for device / profile owner.
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getDeviceId() {
         try {
             ITelephony telephony = getITelephony();
@@ -1292,8 +1296,11 @@
      * Returns the unique device ID of a subscription, for example, the IMEI for
      * GSM and the MEID for CDMA phones. Return null if device ID is not available.
      *
-     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
-     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+     * device or profile owner. The profile owner is an app that owns a managed profile on the
+     * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+     * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+     * release.
      *
      * @param slotIndex of which deviceID is returned
      *
@@ -1301,8 +1308,8 @@
      * MEID for CDMA.
      */
     @Deprecated
-    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @SuppressAutoDoc // No support for device / profile owner.
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getDeviceId(int slotIndex) {
         // FIXME this assumes phoneId == slotIndex
         try {
@@ -1321,11 +1328,14 @@
      * Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
      * available.
      *
-     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
-     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+     * device or profile owner. The profile owner is an app that owns a managed profile on the
+     * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+     * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+     * release.
      */
-    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @SuppressAutoDoc // No support for device / profile owner.
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getImei() {
         return getImei(getSlotIndex());
     }
@@ -1334,13 +1344,16 @@
      * Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
      * available.
      *
-     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
-     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+     * device or profile owner. The profile owner is an app that owns a managed profile on the
+     * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+     * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+     * release.
      *
      * @param slotIndex of which IMEI is returned
      */
-    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @SuppressAutoDoc // No support for device / profile owner.
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getImei(int slotIndex) {
         ITelephony telephony = getITelephony();
         if (telephony == null) return null;
@@ -1384,11 +1397,14 @@
     /**
      * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
      *
-     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
-     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+     * device or profile owner. The profile owner is an app that owns a managed profile on the
+     * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+     * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+     * release.
      */
-    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @SuppressAutoDoc // No support for device / profile owner.
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getMeid() {
         return getMeid(getSlotIndex());
     }
@@ -1396,13 +1412,16 @@
     /**
      * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
      *
-     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
-     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or for the calling package to be the
+     * device or profile owner. The profile owner is an app that owns a managed profile on the
+     * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+     * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+     * release.
      *
      * @param slotIndex of which MEID is returned
      */
-    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @SuppressAutoDoc // No support for device / profile owner.
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getMeid(int slotIndex) {
         ITelephony telephony = getITelephony();
         if (telephony == null) return null;
@@ -2428,39 +2447,46 @@
      *
      * These are the ordinal value of IccCardConstants.State.
      */
-    public static final int SIM_STATE_UNKNOWN = 0;
+
+    public static final int SIM_STATE_UNKNOWN = TelephonyProtoEnums.SIM_STATE_UNKNOWN;  // 0
     /** SIM card state: no SIM card is available in the device */
-    public static final int SIM_STATE_ABSENT = 1;
+    public static final int SIM_STATE_ABSENT = TelephonyProtoEnums.SIM_STATE_ABSENT;  // 1
     /** SIM card state: Locked: requires the user's SIM PIN to unlock */
-    public static final int SIM_STATE_PIN_REQUIRED = 2;
+    public static final int SIM_STATE_PIN_REQUIRED =
+            TelephonyProtoEnums.SIM_STATE_PIN_REQUIRED;  // 2
     /** SIM card state: Locked: requires the user's SIM PUK to unlock */
-    public static final int SIM_STATE_PUK_REQUIRED = 3;
+    public static final int SIM_STATE_PUK_REQUIRED =
+            TelephonyProtoEnums.SIM_STATE_PUK_REQUIRED;  // 3
     /** SIM card state: Locked: requires a network PIN to unlock */
-    public static final int SIM_STATE_NETWORK_LOCKED = 4;
+    public static final int SIM_STATE_NETWORK_LOCKED =
+            TelephonyProtoEnums.SIM_STATE_NETWORK_LOCKED;  // 4
     /** SIM card state: Ready */
-    public static final int SIM_STATE_READY = 5;
+    public static final int SIM_STATE_READY = TelephonyProtoEnums.SIM_STATE_READY;  // 5
     /** SIM card state: SIM Card is NOT READY */
-    public static final int SIM_STATE_NOT_READY = 6;
+    public static final int SIM_STATE_NOT_READY = TelephonyProtoEnums.SIM_STATE_NOT_READY;  // 6
     /** SIM card state: SIM Card Error, permanently disabled */
-    public static final int SIM_STATE_PERM_DISABLED = 7;
+    public static final int SIM_STATE_PERM_DISABLED =
+            TelephonyProtoEnums.SIM_STATE_PERM_DISABLED;  // 7
     /** SIM card state: SIM Card Error, present but faulty */
-    public static final int SIM_STATE_CARD_IO_ERROR = 8;
+    public static final int SIM_STATE_CARD_IO_ERROR =
+            TelephonyProtoEnums.SIM_STATE_CARD_IO_ERROR;  // 8
     /** SIM card state: SIM Card restricted, present but not usable due to
      * carrier restrictions.
      */
-    public static final int SIM_STATE_CARD_RESTRICTED = 9;
+    public static final int SIM_STATE_CARD_RESTRICTED =
+            TelephonyProtoEnums.SIM_STATE_CARD_RESTRICTED;  // 9
     /**
      * SIM card state: Loaded: SIM card applications have been loaded
      * @hide
      */
     @SystemApi
-    public static final int SIM_STATE_LOADED = 10;
+    public static final int SIM_STATE_LOADED = TelephonyProtoEnums.SIM_STATE_LOADED;  // 10
     /**
      * SIM card state: SIM Card is present
      * @hide
      */
     @SystemApi
-    public static final int SIM_STATE_PRESENT = 11;
+    public static final int SIM_STATE_PRESENT = TelephonyProtoEnums.SIM_STATE_PRESENT;  // 11
 
     /**
      * Extra included in {@link #ACTION_SIM_CARD_STATE_CHANGED} and
@@ -2886,11 +2912,15 @@
      * Returns the serial number of the SIM, if applicable. Return null if it is
      * unavailable.
      *
-     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
-     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+     * profile owner, or that the calling app has carrier privileges (see {@link
+     * #hasCarrierPrivileges}). The profile owner is an app that owns a managed profile on the
+     * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+     * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+     * release.
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getSimSerialNumber() {
          return getSimSerialNumber(getSubId());
     }
@@ -2898,11 +2928,18 @@
     /**
      * Returns the serial number for the given subscription, if applicable. Return null if it is
      * unavailable.
-     * <p>
+     *
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+     * profile owner, or that the calling app has carrier privileges (see {@link
+     * #hasCarrierPrivileges}). The profile owner is an app that owns a managed profile on the
+     * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+     * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+     * release.
+     *
      * @param subId for which Sim Serial number is returned
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @UnsupportedAppUsage
     public String getSimSerialNumber(int subId) {
         try {
@@ -3037,11 +3074,15 @@
      * Returns the unique subscriber ID, for example, the IMSI for a GSM phone.
      * Return null if it is unavailable.
      *
-     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
-     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+     * profile owner, or that the calling app has carrier privileges (see {@link
+     * #hasCarrierPrivileges}). The profile owner is an app that owns a managed profile on the
+     * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+     * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+     * release.
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getSubscriberId() {
         return getSubscriberId(getSubId());
     }
@@ -3051,10 +3092,17 @@
      * for a subscription.
      * Return null if it is unavailable.
      *
+     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
+     * profile owner, or that the calling app has carrier privileges (see {@link
+     * #hasCarrierPrivileges}). The profile owner is an app that owns a managed profile on the
+     * device; for more details see <a href="https://developer.android.com/work/managed-profiles">
+     * Work profiles</a>. Profile owner access is deprecated and will be removed in a future
+     * release.
+     *
      * @param subId whose subscriber id is returned
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @UnsupportedAppUsage
     public String getSubscriberId(int subId) {
         try {
@@ -5355,7 +5403,7 @@
     @UnsupportedAppUsage
     public static String getTelephonyProperty(String property, String defaultVal) {
         String propVal = SystemProperties.get(property);
-        return propVal == null ? defaultVal : propVal;
+        return TextUtils.isEmpty(propVal) ? defaultVal : propVal;
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 8379f8c..eb144f9 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -80,7 +80,7 @@
      */
     public static final int TYPE_ALL = ApnTypes.ALL;
     /** APN type for default data traffic. */
-    public static final int TYPE_DEFAULT = ApnTypes.DEFAULT;
+    public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI;
     /** APN type for MMS traffic. */
     public static final int TYPE_MMS = ApnTypes.MMS;
     /** APN type for SUPL assisted GPS. */
@@ -979,7 +979,7 @@
             return false;
         }
         // DEFAULT can handle HIPRI.
-        if (hasApnType(type) || (type == TYPE_HIPRI && hasApnType(TYPE_DEFAULT))) {
+        if (hasApnType(type)) {
             return true;
         }
         return false;
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 3a26350..cb8269e 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -420,6 +420,7 @@
     int RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING = 201;
     int RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA = 202;
     int RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA = 203;
+    int RIL_REQUEST_SET_PREFERRED_DATA_MODEM = 204;
 
     /* Responses begin */
     int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 23ea237..dac7e04 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -19,11 +19,16 @@
 
 import android.Manifest;
 import android.app.AppOpsManager;
+import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.telephony.Rlog;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -135,6 +140,169 @@
     }
 
     /**
+     * Check whether the caller (or self, if not processing an IPC) can read device identifiers.
+     *
+     * <p>This method behaves in one of the following ways:
+     * <ul>
+     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission or the
+     *       calling package passes a DevicePolicyManager Device Owner / Profile Owner device
+     *       identifier access check,
+     *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
+     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
+     *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+     *       permission. In this case the caller would expect to have access to the device
+     *       identifiers so false is returned instead of throwing a SecurityException to indicate
+     *       the calling function should return dummy data.
+     * </ul>
+     */
+    public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context,
+            String callingPackage, String message) {
+        return checkCallingOrSelfReadDeviceIdentifiers(context,
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage, message);
+    }
+
+    /**
+     * Check whether the caller (or self, if not processing an IPC) can read device identifiers.
+     *
+     * <p>This method behaves in one of the following ways:
+     * <ul>
+     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission or the
+     *       calling package passes a DevicePolicyManager Device Owner / Profile Owner device
+     *       identifier access check,
+     *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
+     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission
+     *       or carrier privileges.
+     *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+     *       permission or carrier privileges. In this case the caller would expect to have access
+     *       to the device identifiers so false is returned instead of throwing a SecurityException
+     *       to indicate the calling function should return dummy data.
+     * </ul>
+     */
+    public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, int subId,
+            String callingPackage, String message) {
+        int pid = Binder.getCallingPid();
+        int uid = Binder.getCallingUid();
+        // if the device identifier check completes successfully then grant access.
+        if (checkReadDeviceIdentifiers(context, pid, uid, callingPackage)) {
+            return true;
+        }
+        // else the calling package is not authorized to access the device identifiers; call
+        // a central method to report the failure based on the target SDK and if the calling package
+        // has the READ_PHONE_STATE permission or carrier privileges that were previously required
+        // to access the identifiers.
+        return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
+                message);
+    }
+
+    /**
+     * Check whether the caller (or self, if not processing an IPC) can read subscriber identifiers.
+     *
+     * <p>This method behaves in one of the following ways:
+     * <ul>
+     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
+     *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
+     *       access check, or the calling package has carrier privleges.
+     *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
+     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
+     *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+     *       permission. In this case the caller would expect to have access to the device
+     *       identifiers so false is returned instead of throwing a SecurityException to indicate
+     *       the calling function should return dummy data.
+     * </ul>
+     */
+    public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
+            String callingPackage, String message) {
+        int pid = Binder.getCallingPid();
+        int uid = Binder.getCallingUid();
+        // if the device identifiers can be read then grant access to the subscriber identifiers
+        if (checkReadDeviceIdentifiers(context, pid, uid, callingPackage)) {
+            return true;
+        }
+        // If the calling package has carrier privileges then allow access to the subscriber
+        // identifiers.
+        if (SubscriptionManager.isValidSubscriptionId(subId) && getCarrierPrivilegeStatus(
+                TELEPHONY_SUPPLIER, subId, uid)
+                == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+            return true;
+        }
+        return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
+                message);
+    }
+
+    /**
+     * Checks whether the app with the given pid/uid can read device identifiers.
+     *
+     * @returns true if the caller has the READ_PRIVILEGED_PHONE_STATE permission or the calling
+     * package passes a DevicePolicyManager Device Owner / Profile Owner device identifier access
+     * check.
+     */
+    private static boolean checkReadDeviceIdentifiers(Context context, int pid, int uid,
+            String callingPackage) {
+        // Allow system and root access to the device identifiers.
+        final int appId = UserHandle.getAppId(uid);
+        if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) {
+            return true;
+        }
+        // Allow access to packages that have the READ_PRIVILEGED_PHONE_STATE permission.
+        if (context.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid,
+                uid) == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        }
+        // if the calling package is null then return now as there's no way to perform the
+        // DevicePolicyManager device / profile owner checks.
+        if (callingPackage == null) {
+            return false;
+        }
+        // Allow access to a device / profile owner app.
+        DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        if (devicePolicyManager != null && devicePolicyManager.checkDeviceIdentifierAccessAsUser(
+                callingPackage, Binder.getCallingUserHandle().getIdentifier())) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Reports a failure when the app with the given pid/uid cannot access the requested identifier.
+     *
+     * @returns false if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+     * permission or carrier privileges.
+     * @throws SecurityException if the caller does not meet any of the requirements for the
+     *                           requested identifier and is targeting Q or is targeting pre-Q
+     *                           and does not have the READ_PHONE_STATE permission or carrier
+     *                           privileges.
+     */
+    private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
+            int uid, String callingPackage, String message) {
+        if (callingPackage != null) {
+            try {
+                // if the target SDK is pre-Q then check if the calling package would have
+                // previously had access to device identifiers.
+                ApplicationInfo callingPackageInfo = context.getPackageManager().getApplicationInfo(
+                        callingPackage, 0);
+                if (callingPackageInfo != null
+                        && callingPackageInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
+                    if (context.checkPermission(android.Manifest.permission.READ_PHONE_STATE, pid,
+                            uid) == PackageManager.PERMISSION_GRANTED) {
+                        return false;
+                    }
+                    if (SubscriptionManager.isValidSubscriptionId(subId)
+                            && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, uid)
+                            == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+                        return false;
+                    }
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                // If the application info for the calling package could not be found then default
+                // to throwing the SecurityException.
+            }
+        }
+        throw new SecurityException(message + ": The user " + uid + " does not have the "
+                + "READ_PRIVILEGED_PHONE_STATE permission to access the device identifiers");
+    }
+
+    /**
      * Check whether the app with the given pid/uid can read the call log.
      * @return {@code true} if the specified app has the read call log permission and AppOpp granted
      *      to it, {@code false} otherwise.
diff --git a/tests/ActivityTests/Android.mk b/tests/ActivityTests/Android.mk
index 4c68c8b..94294f6 100644
--- a/tests/ActivityTests/Android.mk
+++ b/tests/ActivityTests/Android.mk
@@ -10,9 +10,5 @@
 LOCAL_CERTIFICATE := platform
 
 LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/tests/ActivityTests/AndroidManifest.xml:42: error: unexpected element <preferred> found in <manifest><application><activity>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_PACKAGE)
diff --git a/tests/NetworkSecurityConfigTest/Android.mk b/tests/NetworkSecurityConfigTest/Android.mk
index c225e17..a6c21db 100644
--- a/tests/NetworkSecurityConfigTest/Android.mk
+++ b/tests/NetworkSecurityConfigTest/Android.mk
@@ -7,7 +7,6 @@
 
 LOCAL_JAVA_LIBRARIES := \
     android.test.runner \
-    conscrypt \
     android.test.base \
 
 LOCAL_STATIC_JAVA_LIBRARIES := junit
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 750e2fb..132135d 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -63,7 +63,8 @@
     libunwindstack \
     libutilscallstack \
     libziparchive \
-    libz
+    libz \
+    netd_aidl_interface-cpp
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
@@ -92,7 +93,8 @@
   liblog \
   libcutils \
   libnativehelper \
-  libnetdaidl
+  libnetdaidl \
+  netd_aidl_interface-cpp
 
 LOCAL_STATIC_LIBRARIES := \
   libpcap \
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 37013c0..adf85b0 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -36,6 +36,7 @@
 #include "cmd/Dump.h"
 #include "cmd/Link.h"
 #include "cmd/Optimize.h"
+#include "io/FileStream.h"
 #include "util/Files.h"
 #include "util/Util.h"
 
@@ -68,10 +69,11 @@
 /** The main entry point of AAPT. */
 class MainCommand : public Command {
  public:
-  explicit MainCommand(IDiagnostics* diagnostics) : Command("aapt2"), diagnostics_(diagnostics) {
+  explicit MainCommand(text::Printer* printer, IDiagnostics* diagnostics)
+      : Command("aapt2"), diagnostics_(diagnostics) {
     AddOptionalSubcommand(util::make_unique<CompileCommand>(diagnostics));
     AddOptionalSubcommand(util::make_unique<LinkCommand>(diagnostics));
-    AddOptionalSubcommand(util::make_unique<DumpCommand>(diagnostics));
+    AddOptionalSubcommand(util::make_unique<DumpCommand>(printer, diagnostics));
     AddOptionalSubcommand(util::make_unique<DiffCommand>());
     AddOptionalSubcommand(util::make_unique<OptimizeCommand>());
     AddOptionalSubcommand(util::make_unique<ConvertCommand>());
@@ -101,13 +103,14 @@
  */
 class DaemonCommand : public Command {
  public:
-  explicit DaemonCommand(IDiagnostics* diagnostics) : Command("daemon", "m"),
-                                                      diagnostics_(diagnostics) {
+  explicit DaemonCommand(io::FileOutputStream* out, IDiagnostics* diagnostics)
+      : Command("daemon", "m"), out_(out), diagnostics_(diagnostics) {
     SetDescription("Runs aapt in daemon mode. Each subsequent line is a single parameter to the\n"
         "command. The end of an invocation is signaled by providing an empty line.");
   }
 
   int Action(const std::vector<std::string>& /* args */) override {
+    text::Printer printer(out_);
     std::cout << "Ready" << std::endl;
 
     while (true) {
@@ -132,7 +135,9 @@
 
       std::vector<StringPiece> args;
       args.insert(args.end(), raw_args.begin(), raw_args.end());
-      if (MainCommand(diagnostics_).Execute(args, &std::cerr) != 0) {
+      int result = MainCommand(&printer, diagnostics_).Execute(args, &std::cerr);
+      out_->Flush();
+      if (result != 0) {
         std::cerr << "Error" << std::endl;
       }
       std::cerr << "Done" << std::endl;
@@ -143,6 +148,7 @@
   }
 
  private:
+  io::FileOutputStream* out_;
   IDiagnostics* diagnostics_;
 };
 
@@ -159,11 +165,17 @@
     args.push_back(argv[i]);
   }
 
-  // Add the daemon subcommand here so it cannot be called while executing the daemon
-  aapt::StdErrDiagnostics diagnostics;
-  auto main_command = new aapt::MainCommand(&diagnostics);
-  main_command->AddOptionalSubcommand(aapt::util::make_unique<aapt::DaemonCommand>(&diagnostics));
+  // Use a smaller buffer so that there is less latency for printing to stdout.
+  constexpr size_t kStdOutBufferSize = 1024u;
+  aapt::io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+  aapt::text::Printer printer(&fout);
 
+  aapt::StdErrDiagnostics diagnostics;
+  auto main_command = new aapt::MainCommand(&printer, &diagnostics);
+
+  // Add the daemon subcommand here so it cannot be called while executing the daemon
+  main_command->AddOptionalSubcommand(
+      aapt::util::make_unique<aapt::DaemonCommand>(&fout, &diagnostics));
   return main_command->Execute(args, &std::cerr);
 }
 
diff --git a/tools/aapt2/OWNERS b/tools/aapt2/OWNERS
index 23ec5ab..f1903a5 100644
--- a/tools/aapt2/OWNERS
+++ b/tools/aapt2/OWNERS
@@ -1,2 +1,3 @@
 set noparent
 toddke@google.com
+rtmitchell@google.com
\ No newline at end of file
diff --git a/tools/aapt2/cmd/Command.cpp b/tools/aapt2/cmd/Command.cpp
index 09411b9..bdee5c9 100644
--- a/tools/aapt2/cmd/Command.cpp
+++ b/tools/aapt2/cmd/Command.cpp
@@ -93,9 +93,13 @@
   flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 0, false});
 }
 
-void Command::AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand) {
+void Command::AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental) {
   subcommand->fullname_ = name_ + " " + subcommand->name_;
-  subcommands_.push_back(std::move(subcommand));
+  if (experimental) {
+    experimental_subcommands_.push_back(std::move(subcommand));
+  } else {
+    subcommands_.push_back(std::move(subcommand));
+  }
 }
 
 void Command::SetDescription(const android::StringPiece& description) {
@@ -162,7 +166,7 @@
   for (size_t i = 0; i < args.size(); i++) {
     StringPiece arg = args[i];
     if (*(arg.data()) != '-') {
-      // Continue parsing as the sub command if the first argument matches one of the subcommands
+      // Continue parsing as the subcommand if the first argument matches one of the subcommands
       if (i == 0) {
         for (auto& subcommand : subcommands_) {
           if (arg == subcommand->name_ || arg==subcommand->short_name_) {
@@ -170,6 +174,12 @@
                 std::vector<android::StringPiece>(args.begin() + 1, args.end()), out_error);
           }
         }
+        for (auto& subcommand : experimental_subcommands_) {
+          if (arg == subcommand->name_ || arg==subcommand->short_name_) {
+            return subcommand->Execute(
+              std::vector<android::StringPiece>(args.begin() + 1, args.end()), out_error);
+          }
+        }
       }
 
       file_args.push_back(arg.to_string());
diff --git a/tools/aapt2/cmd/Command.h b/tools/aapt2/cmd/Command.h
index 71dc6fe..1694988 100644
--- a/tools/aapt2/cmd/Command.h
+++ b/tools/aapt2/cmd/Command.h
@@ -49,7 +49,7 @@
       const android::StringPiece& description, std::unordered_set<std::string>* value);
   void AddOptionalSwitch(const android::StringPiece& name, const android::StringPiece& description,
       bool* value);
-  void AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand);
+  void AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental = false);
 
   void SetDescription(const android::StringPiece& name);
 
@@ -83,6 +83,7 @@
   std::string fullname_;
   std::vector<Flag> flags_;
   std::vector<std::unique_ptr<Command>> subcommands_;
+  std::vector<std::unique_ptr<Command>> experimental_subcommands_;
 };
 
 }  // namespace aapt
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 954f1ed..3ea1755 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -46,7 +46,7 @@
   IApkSerializer(IAaptContext* context, const Source& source) : context_(context), source_(source) {}
 
   virtual bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
-                            IArchiveWriter* writer) = 0;
+                            IArchiveWriter* writer, uint32_t compression_flags) = 0;
   virtual bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) = 0;
   virtual bool SerializeFile(FileReference* file, IArchiveWriter* writer) = 0;
 
@@ -59,7 +59,10 @@
 
 bool ConvertApk(IAaptContext* context, unique_ptr<LoadedApk> apk, IApkSerializer* serializer,
                 IArchiveWriter* writer) {
-  if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/, writer)) {
+  io::IFile* manifest = apk->GetFileCollection()->FindFile(kAndroidManifestPath);
+  if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/, writer,
+                                (manifest != nullptr && manifest->WasCompressed())
+                                    ? ArchiveEntry::kCompress : 0u)) {
     context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
                                      << "failed to serialize AndroidManifest.xml");
     return false;
@@ -133,7 +136,7 @@
       : IApkSerializer(context, source), tableFlattenerOptions_(options) {}
 
   bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
-                    IArchiveWriter* writer) override {
+                    IArchiveWriter* writer, uint32_t compression_flags) override {
     BigBuffer buffer(4096);
     XmlFlattenerOptions options = {};
     options.use_utf16 = utf16;
@@ -144,8 +147,7 @@
     }
 
     io::BigBufferInputStream input_stream(&buffer);
-    return io::CopyInputStreamToArchive(context_, &input_stream, path, ArchiveEntry::kCompress,
-                                        writer);
+    return io::CopyInputStreamToArchive(context_, &input_stream, path, compression_flags, writer);
   }
 
   bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
@@ -186,7 +188,8 @@
         return false;
       }
 
-      if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer)) {
+      if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
+                        file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
         context_->GetDiagnostics()->Error(DiagMessage(source_)
                                           << "failed to serialize to binary XML: " << *file->path);
         return false;
@@ -216,10 +219,10 @@
       : IApkSerializer(context, source) {}
 
   bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
-                    IArchiveWriter* writer) override {
+                    IArchiveWriter* writer, uint32_t compression_flags) override {
     pb::XmlNode pb_node;
     SerializeXmlResourceToPb(*xml, &pb_node);
-    return io::CopyProtoToArchive(context_, &pb_node, path, ArchiveEntry::kCompress, writer);
+    return io::CopyProtoToArchive(context_, &pb_node, path, compression_flags, writer);
   }
 
   bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
@@ -246,7 +249,8 @@
         return false;
       }
 
-      if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer)) {
+      if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
+                        file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
         context_->GetDiagnostics()->Error(DiagMessage(source_)
                                           << "failed to serialize to proto XML: " << *file->path);
         return false;
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index d80b5ea..a23a6a4 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -125,9 +125,6 @@
 
 }  // namespace
 
-// Use a smaller buffer so that there is less latency for dumping to stdout.
-constexpr size_t kStdOutBufferSize = 1024u;
-
 int DumpAPCCommand::Action(const std::vector<std::string>& args) {
   DumpContext context;
   DebugPrintTableOptions print_options;
@@ -135,41 +132,41 @@
   print_options.show_values = !no_values_;
 
   if (args.size() < 1) {
-    diag_->Error(DiagMessage() << "No dump container specified.");
+    diag_->Error(DiagMessage() << "No dump container specified");
     return 1;
   }
 
-  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
-  Printer printer(&fout);
-
+  bool error = false;
   for (auto container : args) {
     io::FileInputStream input(container);
     if (input.HadError()) {
       context.GetDiagnostics()->Error(DiagMessage(container)
-                                          << "failed to open file: " << input.GetError());
-      return false;
+                                      << "failed to open file: " << input.GetError());
+      error = true;
+      continue;
     }
 
     // Try as a compiled file.
     ContainerReader reader(&input);
     if (reader.HadError()) {
       context.GetDiagnostics()->Error(DiagMessage(container)
-                                           << "failed to read container: " << reader.GetError());
-      return false;
+                                      << "failed to read container: " << reader.GetError());
+      error = true;
+      continue;
     }
 
-    printer.Println("AAPT2 Container (APC)");
+    printer_->Println("AAPT2 Container (APC)");
     ContainerReaderEntry* entry;
     std::string error;
     while ((entry = reader.Next()) != nullptr) {
       if (entry->Type() == ContainerEntryType::kResTable) {
-        printer.Println("kResTable");
+        printer_->Println("kResTable");
 
         pb::ResourceTable pb_table;
         if (!entry->GetResTable(&pb_table)) {
           context.GetDiagnostics()->Error(DiagMessage(container)
-                                               << "failed to parse proto table: "
-                                               << entry->GetError());
+                                          << "failed to parse proto table: " << entry->GetError());
+          error = true;
           continue;
         }
 
@@ -177,65 +174,61 @@
         error.clear();
         if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) {
           context.GetDiagnostics()->Error(DiagMessage(container)
-                                               << "failed to parse table: " << error);
+                                          << "failed to parse table: " << error);
+          error = true;
           continue;
         }
 
-        printer.Indent();
-        Debug::PrintTable(table, print_options, &printer);
-        printer.Undent();
+        printer_->Indent();
+        Debug::PrintTable(table, print_options, printer_);
+        printer_->Undent();
       } else if (entry->Type() == ContainerEntryType::kResFile) {
-        printer.Println("kResFile");
+        printer_->Println("kResFile");
         pb::internal::CompiledFile pb_compiled_file;
         off64_t offset;
         size_t length;
         if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) {
-          context.GetDiagnostics()->Error(
-              DiagMessage(container) << "failed to parse compiled proto file: "
-                                     << entry->GetError());
+          context.GetDiagnostics()->Error(DiagMessage(container)
+                                          << "failed to parse compiled proto file: "
+                                          << entry->GetError());
+          error = true;
           continue;
         }
 
         ResourceFile file;
         if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) {
           context.GetDiagnostics()->Warn(DiagMessage(container)
-                                              << "failed to parse compiled file: " << error);
+                                         << "failed to parse compiled file: " << error);
+          error = true;
           continue;
         }
 
-        printer.Indent();
-        DumpCompiledFile(file, Source(container), offset, length, &printer);
-        printer.Undent();
+        printer_->Indent();
+        DumpCompiledFile(file, Source(container), offset, length, printer_);
+        printer_->Undent();
       }
     }
   }
 
-  return 0;
+  return (error) ? 1 : 0;
 }
 
-int DumpConfigsCommand::Action(const std::vector<std::string>& args) {
-  if (args.size() < 1) {
-    diag_->Error(DiagMessage() << "No dump apk specified.");
-    return 1;
-  }
+int DumpBadgerCommand::Action(const std::vector<std::string>& args) {
+  printer_->Print(StringPrintf("%s", kBadgerData));
+  printer_->Print("Did you mean \"aapt2 dump badging\"?\n");
+  return 1;
+}
 
-  auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_);
-  if (!loaded_apk) {
-    return 1;
-  }
-
-  ResourceTable* table = loaded_apk->GetResourceTable();
+int DumpConfigsCommand::Dump(LoadedApk* apk) {
+  ResourceTable* table = apk->GetResourceTable();
   if (!table) {
-    diag_->Error(DiagMessage() << "Failed to retrieve resource table.");
+    GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
     return 1;
   }
 
-  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
-  Printer printer(&fout);
-
   // Comparison function used to order configurations
   auto compare = [](android::ConfigDescription c1, android::ConfigDescription c2) -> bool {
-      return c1.compare(c2) < 0;
+    return c1.compare(c2) < 0;
   };
 
   // Insert the configurations into a set in order to keep every configuarion seen
@@ -252,132 +245,93 @@
 
   // Print the configurations in order
   for (auto& config : configs) {
-    printer.Print(StringPrintf("%s\n", config.to_string().data()));
+    GetPrinter()->Print(StringPrintf("%s\n", config.to_string().data()));
   }
-
   return 0;
 }
 
-int DumpStringsCommand::Action(const std::vector<std::string>& args) {
-  DumpContext context;
-  if (args.size() < 1) {
-    diag_->Error(DiagMessage() << "No dump apk specified.");
+int DumpPackageNameCommand::Dump(LoadedApk* apk) {
+  Maybe<std::string> package_name = GetPackageName(apk);
+  if (!package_name) {
     return 1;
   }
 
-  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
-  Printer printer(&fout);
-
-  for (auto apk : args) {
-    auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
-    if (!loaded_apk) {
-      return 1;
-    }
-
-    ResourceTable* table = loaded_apk->GetResourceTable();
-    if (!table) {
-      diag_->Error(DiagMessage() << "Failed to retrieve resource table.");
-      return 1;
-    }
-
-    // Load the run-time xml string pool using the flattened data
-    BigBuffer buffer(4096);
-    StringPool::FlattenUtf8(&buffer, table->string_pool, context.GetDiagnostics());
-    auto data = buffer.to_string();
-    android::ResStringPool pool(data.data(), data.size(), false);
-    Debug::DumpResStringPool(&pool, &printer);
-  }
-
+  GetPrinter()->Println(package_name.value());
   return 0;
 }
 
-int DumpTableCommand::Action(const std::vector<std::string>& args) {
-  if (args.size() < 1) {
-    diag_->Error(DiagMessage() << "No dump apk specified.");
+int DumpStringsCommand::Dump(LoadedApk* apk) {
+  ResourceTable* table = apk->GetResourceTable();
+  if (!table) {
+    GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
     return 1;
   }
 
-  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
-  Printer printer(&fout);
+  // Load the run-time xml string pool using the flattened data
+  BigBuffer buffer(4096);
+  StringPool::FlattenUtf8(&buffer, table->string_pool, GetDiagnostics());
+  auto data = buffer.to_string();
+  android::ResStringPool pool(data.data(), data.size(), false);
+  Debug::DumpResStringPool(&pool, GetPrinter());
+  return 0;
+}
+
+int DumpStyleParentCommand::Dump(LoadedApk* apk) {
+  Maybe<std::string> package_name = GetPackageName(apk);
+  if (!package_name) {
+    return 1;
+  }
+
+  const auto target_style = ResourceName(package_name.value(), ResourceType::kStyle, style_);
+  const auto table = apk->GetResourceTable();
+
+  if (!table) {
+    GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
+    return 1;
+  }
+
+  Maybe<ResourceTable::SearchResult> target = table->FindResource(target_style);
+  if (!target) {
+    GetDiagnostics()->Error(
+        DiagMessage() << "Target style \"" << target_style.entry << "\" does not exist");
+    return 1;
+  }
+
+  Debug::PrintStyleGraph(table, target_style);
+  return 0;
+}
+
+int DumpTableCommand::Dump(LoadedApk* apk) {
+  if (apk->GetApkFormat() == ApkFormat::kProto) {
+    GetPrinter()->Println("Proto APK");
+  } else {
+    GetPrinter()->Println("Binary APK");
+  }
+
+  ResourceTable* table = apk->GetResourceTable();
+  if (!table) {
+    GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table");
+    return 1;
+  }
 
   DebugPrintTableOptions print_options;
   print_options.show_sources = true;
   print_options.show_values = !no_values_;
-
-  for (auto apk : args) {
-    auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
-    if (!loaded_apk) {
-      return 1;
-    }
-
-    if (loaded_apk->GetApkFormat() == ApkFormat::kProto) {
-      printer.Println("Proto APK");
-    } else {
-      printer.Println("Binary APK");
-    }
-
-    ResourceTable* table = loaded_apk->GetResourceTable();
-    if (!table) {
-      diag_->Error(DiagMessage() << "Failed to retrieve resource table.");
-      return 1;
-    }
-
-    Debug::PrintTable(*table, print_options, &printer);
-  }
-
+  Debug::PrintTable(*table, print_options, GetPrinter());
   return 0;
 }
 
-int DumpXmlTreeCommand::Action(const std::vector<std::string>& args) {
-  if (args.size() < 1) {
-    diag_->Error(DiagMessage() << "No dump apk specified");
-    return 1;
-  }
-
-  auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_);
-  if (!loaded_apk) {
-    return 1;
-  }
-
-  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
-  Printer printer(&fout);
-
-  // Dump the xml tree of every passed in file
-  for (auto file : files_) {
-    auto xml = loaded_apk->LoadXml(file, diag_);
-    if (!xml) {
-      return 1;
-    }
-
-    Debug::DumpXml(*xml, &printer);
-  }
-
-  return 0;
-}
-
-int DumpXmlStringsCommand::Action(const std::vector<std::string>& args) {
+int DumpXmlStringsCommand::Dump(LoadedApk* apk) {
   DumpContext context;
-  if (args.size() < 1) {
-    diag_->Error(DiagMessage() << "No dump apk specified.");
-    return 1;
-  }
-
-  auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_);
-  if (!loaded_apk) {
-    return 1;
-  }
-
-  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
-  Printer printer(&fout);
-
-  // Dump the xml strings of every passed in file
+  bool error = false;
   for (auto xml_file : files_) {
     android::ResXMLTree tree;
 
-    if (loaded_apk->GetApkFormat() == ApkFormat::kProto) {
-      auto xml = loaded_apk->LoadXml(xml_file, diag_);
+    if (apk->GetApkFormat() == ApkFormat::kProto) {
+      auto xml = apk->LoadXml(xml_file, GetDiagnostics());
       if (!xml) {
-        return 1;
+        error = true;
+        continue;
       }
 
       // Flatten the xml document to get a binary representation of the proto xml file
@@ -386,76 +340,208 @@
       options.keep_raw_values = true;
       XmlFlattener flattener(&buffer, options);
       if (!flattener.Consume(&context, xml.get())) {
-        return 1;
+        error = true;
+        continue;
       }
 
       // Load the run-time xml tree using the flattened data
       std::string data = buffer.to_string();
       tree.setTo(data.data(), data.size(), /** copyData */ true);
 
-    } else if (loaded_apk->GetApkFormat() == ApkFormat::kBinary) {
-      io::IFile* file = loaded_apk->GetFileCollection()->FindFile(xml_file);
+    } else if (apk->GetApkFormat() == ApkFormat::kBinary) {
+      io::IFile* file = apk->GetFileCollection()->FindFile(xml_file);
       if (!file) {
-        diag_->Error(DiagMessage(xml_file) << "file '" << xml_file << "' not found in APK");
-        return 1;
+        GetDiagnostics()->Error(DiagMessage(xml_file)
+                                << "File '" << xml_file << "' not found in APK");
+        error = true;
+        continue;
       }
 
       std::unique_ptr<io::IData> data = file->OpenAsData();
       if (!data) {
-        diag_->Error(DiagMessage() << "failed to open file");
-        return 1;
+        GetDiagnostics()->Error(DiagMessage() << "Failed to open " << xml_file);
+        error = true;
+        continue;
       }
 
       // Load the run-time xml tree from the file data
       tree.setTo(data->data(), data->size(), /** copyData */ true);
+    } else {
+      GetDiagnostics()->Error(DiagMessage(apk->GetSource()) << "Unknown APK format");
+      error = true;
+      continue;
     }
 
-    Debug::DumpResStringPool(&tree.getStrings(), &printer);
+    Debug::DumpResStringPool(&tree.getStrings(), GetPrinter());
   }
+  return (error) ? 1 : 0;
+}
 
+int DumpXmlTreeCommand::Dump(LoadedApk* apk) {
+  for (auto file : files_) {
+    auto xml = apk->LoadXml(file, GetDiagnostics());
+    if (!xml) {
+      return 1;
+    }
+    Debug::DumpXml(*xml, GetPrinter());
+  }
   return 0;
 }
 
-int DumpPackageNameCommand::Action(const std::vector<std::string>& args) {
-  if (args.size() < 1) {
-    diag_->Error(DiagMessage() << "No dump apk specified.");
-    return 1;
-  }
-
-  auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_);
-  if (!loaded_apk) {
-    return 1;
-  }
-
-  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
-  Printer printer(&fout);
-
-  xml::Element* manifest_el = loaded_apk->GetManifest()->root.get();
-  if (!manifest_el) {
-    diag_->Error(DiagMessage() << "No AndroidManifest.");
-    return 1;
-  }
-
-  xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
-  if (!attr) {
-    diag_->Error(DiagMessage() << "No package name.");
-    return 1;
-  }
-  printer.Println(StringPrintf("%s", attr->value.c_str()));
-
-  return 0;
-}
-
-/** Preform no action because a subcommand is required. */
-int DumpCommand::Action(const std::vector<std::string>& args) {
-  if (args.size() == 0) {
-    diag_->Error(DiagMessage() << "no subcommand specified");
-  } else {
-    diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
-  }
-
-  Usage(&std::cerr);
-  return 1;
-}
+const char DumpBadgerCommand::kBadgerData[2925] = {
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  95,  46,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  61,  63,  86,  35,  40,  46,  46,
+    95,  95,  95,  95,  97,  97,  44,  32,  46,  124, 42,  33,  83,  62,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  58,  46,  58,  59,  61,  59,  61,  81,  81,  81,  81,  66,  96,  61,  61,  58,  46,
+    46,  46,  58,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  46,  61,  59,  59,  59,  58,  106, 81,  81,
+    81,  81,  102, 59,  61,  59,  59,  61,  61,  61,  58,  46,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    61,  59,  59,  59,  58,  109, 81,  81,  81,  81,  61,  59,  59,  59,  59,  59,  58,  59,  59,
+    46,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  46,  61,  59,  59,  59,  60,  81,  81,  81,  81,  87,  58,
+    59,  59,  59,  59,  59,  59,  61,  119, 44,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  46,  47,  61,  59,  59,
+    58,  100, 81,  81,  81,  81,  35,  58,  59,  59,  59,  59,  59,  58,  121, 81,  91,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  46,  109, 58,  59,  59,  61,  81,  81,  81,  81,  81,  109, 58,  59,  59,  59,
+    59,  61,  109, 81,  81,  76,  46,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  41,  87,  59,  61,  59,  41,  81,  81,
+    81,  81,  81,  81,  59,  61,  59,  59,  58,  109, 81,  81,  87,  39,  46,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    60,  81,  91,  59,  59,  61,  81,  81,  81,  81,  81,  87,  43,  59,  58,  59,  60,  81,  81,
+    81,  76,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  52,  91,  58,  45,  59,  87,  81,  81,  81,  81,
+    70,  58,  58,  58,  59,  106, 81,  81,  81,  91,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  93,  40,
+    32,  46,  59,  100, 81,  81,  81,  81,  40,  58,  46,  46,  58,  100, 81,  81,  68,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  46,  46,  46,  32,  46,
+    46,  46,  32,  46,  32,  46,  45,  91,  59,  61,  58,  109, 81,  81,  81,  87,  46,  58,  61,
+    59,  60,  81,  81,  80,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  46,  46,
+    61,  59,  61,  61,  61,  59,  61,  61,  59,  59,  59,  58,  58,  46,  46,  41,  58,  59,  58,
+    81,  81,  81,  81,  69,  58,  59,  59,  60,  81,  81,  68,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,
+    32,  32,  32,  32,  58,  59,  61,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,
+    59,  59,  61,  61,  46,  61,  59,  93,  81,  81,  81,  81,  107, 58,  59,  58,  109, 87,  68,
+    96,  32,  32,  32,  46,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  10,  32,  32,  32,  46,  60,  61,  61,  59,  59,  59,  59,  59,  59,
+    59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  58,  58,  58,  115, 109, 68,  41,  36,
+    81,  109, 46,  61,  61,  81,  69,  96,  46,  58,  58,  46,  58,  46,  46,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  46,  32,  95,  81,  67,
+    61,  61,  58,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,
+    59,  59,  58,  68,  39,  61,  105, 61,  63,  81,  119, 58,  106, 80,  32,  58,  61,  59,  59,
+    61,  59,  61,  59,  61,  46,  95,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  10,  32,  32,  36,  81,  109, 105, 59,  61,  59,  59,  59,  59,  59,  59,  59,  59,
+    59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  46,  58,  37,  73,  108, 108, 62,  52,  81,
+    109, 34,  32,  61,  59,  59,  59,  59,  59,  59,  59,  59,  59,  61,  59,  61,  61,  46,  46,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  46,  45,  57,  101, 43,  43,  61,
+    61,  59,  59,  59,  59,  59,  59,  61,  59,  59,  59,  59,  59,  59,  59,  59,  59,  58,  97,
+    46,  61,  108, 62,  126, 58,  106, 80,  96,  46,  61,  61,  59,  59,  59,  59,  59,  59,  59,
+    59,  59,  59,  59,  59,  59,  61,  61,  97,  103, 97,  32,  32,  32,  32,  32,  32,  32,  10,
+    32,  32,  32,  32,  45,  46,  32,  46,  32,  32,  32,  32,  32,  32,  32,  32,  45,  45,  45,
+    58,  59,  59,  59,  59,  61,  119, 81,  97,  124, 105, 124, 124, 39,  126, 95,  119, 58,  61,
+    58,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  61,  119, 81,  81,
+    99,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  58,  59,  59,  58,  106, 81,  81,  81,  109, 119,
+    119, 119, 109, 109, 81,  81,  122, 58,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,
+    59,  59,  59,  58,  115, 81,  87,  81,  102, 32,  32,  32,  32,  32,  32,  10,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  61,  58,
+    59,  61,  81,  81,  81,  81,  81,  81,  87,  87,  81,  81,  81,  81,  81,  58,  59,  59,  59,
+    59,  59,  59,  59,  59,  58,  45,  45,  45,  59,  59,  59,  41,  87,  66,  33,  32,  32,  32,
+    32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  58,  59,  59,  93,  81,  81,  81,  81,  81,  81,  81,  81,  81,
+    81,  81,  81,  81,  40,  58,  59,  59,  59,  58,  45,  32,  46,  32,  32,  32,  32,  32,  46,
+    32,  126, 96,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  58,  61,  59,  58,  81,
+    81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  40,  58,  59,  59,  59,  58,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  58,  59,  59,  58,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,
+    81,  40,  58,  59,  59,  59,  46,  46,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  58,  61,  59,  60,  81,  81,  81,  81,
+    81,  81,  81,  81,  81,  81,  81,  81,  81,  59,  61,  59,  59,  61,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    58,  59,  59,  93,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  40,  59,
+    59,  59,  59,  32,  46,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  58,  61,  58,  106, 81,  81,  81,  81,  81,  81,  81,
+    81,  81,  81,  81,  81,  81,  76,  58,  59,  59,  59,  32,  46,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  61,  58,  58,
+    81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  87,  58,  59,  59,  59,  59,
+    32,  46,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  58,  59,  61,  41,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,
+    81,  81,  87,  59,  61,  58,  59,  59,  46,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  58,  61,  58,  61,  81,  81,
+    81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  107, 58,  59,  59,  59,  59,  58,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  58,  59,  59,  58,  51,  81,  81,  81,  81,  81,  81,  81,  81,  81,  81,  102, 94,
+    59,  59,  59,  59,  59,  61,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  58,  61,  59,  59,  59,  43,  63,  36,  81,
+    81,  81,  87,  64,  86,  102, 58,  59,  59,  59,  59,  59,  59,  59,  46,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  46,  61,
+    59,  59,  59,  59,  59,  59,  59,  43,  33,  58,  126, 126, 58,  59,  59,  59,  59,  59,  59,
+    59,  59,  59,  59,  32,  46,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  46,  61,  59,  59,  59,  58,  45,  58,  61,  59,  58,  58,  58,  61,
+    59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  59,  58,  32,  46,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  46,  61,  59,  59,  59,  59,  59,
+    58,  95,  32,  45,  61,  59,  61,  59,  59,  59,  59,  59,  59,  59,  45,  58,  59,  59,  59,
+    59,  61,  58,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  58,  61,  59,  59,  59,  59,  59,  61,  59,  61,  46,  46,  32,  45,  45,  45,  59,  58,
+    45,  45,  46,  58,  59,  59,  59,  59,  59,  59,  61,  46,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  46,  58,  59,  59,  59,  59,  59,  59,  59,  59,  59,
+    61,  59,  46,  32,  32,  46,  32,  46,  32,  58,  61,  59,  59,  59,  59,  59,  59,  59,  59,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  45,
+    59,  59,  59,  59,  59,  59,  59,  59,  58,  32,  32,  32,  32,  32,  32,  32,  32,  32,  61,
+    59,  59,  59,  59,  59,  59,  59,  58,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  46,  61,  59,  59,  59,  59,  59,  59,  59,  32,  46,  32,
+    32,  32,  32,  32,  32,  61,  46,  61,  59,  59,  59,  59,  59,  59,  58,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  61,  59,  59,  59,
+    59,  59,  59,  59,  59,  32,  46,  32,  32,  32,  32,  32,  32,  32,  46,  61,  58,  59,  59,
+    59,  59,  59,  58,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  58,  59,  59,  59,  59,  59,  59,  59,  59,  46,  46,  32,  32,  32,  32,
+    32,  32,  32,  61,  59,  59,  59,  59,  59,  59,  59,  45,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  46,  32,  45,  61,  59,  59,  59,  59,
+    59,  58,  32,  46,  32,  32,  32,  32,  32,  32,  32,  58,  59,  59,  59,  59,  59,  58,  45,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  45,  45,  45,  45,  32,  46,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  45,  61,  59,  58,  45,  45,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  10,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  46,  32,  32,  46,  32,  32,  32,  32,  32,  32,
+    32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  32,  10};
 
 }  // namespace aapt
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
index 9ec820d..89d19cf 100644
--- a/tools/aapt2/cmd/Dump.h
+++ b/tools/aapt2/cmd/Dump.h
@@ -19,14 +19,77 @@
 
 #include "Command.h"
 #include "Debug.h"
+#include "LoadedApk.h"
 #include "dump/DumpManifest.h"
 
 namespace aapt {
 
-/** Command the contents of files generated from the compilation stage. */
+/**
+ * The base command for dumping information about apks. When the command is executed, the command
+ * performs the DumpApkCommand::Dump() operation on each apk provided as a file argument.
+ **/
+class DumpApkCommand : public Command {
+ public:
+  explicit DumpApkCommand(const std::string&& name, text::Printer* printer, IDiagnostics* diag)
+      : Command(name), printer_(printer), diag_(diag) {
+  }
+
+  text::Printer* GetPrinter() {
+    return printer_;
+  }
+
+  IDiagnostics* GetDiagnostics() {
+    return diag_;
+  }
+
+  Maybe<std::string> GetPackageName(LoadedApk* apk) {
+    xml::Element* manifest_el = apk->GetManifest()->root.get();
+    if (!manifest_el) {
+      GetDiagnostics()->Error(DiagMessage() << "No AndroidManifest.");
+      return Maybe<std::string>();
+    }
+
+    xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
+    if (!attr) {
+      GetDiagnostics()->Error(DiagMessage() << "No package name.");
+      return Maybe<std::string>();
+    }
+    return attr->value;
+  }
+
+  /** Perform the dump operation on the apk. */
+  virtual int Dump(LoadedApk* apk) = 0;
+
+  int Action(const std::vector<std::string>& args) final {
+    if (args.size() < 1) {
+      diag_->Error(DiagMessage() << "No dump apk specified.");
+      return 1;
+    }
+
+    bool error = false;
+    for (auto apk : args) {
+      auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
+      if (!loaded_apk) {
+        error = true;
+        continue;
+      }
+
+      error |= Dump(loaded_apk.get());
+    }
+
+    return error;
+  }
+
+ private:
+  text::Printer* printer_;
+  IDiagnostics* diag_;
+};
+
+/** Command that prints contents of files generated from the compilation stage. */
 class DumpAPCCommand : public Command {
  public:
-  explicit DumpAPCCommand(IDiagnostics* diag) : Command("apc"), diag_(diag) {
+  explicit DumpAPCCommand(text::Printer* printer, IDiagnostics* diag)
+      : Command("apc"), printer_(printer), diag_(diag) {
     SetDescription("Print the contents of the AAPT2 Container (APC) generated fom compilation.");
     AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
                       &no_values_);
@@ -36,120 +99,178 @@
   int Action(const std::vector<std::string>& args) override;
 
  private:
+  text::Printer* printer_;
   IDiagnostics* diag_;
-  bool verbose_ = false;
   bool no_values_ = false;
+  bool verbose_ = false;
 };
 
-/** Prints every configuration used by a resource in an APK. */
-class DumpConfigsCommand : public Command {
+/** Easter egg command shown when users enter "badger" instead of "badging". */
+class DumpBadgerCommand : public Command {
  public:
-  explicit DumpConfigsCommand(IDiagnostics* diag) : Command("configurations"), diag_(diag) {
-    SetDescription("Print every configuration used by a resource in the APK.");
+  explicit DumpBadgerCommand(text::Printer* printer) : Command("badger"), printer_(printer) {
   }
 
   int Action(const std::vector<std::string>& args) override;
 
  private:
-  IDiagnostics* diag_;
+  text::Printer* printer_;
+  const static char kBadgerData[2925];
 };
 
-/** Prints the contents of the resource table string pool in the APK. */
-class DumpStringsCommand : public Command {
-  public:
-    explicit DumpStringsCommand(IDiagnostics* diag) : Command("strings"), diag_(diag) {
-      SetDescription("Print the contents of the resource table string pool in the APK.");
-    }
-
-    int Action(const std::vector<std::string>& args) override;
-
-  private:
-    IDiagnostics* diag_;
-};
-
-/** Prints the contents of the resource table from the APK. */
-class DumpTableCommand : public Command {
+class DumpBadgingCommand : public DumpApkCommand {
  public:
-  explicit DumpTableCommand(IDiagnostics* diag) : Command("resources"), diag_(diag) {
+  explicit DumpBadgingCommand(text::Printer* printer, IDiagnostics* diag)
+      : DumpApkCommand("badging", printer, diag) {
+    SetDescription("Print information extracted from the manifest of the APK.");
+    AddOptionalSwitch("--include-meta-data", "Include meta-data information.",
+                      &options_.include_meta_data);
+  }
+
+  int Dump(LoadedApk* apk) override {
+    return DumpManifest(apk, options_, GetPrinter(), GetDiagnostics());
+  }
+
+ private:
+  DumpManifestOptions options_;
+};
+
+class DumpConfigsCommand : public DumpApkCommand {
+ public:
+  explicit DumpConfigsCommand(text::Printer* printer, IDiagnostics* diag)
+      : DumpApkCommand("configurations", printer, diag) {
+    SetDescription("Print every configuration used by a resource in the APK.");
+  }
+
+  int Dump(LoadedApk* apk) override;
+};
+
+class DumpPackageNameCommand : public DumpApkCommand {
+ public:
+  explicit DumpPackageNameCommand(text::Printer* printer, IDiagnostics* diag)
+      : DumpApkCommand("packagename", printer, diag) {
+    SetDescription("Print the package name of the APK.");
+  }
+
+  int Dump(LoadedApk* apk) override;
+};
+
+class DumpPermissionsCommand : public DumpApkCommand {
+ public:
+  explicit DumpPermissionsCommand(text::Printer* printer, IDiagnostics* diag)
+      : DumpApkCommand("permissions", printer, diag) {
+    SetDescription("Print the permissions extracted from the manifest of the APK.");
+  }
+
+  int Dump(LoadedApk* apk) override {
+    DumpManifestOptions options;
+    options.only_permissions = true;
+    return DumpManifest(apk, options, GetPrinter(), GetDiagnostics());
+  }
+};
+
+class DumpStringsCommand : public DumpApkCommand {
+ public:
+  explicit DumpStringsCommand(text::Printer* printer, IDiagnostics* diag)
+      : DumpApkCommand("strings", printer, diag) {
+    SetDescription("Print the contents of the resource table string pool in the APK.");
+  }
+
+  int Dump(LoadedApk* apk) override;
+};
+
+/** Prints the graph of parents of a style in an APK. */
+class DumpStyleParentCommand : public DumpApkCommand {
+ public:
+  explicit DumpStyleParentCommand(text::Printer* printer, IDiagnostics* diag)
+      : DumpApkCommand("styleparents", printer, diag) {
+    SetDescription("Print the parents of a style in an APK.");
+    AddRequiredFlag("--style", "The name of the style to print", &style_);
+  }
+
+  int Dump(LoadedApk* apk) override;
+
+ private:
+  std::string style_;
+};
+
+class DumpTableCommand : public DumpApkCommand {
+ public:
+  explicit DumpTableCommand(text::Printer* printer, IDiagnostics* diag)
+      : DumpApkCommand("resources", printer, diag) {
     SetDescription("Print the contents of the resource table from the APK.");
     AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.",
                       &no_values_);
     AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_);
   }
 
-  int Action(const std::vector<std::string>& args) override;
+  int Dump(LoadedApk* apk) override;
 
  private:
-  IDiagnostics* diag_;
-  bool verbose_ = false;
   bool no_values_ = false;
+  bool verbose_ = false;
 };
 
-/** Prints the string pool of a compiled xml in an APK. */
-class DumpXmlStringsCommand : public Command {
-public:
-    explicit DumpXmlStringsCommand(IDiagnostics* diag) : Command("xmlstrings"), diag_(diag) {
-      SetDescription("Print the string pool of a compiled xml in an APK.");
-      AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
-    }
-
-    int Action(const std::vector<std::string>& args) override;
-
-private:
-    IDiagnostics* diag_;
-    std::vector<std::string> files_;
-};
-
-
-/** Prints the tree of a compiled xml in an APK. */
-class DumpXmlTreeCommand : public Command {
+class DumpXmlStringsCommand : public DumpApkCommand {
  public:
-  explicit DumpXmlTreeCommand(IDiagnostics* diag) : Command("xmltree"), diag_(diag) {
+  explicit DumpXmlStringsCommand(text::Printer* printer, IDiagnostics* diag)
+      : DumpApkCommand("xmlstrings", printer, diag) {
+    SetDescription("Print the string pool of a compiled xml in an APK.");
+    AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
+  }
+
+  int Dump(LoadedApk* apk) override;
+
+ private:
+  std::vector<std::string> files_;
+};
+
+class DumpXmlTreeCommand : public DumpApkCommand {
+ public:
+  explicit DumpXmlTreeCommand(text::Printer* printer, IDiagnostics* diag)
+      : DumpApkCommand("xmltree", printer, diag) {
     SetDescription("Print the tree of a compiled xml in an APK.");
     AddRequiredFlagList("--file", "A compiled xml file to print", &files_);
   }
 
-  int Action(const std::vector<std::string>& args) override;
+  int Dump(LoadedApk* apk) override;
 
  private:
-  IDiagnostics* diag_;
   std::vector<std::string> files_;
 };
 
-/** Prints the contents of the resource table from the APK. */
-class DumpPackageNameCommand : public Command {
- public:
-  explicit DumpPackageNameCommand(IDiagnostics* diag) : Command("packagename"), diag_(diag) {
-    SetDescription("Print the package name of the APK.");
-  }
-
-  int Action(const std::vector<std::string>& args) override;
-
- private:
-  IDiagnostics* diag_;
-};
-
 /** The default dump command. Performs no action because a subcommand is required. */
 class DumpCommand : public Command {
  public:
-  explicit DumpCommand(IDiagnostics* diag) : Command("dump", "d"), diag_(diag) {
-    AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(diag_));
-    AddOptionalSubcommand(util::make_unique<DumpBadgingCommand>(diag_));
-    AddOptionalSubcommand(util::make_unique<DumpConfigsCommand>(diag_));
-    AddOptionalSubcommand(util::make_unique<DumpPackageNameCommand>(diag_));
-    AddOptionalSubcommand(util::make_unique<DumpPermissionsCommand>(diag_));
-    AddOptionalSubcommand(util::make_unique<DumpStringsCommand>(diag_));
-    AddOptionalSubcommand(util::make_unique<DumpTableCommand>(diag_));
-    AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(diag_));
-    AddOptionalSubcommand(util::make_unique<DumpXmlTreeCommand>(diag_));
+  explicit DumpCommand(text::Printer* printer, IDiagnostics* diag)
+      : Command("dump", "d"), diag_(diag) {
+    AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(printer, diag_));
+    AddOptionalSubcommand(util::make_unique<DumpBadgingCommand>(printer, diag_));
+    AddOptionalSubcommand(util::make_unique<DumpConfigsCommand>(printer, diag_));
+    AddOptionalSubcommand(util::make_unique<DumpPackageNameCommand>(printer, diag_));
+    AddOptionalSubcommand(util::make_unique<DumpPermissionsCommand>(printer, diag_));
+    AddOptionalSubcommand(util::make_unique<DumpStringsCommand>(printer, diag_));
+    AddOptionalSubcommand(util::make_unique<DumpStyleParentCommand>(printer, diag_));
+    AddOptionalSubcommand(util::make_unique<DumpTableCommand>(printer, diag_));
+    AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(printer, diag_));
+    AddOptionalSubcommand(util::make_unique<DumpXmlTreeCommand>(printer, diag_));
+    AddOptionalSubcommand(util::make_unique<DumpBadgerCommand>(printer), /* hidden */ true);
   }
 
-  int Action(const std::vector<std::string>& args) override;
+  int Action(const std::vector<std::string>& args) override {
+    if (args.size() == 0) {
+      diag_->Error(DiagMessage() << "no subcommand specified");
+    } else {
+      diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'");
+    }
+    Usage(&std::cerr);
+    return 1;
+  }
 
  private:
   IDiagnostics* diag_;
 };
 
-}// namespace aapt
+}  // namespace aapt
 
-#endif //AAPT2_DUMP_H
+#endif  // AAPT2_DUMP_H
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 186f8a1..6a7da0c 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1776,10 +1776,12 @@
 
     // Before we process anything, remove the resources whose default values don't exist.
     // We want to force any references to these to fail the build.
-    if (!NoDefaultResourceRemover{}.Consume(context_, &final_table_)) {
-      context_->GetDiagnostics()->Error(DiagMessage()
-                                        << "failed removing resources with no defaults");
-      return 1;
+    if (!options_.no_resource_removal) {
+      if (!NoDefaultResourceRemover{}.Consume(context_, &final_table_)) {
+        context_->GetDiagnostics()->Error(DiagMessage()
+                                          << "failed removing resources with no defaults");
+        return 1;
+      }
     }
 
     ReferenceLinker linker;
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index a42c0f2..950dac2 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -59,6 +59,7 @@
   bool no_version_vectors = false;
   bool no_version_transitions = false;
   bool no_resource_deduping = false;
+  bool no_resource_removal = false;
   bool no_xml_namespaces = false;
   bool do_not_compress_anything = false;
   std::unordered_set<std::string> extensions_to_not_compress;
@@ -136,6 +137,9 @@
     AddOptionalSwitch("--no-resource-deduping", "Disables automatic deduping of resources with\n"
             "identical values across compatible configurations.",
         &options_.no_resource_deduping);
+    AddOptionalSwitch("--no-resource-removal", "Disables automatic removal of resources without\n"
+            "defaults. Use this only when building runtime resource overlay packages.",
+        &options_.no_resource_removal);
     AddOptionalSwitch("--enable-sparse-encoding",
         "This decreases APK size at the cost of resource retrieval performance.",
         &options_.table_flattener_options.use_sparse_entries);
@@ -280,4 +284,4 @@
 
 }// namespace aapt
 
-#endif //AAPT2_LINK_H
\ No newline at end of file
+#endif //AAPT2_LINK_H
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index c0e1dc6..11a4074 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -109,15 +109,8 @@
 
 class ManifestExtractor {
  public:
-  struct Options {
-    /** Include meta information from <meta-data> elements in the output. */
-    bool include_meta_data = false;
 
-    /** Only output permission information. */
-    bool only_permissions = false;
-  };
-
-  explicit ManifestExtractor(LoadedApk* apk, ManifestExtractor::Options options)
+  explicit ManifestExtractor(LoadedApk* apk, DumpManifestOptions& options)
       : apk_(apk), options_(options) { }
 
   class Element {
@@ -128,7 +121,7 @@
     static std::unique_ptr<Element> Inflate(ManifestExtractor* extractor, xml::Element* el);
 
     /** Writes out the extracted contents of the element. */
-    virtual void Print(text::Printer& printer) { }
+    virtual void Print(text::Printer* printer) { }
 
     /** Adds an element to the list of children of the element. */
     void AddChild(std::unique_ptr<Element>& child) { children_.push_back(std::move(child)); }
@@ -332,7 +325,7 @@
     return config;
   }
 
-  bool Dump(text::Printer& printer, IDiagnostics* diag);
+  bool Dump(text::Printer* printer, IDiagnostics* diag);
 
   /** Recursively visit the xml element tree and return a processed badging element tree. */
   std::unique_ptr<Element> Visit(xml::Element* element);
@@ -378,7 +371,7 @@
   }
 
   LoadedApk* const apk_;
-  const Options options_;
+  DumpManifestOptions& options_;
 
  private:
   std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_ = util::make_unique<CommonFeatureGroup>();
@@ -450,40 +443,40 @@
     installLocation = GetAttributeInteger(FindAttribute(manifest, INSTALL_LOCATION_ATTR));
   }
 
-  void Print(text::Printer& printer) override {
-    printer.Print(StringPrintf("package: name='%s' ", package.data()));
-    printer.Print(StringPrintf("versionCode='%s' ",
+  void Print(text::Printer* printer) override {
+    printer->Print(StringPrintf("package: name='%s' ", package.data()));
+    printer->Print(StringPrintf("versionCode='%s' ",
                                (versionCode > 0) ? std::to_string(versionCode).data() : ""));
-    printer.Print(StringPrintf("versionName='%s'", versionName.data()));
+    printer->Print(StringPrintf("versionName='%s'", versionName.data()));
 
     if (split) {
-      printer.Print(StringPrintf(" split='%s'", split->data()));
+      printer->Print(StringPrintf(" split='%s'", split->data()));
     }
     if (platformVersionName) {
-      printer.Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data()));
+      printer->Print(StringPrintf(" platformBuildVersionName='%s'", platformVersionName->data()));
     }
     if (platformVersionCode) {
-      printer.Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data()));
+      printer->Print(StringPrintf(" platformBuildVersionCode='%s'", platformVersionCode->data()));
     }
     if (compilesdkVersion) {
-      printer.Print(StringPrintf(" compileSdkVersion='%d'", *compilesdkVersion));
+      printer->Print(StringPrintf(" compileSdkVersion='%d'", *compilesdkVersion));
     }
     if (compilesdkVersionCodename) {
-      printer.Print(StringPrintf(" compileSdkVersionCodename='%s'",
+      printer->Print(StringPrintf(" compileSdkVersionCodename='%s'",
                                  compilesdkVersionCodename->data()));
     }
-    printer.Print("\n");
+    printer->Print("\n");
 
     if (installLocation) {
       switch (*installLocation) {
         case 0:
-          printer.Print("install-location:'auto'\n");
+          printer->Print("install-location:'auto'\n");
           break;
         case 1:
-          printer.Print("install-location:'internalOnly'\n");
+          printer->Print("install-location:'internalOnly'\n");
           break;
         case 2:
-          printer.Print("install-location:'preferExternal'\n");
+          printer->Print("install-location:'preferExternal'\n");
           break;
         default:
           break;
@@ -544,15 +537,15 @@
     }
   }
 
-  void Print(text::Printer& printer) override {
+  void Print(text::Printer* printer) override {
     // Print the labels for every locale
     for (auto p : locale_labels) {
       if (p.first.empty()) {
-        printer.Print(StringPrintf("application-label:'%s'\n",
+        printer->Print(StringPrintf("application-label:'%s'\n",
                                     android::ResTable::normalizeForOutput(p.second.data())
                                         .c_str()));
       } else {
-        printer.Print(StringPrintf("application-label-%s:'%s'\n", p.first.data(),
+        printer->Print(StringPrintf("application-label-%s:'%s'\n", p.first.data(),
                                     android::ResTable::normalizeForOutput(p.second.data())
                                         .c_str()));
       }
@@ -560,26 +553,26 @@
 
     // Print the icon paths for every density
     for (auto p : density_icons) {
-      printer.Print(StringPrintf("application-icon-%d:'%s'\n", p.first, p.second.data()));
+      printer->Print(StringPrintf("application-icon-%d:'%s'\n", p.first, p.second.data()));
     }
 
     // Print the application info
-    printer.Print(StringPrintf("application: label='%s' ",
+    printer->Print(StringPrintf("application: label='%s' ",
                                 android::ResTable::normalizeForOutput(label.data()).c_str()));
-    printer.Print(StringPrintf("icon='%s'", icon.data()));
+    printer->Print(StringPrintf("icon='%s'", icon.data()));
     if (!banner.empty()) {
-      printer.Print(StringPrintf(" banner='%s'", banner.data()));
+      printer->Print(StringPrintf(" banner='%s'", banner.data()));
     }
-    printer.Print("\n");
+    printer->Print("\n");
 
     if (test_only != 0) {
-      printer.Print(StringPrintf("testOnly='%d'\n", test_only));
+      printer->Print(StringPrintf("testOnly='%d'\n", test_only));
     }
     if (is_game != 0) {
-      printer.Print("application-isGame\n");
+      printer->Print("application-isGame\n");
     }
     if (debuggable != 0) {
-      printer.Print("application-debuggable\n");
+      printer->Print("application-debuggable\n");
     }
   }
 };
@@ -614,19 +607,19 @@
     }
   }
 
-  void Print(text::Printer& printer) override {
+  void Print(text::Printer* printer) override {
     if (min_sdk) {
-      printer.Print(StringPrintf("sdkVersion:'%d'\n", *min_sdk));
+      printer->Print(StringPrintf("sdkVersion:'%d'\n", *min_sdk));
     } else if (min_sdk_name) {
-      printer.Print(StringPrintf("sdkVersion:'%s'\n", min_sdk_name->data()));
+      printer->Print(StringPrintf("sdkVersion:'%s'\n", min_sdk_name->data()));
     }
     if (max_sdk) {
-      printer.Print(StringPrintf("maxSdkVersion:'%d'\n", *max_sdk));
+      printer->Print(StringPrintf("maxSdkVersion:'%d'\n", *max_sdk));
     }
     if (target_sdk) {
-      printer.Print(StringPrintf("targetSdkVersion:'%d'\n", *target_sdk));
+      printer->Print(StringPrintf("targetSdkVersion:'%d'\n", *target_sdk));
     } else if (target_sdk_name) {
-      printer.Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data()));
+      printer->Print(StringPrintf("targetSdkVersion:'%s'\n", target_sdk_name->data()));
     }
   }
 };
@@ -654,24 +647,24 @@
         FindAttribute(element, REQ_FIVE_WAY_NAV_ATTR), 0);
   }
 
-  void Print(text::Printer& printer) override {
-    printer.Print("uses-configuration:");
+  void Print(text::Printer* printer) override {
+    printer->Print("uses-configuration:");
     if (req_touch_screen != 0) {
-      printer.Print(StringPrintf(" reqTouchScreen='%d'", req_touch_screen));
+      printer->Print(StringPrintf(" reqTouchScreen='%d'", req_touch_screen));
     }
     if (req_keyboard_type != 0) {
-      printer.Print(StringPrintf(" reqKeyboardType='%d'", req_keyboard_type));
+      printer->Print(StringPrintf(" reqKeyboardType='%d'", req_keyboard_type));
     }
     if (req_hard_keyboard != 0) {
-      printer.Print(StringPrintf(" reqHardKeyboard='%d'", req_hard_keyboard));
+      printer->Print(StringPrintf(" reqHardKeyboard='%d'", req_hard_keyboard));
     }
     if (req_navigation != 0) {
-      printer.Print(StringPrintf(" reqNavigation='%d'", req_navigation));
+      printer->Print(StringPrintf(" reqNavigation='%d'", req_navigation));
     }
     if (req_five_way_nav != 0) {
-      printer.Print(StringPrintf(" reqFiveWayNav='%d'", req_five_way_nav));
+      printer->Print(StringPrintf(" reqFiveWayNav='%d'", req_five_way_nav));
     }
-    printer.Print("\n");
+    printer->Print("\n");
   }
 };
 
@@ -715,7 +708,7 @@
     }
   }
 
-  void PrintScreens(text::Printer& printer, int32_t target_sdk) {
+  void PrintScreens(text::Printer* printer, int32_t target_sdk) {
     int32_t small_screen_temp = small_screen;
     int32_t normal_screen_temp  = normal_screen;
     int32_t large_screen_temp  = large_screen;
@@ -745,30 +738,30 @@
     }
 
     // Print the formatted screen info
-    printer.Print("supports-screens:");
+    printer->Print("supports-screens:");
     if (small_screen_temp  != 0) {
-      printer.Print(" 'small'");
+      printer->Print(" 'small'");
     }
     if (normal_screen_temp  != 0) {
-      printer.Print(" 'normal'");
+      printer->Print(" 'normal'");
     }
     if (large_screen_temp   != 0) {
-      printer.Print(" 'large'");
+      printer->Print(" 'large'");
     }
     if (xlarge_screen_temp  != 0) {
-      printer.Print(" 'xlarge'");
+      printer->Print(" 'xlarge'");
     }
-    printer.Print("\n");
-    printer.Print(StringPrintf("supports-any-density: '%s'\n",
+    printer->Print("\n");
+    printer->Print(StringPrintf("supports-any-density: '%s'\n",
                                 (any_density_temp ) ? "true" : "false"));
     if (requires_smallest_width_dp > 0) {
-      printer.Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp));
+      printer->Print(StringPrintf("requires-smallest-width:'%d'\n", requires_smallest_width_dp));
     }
     if (compatible_width_limit_dp > 0) {
-      printer.Print(StringPrintf("compatible-width-limit:'%d'\n", compatible_width_limit_dp));
+      printer->Print(StringPrintf("compatible-width-limit:'%d'\n", compatible_width_limit_dp));
     }
     if (largest_width_limit_dp > 0) {
-      printer.Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp));
+      printer->Print(StringPrintf("largest-width-limit:'%d'\n", largest_width_limit_dp));
     }
   }
 };
@@ -784,20 +777,20 @@
     label = GetAttributeStringDefault(FindAttribute(element, LABEL_ATTR), "");
   }
 
-  virtual void PrintGroup(text::Printer& printer) {
-    printer.Print(StringPrintf("feature-group: label='%s'\n", label.data()));
+  virtual void PrintGroup(text::Printer* printer) {
+    printer->Print(StringPrintf("feature-group: label='%s'\n", label.data()));
     if (open_gles_version > 0) {
-      printer.Print(StringPrintf("  uses-gl-es: '0x%x'\n", open_gles_version));
+      printer->Print(StringPrintf("  uses-gl-es: '0x%x'\n", open_gles_version));
     }
 
     for (auto feature : features_) {
-      printer.Print(StringPrintf("  uses-feature%s: name='%s'",
+      printer->Print(StringPrintf("  uses-feature%s: name='%s'",
                                  (feature.second.required ? "" : "-not-required"),
                                  feature.first.data()));
       if (feature.second.version > 0) {
-        printer.Print(StringPrintf(" version='%d'", feature.second.version));
+        printer->Print(StringPrintf(" version='%d'", feature.second.version));
       }
-      printer.Print("\n");
+      printer->Print("\n");
     }
   }
 
@@ -863,29 +856,29 @@
 class CommonFeatureGroup : public FeatureGroup {
  public:
   CommonFeatureGroup() = default;
-  void PrintGroup(text::Printer& printer) override {
+  void PrintGroup(text::Printer* printer) override {
     FeatureGroup::PrintGroup(printer);
 
     // Also print the implied features
     for (auto feature : implied_features_) {
       if (features_.find(feature.first) == features_.end()) {
         const char* sdk23 = feature.second.implied_from_sdk_k23 ? "-sdk-23" : "";
-        printer.Print(StringPrintf("  uses-feature%s: name='%s'\n", sdk23, feature.first.data()));
-        printer.Print(StringPrintf("  uses-implied-feature%s: name='%s' reason='", sdk23,
+        printer->Print(StringPrintf("  uses-feature%s: name='%s'\n", sdk23, feature.first.data()));
+        printer->Print(StringPrintf("  uses-implied-feature%s: name='%s' reason='", sdk23,
                                     feature.first.data()));
 
         // Print the reasons as a sentence
         size_t count = 0;
         for (auto reason : feature.second.reasons) {
-          printer.Print(reason);
+          printer->Print(reason);
           if (count + 2 < feature.second.reasons.size()) {
-            printer.Print(", ");
+            printer->Print(", ");
           } else if (count + 1 < feature.second.reasons.size()) {
-            printer.Print(", and ");
+            printer->Print(", and ");
           }
           count++;
         }
-        printer.Print("'\n");
+        printer->Print("'\n");
       }
     }
   }
@@ -1070,35 +1063,35 @@
     }
   }
 
-  void Print(text::Printer& printer) override {
+  void Print(text::Printer* printer) override {
     if (!name.empty()) {
-      printer.Print(StringPrintf("uses-permission: name='%s'", name.data()));
+      printer->Print(StringPrintf("uses-permission: name='%s'", name.data()));
       if (maxSdkVersion >= 0) {
-        printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+        printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
       }
       if (!requiredFeature.empty()) {
-        printer.Print(StringPrintf(" requiredFeature='%s'", requiredFeature.data()));
+        printer->Print(StringPrintf(" requiredFeature='%s'", requiredFeature.data()));
       }
       if (!requiredNotFeature.empty()) {
-        printer.Print(StringPrintf(" requiredNotFeature='%s'", requiredNotFeature.data()));
+        printer->Print(StringPrintf(" requiredNotFeature='%s'", requiredNotFeature.data()));
       }
-      printer.Print("\n");
+      printer->Print("\n");
       if (required == 0) {
-        printer.Print(StringPrintf("optional-permission: name='%s'", name.data()));
+        printer->Print(StringPrintf("optional-permission: name='%s'", name.data()));
         if (maxSdkVersion >= 0) {
-          printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+          printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
         }
-        printer.Print("\n");
+        printer->Print("\n");
       }
     }
   }
 
-  void PrintImplied(text::Printer& printer, const std::string& reason) {
-    printer.Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
+  void PrintImplied(text::Printer* printer, const std::string& reason) {
+    printer->Print(StringPrintf("uses-implied-permission: name='%s'", name.data()));
     if (maxSdkVersion >= 0) {
-      printer.Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
+      printer->Print(StringPrintf(" maxSdkVersion='%d'", maxSdkVersion));
     }
-    printer.Print(StringPrintf(" reason='%s'\n", reason.data()));
+    printer->Print(StringPrintf(" reason='%s'\n", reason.data()));
   }
 };
 
@@ -1119,13 +1112,13 @@
     }
   }
 
-  void Print(text::Printer& printer) override {
+  void Print(text::Printer* printer) override {
     if (name) {
-      printer.Print(StringPrintf("uses-permission-sdk-23: name='%s'", name->data()));
+      printer->Print(StringPrintf("uses-permission-sdk-23: name='%s'", name->data()));
       if (maxSdkVersion) {
-        printer.Print(StringPrintf(" maxSdkVersion='%d'", *maxSdkVersion));
+        printer->Print(StringPrintf(" maxSdkVersion='%d'", *maxSdkVersion));
       }
-      printer.Print("\n");
+      printer->Print("\n");
     }
   }
 };
@@ -1140,9 +1133,9 @@
     name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
   }
 
-  void Print(text::Printer& printer) override {
+  void Print(text::Printer* printer) override {
     if (extractor()->options_.only_permissions && !name.empty()) {
-      printer.Print(StringPrintf("permission: %s\n", name.data()));
+      printer->Print(StringPrintf("permission: %s\n", name.data()));
     }
   }
 };
@@ -1202,25 +1195,25 @@
     }
   }
 
-  void Print(text::Printer& printer) override {
+  void Print(text::Printer* printer) override {
     // Print whether the activity has the HOME category and a the MAIN action
     if (has_main_action && has_launcher_category) {
-      printer.Print("launchable-activity:");
+      printer->Print("launchable-activity:");
       if (!name.empty()) {
-        printer.Print(StringPrintf(" name='%s' ", name.data()));
+        printer->Print(StringPrintf(" name='%s' ", name.data()));
       }
-      printer.Print(StringPrintf(" label='%s' icon='%s'\n",
+      printer->Print(StringPrintf(" label='%s' icon='%s'\n",
                                   android::ResTable::normalizeForOutput(label.data()).c_str(),
                                   icon.data()));
     }
 
     // Print wether the activity has the HOME category and a the MAIN action
     if (has_leanback_launcher_category) {
-      printer.Print("leanback-launchable-activity:");
+      printer->Print("leanback-launchable-activity:");
       if (!name.empty()) {
-        printer.Print(StringPrintf(" name='%s' ", name.data()));
+        printer->Print(StringPrintf(" name='%s' ", name.data()));
       }
-      printer.Print(StringPrintf(" label='%s' icon='%s' banner='%s'\n",
+      printer->Print(StringPrintf(" label='%s' icon='%s' banner='%s'\n",
                                   android::ResTable::normalizeForOutput(label.data()).c_str(),
                                   icon.data(), banner.data()));
     }
@@ -1319,9 +1312,9 @@
     }
   }
 
-  void Print(text::Printer& printer) override {
+  void Print(text::Printer* printer) override {
     if (!name.empty()) {
-      printer.Print(StringPrintf("uses-library%s:'%s'\n",
+      printer->Print(StringPrintf("uses-library%s:'%s'\n",
                                  (required == 0) ? "-not-required" : "", name.data()));
     }
   }
@@ -1344,8 +1337,8 @@
     }
   }
 
-  void Print(text::Printer& printer) override {
-    printer.Print(StringPrintf(
+  void Print(text::Printer* printer) override {
+    printer->Print(StringPrintf(
       "static-library: name='%s' version='%d' versionMajor='%d'\n",
       name.data(), version, versionMajor));
   }
@@ -1380,14 +1373,14 @@
     }
   }
 
-  void Print(text::Printer& printer) override {
-    printer.Print(StringPrintf(
+  void Print(text::Printer* printer) override {
+    printer->Print(StringPrintf(
       "uses-static-library: name='%s' version='%d' versionMajor='%d'",
       name.data(), version, versionMajor));
     for (size_t i = 0; i < certDigests.size(); i++) {
-      printer.Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
+      printer->Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
     }
-    printer.Print("\n");
+    printer->Print("\n");
   }
 };
 
@@ -1412,21 +1405,21 @@
     resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR));
   }
 
-  void Print(text::Printer& printer) override {
+  void Print(text::Printer* printer) override {
     if (extractor()->options_.include_meta_data && !name.empty()) {
-      printer.Print(StringPrintf("meta-data: name='%s' ", name.data()));
+      printer->Print(StringPrintf("meta-data: name='%s' ", name.data()));
       if (!value.empty()) {
-        printer.Print(StringPrintf("value='%s' ", value.data()));
+        printer->Print(StringPrintf("value='%s' ", value.data()));
       } else if (value_int) {
-        printer.Print(StringPrintf("value='%d' ", *value_int));
+        printer->Print(StringPrintf("value='%d' ", *value_int));
       } else {
         if (!resource.empty()) {
-          printer.Print(StringPrintf("resource='%s' ", resource.data()));
+          printer->Print(StringPrintf("resource='%s' ", resource.data()));
         } else if (resource_int) {
-          printer.Print(StringPrintf("resource='%d' ", *resource_int));
+          printer->Print(StringPrintf("resource='%d' ", *resource_int));
         }
       }
-      printer.Print("\n");
+      printer->Print("\n");
     }
   }
 };
@@ -1548,14 +1541,14 @@
   SupportsInput() = default;
   std::vector<std::string> inputs;
 
-  void Print(text::Printer& printer) override {
+  void Print(text::Printer* printer) override {
     const size_t size = inputs.size();
     if (size > 0) {
-      printer.Print("supports-input: '");
+      printer->Print("supports-input: '");
       for (size_t i = 0; i < size; i++) {
-        printer.Print(StringPrintf("value='%s' ", inputs[i].data()));
+        printer->Print(StringPrintf("value='%s' ", inputs[i].data()));
       }
-      printer.Print("\n");
+      printer->Print("\n");
     }
   }
 };
@@ -1586,9 +1579,9 @@
     name = GetAttributeString(FindAttribute(element, NAME_ATTR));
   }
 
-  void Print(text::Printer& printer) override {
+  void Print(text::Printer* printer) override {
     if (name) {
-      printer.Print(StringPrintf("original-package:'%s'\n", name->data()));
+      printer->Print(StringPrintf("original-package:'%s'\n", name->data()));
     }
   }
 };
@@ -1605,9 +1598,9 @@
     public_key = GetAttributeString(FindAttribute(element, PUBLIC_KEY_ATTR));
   }
 
-  void Print(text::Printer& printer) override {
+  void Print(text::Printer* printer) override {
     if (name && public_key) {
-      printer.Print(StringPrintf("package-verifier: name='%s' publicKey='%s'\n",
+      printer->Print(StringPrintf("package-verifier: name='%s' publicKey='%s'\n",
                                  name->data(), public_key->data()));
     }
   }
@@ -1644,18 +1637,18 @@
     }
   }
 
-  void Print(text::Printer& printer) override {
+  void Print(text::Printer* printer) override {
     if (name) {
       if (packageType) {
-        printer.Print(StringPrintf(
+        printer->Print(StringPrintf(
           "uses-typed-package: type='%s' name='%s' version='%d' versionMajor='%d'",
           packageType->data(), name->data(), version, versionMajor));
         for (size_t i = 0; i < certDigests.size(); i++) {
-          printer.Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
+          printer->Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
         }
-        printer.Print("\n");
+        printer->Print("\n");
       } else {
-        printer.Print(StringPrintf("uses-package:'%s'\n", name->data()));
+        printer->Print(StringPrintf("uses-package:'%s'\n", name->data()));
       }
     }
   }
@@ -1700,8 +1693,8 @@
 class CompatibleScreens : public ManifestExtractor::Element {
  public:
   CompatibleScreens() = default;
-  void Print(text::Printer& printer) override {
-    printer.Print("compatible-screens:");
+  void Print(text::Printer* printer) override {
+    printer->Print("compatible-screens:");
 
     bool first = true;
     ForEachChild(this, [&printer, &first](ManifestExtractor::Element* el){
@@ -1709,15 +1702,15 @@
         if (first) {
           first = false;
         } else {
-          printer.Print(",");
+          printer->Print(",");
         }
 
         if (screen->size && screen->density) {
-          printer.Print(StringPrintf("'%d/%d'", *screen->size, *screen->density));
+          printer->Print(StringPrintf("'%d/%d'", *screen->size, *screen->density));
         }
       }
     });
-    printer.Print("\n");
+    printer->Print("\n");
   }
 };
 
@@ -1731,22 +1724,22 @@
     name = GetAttributeString(FindAttribute(element, NAME_ATTR));
   }
 
-  void Print(text::Printer& printer) override {
+  void Print(text::Printer* printer) override {
     if (name) {
-      printer.Print(StringPrintf("supports-gl-texture:'%s'\n", name->data()));
+      printer->Print(StringPrintf("supports-gl-texture:'%s'\n", name->data()));
     }
   }
 };
 
 /** Recursively prints the extracted badging element. */
-static void Print(ManifestExtractor::Element* el, text::Printer& printer) {
+static void Print(ManifestExtractor::Element* el, text::Printer* printer) {
   el->Print(printer);
   for (auto &child : el->children()) {
     Print(child.get(), printer);
   }
 }
 
-bool ManifestExtractor::Dump(text::Printer& printer, IDiagnostics* diag) {
+bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) {
   // Load the manifest
   std::unique_ptr<xml::XmlResource> doc = apk_->LoadXml("AndroidManifest.xml", diag);
   if (doc == nullptr) {
@@ -1775,7 +1768,7 @@
         }
       }
 
-      printer.Print(StringPrintf("package: %s\n", manifest->package.data()));
+      printer->Print(StringPrintf("package: %s\n", manifest->package.data()));
       ForEachChild(manifest, [&printer](ManifestExtractor::Element* el) -> void {
         el->Print(printer);
       });
@@ -1992,7 +1985,7 @@
   // Print the components types if they are present
   auto PrintComponent = [&components, &printer](const std::string& component) -> void {
     if (components.find(component) != components.end()) {
-      printer.Print(StringPrintf("provides-component:'%s'\n", component.data()));
+      printer->Print(StringPrintf("provides-component:'%s'\n", component.data()));
     }
   };
 
@@ -2013,14 +2006,14 @@
 
   // Print presence of main activity
   if (components.find("main") != components.end()) {
-    printer.Print("main\n");
+    printer->Print("main\n");
   }
 
   // Print presence of activities, recivers, and services with no special components
   FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
     if (auto activity = ElementCast<Activity>(el)) {
       if (!activity->has_component_) {
-        printer.Print("other-activities\n");
+        printer->Print("other-activities\n");
         return true;
       }
     }
@@ -2030,7 +2023,7 @@
   FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
     if (auto receiver = ElementCast<Receiver>(el)) {
       if (!receiver->has_component) {
-        printer.Print("other-receivers\n");
+        printer->Print("other-receivers\n");
         return true;
       }
     }
@@ -2040,7 +2033,7 @@
   FindElement(root.get(), [&printer](ManifestExtractor::Element* el) -> bool {
     if (auto service = ElementCast<Service>(el)) {
       if (!service->has_component) {
-        printer.Print("other-services\n");
+        printer->Print("other-services\n");
         return true;
       }
     }
@@ -2062,22 +2055,22 @@
   }
 
   // Print all the unique locales of the apk
-  printer.Print("locales:");
+  printer->Print("locales:");
   for (auto& config : locales_) {
     if (config.first.empty()) {
-      printer.Print(" '--_--'");
+      printer->Print(" '--_--'");
     } else {
-      printer.Print(StringPrintf(" '%s'", config.first.data()));
+      printer->Print(StringPrintf(" '%s'", config.first.data()));
     }
   }
-  printer.Print("\n");
+  printer->Print("\n");
 
   // Print all the densities locales of the apk
-  printer.Print("densities:");
+  printer->Print("densities:");
   for (auto& config : densities_) {
-    printer.Print(StringPrintf(" '%d'", config.first));
+    printer->Print(StringPrintf(" '%d'", config.first));
   }
-  printer.Print("\n");
+  printer->Print("\n");
 
   // Print the supported architectures of the app
   std::set<std::string> architectures;
@@ -2131,7 +2124,7 @@
     }
 
     if (arch != architectures.end()) {
-      printer.Print(StringPrintf("native-code: '%s'\n", arch->data()));
+      printer->Print(StringPrintf("native-code: '%s'\n", arch->data()));
       architectures.erase(arch);
       output_alt_native_code = true;
     }
@@ -2139,13 +2132,13 @@
 
   if (architectures.size() > 0) {
     if (output_alt_native_code) {
-      printer.Print("alt-");
+      printer->Print("alt-");
     }
-    printer.Print("native-code:");
+    printer->Print("native-code:");
     for (auto& arch : architectures) {
-      printer.Print(StringPrintf(" '%s'", arch.data()));
+      printer->Print(StringPrintf(" '%s'", arch.data()));
     }
-    printer.Print("\n");
+    printer->Print("\n");
   }
 
   return true;
@@ -2272,55 +2265,11 @@
   return element;
 }
 
-// Use a smaller buffer so that there is less latency for dumping to stdout.
-constexpr size_t kStdOutBufferSize = 1024u;
 
-int DumpBadgingCommand::Action(const std::vector<std::string>& args) {
-  if (args.size() < 1) {
-    diag_->Error(DiagMessage() << "No dump apk specified.");
-    return 1;
-  }
-
-  ManifestExtractor::Options options;
-  options.include_meta_data = include_metadata_;
-
-  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
-  text::Printer printer(&fout);
-  for (auto apk : args) {
-    auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
-    if (!loaded_apk) {
-      return 1;
-    }
-
-    ManifestExtractor extractor(loaded_apk.get(), options);
-    extractor.Dump(printer, diag_);
-  }
-
-  return 0;
-}
-
-int DumpPermissionsCommand::Action(const std::vector<std::string>& args) {
-  if (args.size() < 1) {
-    diag_->Error(DiagMessage() << "No dump apk specified.");
-    return 1;
-  }
-
-  ManifestExtractor::Options options;
-  options.only_permissions = true;
-
-  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
-  text::Printer printer(&fout);
-  for (auto apk : args) {
-    auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_);
-    if (!loaded_apk) {
-      return 1;
-    }
-
-    ManifestExtractor extractor(loaded_apk.get(), options);
-    extractor.Dump(printer, diag_);
-  }
-
-  return 0;
+int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
+                 IDiagnostics* diag) {
+  ManifestExtractor extractor(apk, options);
+  return extractor.Dump(printer, diag);
 }
 
 } // namespace aapt
diff --git a/tools/aapt2/dump/DumpManifest.h b/tools/aapt2/dump/DumpManifest.h
index a70be53..daf22ed 100644
--- a/tools/aapt2/dump/DumpManifest.h
+++ b/tools/aapt2/dump/DumpManifest.h
@@ -17,45 +17,23 @@
 #ifndef AAPT2_DUMP_MANIFEST_H
 #define AAPT2_DUMP_MANIFEST_H
 
-#include <Diagnostics.h>
-#include <ValueVisitor.h>
-#include <io/ZipArchive.h>
-
-
-#include "cmd/Command.h"
-#include "process/IResourceTableConsumer.h"
+#include "Diagnostics.h"
+#include "LoadedApk.h"
 #include "text/Printer.h"
-#include "xml/XmlDom.h"
 
 namespace aapt {
 
-class DumpBadgingCommand : public Command {
- public:
-  explicit DumpBadgingCommand(IDiagnostics* diag) : Command("badging"), diag_(diag) {
-    SetDescription("Print information extracted from the manifest of the APK.");
-    AddOptionalSwitch("--include-meta-data", "Include meta-data information.",
-                      &include_metadata_);
-  }
-
-  int Action(const std::vector<std::string>& args) override;
-
- private:
-  IDiagnostics* diag_;
-  bool include_metadata_ = false;
+struct DumpManifestOptions {
+  /** Include meta information from <meta-data> elements in the output. */
+  bool include_meta_data = false;
+  /** Only output permission information. */
+  bool only_permissions = false;
 };
 
-class DumpPermissionsCommand : public Command {
- public:
-  explicit DumpPermissionsCommand(IDiagnostics* diag) : Command("permissions"), diag_(diag) {
-    SetDescription("Print the permissions extracted from the manifest of the APK.");
-  }
+/** Print information extracted from the manifest of the APK. */
+int DumpManifest(LoadedApk* apk, DumpManifestOptions& options, text::Printer* printer,
+                 IDiagnostics* diag);
 
-  int Action(const std::vector<std::string>& args) override;
+}  // namespace aapt
 
- private:
-  IDiagnostics* diag_;
-};
-
-}// namespace aapt
-
-#endif //AAPT2_DUMP_MANIFEST_H
\ No newline at end of file
+#endif  // AAPT2_DUMP_MANIFEST_H
\ No newline at end of file
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 5c9df6a..c7993e3 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
@@ -189,8 +189,7 @@
         Map<String, Long> homeNetworkIds = new HashMap<>();
         byte[] rawSsidBytes = new byte[33];
         Arrays.fill(rawSsidBytes, (byte) 'a');
-        homeNetworkIds.put(
-                StringFactory.newStringFromBytes(rawSsidBytes, StandardCharsets.UTF_8), 0x1234L);
+        homeNetworkIds.put(new String(rawSsidBytes, StandardCharsets.UTF_8), 0x1234L);
         homeSp.setHomeNetworkIds(homeNetworkIds);
         assertFalse(homeSp.validate());
     }