Merge "Address API review comments"
diff --git a/Android.bp b/Android.bp
index e8f3561..f4e8b63 100644
--- a/Android.bp
+++ b/Android.bp
@@ -225,6 +225,7 @@
         "core/java/android/net/INetworkScoreService.aidl",
         "core/java/android/net/INetworkStatsService.aidl",
         "core/java/android/net/INetworkStatsSession.aidl",
+        "core/java/android/net/ISocketKeepaliveCallback.aidl",
         "core/java/android/net/ITestNetworkManager.aidl",
         "core/java/android/net/ITetheringEventCallback.aidl",
         "core/java/android/net/ITetheringStatsProvider.aidl",
@@ -736,7 +737,7 @@
         "updatable_media_stubs",
     ],
 
-    jarjar_rules: "jarjar_rules_hidl.txt",
+    jarjar_rules: ":framework-jarjar-rules",
 
     static_libs: [
         "apex_aidl_interface-java",
@@ -789,6 +790,11 @@
 }
 
 filegroup {
+    name: "framework-jarjar-rules",
+    srcs: ["jarjar_rules_hidl.txt"],
+}
+
+filegroup {
     name: "libincident_aidl",
     srcs: [
         "core/java/android/os/IIncidentManager.aidl",
diff --git a/api/current.txt b/api/current.txt
index 265d932..d1b77f2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4263,24 +4263,24 @@
   }
 
   public class AppOpsManager {
-    method @Deprecated public int checkOp(String, int, String);
-    method @Deprecated public int checkOpNoThrow(String, int, String);
-    method public void checkPackage(int, String);
-    method public void finishOp(String, int, String);
-    method public int noteOp(String, int, String);
-    method public int noteOpNoThrow(String, int, String);
-    method public int noteProxyOp(String, String);
-    method public int noteProxyOpNoThrow(String, String);
+    method @Deprecated public int checkOp(@NonNull String, int, @NonNull String);
+    method @Deprecated public int checkOpNoThrow(@NonNull String, int, @NonNull String);
+    method public void checkPackage(int, @NonNull String);
+    method public void finishOp(@NonNull String, int, @NonNull String);
+    method public int noteOp(@NonNull String, int, @NonNull String);
+    method public int noteOpNoThrow(@NonNull String, int, @NonNull String);
+    method public int noteProxyOp(@NonNull String, @NonNull String);
+    method public int noteProxyOpNoThrow(@NonNull String, @NonNull String);
     method public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int);
     method public static String permissionToOp(String);
-    method public int startOp(String, int, String);
-    method public int startOpNoThrow(String, int, String);
-    method public void startWatchingMode(String, String, android.app.AppOpsManager.OnOpChangedListener);
-    method public void startWatchingMode(String, String, int, android.app.AppOpsManager.OnOpChangedListener);
-    method public void stopWatchingMode(android.app.AppOpsManager.OnOpChangedListener);
-    method public int unsafeCheckOp(String, int, String);
-    method public int unsafeCheckOpNoThrow(String, int, String);
-    method public int unsafeCheckOpRaw(@NonNull String, int, String);
+    method public int startOp(@NonNull String, int, @NonNull String);
+    method public int startOpNoThrow(@NonNull String, int, @NonNull String);
+    method public void startWatchingMode(@NonNull String, @Nullable String, @NonNull android.app.AppOpsManager.OnOpChangedListener);
+    method public void startWatchingMode(@NonNull String, @Nullable String, int, @NonNull android.app.AppOpsManager.OnOpChangedListener);
+    method public void stopWatchingMode(@NonNull android.app.AppOpsManager.OnOpChangedListener);
+    method public int unsafeCheckOp(@NonNull String, int, @NonNull String);
+    method public int unsafeCheckOpNoThrow(@NonNull String, int, @NonNull String);
+    method public int unsafeCheckOpRaw(@NonNull String, int, @NonNull String);
     method public int unsafeCheckOpRawNoThrow(@NonNull String, int, @NonNull String);
     field public static final int MODE_ALLOWED = 0; // 0x0
     field public static final int MODE_DEFAULT = 3; // 0x3
@@ -6641,7 +6641,7 @@
     method @NonNull public java.util.List<java.lang.String> getDelegatedScopes(@Nullable android.content.ComponentName, @NonNull String);
     method public CharSequence getDeviceOwnerLockScreenInfo();
     method public CharSequence getEndUserSessionMessage(@NonNull android.content.ComponentName);
-    method public String getGlobalPrivateDnsHost(@NonNull android.content.ComponentName);
+    method @Nullable public String getGlobalPrivateDnsHost(@NonNull android.content.ComponentName);
     method public int getGlobalPrivateDnsMode(@NonNull android.content.ComponentName);
     method @NonNull public java.util.List<byte[]> getInstalledCaCerts(@Nullable android.content.ComponentName);
     method @Nullable public java.util.List<java.lang.String> getKeepUninstalledPackages(@Nullable android.content.ComponentName);
@@ -7966,9 +7966,9 @@
     method public boolean isMultipleAdvertisementSupported();
     method public boolean isOffloadedFilteringSupported();
     method public boolean isOffloadedScanBatchingSupported();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothServerSocket listenUsingInsecureL2capChannel() throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothServerSocket listenUsingL2capChannel() throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothServerSocket listenUsingRfcommWithServiceRecord(String, java.util.UUID) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setName(String);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean startDiscovery();
@@ -8336,9 +8336,9 @@
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
     method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean createBond();
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothSocket createInsecureL2capChannel(int) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
-    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
+    method @RequiresPermission(android.Manifest.permission.BLUETOOTH) @NonNull public android.bluetooth.BluetoothSocket createL2capChannel(int) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
     method public int describeContents();
     method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean fetchUuidsWithSdp();
@@ -15802,7 +15802,7 @@
     ctor public Font.Builder(@NonNull android.os.ParcelFileDescriptor, @IntRange(from=0) long, @IntRange(from=0xffffffff) long);
     ctor public Font.Builder(@NonNull android.content.res.AssetManager, @NonNull String);
     ctor public Font.Builder(@NonNull android.content.res.Resources, int);
-    method @Nullable public android.graphics.fonts.Font build() throws java.io.IOException;
+    method @NonNull public android.graphics.fonts.Font build() throws java.io.IOException;
     method @NonNull public android.graphics.fonts.Font.Builder setFontVariationSettings(@Nullable String);
     method @NonNull public android.graphics.fonts.Font.Builder setFontVariationSettings(@Nullable android.graphics.fonts.FontVariationAxis[]);
     method @NonNull public android.graphics.fonts.Font.Builder setSlant(int);
@@ -15929,13 +15929,13 @@
 
   public static class LineBreaker.ParagraphConstraints {
     ctor public LineBreaker.ParagraphConstraints();
-    method @Px @IntRange(from=0) public int getDefaultTabStop();
+    method @Px @FloatRange(from=0) public float getDefaultTabStop();
     method @Px @FloatRange(from=0.0f) public float getFirstWidth();
     method @Px @IntRange(from=0) public int getFirstWidthLineCount();
-    method @Nullable public int[] getTabStops();
+    method @Nullable public float[] getTabStops();
     method @Px @FloatRange(from=0.0f) public float getWidth();
     method public void setIndent(@Px @FloatRange(from=0.0f) float, @Px @IntRange(from=0) int);
-    method public void setTabStops(@Nullable int[], @Px @IntRange(from=0) int);
+    method public void setTabStops(@Nullable float[], @Px @FloatRange(from=0) float);
     method public void setWidth(@Px @FloatRange(from=0.0f) float);
   }
 
@@ -22693,10 +22693,9 @@
     method @Deprecated public double getCarrierPhase();
     method @Deprecated public double getCarrierPhaseUncertainty();
     method public double getCn0DbHz();
-    method public int getCodeType();
+    method @NonNull public String getCodeType();
     method public int getConstellationType();
     method public int getMultipathIndicator();
-    method @NonNull public String getOtherCodeTypeName();
     method public double getPseudorangeRateMetersPerSecond();
     method public double getPseudorangeRateUncertaintyMetersPerSecond();
     method public long getReceivedSvTimeNanos();
@@ -22719,22 +22718,6 @@
     field public static final int ADR_STATE_RESET = 2; // 0x2
     field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
     field public static final int ADR_STATE_VALID = 1; // 0x1
-    field public static final int CODE_TYPE_A = 0; // 0x0
-    field public static final int CODE_TYPE_B = 1; // 0x1
-    field public static final int CODE_TYPE_C = 2; // 0x2
-    field public static final int CODE_TYPE_I = 3; // 0x3
-    field public static final int CODE_TYPE_L = 4; // 0x4
-    field public static final int CODE_TYPE_M = 5; // 0x5
-    field public static final int CODE_TYPE_N = 13; // 0xd
-    field public static final int CODE_TYPE_OTHER = 255; // 0xff
-    field public static final int CODE_TYPE_P = 6; // 0x6
-    field public static final int CODE_TYPE_Q = 7; // 0x7
-    field public static final int CODE_TYPE_S = 8; // 0x8
-    field public static final int CODE_TYPE_UNKNOWN = -1; // 0xffffffff
-    field public static final int CODE_TYPE_W = 9; // 0x9
-    field public static final int CODE_TYPE_X = 10; // 0xa
-    field public static final int CODE_TYPE_Y = 11; // 0xb
-    field public static final int CODE_TYPE_Z = 12; // 0xc
     field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
     field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
     field public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; // 0x2
@@ -22850,6 +22833,24 @@
     method @Deprecated public boolean usedInFix();
   }
 
+  @Deprecated public final class GpsStatus {
+    method @Deprecated public int getMaxSatellites();
+    method @Deprecated public Iterable<android.location.GpsSatellite> getSatellites();
+    method @Deprecated public int getTimeToFirstFix();
+    field @Deprecated public static final int GPS_EVENT_FIRST_FIX = 3; // 0x3
+    field @Deprecated public static final int GPS_EVENT_SATELLITE_STATUS = 4; // 0x4
+    field @Deprecated public static final int GPS_EVENT_STARTED = 1; // 0x1
+    field @Deprecated public static final int GPS_EVENT_STOPPED = 2; // 0x2
+  }
+
+  @Deprecated public static interface GpsStatus.Listener {
+    method @Deprecated public void onGpsStatusChanged(int);
+  }
+
+  @Deprecated public static interface GpsStatus.NmeaListener {
+    method @Deprecated public void onNmeaReceived(long, String);
+  }
+
   public class Location implements android.os.Parcelable {
     ctor public Location(String);
     ctor public Location(android.location.Location);
@@ -22918,6 +22919,7 @@
   }
 
   public class LocationManager {
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(@NonNull android.location.OnNmeaMessageListener, @Nullable android.os.Handler);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void addProximityAlert(double, double, float, long, @NonNull android.app.PendingIntent);
@@ -22929,6 +22931,7 @@
     method @Nullable public String getBestProvider(@NonNull android.location.Criteria, boolean);
     method @Nullable public String getGnssHardwareModelName();
     method public int getGnssYearOfHardware();
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GpsStatus getGpsStatus(@Nullable android.location.GpsStatus);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) @Nullable public android.location.Location getLastKnownLocation(@NonNull String);
     method @Nullable public android.location.LocationProvider getProvider(@NonNull String);
     method @NonNull public java.util.List<java.lang.String> getProviders(boolean);
@@ -22941,6 +22944,7 @@
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssStatusCallback(@NonNull android.location.GnssStatus.Callback, @Nullable android.os.Handler);
+    method @Deprecated public void removeGpsStatusListener(android.location.GpsStatus.Listener);
     method public void removeNmeaListener(@NonNull android.location.OnNmeaMessageListener);
     method @RequiresPermission(anyOf={"android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION"}, apis="..22") public void removeProximityAlert(@NonNull android.app.PendingIntent);
     method public void removeTestProvider(@NonNull String);
@@ -24753,6 +24757,10 @@
 
   public final class MediaDrm implements java.lang.AutoCloseable {
     ctor public MediaDrm(@NonNull java.util.UUID) throws android.media.UnsupportedSchemeException;
+    method public void clearOnEventListener();
+    method public void clearOnExpirationUpdateListener();
+    method public void clearOnKeyStatusChangeListener();
+    method public void clearOnSessionLostStateListener();
     method public void close();
     method public void closeSession(@NonNull byte[]);
     method @android.media.MediaDrm.HdcpLevel public int getConnectedHdcpLevel();
@@ -24789,9 +24797,14 @@
     method public void removeSecureStop(@NonNull byte[]);
     method public void restoreKeys(@NonNull byte[], @NonNull byte[]);
     method public void setOnEventListener(@Nullable android.media.MediaDrm.OnEventListener);
+    method public void setOnEventListener(@Nullable android.media.MediaDrm.OnEventListener, @Nullable android.os.Handler);
+    method public void setOnEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaDrm.OnEventListener);
     method public void setOnExpirationUpdateListener(@Nullable android.media.MediaDrm.OnExpirationUpdateListener, @Nullable android.os.Handler);
+    method public void setOnExpirationUpdateListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaDrm.OnExpirationUpdateListener);
     method public void setOnKeyStatusChangeListener(@Nullable android.media.MediaDrm.OnKeyStatusChangeListener, @Nullable android.os.Handler);
+    method public void setOnKeyStatusChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaDrm.OnKeyStatusChangeListener);
     method public void setOnSessionLostStateListener(@Nullable android.media.MediaDrm.OnSessionLostStateListener, @Nullable android.os.Handler);
+    method public void setOnSessionLostStateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaDrm.OnSessionLostStateListener);
     method public void setPropertyByteArray(@NonNull String, @NonNull byte[]);
     method public void setPropertyString(@NonNull String, @NonNull String);
     field @Deprecated public static final int EVENT_KEY_EXPIRED = 3; // 0x3
@@ -24833,7 +24846,7 @@
     method public boolean verify(@NonNull byte[], @NonNull byte[], @NonNull byte[]);
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.media.MediaDrm.HDCP_LEVEL_UNKNOWN, android.media.MediaDrm.HDCP_NONE, android.media.MediaDrm.HDCP_V1, android.media.MediaDrm.HDCP_V2, android.media.MediaDrm.HDCP_V2_1, android.media.MediaDrm.HDCP_V2_2, android.media.MediaDrm.HDCP_V2_3, android.media.MediaDrm.HDCP_NO_DIGITAL_OUTPUT}) public static @interface MediaDrm.HdcpLevel {
+  @Deprecated @IntDef({android.media.MediaDrm.HDCP_LEVEL_UNKNOWN, android.media.MediaDrm.HDCP_NONE, android.media.MediaDrm.HDCP_V1, android.media.MediaDrm.HDCP_V2, android.media.MediaDrm.HDCP_V2_1, android.media.MediaDrm.HDCP_V2_2, android.media.MediaDrm.HDCP_V2_3, android.media.MediaDrm.HDCP_NO_DIGITAL_OUTPUT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MediaDrm.HdcpLevel {
   }
 
   public static final class MediaDrm.KeyRequest {
@@ -24920,7 +24933,7 @@
     method @NonNull public String getDefaultUrl();
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.media.MediaDrm.SECURITY_LEVEL_UNKNOWN, android.media.MediaDrm.SECURITY_LEVEL_SW_SECURE_CRYPTO, android.media.MediaDrm.SECURITY_LEVEL_SW_SECURE_DECODE, android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_CRYPTO, android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_DECODE, android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_ALL}) public static @interface MediaDrm.SecurityLevel {
+  @Deprecated @IntDef({android.media.MediaDrm.SECURITY_LEVEL_UNKNOWN, android.media.MediaDrm.SECURITY_LEVEL_SW_SECURE_CRYPTO, android.media.MediaDrm.SECURITY_LEVEL_SW_SECURE_DECODE, android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_CRYPTO, android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_DECODE, android.media.MediaDrm.SECURITY_LEVEL_HW_SECURE_ALL}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MediaDrm.SecurityLevel {
   }
 
   public static final class MediaDrm.SessionException extends java.lang.RuntimeException {
@@ -26412,7 +26425,7 @@
   public final class Session2Token implements android.os.Parcelable {
     ctor public Session2Token(@NonNull android.content.Context, @NonNull android.content.ComponentName);
     method public int describeContents();
-    method @Nullable public android.os.Bundle getExtras();
+    method @NonNull public android.os.Bundle getExtras();
     method @NonNull public String getPackageName();
     method @Nullable public String getServiceName();
     method public int getType();
@@ -30111,8 +30124,8 @@
     method @NonNull public android.net.wifi.WifiNetworkSpecifier build();
     method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setBssid(@NonNull android.net.MacAddress);
     method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setBssidPattern(@NonNull android.net.MacAddress, @NonNull android.net.MacAddress);
-    method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setIsEnhancedOpen();
-    method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setIsHiddenSsid();
+    method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setIsEnhancedOpen(boolean);
+    method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setIsHiddenSsid(boolean);
     method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setSsid(@NonNull String);
     method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setSsidPattern(@NonNull android.os.PatternMatcher);
     method @NonNull public android.net.wifi.WifiNetworkSpecifier.Builder setWpa2EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
@@ -30131,12 +30144,12 @@
     ctor public WifiNetworkSuggestion.Builder();
     method @NonNull public android.net.wifi.WifiNetworkSuggestion build();
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setBssid(@NonNull android.net.MacAddress);
-    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsAppInteractionRequired();
-    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedOpen();
-    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsHiddenSsid();
-    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsMetered();
-    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired();
-    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(int);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsAppInteractionRequired(boolean);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedOpen(boolean);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsHiddenSsid(boolean);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsMetered(boolean);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
+    method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSsid(@NonNull String);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa2EnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
     method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWpa2Passphrase(@NonNull String);
@@ -38993,12 +39006,10 @@
     method public static long getLong(android.content.ContentResolver, String) throws android.provider.Settings.SettingNotFoundException;
     method public static String getString(android.content.ContentResolver, String);
     method public static android.net.Uri getUriFor(String);
-    method @Deprecated public static boolean isLocationProviderEnabled(android.content.ContentResolver, String);
     method public static boolean putFloat(android.content.ContentResolver, String, float);
     method public static boolean putInt(android.content.ContentResolver, String, int);
     method public static boolean putLong(android.content.ContentResolver, String, long);
     method public static boolean putString(android.content.ContentResolver, String, String);
-    method @Deprecated public static void setLocationProviderEnabled(android.content.ContentResolver, String, boolean);
     field public static final String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED = "accessibility_display_inversion_enabled";
     field public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
     field @Deprecated public static final String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
@@ -43336,9 +43347,9 @@
   public abstract class CallRedirectionService extends android.app.Service {
     ctor public CallRedirectionService();
     method public final void cancelCall();
-    method public final android.os.IBinder onBind(android.content.Intent);
+    method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method public abstract void onPlaceCall(@NonNull android.net.Uri, @NonNull android.telecom.PhoneAccountHandle, boolean);
-    method public final boolean onUnbind(android.content.Intent);
+    method public final boolean onUnbind(@NonNull android.content.Intent);
     method public final void placeCallUnmodified();
     method public final void redirectCall(@NonNull android.net.Uri, @NonNull android.telecom.PhoneAccountHandle, boolean);
     field public static final String SERVICE_INTERFACE = "android.telecom.CallRedirectionService";
@@ -44401,12 +44412,12 @@
   }
 
   public final class CellIdentityNr extends android.telephony.CellIdentity {
-    method public String getMccString();
-    method public String getMncString();
+    method @Nullable public String getMccString();
+    method @Nullable public String getMncString();
     method public long getNci();
-    method public int getNrarfcn();
-    method public int getPci();
-    method public int getTac();
+    method @IntRange(from=0, to=3279165) public int getNrarfcn();
+    method @IntRange(from=0, to=1007) public int getPci();
+    method @IntRange(from=0, to=65535) public int getTac();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellIdentityNr> CREATOR;
   }
@@ -44473,8 +44484,8 @@
   }
 
   public final class CellInfoNr extends android.telephony.CellInfo {
-    method public android.telephony.CellIdentity getCellIdentity();
-    method public android.telephony.CellSignalStrength getCellSignalStrength();
+    method @NonNull public android.telephony.CellIdentity getCellIdentity();
+    method @NonNull public android.telephony.CellSignalStrength getCellSignalStrength();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoNr> CREATOR;
   }
@@ -45455,26 +45466,26 @@
   public static class ApnSetting.Builder {
     ctor public ApnSetting.Builder();
     method public android.telephony.data.ApnSetting build();
-    method public android.telephony.data.ApnSetting.Builder setApnName(String);
-    method public android.telephony.data.ApnSetting.Builder setApnTypeBitmask(int);
-    method public android.telephony.data.ApnSetting.Builder setAuthType(int);
-    method public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setApnName(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setApnTypeBitmask(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setAuthType(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setCarrierEnabled(boolean);
     method @NonNull public android.telephony.data.ApnSetting.Builder setCarrierId(int);
-    method public android.telephony.data.ApnSetting.Builder setEntryName(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setEntryName(String);
     method @Deprecated public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(java.net.InetAddress);
-    method public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(String);
-    method public android.telephony.data.ApnSetting.Builder setMmsProxyPort(int);
-    method public android.telephony.data.ApnSetting.Builder setMmsc(android.net.Uri);
-    method public android.telephony.data.ApnSetting.Builder setMvnoType(int);
-    method public android.telephony.data.ApnSetting.Builder setNetworkTypeBitmask(int);
-    method public android.telephony.data.ApnSetting.Builder setOperatorNumeric(String);
-    method public android.telephony.data.ApnSetting.Builder setPassword(String);
-    method public android.telephony.data.ApnSetting.Builder setProtocol(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setMmsProxyAddress(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setMmsProxyPort(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setMmsc(android.net.Uri);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setMvnoType(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setNetworkTypeBitmask(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setOperatorNumeric(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setPassword(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setProtocol(int);
     method @Deprecated public android.telephony.data.ApnSetting.Builder setProxyAddress(java.net.InetAddress);
-    method public android.telephony.data.ApnSetting.Builder setProxyAddress(String);
-    method public android.telephony.data.ApnSetting.Builder setProxyPort(int);
-    method public android.telephony.data.ApnSetting.Builder setRoamingProtocol(int);
-    method public android.telephony.data.ApnSetting.Builder setUser(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setProxyAddress(String);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setProxyPort(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setRoamingProtocol(int);
+    method @NonNull public android.telephony.data.ApnSetting.Builder setUser(String);
   }
 
 }
@@ -45543,7 +45554,7 @@
     method public boolean isEnabled();
     method public void startResolutionActivity(android.app.Activity, int, android.content.Intent, android.app.PendingIntent) throws android.content.IntentSender.SendIntentException;
     method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, android.app.PendingIntent);
-    method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void updateSubscriptionNickname(int, String, android.app.PendingIntent);
+    method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void updateSubscriptionNickname(int, @Nullable String, @NonNull android.app.PendingIntent);
     field public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
     field public static final String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
     field public static final int EMBEDDED_SUBSCRIPTION_RESULT_ERROR = 2; // 0x2
@@ -50346,6 +50357,7 @@
     method @IdRes public int getAccessibilityTraversalBefore();
     method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getAlpha();
     method public android.view.animation.Animation getAnimation();
+    method @Nullable public android.graphics.Matrix getAnimationMatrix();
     method public android.os.IBinder getApplicationWindowToken();
     method @NonNull public int[] getAttributeResolutionStack(@AttrRes int);
     method @NonNull public java.util.Map<java.lang.Integer,java.lang.Integer> getAttributeSourceResourceMap();
@@ -53479,27 +53491,12 @@
     method @Nullable public <T> android.view.inspector.InspectionCompanion<T> provide(@NonNull Class<T>);
   }
 
-  public final class IntEnumMapping {
-    method @Nullable public String get(int);
-  }
-
-  public static final class IntEnumMapping.Builder {
-    ctor public IntEnumMapping.Builder();
-    method @NonNull public android.view.inspector.IntEnumMapping.Builder addValue(@NonNull String, int);
-    method @NonNull public android.view.inspector.IntEnumMapping build();
-  }
-
   public final class IntFlagMapping {
+    ctor public IntFlagMapping();
+    method public void add(int, int, @NonNull String);
     method @NonNull public java.util.Set<java.lang.String> get(int);
   }
 
-  public static final class IntFlagMapping.Builder {
-    ctor public IntFlagMapping.Builder();
-    method @NonNull public android.view.inspector.IntFlagMapping.Builder addFlag(@NonNull String, int);
-    method @NonNull public android.view.inspector.IntFlagMapping.Builder addFlag(@NonNull String, int, int);
-    method @NonNull public android.view.inspector.IntFlagMapping build();
-  }
-
   public interface PropertyMapper {
     method public int mapBoolean(@NonNull String, @AttrRes int);
     method public int mapByte(@NonNull String, @AttrRes int);
@@ -53509,8 +53506,8 @@
     method public int mapFloat(@NonNull String, @AttrRes int);
     method public int mapGravity(@NonNull String, @AttrRes int);
     method public int mapInt(@NonNull String, @AttrRes int);
-    method public int mapIntEnum(@NonNull String, @AttrRes int, @NonNull android.view.inspector.IntEnumMapping);
-    method public int mapIntFlag(@NonNull String, @AttrRes int, @NonNull android.view.inspector.IntFlagMapping);
+    method public int mapIntEnum(@NonNull String, @AttrRes int, @NonNull java.util.function.IntFunction<java.lang.String>);
+    method public int mapIntFlag(@NonNull String, @AttrRes int, @NonNull java.util.function.IntFunction<java.util.Set<java.lang.String>>);
     method public int mapLong(@NonNull String, @AttrRes int);
     method public int mapObject(@NonNull String, @AttrRes int);
     method public int mapResourceId(@NonNull String, @AttrRes int);
@@ -56385,10 +56382,12 @@
     method public int getWindowLayoutType();
     method public boolean isAboveAnchor();
     method public boolean isAttachedInDecor();
-    method public boolean isClipToScreenEnabled();
+    method @Deprecated public boolean isClipToScreenEnabled();
+    method public boolean isClippedToScreen();
     method public boolean isClippingEnabled();
     method public boolean isFocusable();
-    method public boolean isLayoutInScreenEnabled();
+    method public boolean isLaidOutInScreen();
+    method @Deprecated public boolean isLayoutInScreenEnabled();
     method public boolean isOutsideTouchable();
     method public boolean isShowing();
     method public boolean isSplitTouchEnabled();
@@ -56397,7 +56396,7 @@
     method public void setAnimationStyle(int);
     method public void setAttachedInDecor(boolean);
     method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setClipToScreenEnabled(boolean);
+    method @Deprecated public void setClipToScreenEnabled(boolean);
     method public void setClippingEnabled(boolean);
     method public void setContentView(android.view.View);
     method public void setElevation(float);
@@ -56408,7 +56407,9 @@
     method public void setHeight(int);
     method public void setIgnoreCheekPress();
     method public void setInputMethodMode(int);
-    method public void setLayoutInScreenEnabled(boolean);
+    method public void setIsClippedToScreen(boolean);
+    method public void setIsLaidOutInScreen(boolean);
+    method @Deprecated public void setLayoutInScreenEnabled(boolean);
     method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener);
     method public void setOutsideTouchable(boolean);
     method public void setOverlapAnchor(boolean);
diff --git a/api/removed.txt b/api/removed.txt
index 93d06928..5108dd0 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -282,24 +282,6 @@
 
 package android.location {
 
-  @Deprecated public final class GpsStatus {
-    method public int getMaxSatellites();
-    method public Iterable<android.location.GpsSatellite> getSatellites();
-    method public int getTimeToFirstFix();
-    field public static final int GPS_EVENT_FIRST_FIX = 3; // 0x3
-    field public static final int GPS_EVENT_SATELLITE_STATUS = 4; // 0x4
-    field public static final int GPS_EVENT_STARTED = 1; // 0x1
-    field public static final int GPS_EVENT_STOPPED = 2; // 0x2
-  }
-
-  @Deprecated public static interface GpsStatus.Listener {
-    method public void onGpsStatusChanged(int);
-  }
-
-  @Deprecated public static interface GpsStatus.NmeaListener {
-    method public void onNmeaReceived(long, String);
-  }
-
   public class Location implements android.os.Parcelable {
     method @Deprecated public void removeBearingAccuracy();
     method @Deprecated public void removeSpeedAccuracy();
@@ -307,10 +289,7 @@
   }
 
   public class LocationManager {
-    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
-    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.location.GpsStatus getGpsStatus(@Nullable android.location.GpsStatus);
-    method @Deprecated public void removeGpsStatusListener(android.location.GpsStatus.Listener);
     method @Deprecated public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
   }
 
@@ -574,6 +553,11 @@
     field @Deprecated public static final String CONTACT_METADATA_SYNC = "contact_metadata_sync";
   }
 
+  public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
+    method @Deprecated public static boolean isLocationProviderEnabled(android.content.ContentResolver, String);
+    method @Deprecated public static void setLocationProviderEnabled(android.content.ContentResolver, String, boolean);
+  }
+
   public static final class Settings.System extends android.provider.Settings.NameValueTable {
     field public static final String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
     field public static final String VOLUME_ALARM = "volume_alarm";
diff --git a/api/system-current.txt b/api/system-current.txt
index 30cc3a5..61a7f58 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -312,7 +312,7 @@
   public class AppOpsManager {
     method @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public void getHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
     method public static String[] getOpStrs();
-    method @Deprecated @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, String, int[]);
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable int[]);
     method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable java.lang.String...);
     method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[]);
     method public static int opToDefaultMode(@NonNull String);
@@ -465,7 +465,7 @@
 
   public static final class AppOpsManager.PackageOps implements android.os.Parcelable {
     method public int describeContents();
-    method public java.util.List<android.app.AppOpsManager.OpEntry> getOps();
+    method @NonNull public java.util.List<android.app.AppOpsManager.OpEntry> getOps();
     method @NonNull public String getPackageName();
     method public int getUid();
     method public void writeToParcel(android.os.Parcel, int);
@@ -546,10 +546,8 @@
 
   public class NotificationManager {
     method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
-    method @Nullable public android.content.ComponentName getAllowedNotificationAssistantForUser(@NonNull android.os.UserHandle);
     method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
     method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
-    method public void setNotificationAssistantAccessGrantedForUser(@Nullable android.content.ComponentName, @NonNull android.os.UserHandle, boolean);
   }
 
   public final class StatsManager {
@@ -680,7 +678,7 @@
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
     method @Deprecated @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
-    method @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIdsForUser(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
+    method @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
     field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
     field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
     field public static final String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION";
@@ -985,6 +983,7 @@
 
   public final class ContentSuggestionsManager {
     method public void classifyContentSelections(@NonNull android.app.contentsuggestions.ClassificationsRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.contentsuggestions.ContentSuggestionsManager.ClassificationsCallback);
+    method public boolean isEnabled();
     method public void notifyInteraction(@NonNull String, @NonNull android.os.Bundle);
     method public void provideContextImage(int, @NonNull android.os.Bundle);
     method public void suggestContentSelections(@NonNull android.app.contentsuggestions.SelectionsRequest, @NonNull java.util.concurrent.Executor, @NonNull android.app.contentsuggestions.ContentSuggestionsManager.SelectionsCallback);
@@ -1030,22 +1029,22 @@
     method public int describeContents();
     method @Nullable public android.os.Bundle getExtras();
     method @NonNull public String getPackageName();
-    method public int getPredictedTargetCount();
-    method public String getUiSurface();
-    method public void writeToParcel(android.os.Parcel, int);
+    method @IntRange(from=0) public int getPredictedTargetCount();
+    method @NonNull public String getUiSurface();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.prediction.AppPredictionContext> CREATOR;
   }
 
   public static final class AppPredictionContext.Builder {
     ctor public AppPredictionContext.Builder(@NonNull android.content.Context);
-    method public android.app.prediction.AppPredictionContext build();
-    method public android.app.prediction.AppPredictionContext.Builder setExtras(@Nullable android.os.Bundle);
-    method public android.app.prediction.AppPredictionContext.Builder setPredictedTargetCount(int);
-    method public android.app.prediction.AppPredictionContext.Builder setUiSurface(@Nullable String);
+    method @NonNull public android.app.prediction.AppPredictionContext build();
+    method @NonNull public android.app.prediction.AppPredictionContext.Builder setExtras(@Nullable android.os.Bundle);
+    method @NonNull public android.app.prediction.AppPredictionContext.Builder setPredictedTargetCount(@IntRange(from=0) int);
+    method @NonNull public android.app.prediction.AppPredictionContext.Builder setUiSurface(@NonNull String);
   }
 
   public final class AppPredictionManager {
-    method public android.app.prediction.AppPredictor createAppPredictionSession(@NonNull android.app.prediction.AppPredictionContext);
+    method @NonNull public android.app.prediction.AppPredictor createAppPredictionSession(@NonNull android.app.prediction.AppPredictionContext);
   }
 
   public final class AppPredictionSessionId implements android.os.Parcelable {
@@ -1075,7 +1074,7 @@
     method @Nullable public String getClassName();
     method @NonNull public android.app.prediction.AppTargetId getId();
     method @NonNull public String getPackageName();
-    method public int getRank();
+    method @IntRange(from=0) public int getRank();
     method @Nullable public android.content.pm.ShortcutInfo getShortcutInfo();
     method @NonNull public android.os.UserHandle getUser();
     method public void writeToParcel(android.os.Parcel, int);
@@ -1084,8 +1083,8 @@
 
   public final class AppTargetEvent implements android.os.Parcelable {
     method public int describeContents();
-    method @NonNull public int getAction();
-    method @NonNull public String getLaunchLocation();
+    method public int getAction();
+    method @Nullable public String getLaunchLocation();
     method @Nullable public android.app.prediction.AppTarget getTarget();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_DISMISS = 2; // 0x2
@@ -1096,8 +1095,8 @@
 
   public static final class AppTargetEvent.Builder {
     ctor public AppTargetEvent.Builder(@Nullable android.app.prediction.AppTarget, int);
-    method public android.app.prediction.AppTargetEvent build();
-    method public android.app.prediction.AppTargetEvent.Builder setLaunchLocation(String);
+    method @NonNull public android.app.prediction.AppTargetEvent build();
+    method @NonNull public android.app.prediction.AppTargetEvent.Builder setLaunchLocation(@Nullable String);
   }
 
   public final class AppTargetId implements android.os.Parcelable {
@@ -1198,7 +1197,8 @@
     method public int getUsageSource();
     method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @Nullable android.app.PendingIntent);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
-    method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
     method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String);
     method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String, long);
     method public void reportUsageStop(@NonNull android.app.Activity, @NonNull String);
@@ -1603,7 +1603,6 @@
     method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public abstract boolean arePermissionsIndividuallyControlled();
     method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(String);
-    method public boolean getAppDetailsActivityEnabled(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.pm.ApplicationInfo getApplicationInfoAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method @NonNull public android.content.pm.dex.ArtManager getArtManager();
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract String getDefaultBrowserPackageNameAsUser(int);
@@ -1617,6 +1616,7 @@
     method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(String);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract int getIntentVerificationStatusAsUser(String, int);
     method @android.content.pm.PackageManager.PermissionFlags @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.GET_RUNTIME_PERMISSIONS}) public abstract int getPermissionFlags(String, String, @NonNull android.os.UserHandle);
+    method public boolean getSyntheticAppDetailsActivityEnabled(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] getUnsuspendablePackages(@NonNull String[]);
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method @Deprecated public abstract int installExistingPackage(String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -1630,12 +1630,12 @@
     method @Deprecated public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName);
     method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method public void sendDeviceCustomizationReadyBroadcast();
-    method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public void setAppDetailsActivityEnabled(@NonNull String, boolean);
     method @RequiresPermission(allOf={android.Manifest.permission.SET_PREFERRED_APPLICATIONS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract boolean setDefaultBrowserPackageNameAsUser(String, int);
     method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setDistractingPackageRestrictions(@NonNull String[], int);
     method @RequiresPermission(android.Manifest.permission.SET_HARMFUL_APP_WARNINGS) public void setHarmfulAppWarning(@NonNull String, @Nullable CharSequence);
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable String);
     method @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable android.content.pm.SuspendDialogInfo);
+    method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public void setSyntheticAppDetailsActivityEnabled(@NonNull String, boolean);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public abstract void setUpdateAvailable(String, boolean);
     method @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS) public abstract boolean updateIntentVerificationStatusAsUser(String, int, int);
     method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract void updatePermissionFlags(String, String, @android.content.pm.PackageManager.PermissionFlags int, @android.content.pm.PackageManager.PermissionFlags int, @NonNull android.os.UserHandle);
@@ -1754,9 +1754,9 @@
 
   public static final class ShortcutManager.ShareShortcutInfo implements android.os.Parcelable {
     method public int describeContents();
-    method public android.content.pm.ShortcutInfo getShortcutInfo();
-    method public android.content.ComponentName getTargetComponent();
-    method public void writeToParcel(android.os.Parcel, int);
+    method @NonNull public android.content.pm.ShortcutInfo getShortcutInfo();
+    method @NonNull public android.content.ComponentName getTargetComponent();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.ShortcutManager.ShareShortcutInfo> CREATOR;
   }
 
@@ -3721,10 +3721,6 @@
 
 package android.media.session {
 
-  public static final class MediaController.PlaybackInfo implements android.os.Parcelable {
-    ctor public MediaController.PlaybackInfo(int, int, int, int, android.media.AudioAttributes);
-  }
-
   public final class MediaSessionManager {
     method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler);
@@ -4069,7 +4065,7 @@
   }
 
   public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
-    method public void onEntitlementResult(int);
+    method public void onTetheringEntitlementResult(int);
   }
 
   public abstract static class ConnectivityManager.OnTetheringEventCallback {
@@ -4746,7 +4742,7 @@
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @NonNull @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>);
-    method @NonNull @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(java.util.List<android.net.wifi.ScanResult>);
+    method @NonNull @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(@Nullable java.util.List<android.net.wifi.ScanResult>);
     method @NonNull @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
@@ -5452,7 +5448,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSaveEnabled(boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSavePolicy(@NonNull android.os.BatterySaverPolicyConfig);
     method @RequiresPermission(android.Manifest.permission.POWER_SAVER) public boolean setDynamicPowerSavings(boolean, int);
-    method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveMode(boolean);
+    method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.USER_ACTIVITY}) public void userActivity(long, int, int);
     field public static final int POWER_SAVER_MODE_DYNAMIC = 1; // 0x1
     field public static final int POWER_SAVER_MODE_PERCENTAGE = 0; // 0x0
@@ -5850,49 +5846,41 @@
   public final class DeviceConfig {
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
-    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(String, String, boolean);
-    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static float getFloat(String, String, float);
-    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static int getInt(String, String, int);
-    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static long getLong(String, String, long);
-    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getProperty(String, String);
-    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(String, String, String);
+    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(@NonNull String, @NonNull String, boolean);
+    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static float getFloat(@NonNull String, @NonNull String, float);
+    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static int getInt(@NonNull String, @NonNull String, int);
+    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static long getLong(@NonNull String, @NonNull String, long);
+    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getProperty(@NonNull String, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(@NonNull String, @NonNull String, @Nullable String);
     method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
     method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
-    method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(String, String, String, boolean);
+    method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
     field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
     field public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT = "activity_manager_native_boot";
+    field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
     field public static final String NAMESPACE_AUTOFILL = "autofill";
     field public static final String NAMESPACE_CONNECTIVITY = "connectivity";
     field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
     field public static final String NAMESPACE_DEX_BOOT = "dex_boot";
     field public static final String NAMESPACE_GAME_DRIVER = "game_driver";
     field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
+    field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
     field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
     field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
+    field public static final String NAMESPACE_RUNTIME = "runtime";
+    field public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
     field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
     field public static final String NAMESPACE_SYSTEMUI = "systemui";
     field public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
   }
 
-  public static interface DeviceConfig.AttentionManagerService {
-    field public static final String COMPONENT_NAME = "component_name";
-    field public static final String NAMESPACE = "attention_manager_service";
-    field public static final String SERVICE_ENABLED = "service_enabled";
-  }
-
-  public static interface DeviceConfig.IntelligenceAttention {
-    field public static final String ATTENTION_ENABLED = "attention_enabled";
-    field public static final String ATTENTION_SETTINGS = "attention_settings";
-    field public static final String NAMESPACE = "intelligence_attention";
-  }
-
   public static interface DeviceConfig.OnPropertiesChangedListener {
     method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
   }
 
   public static interface DeviceConfig.OnPropertyChangedListener {
-    method public void onPropertyChanged(String, String, String);
+    method public void onPropertyChanged(@NonNull String, @NonNull String, @Nullable String);
   }
 
   public static interface DeviceConfig.Privacy {
@@ -5918,15 +5906,6 @@
     field public static final String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
   }
 
-  public static interface DeviceConfig.Runtime {
-    field public static final String NAMESPACE = "runtime";
-    field public static final String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled";
-  }
-
-  public static interface DeviceConfig.RuntimeNative {
-    field public static final String NAMESPACE = "runtime_native";
-  }
-
   public static interface DeviceConfig.Scheduler {
     field public static final String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection";
     field public static final String NAMESPACE = "scheduler";
@@ -6137,7 +6116,6 @@
     field public static final String LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE = "location_permissions_upgrade_to_q_mode";
     field public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications";
     field public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications";
-    field public static final String MANUAL_RINGER_TOGGLE_COUNT = "manual_ringer_toggle_count";
     field public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES = "theme_customization_overlay_packages";
     field public static final String USER_SETUP_COMPLETE = "user_setup_complete";
     field public static final int USER_SETUP_PERSONALIZATION_COMPLETE = 10; // 0xa
@@ -6146,6 +6124,9 @@
     field public static final int USER_SETUP_PERSONALIZATION_STARTED = 1; // 0x1
     field public static final String USER_SETUP_PERSONALIZATION_STATE = "user_setup_personalization_state";
     field public static final String VOLUME_HUSH_GESTURE = "volume_hush_gesture";
+    field public static final int VOLUME_HUSH_MUTE = 2; // 0x2
+    field public static final int VOLUME_HUSH_OFF = 0; // 0x0
+    field public static final int VOLUME_HUSH_VIBRATE = 1; // 0x1
   }
 
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
@@ -6324,7 +6305,7 @@
   public abstract class AppPredictionService extends android.app.Service {
     ctor public AppPredictionService();
     method @MainThread public abstract void onAppTargetEvent(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull android.app.prediction.AppTargetEvent);
-    method public final android.os.IBinder onBind(android.content.Intent);
+    method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method public void onCreatePredictionSession(@NonNull android.app.prediction.AppPredictionContext, @NonNull android.app.prediction.AppPredictionSessionId);
     method @MainThread public void onDestroyPredictionSession(@NonNull android.app.prediction.AppPredictionSessionId);
     method @MainThread public abstract void onLocationShown(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
@@ -6341,7 +6322,7 @@
 
   public abstract class AttentionService extends android.app.Service {
     ctor public AttentionService();
-    method public final android.os.IBinder onBind(android.content.Intent);
+    method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method public abstract void onCancelAttentionCheck(int);
     method public abstract void onCheckAttention(int, @NonNull android.service.attention.AttentionService.AttentionCallback);
     field public static final int ATTENTION_FAILURE_PREEMPTED = 2; // 0x2
@@ -6447,6 +6428,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.service.contentcapture.ActivityEvent> CREATOR;
     field public static final int TYPE_ACTIVITY_PAUSED = 2; // 0x2
     field public static final int TYPE_ACTIVITY_RESUMED = 1; // 0x1
+    field public static final int TYPE_ACTIVITY_STOPPED = 23; // 0x17
   }
 
   public abstract class ContentCaptureService extends android.app.Service {
@@ -7174,9 +7156,10 @@
 
 package android.telephony {
 
-  public static final class AccessNetworkConstants.TransportType {
-    field public static final int WLAN = 2; // 0x2
-    field public static final int WWAN = 1; // 0x1
+  public final class AccessNetworkConstants {
+    field public static final int TRANSPORT_TYPE_INVALID = -1; // 0xffffffff
+    field public static final int TRANSPORT_TYPE_WLAN = 2; // 0x2
+    field public static final int TRANSPORT_TYPE_WWAN = 1; // 0x1
   }
 
   public final class CallAttributes implements android.os.Parcelable {
@@ -7251,6 +7234,7 @@
     field public static final int ACCESS_BLOCK_ALL = 2088; // 0x828
     field public static final int ACCESS_CLASS_DSAC_REJECTION = 2108; // 0x83c
     field public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128; // 0x850
+    field public static final int ACCESS_PROBE_LIMIT_REACHED = 2079; // 0x81f
     field public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 48; // 0x30
     field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e
     field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f
@@ -7365,7 +7349,9 @@
     field public static final int INVALID_PRIMARY_NSAPI = 2158; // 0x86e
     field public static final int INVALID_SIM_STATE = 2224; // 0x8b0
     field public static final int INVALID_TRANSACTION_ID = 81; // 0x51
+    field public static final int IPV4_CONNECTIONS_LIMIT_REACHED = 2052; // 0x804
     field public static final int IPV6_ADDRESS_TRANSFER_FAILED = 2047; // 0x7ff
+    field public static final int IPV6_CONNECTIONS_LIMIT_REACHED = 2053; // 0x805
     field public static final int IPV6_PREFIX_UNAVAILABLE = 2250; // 0x8ca
     field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77
     field public static final int IP_VERSION_MISMATCH = 2055; // 0x807
@@ -7384,10 +7370,6 @@
     field public static final int MAC_FAILURE = 2183; // 0x887
     field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d
     field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876
-    field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f
-    field public static final int MAX_IPV4_CONNECTIONS = 2052; // 0x804
-    field public static final int MAX_IPV6_CONNECTIONS = 2053; // 0x805
-    field public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
     field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f
     field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61
     field public static final int MIP_CONFIG_FAILURE = 2050; // 0x802
@@ -7496,6 +7478,7 @@
     field public static final int PPP_AUTH_FAILURE = 2229; // 0x8b5
     field public static final int PPP_CHAP_FAILURE = 2232; // 0x8b8
     field public static final int PPP_CLOSE_IN_PROGRESS = 2233; // 0x8b9
+    field public static final int PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
     field public static final int PPP_OPTION_MISMATCH = 2230; // 0x8b6
     field public static final int PPP_PAP_FAILURE = 2231; // 0x8b7
     field public static final int PPP_TIMEOUT = 2228; // 0x8b4
@@ -8048,9 +8031,9 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
-    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getLogicalToPhysicalSlotMapping();
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping();
     method public static long getMaxNumberVerificationTimeoutMillis();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmap();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmask();
     method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState();
     method public int getSimApplicationState();
     method public int getSimCardState();
@@ -8062,6 +8045,10 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String);
+    method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String);
+    method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
     method public boolean isDataConnectivityPossible();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
@@ -8083,7 +8070,7 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultisimCarrierRestriction(boolean);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmap(long);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadioPower(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSimPowerState(int);
@@ -8097,7 +8084,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff();
     method public void updateServiceLocation();
-    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_DEBUG_EVENT = "android.telephony.action.DEBUG_EVENT";
+    field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED";
     field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
     field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
     field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
@@ -8105,8 +8092,8 @@
     field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
     field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
     field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
-    field public static final String EXTRA_DEBUG_EVENT_DESCRIPTION = "android.telephony.extra.DEBUG_EVENT_DESCRIPTION";
-    field public static final String EXTRA_DEBUG_EVENT_ID = "android.telephony.extra.DEBUG_EVENT_ID";
+    field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION";
+    field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
     field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
     field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
     field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
@@ -9535,6 +9522,7 @@
     method public int getTaskId();
     field public static final int FLAG_DISABLED_BY_APP = 1; // 0x1
     field public static final int FLAG_DISABLED_BY_FLAG_SECURE = 2; // 0x2
+    field public static final int FLAG_RECONNECTED = 4; // 0x4
   }
 
   public final class ContentCaptureEvent implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 2913743..4ccfa1c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -146,7 +146,7 @@
     method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(String, int, int);
     method public void startWatchingActive(@NonNull int[], @NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
     method public void stopWatchingActive(@NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
-    method public static int strOpToOp(String);
+    method public static int strOpToOp(@NonNull String);
     field public static final int HISTORICAL_MODE_DISABLED = 0; // 0x0
     field public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1; // 0x1
     field public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2; // 0x2
@@ -427,22 +427,22 @@
     method public int describeContents();
     method @Nullable public android.os.Bundle getExtras();
     method @NonNull public String getPackageName();
-    method public int getPredictedTargetCount();
-    method public String getUiSurface();
-    method public void writeToParcel(android.os.Parcel, int);
+    method @IntRange(from=0) public int getPredictedTargetCount();
+    method @NonNull public String getUiSurface();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.prediction.AppPredictionContext> CREATOR;
   }
 
   public static final class AppPredictionContext.Builder {
     ctor public AppPredictionContext.Builder(@NonNull android.content.Context);
-    method public android.app.prediction.AppPredictionContext build();
-    method public android.app.prediction.AppPredictionContext.Builder setExtras(@Nullable android.os.Bundle);
-    method public android.app.prediction.AppPredictionContext.Builder setPredictedTargetCount(int);
-    method public android.app.prediction.AppPredictionContext.Builder setUiSurface(@Nullable String);
+    method @NonNull public android.app.prediction.AppPredictionContext build();
+    method @NonNull public android.app.prediction.AppPredictionContext.Builder setExtras(@Nullable android.os.Bundle);
+    method @NonNull public android.app.prediction.AppPredictionContext.Builder setPredictedTargetCount(@IntRange(from=0) int);
+    method @NonNull public android.app.prediction.AppPredictionContext.Builder setUiSurface(@NonNull String);
   }
 
   public final class AppPredictionManager {
-    method public android.app.prediction.AppPredictor createAppPredictionSession(@NonNull android.app.prediction.AppPredictionContext);
+    method @NonNull public android.app.prediction.AppPredictor createAppPredictionSession(@NonNull android.app.prediction.AppPredictionContext);
   }
 
   public final class AppPredictionSessionId implements android.os.Parcelable {
@@ -472,7 +472,7 @@
     method @Nullable public String getClassName();
     method @NonNull public android.app.prediction.AppTargetId getId();
     method @NonNull public String getPackageName();
-    method public int getRank();
+    method @IntRange(from=0) public int getRank();
     method @Nullable public android.content.pm.ShortcutInfo getShortcutInfo();
     method @NonNull public android.os.UserHandle getUser();
     method public void writeToParcel(android.os.Parcel, int);
@@ -481,8 +481,8 @@
 
   public final class AppTargetEvent implements android.os.Parcelable {
     method public int describeContents();
-    method @NonNull public int getAction();
-    method @NonNull public String getLaunchLocation();
+    method public int getAction();
+    method @Nullable public String getLaunchLocation();
     method @Nullable public android.app.prediction.AppTarget getTarget();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_DISMISS = 2; // 0x2
@@ -493,8 +493,8 @@
 
   public static final class AppTargetEvent.Builder {
     ctor public AppTargetEvent.Builder(@Nullable android.app.prediction.AppTarget, int);
-    method public android.app.prediction.AppTargetEvent build();
-    method public android.app.prediction.AppTargetEvent.Builder setLaunchLocation(String);
+    method @NonNull public android.app.prediction.AppTargetEvent build();
+    method @NonNull public android.app.prediction.AppTargetEvent.Builder setLaunchLocation(@Nullable String);
   }
 
   public final class AppTargetId implements android.os.Parcelable {
@@ -599,6 +599,7 @@
     method public void setAutofillOptions(@Nullable android.content.AutofillOptions);
     method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions);
     field public static final String ROLLBACK_SERVICE = "rollback";
+    field public static final String TEST_NETWORK_SERVICE = "test_network";
   }
 
   public class ContextWrapper extends android.content.Context {
@@ -945,10 +946,9 @@
     method @Deprecated public void setCarrierPhase(double);
     method @Deprecated public void setCarrierPhaseUncertainty(double);
     method public void setCn0DbHz(double);
-    method public void setCodeType(int);
+    method public void setCodeType(@NonNull String);
     method public void setConstellationType(int);
     method public void setMultipathIndicator(int);
-    method public void setOtherCodeTypeName(@NonNull String);
     method public void setPseudorangeRateMetersPerSecond(double);
     method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
     method public void setReceivedSvTimeNanos(long);
@@ -1762,7 +1762,7 @@
   public final class PowerManager {
     method @RequiresPermission("android.permission.POWER_SAVER") public int getPowerSaveMode();
     method @RequiresPermission("android.permission.POWER_SAVER") public boolean setDynamicPowerSavings(boolean, int);
-    method @RequiresPermission(anyOf={"android.permission.DEVICE_POWER", "android.permission.POWER_SAVER"}) public boolean setPowerSaveMode(boolean);
+    method @RequiresPermission(anyOf={"android.permission.DEVICE_POWER", "android.permission.POWER_SAVER"}) public boolean setPowerSaveModeEnabled(boolean);
     field public static final int POWER_SAVER_MODE_DYNAMIC = 1; // 0x1
     field public static final int POWER_SAVER_MODE_PERCENTAGE = 0; // 0x0
   }
@@ -2055,16 +2055,16 @@
   public final class DeviceConfig {
     method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
     method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
-    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static boolean getBoolean(String, String, boolean);
-    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static float getFloat(String, String, float);
-    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static int getInt(String, String, int);
-    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static long getLong(String, String, long);
-    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(String, String);
-    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(String, String, String);
+    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static boolean getBoolean(@NonNull String, @NonNull String, boolean);
+    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static float getFloat(@NonNull String, @NonNull String, float);
+    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static int getInt(@NonNull String, @NonNull String, int);
+    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static long getLong(@NonNull String, @NonNull String, long);
+    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(@NonNull String, @NonNull String);
+    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(@NonNull String, @NonNull String, @Nullable String);
     method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
     method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
-    method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(String, String, String, boolean);
+    method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
     field public static final String NAMESPACE_AUTOFILL = "autofill";
     field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
   }
@@ -2074,7 +2074,7 @@
   }
 
   public static interface DeviceConfig.OnPropertyChangedListener {
-    method public void onPropertyChanged(String, String, String);
+    method public void onPropertyChanged(@NonNull String, @NonNull String, @Nullable String);
   }
 
   public static interface DeviceConfig.Privacy {
@@ -2224,7 +2224,7 @@
   public abstract class AppPredictionService extends android.app.Service {
     ctor public AppPredictionService();
     method @MainThread public abstract void onAppTargetEvent(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull android.app.prediction.AppTargetEvent);
-    method public final android.os.IBinder onBind(android.content.Intent);
+    method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method public void onCreatePredictionSession(@NonNull android.app.prediction.AppPredictionContext, @NonNull android.app.prediction.AppPredictionSessionId);
     method @MainThread public void onDestroyPredictionSession(@NonNull android.app.prediction.AppPredictionSessionId);
     method @MainThread public abstract void onLocationShown(@NonNull android.app.prediction.AppPredictionSessionId, @NonNull String, @NonNull java.util.List<android.app.prediction.AppTargetId>);
@@ -2396,6 +2396,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.service.contentcapture.ActivityEvent> CREATOR;
     field public static final int TYPE_ACTIVITY_PAUSED = 2; // 0x2
     field public static final int TYPE_ACTIVITY_RESUMED = 1; // 0x1
+    field public static final int TYPE_ACTIVITY_STOPPED = 23; // 0x17
   }
 
   public abstract class ContentCaptureService extends android.app.Service {
@@ -3055,6 +3056,7 @@
     method public int getTaskId();
     field public static final int FLAG_DISABLED_BY_APP = 1; // 0x1
     field public static final int FLAG_DISABLED_BY_FLAG_SECURE = 2; // 0x2
+    field public static final int FLAG_RECONNECTED = 4; // 0x4
   }
 
   public final class ContentCaptureEvent implements android.os.Parcelable {
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
index 3666d6a..469c964 100644
--- a/cmds/bootanimation/bootanim.rc
+++ b/cmds/bootanimation/bootanim.rc
@@ -2,9 +2,6 @@
     class core animation
     user graphics
     group graphics audio
-    # bootanimation depends on libandroidicu in the Runtime APEX.
-    # TODO(b/124939955): Remove this dependency on libandroidicu
-    updatable
     disabled
     oneshot
     writepid /dev/stune/top-app/tasks
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 7298da6..ce07d6d 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -219,6 +219,7 @@
         "tests/anomaly/AnomalyTracker_test.cpp",
         "tests/ConfigManager_test.cpp",
         "tests/external/puller_util_test.cpp",
+        "tests/external/GpuStatsPuller_test.cpp",
         "tests/external/IncidentReportArgs_test.cpp",
         "tests/external/StatsPuller_test.cpp",
         "tests/indexed_priority_queue_test.cpp",
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 1526d66..f78ae38 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1198,30 +1198,48 @@
     }
     // TODO: add verifier permission
 
-    userid_t userId = multiuser_get_user_id(uid);
+    bool readTrainInfoSuccess = false;
+    InstallTrainInfo trainInfo;
+    if (trainVersionCode == -1 || experimentIds.empty() || trainName.size() == 0) {
+        readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfo);
+    }
 
-    bool requiresStaging = options & IStatsManager::FLAG_REQUIRE_STAGING;
-    bool rollbackEnabled = options & IStatsManager::FLAG_ROLLBACK_ENABLED;
-    bool requiresLowLatencyMonitor = options & IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
-
-    ProtoOutputStream proto;
-    for (const auto& expId : experimentIds) {
-        proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID,
-                    (long long)expId);
+    if (trainVersionCode == -1 && readTrainInfoSuccess) {
+        trainVersionCode = trainInfo.trainVersionCode;
     }
 
     vector<uint8_t> experimentIdsProtoBuffer;
-    experimentIdsProtoBuffer.resize(proto.size());
-    size_t pos = 0;
-    auto iter = proto.data();
-    while (iter.readBuffer() != NULL) {
-        size_t toRead = iter.currentToRead();
-        std::memcpy(&(experimentIdsProtoBuffer[pos]), iter.readBuffer(), toRead);
-        pos += toRead;
-        iter.rp()->move(toRead);
+    if (readTrainInfoSuccess && experimentIds.empty()) {
+        experimentIdsProtoBuffer = trainInfo.experimentIds;
+    } else {
+        ProtoOutputStream proto;
+        for (const auto& expId : experimentIds) {
+            proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID,
+                        (long long)expId);
+        }
+
+        experimentIdsProtoBuffer.resize(proto.size());
+        size_t pos = 0;
+        auto iter = proto.data();
+        while (iter.readBuffer() != NULL) {
+            size_t toRead = iter.currentToRead();
+            std::memcpy(&(experimentIdsProtoBuffer[pos]), iter.readBuffer(), toRead);
+            pos += toRead;
+            iter.rp()->move(toRead);
+        }
     }
 
-    std::string trainNameUtf8 = std::string(String8(trainName).string());
+    std::string trainNameUtf8;
+    if (readTrainInfoSuccess && trainName.size() == 0) {
+        trainNameUtf8 = trainInfo.trainName;
+    } else {
+        trainNameUtf8 = std::string(String8(trainName).string());
+    }
+
+    userid_t userId = multiuser_get_user_id(uid);
+    bool requiresStaging = options & IStatsManager::FLAG_REQUIRE_STAGING;
+    bool rollbackEnabled = options & IStatsManager::FLAG_ROLLBACK_ENABLED;
+    bool requiresLowLatencyMonitor = options & IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
     LogEvent event(trainNameUtf8, trainVersionCode, requiresStaging, rollbackEnabled,
                    requiresLowLatencyMonitor, state, experimentIdsProtoBuffer, userId);
     mProcessor->OnLogEvent(&event);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 4856f77..3246d19 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -253,7 +253,7 @@
     }
 
     // Pulled events will start at field 10000.
-    // Next: 10056
+    // Next: 10057
     oneof pulled {
         WifiBytesTransfer wifi_bytes_transfer = 10000;
         WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -311,6 +311,7 @@
         SDCardInfo sdcard_info = 10053;
         GpuStatsGlobalInfo gpu_stats_global_info = 10054;
         GpuStatsAppInfo gpu_stats_app_info = 10055;
+        SystemIonHeapSize system_ion_heap_size = 10056;
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP.
@@ -5759,7 +5760,7 @@
     optional string tzdb_version = 1;
 }
 
-/*
+/**
  * Logs the GPU stats global health information.
  *
  * Logged from:
@@ -5791,22 +5792,44 @@
     optional int64 vk_loading_failure_count = 8;
 }
 
-/*
+/**
+ * GPU driver loading time info.
+ */
+message GpuDriverLoadingTime {
+    // List of all the driver loading times for this app. The list size is
+    // capped at 50.
+    repeated int64 driver_loading_time = 1;
+}
+
+/**
  * Logs the GPU stats per app health information.
  *
  * Logged from:
  *   frameworks/native/services/gpuservice/gpustats/
  */
 message GpuStatsAppInfo {
-    // Package name of the application that loads the gpu driver.
+    // Package name of the application that loads the gpu driver. Total number
+    // of different packages is capped at 100.
     optional string app_package_name = 1;
 
     // Version code of the gpu driver this app loads.
     optional int64 driver_version_code = 2;
 
-    // List of all the gl driver loading times for this app.
-    repeated int64 gl_driver_loading_time = 3;
+    // gl driver loading time info.
+    optional GpuDriverLoadingTime gl_driver_loading_time = 3
+            [(android.os.statsd.log_mode) = MODE_BYTES];
 
-    // List of all the Vulkan driver laoding times for this app.
-    repeated int64 vk_driver_loading_time = 4;
+    // Vulkan driver loading time info.
+    optional GpuDriverLoadingTime vk_driver_loading_time = 4
+            [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/*
+ * Logs the size of the system ion heap.
+ *
+ * Pulled from StatsCompanionService.
+ */
+message SystemIonHeapSize {
+    // Size of the system ion heap in bytes.
+    optional int64 size_in_bytes = 1;
 }
diff --git a/cmds/statsd/src/external/GpuStatsPuller.cpp b/cmds/statsd/src/external/GpuStatsPuller.cpp
index 8445803..130bd85 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.cpp
+++ b/cmds/statsd/src/external/GpuStatsPuller.cpp
@@ -70,6 +70,30 @@
     return true;
 }
 
+static bool pullGpuStatsAppInfo(const sp<IGpuService>& gpuService,
+                                std::vector<std::shared_ptr<LogEvent>>* data) {
+    std::vector<GpuStatsAppInfo> stats;
+    status_t status = gpuService->getGpuStatsAppInfo(&stats);
+    if (status != OK) {
+        return false;
+    }
+
+    data->clear();
+    data->reserve(stats.size());
+    for (const auto& info : stats) {
+        std::shared_ptr<LogEvent> event = make_shared<LogEvent>(
+                android::util::GPU_STATS_APP_INFO, getWallClockNs(), getElapsedRealtimeNs());
+        if (!event->write(info.appPackageName)) return false;
+        if (!event->write((int64_t)info.driverVersionCode)) return false;
+        if (!event->write(int64VectorToProtoByteString(info.glDriverLoadingTime))) return false;
+        if (!event->write(int64VectorToProtoByteString(info.vkDriverLoadingTime))) return false;
+        event->init();
+        data->emplace_back(event);
+    }
+
+    return true;
+}
+
 bool GpuStatsPuller::PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) {
     const sp<IGpuService> gpuService = getGpuService();
     if (!gpuService) {
@@ -79,6 +103,8 @@
     switch (mTagId) {
         case android::util::GPU_STATS_GLOBAL_INFO:
             return pullGpuStatsGlobalInfo(gpuService, data);
+        case android::util::GPU_STATS_APP_INFO:
+            return pullGpuStatsAppInfo(gpuService, data);
         default:
             break;
     }
@@ -86,6 +112,35 @@
     return false;
 }
 
+static std::string protoOutputStreamToByteString(ProtoOutputStream& proto) {
+    if (!proto.size()) return "";
+
+    std::string byteString;
+    auto iter = proto.data();
+    while (iter.readBuffer() != nullptr) {
+        const size_t toRead = iter.currentToRead();
+        byteString.append((char*)iter.readBuffer(), toRead);
+        iter.rp()->move(toRead);
+    }
+
+    if (byteString.size() != proto.size()) return "";
+
+    return byteString;
+}
+
+std::string int64VectorToProtoByteString(const std::vector<int64_t>& value) {
+    if (value.empty()) return "";
+
+    ProtoOutputStream proto;
+    for (const auto& ele : value) {
+        proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
+                            1 /* field id */,
+                    (long long)ele);
+    }
+
+    return protoOutputStreamToByteString(proto);
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/external/GpuStatsPuller.h b/cmds/statsd/src/external/GpuStatsPuller.h
index 4c7a4d6..2da199c 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.h
+++ b/cmds/statsd/src/external/GpuStatsPuller.h
@@ -31,6 +31,12 @@
     bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) override;
 };
 
+// convert a int64_t vector into a byte string for proto message like:
+// message RepeatedInt64Wrapper {
+//   repeated int64 value = 1;
+// }
+std::string int64VectorToProtoByteString(const std::vector<int64_t>& value);
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 924704b..c7ae656 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -148,10 +148,14 @@
         {android::util::NATIVE_PROCESS_MEMORY_STATE,
          {.additiveFields = {3, 4, 5, 6},
           .puller = new StatsCompanionServicePuller(android::util::NATIVE_PROCESS_MEMORY_STATE)}},
+        // process_memory_high_water_mark
         {android::util::PROCESS_MEMORY_HIGH_WATER_MARK,
          {.additiveFields = {3},
           .puller =
                   new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
+        // system_ion_heap_size
+        {android::util::SYSTEM_ION_HEAP_SIZE,
+         {.puller = new StatsCompanionServicePuller(android::util::SYSTEM_ION_HEAP_SIZE)}},
         // temperature
         {android::util::TEMPERATURE,
          {.puller = new StatsCompanionServicePuller(android::util::TEMPERATURE)}},
@@ -244,6 +248,9 @@
         // GpuStatsGlobalInfo
         {android::util::GPU_STATS_GLOBAL_INFO,
          {.puller = new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)}},
+        // GpuStatsAppInfo
+        {android::util::GPU_STATS_APP_INFO,
+         {.puller = new GpuStatsPuller(android::util::GPU_STATS_APP_INFO)}},
 };
 
 StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 27ee570..18bfdfc 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -787,7 +787,6 @@
     }
 
     int64_t numBucketsForward = calcBucketsForwardCount(eventTimeNs);
-    mCurrentBucketNum += numBucketsForward;
     if (numBucketsForward > 1) {
         VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
         StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId);
@@ -816,10 +815,9 @@
         mSkippedBuckets.emplace_back(mCurrentBucketStartTimeNs, bucketEndTime);
     }
 
-    if (!mCurrentBucketIsInvalid) {
-        appendToFullBucket(eventTimeNs, fullBucketEndTimeNs);
-    }
+    appendToFullBucket(eventTimeNs, fullBucketEndTimeNs);
     initCurrentSlicedBucket(nextBucketStartTimeNs);
+    mCurrentBucketNum += numBucketsForward;
 }
 
 ValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime,
@@ -879,7 +877,17 @@
 }
 
 void ValueMetricProducer::appendToFullBucket(int64_t eventTimeNs, int64_t fullBucketEndTimeNs) {
-    if (eventTimeNs > fullBucketEndTimeNs) {  // If full bucket, send to anomaly tracker.
+    bool isFullBucketReached = eventTimeNs > fullBucketEndTimeNs;
+    if (mCurrentBucketIsInvalid) {
+        if (isFullBucketReached) {
+            // If the bucket is invalid, we ignore the full bucket since it contains invalid data.
+            mCurrentFullBucket.clear();
+        }
+        // Current bucket is invalid, we do not add it to the full bucket.
+        return;
+    }
+
+    if (isFullBucketReached) {  // If full bucket, send to anomaly tracker.
         // Accumulate partial buckets with current value and then send to anomaly tracker.
         if (mCurrentFullBucket.size() > 0) {
             for (const auto& slice : mCurrentSlicedBucket) {
@@ -887,7 +895,10 @@
                     continue;
                 }
                 // TODO: fix this when anomaly can accept double values
-                mCurrentFullBucket[slice.first] += slice.second[0].value.long_value;
+                auto& interval = slice.second[0];
+                if (interval.hasValue) {
+                    mCurrentFullBucket[slice.first] += interval.value.long_value;
+                }
             }
             for (const auto& slice : mCurrentFullBucket) {
                 for (auto& tracker : mAnomalyTrackers) {
@@ -903,8 +914,11 @@
                 for (auto& tracker : mAnomalyTrackers) {
                     if (tracker != nullptr) {
                         // TODO: fix this when anomaly can accept double values
-                        tracker->addPastBucket(slice.first, slice.second[0].value.long_value,
-                                               mCurrentBucketNum);
+                        auto& interval = slice.second[0];
+                        if (interval.hasValue) {
+                            tracker->addPastBucket(slice.first, interval.value.long_value,
+                                                   mCurrentBucketNum);
+                        }
                     }
                 }
             }
@@ -913,7 +927,10 @@
         // Accumulate partial bucket.
         for (const auto& slice : mCurrentSlicedBucket) {
             // TODO: fix this when anomaly can accept double values
-            mCurrentFullBucket[slice.first] += slice.second[0].value.long_value;
+            auto& interval = slice.second[0];
+            if (interval.hasValue) {
+                mCurrentFullBucket[slice.first] += interval.value.long_value;
+            }
         }
     }
 }
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index f317c37..a0a1348 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -244,6 +244,7 @@
     FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled);
     FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestFirstBucket);
+    FRIEND_TEST(ValueMetricProducerTest, TestFullBucketResetWhenLastBucketInvalid);
     FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit);
     FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed);
     FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed);
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 5df8fb5..65b183c 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -116,14 +116,16 @@
     const size_t trainNameSizeByteCount = sizeof(trainNameSize);
     result = write(fd, (uint8_t*)&trainNameSize, trainNameSizeByteCount);
     if (result != trainNameSizeByteCount) {
-        VLOG("Failed to write %s", file_name.c_str());
+        VLOG("Failed to write train name size for %s", file_name.c_str());
+        close(fd);
         return false;
     }
 
     // Write trainName to file
     result = write(fd, trainName.c_str(), trainNameSize);
     if (result != trainNameSize) {
-        VLOG("Failed to write %s", file_name.c_str());
+        VLOG("Failed to write train name for%s", file_name.c_str());
+        close(fd);
         return false;
     }
 
@@ -131,7 +133,18 @@
     const size_t statusByteCount = sizeof(status);
     result = write(fd, (uint8_t*)&status, statusByteCount);
     if (result != statusByteCount) {
-        VLOG("Failed to write %s", file_name.c_str());
+        VLOG("Failed to write status for %s", file_name.c_str());
+        close(fd);
+        return false;
+    }
+
+    // Write experiment id size to file.
+    const size_t experimentIdSize = experimentIds.size();
+    const size_t experimentIdsSizeByteCount = sizeof(experimentIdSize);
+    result = write(fd, (uint8_t*) &experimentIdSize, experimentIdsSizeByteCount);
+    if (result != experimentIdsSizeByteCount) {
+        VLOG("Failed to write experiment id size for %s", file_name.c_str());
+        close(fd);
         return false;
     }
 
@@ -140,13 +153,15 @@
     if (result == experimentIds.size()) {
         VLOG("Successfully wrote %s", file_name.c_str());
     } else {
-        VLOG("Failed to write %s", file_name.c_str());
+        VLOG("Failed to write experiment ids for %s", file_name.c_str());
+        close(fd);
         return false;
     }
 
     result = fchown(fd, AID_STATSD, AID_STATSD);
     if (result) {
         VLOG("Failed to chown %s to statsd", file_name.c_str());
+        close(fd);
         return false;
     }
 
@@ -170,39 +185,73 @@
         if (name[0] == '.') {
             continue;
         }
+
+        size_t result;
+
         trainInfo.trainVersionCode = StrToInt64(name);
         string fullPath = StringPrintf("%s/%s", TRAIN_INFO_DIR, name);
         int fd = open(fullPath.c_str(), O_RDONLY | O_CLOEXEC);
-        if (fd != -1) {
-            string str;
-            if (android::base::ReadFdToString(fd, &str)) {
-                close(fd);
-
-                auto it = str.begin();
-
-                // Read # of bytes taken by trainName in the file
-                size_t trainNameSize;
-                const size_t trainNameSizeByteCount = sizeof(trainNameSize);
-                std::copy_n(it, trainNameSizeByteCount, &trainNameSize);
-                it += trainNameSizeByteCount;
-
-                // Read trainName
-                std::copy_n(it, trainNameSize, std::back_inserter(trainInfo.trainName));
-                it += trainNameSize;
-
-                // Read status
-                const size_t statusByteCount = sizeof(trainInfo.status);
-                std::copy_n(it, statusByteCount, &trainInfo.status);
-                it += statusByteCount;
-
-                // Read experimentIds
-                std::copy(it, str.end(), std::back_inserter(trainInfo.experimentIds));
-
-                VLOG("Read train info file successful: %s", fullPath.c_str());
-                return true;
-            }
+        if (fd == -1) {
+            return false;
         }
+
+        // Read # of bytes taken by trainName in the file.
+        size_t trainNameSize;
+        result = read(fd, &trainNameSize, sizeof(size_t));
+        if (result != sizeof(size_t)) {
+            VLOG("Failed to read train name size from file %s", fullPath.c_str());
+            close(fd);
+            return false;
+        }
+
+        // Read trainName
+        trainInfo.trainName.resize(trainNameSize);
+        result = read(fd, trainInfo.trainName.data(), trainNameSize);
+        if (result != trainNameSize) {
+            VLOG("Failed to read train name from file %s", fullPath.c_str());
+            close(fd);
+            return false;
+        }
+
+        // Read status
+        const size_t statusByteCount = sizeof(trainInfo.status);
+        result = read(fd, &trainInfo.status, statusByteCount);
+        if (result != statusByteCount) {
+            VLOG("Failed to read train status from file %s", fullPath.c_str());
+            close(fd);
+            return false;
+        }
+
+        // Read experiment ids size.
+        size_t experimentIdSize;
+        result = read(fd, &experimentIdSize, sizeof(size_t));
+        if (result != sizeof(size_t)) {
+            VLOG("Failed to read train experiment id size from file %s", fullPath.c_str());
+            close(fd);
+            return false;
+        }
+
+        // Read experimentIds
+        trainInfo.experimentIds.resize(experimentIdSize);
+        result = read(fd, trainInfo.experimentIds.data(), experimentIdSize);
+        if (result != experimentIdSize) {
+            VLOG("Failed to read train experiment ids from file %s", fullPath.c_str());
+            close(fd);
+            return false;
+        }
+
+        // Expect to be at EOF.
+        char c;
+        result = read(fd, &c, 1);
+        if (result != 0) {
+            VLOG("Failed to read train info from file %s. Did not get expected EOF.", fullPath.c_str());
+            close(fd);
+            return false;
+        }
+
+        VLOG("Read train info file successful: %s", fullPath.c_str());
         close(fd);
+        return true;
     }
     return false;
 }
diff --git a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
new file mode 100644
index 0000000..8625487
--- /dev/null
+++ b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "GpuStatsPuller_test"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <graphicsenv/GpuStatsInfo.h>
+#include <log/log.h>
+
+#include "src/external/GpuStatsPuller.h"
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// clang-format off
+static const std::string DRIVER_PACKAGE_NAME    = "TEST_DRIVER";
+static const std::string DRIVER_VERSION_NAME    = "TEST_DRIVER_VERSION";
+static const std::string APP_PACKAGE_NAME       = "TEST_APP";
+static const int64_t TIMESTAMP_WALLCLOCK        = 111;
+static const int64_t TIMESTAMP_ELAPSED          = 222;
+static const int64_t DRIVER_VERSION_CODE        = 333;
+static const int64_t DRIVER_BUILD_TIME          = 444;
+static const int64_t GL_LOADING_COUNT           = 3;
+static const int64_t GL_LOADING_FAILURE_COUNT   = 1;
+static const int64_t VK_LOADING_COUNT           = 4;
+static const int64_t VK_LOADING_FAILURE_COUNT   = 0;
+static const int64_t GL_DRIVER_LOADING_TIME_0   = 555;
+static const int64_t GL_DRIVER_LOADING_TIME_1   = 666;
+static const int64_t VK_DRIVER_LOADING_TIME_0   = 777;
+static const int64_t VK_DRIVER_LOADING_TIME_1   = 888;
+static const int64_t VK_DRIVER_LOADING_TIME_2   = 999;
+static const size_t NUMBER_OF_VALUES_GLOBAL     = 8;
+static const size_t NUMBER_OF_VALUES_APP        = 4;
+// clang-format on
+
+class MockGpuStatsPuller : public GpuStatsPuller {
+public:
+    MockGpuStatsPuller(const int tagId, vector<std::shared_ptr<LogEvent>>* data)
+        : GpuStatsPuller(tagId), mData(data){};
+
+private:
+    bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override {
+        *data = *mData;
+        return true;
+    }
+
+    vector<std::shared_ptr<LogEvent>>* mData;
+};
+
+class GpuStatsPuller_test : public ::testing::Test {
+public:
+    GpuStatsPuller_test() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+    ~GpuStatsPuller_test() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+};
+
+TEST_F(GpuStatsPuller_test, PullGpuStatsGlobalInfo) {
+    vector<std::shared_ptr<LogEvent>> inData, outData;
+    std::shared_ptr<LogEvent> event = make_shared<LogEvent>(android::util::GPU_STATS_GLOBAL_INFO,
+                                                            TIMESTAMP_WALLCLOCK, TIMESTAMP_ELAPSED);
+    EXPECT_TRUE(event->write(DRIVER_PACKAGE_NAME));
+    EXPECT_TRUE(event->write(DRIVER_VERSION_NAME));
+    EXPECT_TRUE(event->write(DRIVER_VERSION_CODE));
+    EXPECT_TRUE(event->write(DRIVER_BUILD_TIME));
+    EXPECT_TRUE(event->write(GL_LOADING_COUNT));
+    EXPECT_TRUE(event->write(GL_LOADING_FAILURE_COUNT));
+    EXPECT_TRUE(event->write(VK_LOADING_COUNT));
+    EXPECT_TRUE(event->write(VK_LOADING_FAILURE_COUNT));
+    event->init();
+    inData.emplace_back(event);
+    MockGpuStatsPuller mockPuller(android::util::GPU_STATS_GLOBAL_INFO, &inData);
+    mockPuller.ForceClearCache();
+    mockPuller.Pull(&outData);
+
+    ASSERT_EQ(1, outData.size());
+    EXPECT_EQ(android::util::GPU_STATS_GLOBAL_INFO, outData[0]->GetTagId());
+    ASSERT_EQ(NUMBER_OF_VALUES_GLOBAL, outData[0]->size());
+    EXPECT_EQ(DRIVER_PACKAGE_NAME, outData[0]->getValues()[0].mValue.str_value);
+    EXPECT_EQ(DRIVER_VERSION_NAME, outData[0]->getValues()[1].mValue.str_value);
+    EXPECT_EQ(DRIVER_VERSION_CODE, outData[0]->getValues()[2].mValue.long_value);
+    EXPECT_EQ(DRIVER_BUILD_TIME, outData[0]->getValues()[3].mValue.long_value);
+    EXPECT_EQ(GL_LOADING_COUNT, outData[0]->getValues()[4].mValue.long_value);
+    EXPECT_EQ(GL_LOADING_FAILURE_COUNT, outData[0]->getValues()[5].mValue.long_value);
+    EXPECT_EQ(VK_LOADING_COUNT, outData[0]->getValues()[6].mValue.long_value);
+    EXPECT_EQ(VK_LOADING_FAILURE_COUNT, outData[0]->getValues()[7].mValue.long_value);
+}
+
+TEST_F(GpuStatsPuller_test, PullGpuStatsAppInfo) {
+    vector<std::shared_ptr<LogEvent>> inData, outData;
+    std::shared_ptr<LogEvent> event = make_shared<LogEvent>(android::util::GPU_STATS_APP_INFO,
+                                                            TIMESTAMP_WALLCLOCK, TIMESTAMP_ELAPSED);
+    EXPECT_TRUE(event->write(APP_PACKAGE_NAME));
+    EXPECT_TRUE(event->write(DRIVER_VERSION_CODE));
+    std::vector<int64_t> glDriverLoadingTime;
+    glDriverLoadingTime.emplace_back(GL_DRIVER_LOADING_TIME_0);
+    glDriverLoadingTime.emplace_back(GL_DRIVER_LOADING_TIME_1);
+    std::vector<int64_t> vkDriverLoadingTime;
+    vkDriverLoadingTime.emplace_back(VK_DRIVER_LOADING_TIME_0);
+    vkDriverLoadingTime.emplace_back(VK_DRIVER_LOADING_TIME_1);
+    vkDriverLoadingTime.emplace_back(VK_DRIVER_LOADING_TIME_2);
+    EXPECT_TRUE(event->write(int64VectorToProtoByteString(glDriverLoadingTime)));
+    EXPECT_TRUE(event->write(int64VectorToProtoByteString(vkDriverLoadingTime)));
+    event->init();
+    inData.emplace_back(event);
+    MockGpuStatsPuller mockPuller(android::util::GPU_STATS_APP_INFO, &inData);
+    mockPuller.ForceClearCache();
+    mockPuller.Pull(&outData);
+
+    ASSERT_EQ(1, outData.size());
+    EXPECT_EQ(android::util::GPU_STATS_APP_INFO, outData[0]->GetTagId());
+    ASSERT_EQ(NUMBER_OF_VALUES_APP, outData[0]->size());
+    EXPECT_EQ(APP_PACKAGE_NAME, outData[0]->getValues()[0].mValue.str_value);
+    EXPECT_EQ(DRIVER_VERSION_CODE, outData[0]->getValues()[1].mValue.long_value);
+    EXPECT_EQ(int64VectorToProtoByteString(glDriverLoadingTime),
+              outData[0]->getValues()[2].mValue.str_value);
+    EXPECT_EQ(int64VectorToProtoByteString(vkDriverLoadingTime),
+              outData[0]->getValues()[3].mValue.str_value);
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index e5e4534..90b9e81 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -2500,6 +2500,37 @@
     EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 }
 
+TEST(ValueMetricProducerTest, TestFullBucketResetWhenLastBucketInvalid) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Initialization.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs, 1));
+                return true;
+            }))
+            // notifyAppUpgrade.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(ValueMetricProducerTestHelper::createEvent(
+                        bucketStartTimeNs + bucketSizeNs / 2, 10));
+                return true;
+            }));
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+    ASSERT_EQ(0UL, valueProducer->mCurrentFullBucket.size());
+
+    valueProducer->notifyAppUpgrade(bucketStartTimeNs + bucketSizeNs / 2, "com.foo", 10000, 1);
+    ASSERT_EQ(1UL, valueProducer->mCurrentFullBucket.size());
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs + 1, 4));
+    valueProducer->onDataPulled(allData, /** fails */ false, bucket3StartTimeNs + 1);
+    ASSERT_EQ(0UL, valueProducer->mCurrentFullBucket.size());
+}
+
 TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange) {
     ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index ff8dec1..c6a3d80 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -1756,48 +1756,6 @@
 Lcom/android/internal/statusbar/IStatusBarService$Stub;-><init>()V
 Lcom/android/internal/statusbar/IStatusBarService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/statusbar/IStatusBarService;
 Lcom/android/internal/telecom/ITelecomService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telecom/ITelecomService;
-Lcom/android/internal/telephony/BaseCommands;->mCallStateRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mCallWaitingInfoRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mCatCallSetUpRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mCatCcAlphaRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mCatEventRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mCatProCmdRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mCatSessionEndRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mCdmaPrlChangedRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mCdmaSmsRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mCdmaSubscriptionChangedRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/BaseCommands;->mEmergencyCallbackModeRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mExitEmergencyCallbackModeRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mGsmBroadcastSmsRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mGsmSmsRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mHardwareConfigChangeRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mIccRefreshRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mIccSmsFullRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mIccStatusChangedRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mImsNetworkStateChangedRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mNITZTimeRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mOtaProvisionRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mPhoneRadioCapabilityChangedRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mPhoneType:I
-Lcom/android/internal/telephony/BaseCommands;->mPreferredNetworkType:I
-Lcom/android/internal/telephony/BaseCommands;->mResendIncallMuteRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mRestrictedStateRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mRilCellInfoListRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mRingbackToneRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mRingRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mSignalStrengthRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mSmsOnSimRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mSmsStatusRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mSrvccStateRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mSsnRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mSsRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mStateMonitor:Ljava/lang/Object;
-Lcom/android/internal/telephony/BaseCommands;->mSubscriptionStatusRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/BaseCommands;->mUnsolOemHookRawRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mUSSDRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/BaseCommands;->mVoiceRadioTechChangedRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/Call$State;->ACTIVE:Lcom/android/internal/telephony/Call$State;
 Lcom/android/internal/telephony/Call$State;->ALERTING:Lcom/android/internal/telephony/Call$State;
 Lcom/android/internal/telephony/Call$State;->DIALING:Lcom/android/internal/telephony/Call$State;
 Lcom/android/internal/telephony/Call$State;->DISCONNECTED:Lcom/android/internal/telephony/Call$State;
@@ -1805,232 +1763,22 @@
 Lcom/android/internal/telephony/Call$State;->HOLDING:Lcom/android/internal/telephony/Call$State;
 Lcom/android/internal/telephony/Call$State;->IDLE:Lcom/android/internal/telephony/Call$State;
 Lcom/android/internal/telephony/Call$State;->INCOMING:Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/Call$State;->isAlive()Z
-Lcom/android/internal/telephony/Call$State;->isRinging()Z
 Lcom/android/internal/telephony/Call$State;->values()[Lcom/android/internal/telephony/Call$State;
 Lcom/android/internal/telephony/Call$State;->WAITING:Lcom/android/internal/telephony/Call$State;
 Lcom/android/internal/telephony/Call;-><init>()V
-Lcom/android/internal/telephony/Call;->getConnections()Ljava/util/List;
-Lcom/android/internal/telephony/Call;->getEarliestConnection()Lcom/android/internal/telephony/Connection;
-Lcom/android/internal/telephony/Call;->getLatestConnection()Lcom/android/internal/telephony/Connection;
-Lcom/android/internal/telephony/Call;->getPhone()Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/Call;->getState()Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/Call;->hangup()V
-Lcom/android/internal/telephony/Call;->isIdle()Z
-Lcom/android/internal/telephony/Call;->isMultiparty()Z
-Lcom/android/internal/telephony/Call;->mConnections:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/Call;->mState:Lcom/android/internal/telephony/Call$State;
 Lcom/android/internal/telephony/CallerInfoAsyncQuery$CallerInfoAsyncQueryHandler;-><init>(Lcom/android/internal/telephony/CallerInfoAsyncQuery;Landroid/content/Context;)V
 Lcom/android/internal/telephony/CallerInfoAsyncQuery$CookieWrapper;-><init>()V
 Lcom/android/internal/telephony/CallerInfoAsyncQuery;->release()V
 Lcom/android/internal/telephony/CallForwardInfo;-><init>()V
-Lcom/android/internal/telephony/CallForwardInfo;->number:Ljava/lang/String;
-Lcom/android/internal/telephony/CallForwardInfo;->reason:I
-Lcom/android/internal/telephony/CallForwardInfo;->serviceClass:I
-Lcom/android/internal/telephony/CallForwardInfo;->status:I
-Lcom/android/internal/telephony/CallForwardInfo;->timeSeconds:I
-Lcom/android/internal/telephony/CallForwardInfo;->toa:I
-Lcom/android/internal/telephony/CallManager;->canConference(Lcom/android/internal/telephony/Call;I)Z
-Lcom/android/internal/telephony/CallManager;->canDial(Lcom/android/internal/telephony/Phone;)Z
-Lcom/android/internal/telephony/CallManager;->conference(Lcom/android/internal/telephony/Call;)V
-Lcom/android/internal/telephony/CallManager;->getActiveFgCall(I)Lcom/android/internal/telephony/Call;
-Lcom/android/internal/telephony/CallManager;->getActiveFgCallState(I)Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/CallManager;->getBackgroundCalls()Ljava/util/List;
-Lcom/android/internal/telephony/CallManager;->getBgCallConnections()Ljava/util/List;
-Lcom/android/internal/telephony/CallManager;->getBgPhone()Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/CallManager;->getContext()Landroid/content/Context;
-Lcom/android/internal/telephony/CallManager;->getDefaultPhone()Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/CallManager;->getFgCallConnections()Ljava/util/List;
-Lcom/android/internal/telephony/CallManager;->getFgPhone()Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/CallManager;->getFgPhone(I)Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/CallManager;->getFirstActiveBgCall()Lcom/android/internal/telephony/Call;
-Lcom/android/internal/telephony/CallManager;->getFirstActiveBgCall(I)Lcom/android/internal/telephony/Call;
-Lcom/android/internal/telephony/CallManager;->getFirstActiveRingingCall()Lcom/android/internal/telephony/Call;
-Lcom/android/internal/telephony/CallManager;->getFirstActiveRingingCall(I)Lcom/android/internal/telephony/Call;
-Lcom/android/internal/telephony/CallManager;->getInstance()Lcom/android/internal/telephony/CallManager;
-Lcom/android/internal/telephony/CallManager;->getPhoneInCall()Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/CallManager;->getRingingCalls()Ljava/util/List;
-Lcom/android/internal/telephony/CallManager;->getRingingPhone()Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/CallManager;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
-Lcom/android/internal/telephony/CallManager;->getState(I)Lcom/android/internal/telephony/PhoneConstants$State;
-Lcom/android/internal/telephony/CallManager;->hasActiveBgCall()Z
-Lcom/android/internal/telephony/CallManager;->hasActiveBgCall(I)Z
-Lcom/android/internal/telephony/CallManager;->hasActiveFgCall()Z
-Lcom/android/internal/telephony/CallManager;->hasActiveFgCall(I)Z
-Lcom/android/internal/telephony/CallManager;->hasActiveRingingCall(I)Z
-Lcom/android/internal/telephony/CallManager;->hasMoreThanOneRingingCall()Z
-Lcom/android/internal/telephony/CallManager;->hasMoreThanOneRingingCall(I)Z
-Lcom/android/internal/telephony/CallManager;->mBackgroundCalls:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/CallManager;->mEmptyConnections:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/CallManager;->mForegroundCalls:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/CallManager;->mPhones:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/CallManager;->mRingingCalls:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/CallManager;->registerForDisconnect(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CallManager;->registerForNewRingingConnection(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CallManager;->registerForPreciseCallStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CallManager;->registerPhone(Lcom/android/internal/telephony/Phone;)Z
-Lcom/android/internal/telephony/CallManager;->unregisterForDisconnect(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/CallManager;->unregisterForNewRingingConnection(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/CallManager;->unregisterForPreciseCallStateChanged(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/CallManager;->unregisterPhone(Lcom/android/internal/telephony/Phone;)V
-Lcom/android/internal/telephony/CallStateException;-><init>(Ljava/lang/String;)V
 Lcom/android/internal/telephony/CallTracker;-><init>()V
-Lcom/android/internal/telephony/CallTracker;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
-Lcom/android/internal/telephony/CallTracker;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/CallTracker;->mCi:Lcom/android/internal/telephony/CommandsInterface;
-Lcom/android/internal/telephony/CallTracker;->mNeedsPoll:Z
-Lcom/android/internal/telephony/CallTracker;->mNumberConverted:Z
-Lcom/android/internal/telephony/CallTracker;->mPendingOperations:I
-Lcom/android/internal/telephony/CallTracker;->registerForVoiceCallEnded(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CarrierServiceBindHelper;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/CarrierServiceBindHelper;->mHandler:Landroid/os/Handler;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->CLOSE_CHANNEL:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->DISPLAY_TEXT:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->fromInt(I)Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->GET_CHANNEL_STATUS:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->GET_INKEY:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->GET_INPUT:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->LANGUAGE_NOTIFICATION:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->LAUNCH_BROWSER:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->OPEN_CHANNEL:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->PLAY_TONE:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->PROVIDE_LOCAL_INFORMATION:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->RECEIVE_DATA:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->REFRESH:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SELECT_ITEM:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_DATA:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_DTMF:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_SMS:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_SS:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SEND_USSD:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_CALL:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_EVENT_LIST:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_IDLE_MODE_TEXT:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/AppInterface$CommandType;->SET_UP_MENU:Lcom/android/internal/telephony/cat/AppInterface$CommandType;
 Lcom/android/internal/telephony/cat/AppInterface$CommandType;->values()[Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;->callMsg:Lcom/android/internal/telephony/cat/TextMessage;
-Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;->confirmMsg:Lcom/android/internal/telephony/cat/TextMessage;
-Lcom/android/internal/telephony/cat/CatCmdMessage$SetupEventListSettings;->eventList:[I
-Lcom/android/internal/telephony/cat/CatCmdMessage;->getCallSettings()Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;
-Lcom/android/internal/telephony/cat/CatCmdMessage;->getCmdType()Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/CatCmdMessage;->geTextMessage()Lcom/android/internal/telephony/cat/TextMessage;
-Lcom/android/internal/telephony/cat/CatCmdMessage;->getSetEventList()Lcom/android/internal/telephony/cat/CatCmdMessage$SetupEventListSettings;
-Lcom/android/internal/telephony/cat/CatCmdMessage;->hasIconLoadFailed()Z
-Lcom/android/internal/telephony/cat/CatCmdMessage;->mCallSettings:Lcom/android/internal/telephony/cat/CatCmdMessage$CallSettings;
-Lcom/android/internal/telephony/cat/CatCmdMessage;->mCmdDet:Lcom/android/internal/telephony/cat/CommandDetails;
-Lcom/android/internal/telephony/cat/CatCmdMessage;->mInput:Lcom/android/internal/telephony/cat/Input;
-Lcom/android/internal/telephony/cat/CatCmdMessage;->mMenu:Lcom/android/internal/telephony/cat/Menu;
-Lcom/android/internal/telephony/cat/CatCmdMessage;->mTextMsg:Lcom/android/internal/telephony/cat/TextMessage;
-Lcom/android/internal/telephony/cat/CatLog;->d(Ljava/lang/Object;Ljava/lang/String;)V
-Lcom/android/internal/telephony/cat/CatLog;->d(Ljava/lang/String;Ljava/lang/String;)V
-Lcom/android/internal/telephony/cat/CatLog;->e(Ljava/lang/Object;Ljava/lang/String;)V
-Lcom/android/internal/telephony/cat/CatResponseMessage;->setEventDownload(I[B)V
-Lcom/android/internal/telephony/cat/CatService;->dispose()V
-Lcom/android/internal/telephony/cat/CatService;->isStkAppInstalled()Z
-Lcom/android/internal/telephony/cat/CatService;->mCmdIf:Lcom/android/internal/telephony/CommandsInterface;
-Lcom/android/internal/telephony/cat/CatService;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/cat/CatService;->mCurrntCmd:Lcom/android/internal/telephony/cat/CatCmdMessage;
-Lcom/android/internal/telephony/cat/CatService;->mMenuCmd:Lcom/android/internal/telephony/cat/CatCmdMessage;
-Lcom/android/internal/telephony/cat/CatService;->mMsgDecoder:Lcom/android/internal/telephony/cat/RilMessageDecoder;
-Lcom/android/internal/telephony/cat/CatService;->mSlotId:I
-Lcom/android/internal/telephony/cat/CatService;->mStkAppInstalled:Z
-Lcom/android/internal/telephony/cat/CatService;->mUiccController:Lcom/android/internal/telephony/uicc/UiccController;
-Lcom/android/internal/telephony/cat/CatService;->sendTerminalResponse(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/ResultCode;ZILcom/android/internal/telephony/cat/ResponseData;)V
-Lcom/android/internal/telephony/cat/CatService;->sInstance:[Lcom/android/internal/telephony/cat/CatService;
-Lcom/android/internal/telephony/cat/CatService;->sInstanceLock:Ljava/lang/Object;
-Lcom/android/internal/telephony/cat/CommandDetails;->commandNumber:I
-Lcom/android/internal/telephony/cat/CommandDetails;->commandQualifier:I
-Lcom/android/internal/telephony/cat/CommandDetails;->compRequired:Z
-Lcom/android/internal/telephony/cat/CommandDetails;->typeOfCommand:I
-Lcom/android/internal/telephony/cat/CommandParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;)V
-Lcom/android/internal/telephony/cat/CommandParams;->getCommandType()Lcom/android/internal/telephony/cat/AppInterface$CommandType;
-Lcom/android/internal/telephony/cat/CommandParams;->mCmdDet:Lcom/android/internal/telephony/cat/CommandDetails;
-Lcom/android/internal/telephony/cat/CommandParamsFactory;->dispose()V
-Lcom/android/internal/telephony/cat/CommandParamsFactory;->mIconLoader:Lcom/android/internal/telephony/cat/IconLoader;
-Lcom/android/internal/telephony/cat/CommandParamsFactory;->searchForNextTag(Lcom/android/internal/telephony/cat/ComprehensionTlvTag;Ljava/util/Iterator;)Lcom/android/internal/telephony/cat/ComprehensionTlv;
-Lcom/android/internal/telephony/cat/CommandParamsFactory;->searchForTag(Lcom/android/internal/telephony/cat/ComprehensionTlvTag;Ljava/util/List;)Lcom/android/internal/telephony/cat/ComprehensionTlv;
-Lcom/android/internal/telephony/cat/ComprehensionTlv;->getLength()I
-Lcom/android/internal/telephony/cat/ComprehensionTlv;->getRawValue()[B
-Lcom/android/internal/telephony/cat/ComprehensionTlv;->getTag()I
-Lcom/android/internal/telephony/cat/ComprehensionTlv;->getValueIndex()I
-Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->ADDRESS:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
-Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->ALPHA_ID:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
-Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->COMMAND_DETAILS:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
-Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->DEVICE_IDENTITIES:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
-Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->ICON_ID:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
-Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->RESULT:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
-Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->SMS_TPDU:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
-Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->TEXT_ATTRIBUTE:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
-Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->TEXT_STRING:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
-Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->USSD_STRING:Lcom/android/internal/telephony/cat/ComprehensionTlvTag;
-Lcom/android/internal/telephony/cat/ComprehensionTlvTag;->value()I
-Lcom/android/internal/telephony/cat/DeviceIdentities;->destinationId:I
-Lcom/android/internal/telephony/cat/DisplayTextParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/TextMessage;)V
-Lcom/android/internal/telephony/cat/DisplayTextParams;->mTextMsg:Lcom/android/internal/telephony/cat/TextMessage;
-Lcom/android/internal/telephony/cat/Duration$TimeUnit;->value()I
-Lcom/android/internal/telephony/cat/Duration;->timeInterval:I
-Lcom/android/internal/telephony/cat/Duration;->timeUnit:Lcom/android/internal/telephony/cat/Duration$TimeUnit;
-Lcom/android/internal/telephony/cat/GetInputParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/Input;)V
-Lcom/android/internal/telephony/cat/IconId;->recordNumber:I
-Lcom/android/internal/telephony/cat/IconLoader;->loadIcon(ILandroid/os/Message;)V
-Lcom/android/internal/telephony/cat/Menu;->titleAttrs:Ljava/util/List;
-Lcom/android/internal/telephony/cat/PlayToneParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/TextMessage;Lcom/android/internal/telephony/cat/Tone;Lcom/android/internal/telephony/cat/Duration;Z)V
 Lcom/android/internal/telephony/cat/ResponseData;-><init>()V
-Lcom/android/internal/telephony/cat/ResponseData;->format(Ljava/io/ByteArrayOutputStream;)V
-Lcom/android/internal/telephony/cat/ResultCode;->BACKWARD_MOVE_BY_USER:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->BEYOND_TERMINAL_CAPABILITY:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->BIP_ERROR:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->CMD_DATA_NOT_UNDERSTOOD:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->HELP_INFO_REQUIRED:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->LAUNCH_BROWSER_ERROR:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->NETWORK_CRNTLY_UNABLE_TO_PROCESS:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->NO_RESPONSE_FROM_USER:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->OK:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_ICON_NOT_DISPLAYED:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_LIMITED_SERVICE:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_MODIFIED_BY_NAA:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_NAA_NOT_ACTIVE:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_TONE_NOT_PLAYED:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_ADDITIONAL_EFS_READ:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_MISSING_INFO:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_MODIFICATION:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->PRFRMD_WITH_PARTIAL_COMPREHENSION:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->REQUIRED_VALUES_MISSING:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->TERMINAL_CRNTLY_UNABLE_TO_PROCESS:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->UICC_SESSION_TERM_BY_USER:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->USER_NOT_ACCEPT:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->USIM_CALL_CONTROL_PERMANENT:Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultCode;->value()I
 Lcom/android/internal/telephony/cat/ResultCode;->values()[Lcom/android/internal/telephony/cat/ResultCode;
-Lcom/android/internal/telephony/cat/ResultException;-><init>(Lcom/android/internal/telephony/cat/ResultCode;)V
-Lcom/android/internal/telephony/cat/RilMessage;-><init>(ILjava/lang/String;)V
-Lcom/android/internal/telephony/cat/RilMessage;->mData:Ljava/lang/Object;
-Lcom/android/internal/telephony/cat/RilMessage;->mId:I
-Lcom/android/internal/telephony/cat/RilMessageDecoder;->getInstance(Landroid/os/Handler;Lcom/android/internal/telephony/uicc/IccFileHandler;I)Lcom/android/internal/telephony/cat/RilMessageDecoder;
-Lcom/android/internal/telephony/cat/RilMessageDecoder;->mCmdParamsFactory:Lcom/android/internal/telephony/cat/CommandParamsFactory;
 Lcom/android/internal/telephony/cat/RilMessageDecoder;->mCurrentRilMessage:Lcom/android/internal/telephony/cat/RilMessage;
-Lcom/android/internal/telephony/cat/RilMessageDecoder;->mInstance:[Lcom/android/internal/telephony/cat/RilMessageDecoder;
-Lcom/android/internal/telephony/cat/RilMessageDecoder;->mStateStart:Lcom/android/internal/telephony/cat/RilMessageDecoder$StateStart;
 Lcom/android/internal/telephony/cat/RilMessageDecoder;->sendCmdForExecution(Lcom/android/internal/telephony/cat/RilMessage;)V
 Lcom/android/internal/telephony/cat/RilMessageDecoder;->sendStartDecodingMessageParams(Lcom/android/internal/telephony/cat/RilMessage;)V
-Lcom/android/internal/telephony/cat/SelectItemParams;-><init>(Lcom/android/internal/telephony/cat/CommandDetails;Lcom/android/internal/telephony/cat/Menu;Z)V
-Lcom/android/internal/telephony/cat/TextMessage;-><init>()V
-Lcom/android/internal/telephony/cat/TextMessage;->iconSelfExplanatory:Z
-Lcom/android/internal/telephony/cat/TextMessage;->text:Ljava/lang/String;
 Lcom/android/internal/telephony/cat/ValueObject;-><init>()V
-Lcom/android/internal/telephony/cat/ValueParser;->retrieveAlphaId(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Ljava/lang/String;
 Lcom/android/internal/telephony/cat/ValueParser;->retrieveDeviceIdentities(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Lcom/android/internal/telephony/cat/DeviceIdentities;
-Lcom/android/internal/telephony/cat/ValueParser;->retrieveTextAttribute(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Ljava/util/List;
-Lcom/android/internal/telephony/cat/ValueParser;->retrieveTextString(Lcom/android/internal/telephony/cat/ComprehensionTlv;)Ljava/lang/String;
-Lcom/android/internal/telephony/cdma/CdmaCallWaitingNotification;->number:Ljava/lang/String;
-Lcom/android/internal/telephony/cdma/CdmaMmiCode;->makeEmptyNull(Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/cdma/CdmaMmiCode;->mSc:Ljava/lang/String;
-Lcom/android/internal/telephony/cdma/CdmaSMSDispatcher;->getFormat()Ljava/lang/String;
-Lcom/android/internal/telephony/cdma/CdmaSMSDispatcher;->handleCdmaStatusReport(Lcom/android/internal/telephony/cdma/SmsMessage;)V
-Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;->getCdmaSubscriptionSource()I
-Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;->getInstance(Landroid/content/Context;Lcom/android/internal/telephony/CommandsInterface;Landroid/os/Handler;ILjava/lang/Object;)Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager;
-Lcom/android/internal/telephony/cdma/EriManager$EriDisplayInformation;->mEriIconText:Ljava/lang/String;
-Lcom/android/internal/telephony/cdma/EriManager;->getEriDisplayInformation(II)Lcom/android/internal/telephony/cdma/EriManager$EriDisplayInformation;
 Lcom/android/internal/telephony/cdma/sms/BearerData$CodingException;-><init>(Ljava/lang/String;)V
 Lcom/android/internal/telephony/cdma/sms/BearerData$TimeStamp;-><init>()V
 Lcom/android/internal/telephony/cdma/sms/BearerData;-><init>()V
@@ -2084,130 +1832,6 @@
 Lcom/android/internal/telephony/cdma/SmsMessage;->mEnvelope:Lcom/android/internal/telephony/cdma/sms/SmsEnvelope;
 Lcom/android/internal/telephony/cdma/SmsMessage;->parseSms()V
 Lcom/android/internal/telephony/cdma/SmsMessage;->privateGetSubmitPdu(Ljava/lang/String;ZLcom/android/internal/telephony/cdma/sms/UserData;)Lcom/android/internal/telephony/cdma/SmsMessage$SubmitPdu;
-Lcom/android/internal/telephony/CommandException$Error;->GENERIC_FAILURE:Lcom/android/internal/telephony/CommandException$Error;
-Lcom/android/internal/telephony/CommandException$Error;->PASSWORD_INCORRECT:Lcom/android/internal/telephony/CommandException$Error;
-Lcom/android/internal/telephony/CommandException$Error;->RADIO_NOT_AVAILABLE:Lcom/android/internal/telephony/CommandException$Error;
-Lcom/android/internal/telephony/CommandException$Error;->REQUEST_NOT_SUPPORTED:Lcom/android/internal/telephony/CommandException$Error;
-Lcom/android/internal/telephony/CommandException$Error;->SIM_PUK2:Lcom/android/internal/telephony/CommandException$Error;
-Lcom/android/internal/telephony/CommandException$Error;->SMS_FAIL_RETRY:Lcom/android/internal/telephony/CommandException$Error;
-Lcom/android/internal/telephony/CommandException;-><init>(Lcom/android/internal/telephony/CommandException$Error;)V
-Lcom/android/internal/telephony/CommandException;->fromRilErrno(I)Lcom/android/internal/telephony/CommandException;
-Lcom/android/internal/telephony/CommandException;->getCommandError()Lcom/android/internal/telephony/CommandException$Error;
-Lcom/android/internal/telephony/CommandException;->mError:Lcom/android/internal/telephony/CommandException$Error;
-Lcom/android/internal/telephony/CommandsInterface;->acceptCall(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->acknowledgeLastIncomingCdmaSms(ZILandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->acknowledgeLastIncomingGsmSms(ZILandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->changeBarringPassword(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->deleteSmsOnRuim(ILandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->deleteSmsOnSim(ILandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->exitEmergencyCallbackMode(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getBasebandVersion(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getCdmaBroadcastConfig(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getCDMASubscription(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getDataCallList(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getIccCardStatus(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getIMEISV(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getIMSI(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getLastDataCallFailCause(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getLastPdpFailCause(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getNetworkSelectionMode(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getOperator(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getPDPContextList(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getPreferredNetworkType(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getSignalStrength(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getSmscAddress(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->getVoiceRegistrationState(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->handleCallSetupRequestFromSim(ZLandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->iccIO(IILjava/lang/String;IIILjava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->iccIOForApp(IILjava/lang/String;IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->invokeOemRilRequestRaw([BLandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->queryCallForwardStatus(IILjava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->queryCallWaiting(ILandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->queryFacilityLock(Ljava/lang/String;Ljava/lang/String;ILandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->queryTTYMode(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->registerForAvailable(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->registerForCdmaOtaProvision(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->registerForCellInfoList(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->registerForIccRefresh(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->registerForImsNetworkStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->registerForNotAvailable(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->registerForOffOrNotAvailable(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->registerForOn(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->registerForRadioStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->registerForRilConnected(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->reportSmsMemoryStatus(ZLandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->reportStkServiceIsRunning(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->requestIccSimAuthentication(ILjava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->requestShutdown(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->sendDtmf(CLandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->sendEnvelope(Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->sendTerminalResponse(Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->setCallForward(IIILjava/lang/String;ILandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->setCallWaiting(ZILandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->setCdmaBroadcastActivation(ZLandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->setDataAllowed(ZLandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->setEmergencyCallbackMode(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setFacilityLock(Ljava/lang/String;ZLjava/lang/String;ILandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->setNetworkSelectionModeAutomatic(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->setNetworkSelectionModeManual(Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnCallRing(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnCatCallSetUp(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnCatCcAlphaNotify(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnCatEvent(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnCatProactiveCmd(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnCatSessionEnd(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnIccRefresh(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnIccSmsFull(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnNewGsmBroadcastSms(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnNITZTime(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnSignalStrengthUpdate(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnSmsOnSim(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnSmsStatus(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setOnSuppServiceNotification(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/CommandsInterface;->setPhoneType(I)V
-Lcom/android/internal/telephony/CommandsInterface;->setPreferredNetworkType(ILandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->setRadioPower(ZLandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->setSmscAddress(Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->setTTYMode(ILandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->setUiccSubscription(IIIILandroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->supplyIccPin(Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->switchWaitingOrHoldingAndActive(Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->unregisterForAvailable(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/CommandsInterface;->unregisterForCdmaOtaProvision(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/CommandsInterface;->unregisterForOffOrNotAvailable(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/CommandsInterface;->unregisterForOn(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/CommandsInterface;->unregisterForRilConnected(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/CommandsInterface;->unregisterForVoiceRadioTechChanged(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/CommandsInterface;->writeSmsToRuim(ILjava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/CommandsInterface;->writeSmsToSim(ILjava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/Connection$PostDialState;->CANCELLED:Lcom/android/internal/telephony/Connection$PostDialState;
-Lcom/android/internal/telephony/Connection$PostDialState;->COMPLETE:Lcom/android/internal/telephony/Connection$PostDialState;
-Lcom/android/internal/telephony/Connection$PostDialState;->NOT_STARTED:Lcom/android/internal/telephony/Connection$PostDialState;
-Lcom/android/internal/telephony/Connection$PostDialState;->STARTED:Lcom/android/internal/telephony/Connection$PostDialState;
-Lcom/android/internal/telephony/Connection$PostDialState;->WAIT:Lcom/android/internal/telephony/Connection$PostDialState;
-Lcom/android/internal/telephony/Connection$PostDialState;->WILD:Lcom/android/internal/telephony/Connection$PostDialState;
-Lcom/android/internal/telephony/Connection;-><init>(I)V
-Lcom/android/internal/telephony/Connection;->getAddress()Ljava/lang/String;
-Lcom/android/internal/telephony/Connection;->getCall()Lcom/android/internal/telephony/Call;
-Lcom/android/internal/telephony/Connection;->getConnectTime()J
-Lcom/android/internal/telephony/Connection;->getCreateTime()J
-Lcom/android/internal/telephony/Connection;->getDisconnectCause()I
-Lcom/android/internal/telephony/Connection;->getDisconnectTime()J
-Lcom/android/internal/telephony/Connection;->getDurationMillis()J
-Lcom/android/internal/telephony/Connection;->getState()Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/Connection;->getUserData()Ljava/lang/Object;
-Lcom/android/internal/telephony/Connection;->hangup()V
-Lcom/android/internal/telephony/Connection;->isAlive()Z
-Lcom/android/internal/telephony/Connection;->isIncoming()Z
-Lcom/android/internal/telephony/Connection;->LOG_TAG:Ljava/lang/String;
-Lcom/android/internal/telephony/Connection;->mAddress:Ljava/lang/String;
-Lcom/android/internal/telephony/Connection;->mCnapName:Ljava/lang/String;
-Lcom/android/internal/telephony/Connection;->mCnapNamePresentation:I
-Lcom/android/internal/telephony/Connection;->mDialString:Ljava/lang/String;
-Lcom/android/internal/telephony/Connection;->mDuration:J
-Lcom/android/internal/telephony/Connection;->mIsIncoming:Z
-Lcom/android/internal/telephony/Connection;->mNumberPresentation:I
-Lcom/android/internal/telephony/Connection;->setVideoState(I)V
 Lcom/android/internal/telephony/DctConstants$Activity;->DATAIN:Lcom/android/internal/telephony/DctConstants$Activity;
 Lcom/android/internal/telephony/DctConstants$Activity;->DATAINANDOUT:Lcom/android/internal/telephony/DctConstants$Activity;
 Lcom/android/internal/telephony/DctConstants$Activity;->DATAOUT:Lcom/android/internal/telephony/DctConstants$Activity;
@@ -2220,22 +1844,7 @@
 Lcom/android/internal/telephony/DctConstants$State;->IDLE:Lcom/android/internal/telephony/DctConstants$State;
 Lcom/android/internal/telephony/DctConstants$State;->RETRYING:Lcom/android/internal/telephony/DctConstants$State;
 Lcom/android/internal/telephony/DctConstants$State;->values()[Lcom/android/internal/telephony/DctConstants$State;
-Lcom/android/internal/telephony/DefaultPhoneNotifier;->mRegistry:Lcom/android/internal/telephony/ITelephonyRegistry;
-Lcom/android/internal/telephony/DriverCall$State;->ACTIVE:Lcom/android/internal/telephony/DriverCall$State;
-Lcom/android/internal/telephony/DriverCall$State;->ALERTING:Lcom/android/internal/telephony/DriverCall$State;
-Lcom/android/internal/telephony/DriverCall$State;->DIALING:Lcom/android/internal/telephony/DriverCall$State;
-Lcom/android/internal/telephony/DriverCall$State;->HOLDING:Lcom/android/internal/telephony/DriverCall$State;
-Lcom/android/internal/telephony/DriverCall$State;->INCOMING:Lcom/android/internal/telephony/DriverCall$State;
 Lcom/android/internal/telephony/DriverCall$State;->values()[Lcom/android/internal/telephony/DriverCall$State;
-Lcom/android/internal/telephony/DriverCall$State;->WAITING:Lcom/android/internal/telephony/DriverCall$State;
-Lcom/android/internal/telephony/DriverCall;-><init>()V
-Lcom/android/internal/telephony/DriverCall;->index:I
-Lcom/android/internal/telephony/DriverCall;->isMT:Z
-Lcom/android/internal/telephony/DriverCall;->isVoice:Z
-Lcom/android/internal/telephony/DriverCall;->name:Ljava/lang/String;
-Lcom/android/internal/telephony/DriverCall;->number:Ljava/lang/String;
-Lcom/android/internal/telephony/DriverCall;->numberPresentation:I
-Lcom/android/internal/telephony/DriverCall;->state:Lcom/android/internal/telephony/DriverCall$State;
 Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler$SmsCbConcatInfo;-><init>(Lcom/android/internal/telephony/gsm/SmsCbHeader;Landroid/telephony/SmsCbLocation;)V
 Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler$SmsCbConcatInfo;->matchesLocation(Ljava/lang/String;II)Z
 Lcom/android/internal/telephony/gsm/GsmCellBroadcastHandler;->mSmsCbPageMap:Ljava/util/HashMap;
@@ -2314,79 +1923,7 @@
 Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->mPhoneBookRecords:Ljava/util/ArrayList;
 Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;->reset()V
 Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;-><init>()V
-Lcom/android/internal/telephony/GsmCdmaCall;->attachFake(Lcom/android/internal/telephony/Connection;Lcom/android/internal/telephony/Call$State;)V
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->clearDisconnected()V
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->disableDataCallInEmergencyCall(Ljava/lang/String;)V
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->fakeHoldForegroundBeforeDial()V
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->getPhone()Lcom/android/internal/telephony/GsmCdmaPhone;
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->handleEcmTimer(I)V
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->isPhoneTypeGsm()Z
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->mBackgroundCall:Lcom/android/internal/telephony/GsmCdmaCall;
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->mForegroundCall:Lcom/android/internal/telephony/GsmCdmaCall;
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->mPendingMO:Lcom/android/internal/telephony/GsmCdmaConnection;
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->mPhone:Lcom/android/internal/telephony/GsmCdmaPhone;
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->mRingingCall:Lcom/android/internal/telephony/GsmCdmaCall;
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->mState:Lcom/android/internal/telephony/PhoneConstants$State;
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->obtainCompleteMessage()Landroid/os/Message;
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->obtainCompleteMessage(I)Landroid/os/Message;
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->setMute(Z)V
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->switchWaitingOrHoldingAndActive()V
-Lcom/android/internal/telephony/GsmCdmaCallTracker;->updatePhoneState()V
 Lcom/android/internal/telephony/GsmCdmaConnection$MyHandler;-><init>(Lcom/android/internal/telephony/GsmCdmaConnection;Landroid/os/Looper;)V
-Lcom/android/internal/telephony/GsmCdmaConnection;->acquireWakeLock()V
-Lcom/android/internal/telephony/GsmCdmaConnection;->createWakeLock(Landroid/content/Context;)V
-Lcom/android/internal/telephony/GsmCdmaConnection;->disconnectCauseFromCode(I)I
-Lcom/android/internal/telephony/GsmCdmaConnection;->fetchDtmfToneDelay(Lcom/android/internal/telephony/GsmCdmaPhone;)V
-Lcom/android/internal/telephony/GsmCdmaConnection;->findNextPCharOrNonPOrNonWCharIndex(Ljava/lang/String;I)I
-Lcom/android/internal/telephony/GsmCdmaConnection;->findPOrWCharToAppend(Ljava/lang/String;II)C
-Lcom/android/internal/telephony/GsmCdmaConnection;->formatDialString(Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/GsmCdmaConnection;->getState()Lcom/android/internal/telephony/Call$State;
-Lcom/android/internal/telephony/GsmCdmaConnection;->isPause(C)Z
-Lcom/android/internal/telephony/GsmCdmaConnection;->isPhoneTypeGsm()Z
-Lcom/android/internal/telephony/GsmCdmaConnection;->isWait(C)Z
-Lcom/android/internal/telephony/GsmCdmaConnection;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/GsmCdmaConnection;->maskDialString(Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/GsmCdmaConnection;->mIndex:I
-Lcom/android/internal/telephony/GsmCdmaConnection;->mOwner:Lcom/android/internal/telephony/GsmCdmaCallTracker;
-Lcom/android/internal/telephony/GsmCdmaConnection;->onConnectedInOrOut()V
-Lcom/android/internal/telephony/GsmCdmaConnection;->updateParent(Lcom/android/internal/telephony/GsmCdmaCall;Lcom/android/internal/telephony/GsmCdmaCall;)V
-Lcom/android/internal/telephony/GsmCdmaPhone$Cfu;-><init>(Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/GsmCdmaPhone;->exitEmergencyCallbackMode()V
-Lcom/android/internal/telephony/GsmCdmaPhone;->getCallTracker()Lcom/android/internal/telephony/CallTracker;
-Lcom/android/internal/telephony/GsmCdmaPhone;->getCdmaEriText()Ljava/lang/String;
-Lcom/android/internal/telephony/GsmCdmaPhone;->getEsn()Ljava/lang/String;
-Lcom/android/internal/telephony/GsmCdmaPhone;->getLine1Number()Ljava/lang/String;
-Lcom/android/internal/telephony/GsmCdmaPhone;->getPhoneType()I
-Lcom/android/internal/telephony/GsmCdmaPhone;->getServiceState()Landroid/telephony/ServiceState;
-Lcom/android/internal/telephony/GsmCdmaPhone;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
-Lcom/android/internal/telephony/GsmCdmaPhone;->getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/GsmCdmaPhone;->handleInCallMmiCommands(Ljava/lang/String;)Z
-Lcom/android/internal/telephony/GsmCdmaPhone;->isCfEnable(I)Z
-Lcom/android/internal/telephony/GsmCdmaPhone;->isEriFileLoaded()Z
-Lcom/android/internal/telephony/GsmCdmaPhone;->isInCall()Z
-Lcom/android/internal/telephony/GsmCdmaPhone;->isManualSelProhibitedInGlobalMode()Z
-Lcom/android/internal/telephony/GsmCdmaPhone;->isPhoneTypeGsm()Z
-Lcom/android/internal/telephony/GsmCdmaPhone;->isValidCommandInterfaceCFAction(I)Z
-Lcom/android/internal/telephony/GsmCdmaPhone;->isValidCommandInterfaceCFReason(I)Z
-Lcom/android/internal/telephony/GsmCdmaPhone;->logd(Ljava/lang/String;)V
-Lcom/android/internal/telephony/GsmCdmaPhone;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/GsmCdmaPhone;->mCT:Lcom/android/internal/telephony/GsmCdmaCallTracker;
-Lcom/android/internal/telephony/GsmCdmaPhone;->mEcmExitRespRegistrant:Landroid/os/Registrant;
-Lcom/android/internal/telephony/GsmCdmaPhone;->mEriManager:Lcom/android/internal/telephony/cdma/EriManager;
-Lcom/android/internal/telephony/GsmCdmaPhone;->mIccSmsInterfaceManager:Lcom/android/internal/telephony/IccSmsInterfaceManager;
-Lcom/android/internal/telephony/GsmCdmaPhone;->mIsimUiccRecords:Lcom/android/internal/telephony/uicc/IsimUiccRecords;
-Lcom/android/internal/telephony/GsmCdmaPhone;->mPendingMMIs:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/GsmCdmaPhone;->mSST:Lcom/android/internal/telephony/ServiceStateTracker;
-Lcom/android/internal/telephony/GsmCdmaPhone;->notifyPreciseCallStateChanged()V
-Lcom/android/internal/telephony/GsmCdmaPhone;->notifyServiceStateChanged(Landroid/telephony/ServiceState;)V
-Lcom/android/internal/telephony/GsmCdmaPhone;->setOnEcbModeExitResponse(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/GsmCdmaPhone;->syncClirSetting()V
-Lcom/android/internal/telephony/IccCard;->getState()Lcom/android/internal/telephony/IccCardConstants$State;
-Lcom/android/internal/telephony/IccCard;->registerForNetworkLocked(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/IccCard;->supplyNetworkDepersonalization(Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/IccCard;->supplyPin(Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/IccCard;->supplyPuk(Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
 Lcom/android/internal/telephony/IccCardConstants$State;->ABSENT:Lcom/android/internal/telephony/IccCardConstants$State;
 Lcom/android/internal/telephony/IccCardConstants$State;->CARD_IO_ERROR:Lcom/android/internal/telephony/IccCardConstants$State;
 Lcom/android/internal/telephony/IccCardConstants$State;->NETWORK_LOCKED:Lcom/android/internal/telephony/IccCardConstants$State;
@@ -2397,47 +1934,7 @@
 Lcom/android/internal/telephony/IccCardConstants$State;->READY:Lcom/android/internal/telephony/IccCardConstants$State;
 Lcom/android/internal/telephony/IccCardConstants$State;->UNKNOWN:Lcom/android/internal/telephony/IccCardConstants$State;
 Lcom/android/internal/telephony/IccCardConstants$State;->values()[Lcom/android/internal/telephony/IccCardConstants$State;
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->checkThread()V
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->DBG:Z
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->logd(Ljava/lang/String;)V
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mAdnCache:Lcom/android/internal/telephony/uicc/AdnRecordCache;
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mBaseHandler:Landroid/os/Handler;
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->mPhone:Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;->updateEfForIccType(I)I
 Lcom/android/internal/telephony/IccProvider;-><init>()V
-Lcom/android/internal/telephony/IccProvider;->ADDRESS_BOOK_COLUMN_NAMES:[Ljava/lang/String;
-Lcom/android/internal/telephony/IccProvider;->DBG:Z
-Lcom/android/internal/telephony/IccProvider;->loadRecord(Lcom/android/internal/telephony/uicc/AdnRecord;Landroid/database/MatrixCursor;I)V
-Lcom/android/internal/telephony/IccProvider;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->copyMessageToIccEf(Ljava/lang/String;I[B[B)Z
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->disableCdmaBroadcastRange(II)Z
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->disableGsmBroadcastRange(II)Z
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->enableCdmaBroadcastRange(II)Z
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->enableGsmBroadcastRange(II)Z
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->enforceReceiveAndSend(Ljava/lang/String;)V
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->filterDestAddress(Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->getAllMessagesFromIccEf(Ljava/lang/String;)Ljava/util/List;
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->getImsSmsFormat()Ljava/lang/String;
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->getPremiumSmsPermission(Ljava/lang/String;)I
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->injectSmsPdu([BLjava/lang/String;Landroid/app/PendingIntent;)V
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->isImsSmsSupported()Z
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->mAppOps:Landroid/app/AppOpsManager;
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->mCellBroadcastRangeManager:Lcom/android/internal/telephony/IccSmsInterfaceManager$CellBroadcastRangeManager;
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->mHandler:Landroid/os/Handler;
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->mLock:Ljava/lang/Object;
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->mPhone:Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->mSms:Ljava/util/List;
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->mSuccess:Z
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->sendData(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I[BLandroid/app/PendingIntent;Landroid/app/PendingIntent;)V
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->sendStoredMultipartText(Ljava/lang/String;Landroid/net/Uri;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->sendStoredText(Ljava/lang/String;Landroid/net/Uri;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/app/PendingIntent;)V
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->setCdmaBroadcastConfig([Lcom/android/internal/telephony/cdma/CdmaSmsBroadcastConfigInfo;)Z
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->setCellBroadcastConfig([Lcom/android/internal/telephony/gsm/SmsBroadcastConfigInfo;)Z
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->setPremiumSmsPermission(Ljava/lang/String;I)V
-Lcom/android/internal/telephony/IccSmsInterfaceManager;->updateMessageOnIccEf(Ljava/lang/String;II[B)Z
 Lcom/android/internal/telephony/IIccPhoneBook$Stub$Proxy;->mRemote:Landroid/os/IBinder;
 Lcom/android/internal/telephony/IIccPhoneBook$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IIccPhoneBook;
 Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsInEf(I)Ljava/util/List;
@@ -2446,142 +1943,24 @@
 Lcom/android/internal/telephony/IIccPhoneBook;->getAdnRecordsSizeForSubscriber(II)[I
 Lcom/android/internal/telephony/IIccPhoneBook;->updateAdnRecordsInEfBySearch(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
 Lcom/android/internal/telephony/IMms$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IMms;
-Lcom/android/internal/telephony/imsphone/ImsExternalCall;-><init>(Lcom/android/internal/telephony/Phone;Lcom/android/internal/telephony/imsphone/ImsExternalConnection;)V
 Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker$ExternalCallStateListener;-><init>(Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;)V
 Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker$ExternalConnectionListener;-><init>(Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker;)V
-Lcom/android/internal/telephony/imsphone/ImsExternalConnection;->rebuildCapabilities()V
-Lcom/android/internal/telephony/imsphone/ImsExternalConnection;->setActive()V
-Lcom/android/internal/telephony/imsphone/ImsPhone$Cf;-><init>(Ljava/lang/String;ZLandroid/os/Message;)V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->getActionFromCFAction(I)I
-Lcom/android/internal/telephony/imsphone/ImsPhone;->getBackgroundCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
-Lcom/android/internal/telephony/imsphone/ImsPhone;->getCallForwardingOption(ILandroid/os/Message;)V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->getCallWaiting(Landroid/os/Message;)V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->getConditionFromCFReason(I)I
-Lcom/android/internal/telephony/imsphone/ImsPhone;->getForegroundCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
-Lcom/android/internal/telephony/imsphone/ImsPhone;->getRingingCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
-Lcom/android/internal/telephony/imsphone/ImsPhone;->getServiceState()Landroid/telephony/ServiceState;
-Lcom/android/internal/telephony/imsphone/ImsPhone;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
-Lcom/android/internal/telephony/imsphone/ImsPhone;->handleEnterEmergencyCallbackMode()V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->handleExitEmergencyCallbackMode()V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->handleInCallMmiCommands(Ljava/lang/String;)Z
-Lcom/android/internal/telephony/imsphone/ImsPhone;->isCfEnable(I)Z
-Lcom/android/internal/telephony/imsphone/ImsPhone;->isUtEnabled()Z
-Lcom/android/internal/telephony/imsphone/ImsPhone;->isValidCommandInterfaceCFAction(I)Z
-Lcom/android/internal/telephony/imsphone/ImsPhone;->isValidCommandInterfaceCFReason(I)Z
-Lcom/android/internal/telephony/imsphone/ImsPhone;->isVolteEnabled()Z
-Lcom/android/internal/telephony/imsphone/ImsPhone;->mCT:Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;
-Lcom/android/internal/telephony/imsphone/ImsPhone;->mPendingMMIs:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/imsphone/ImsPhone;->mSS:Landroid/telephony/ServiceState;
 Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyCallForwardingIndicator()V
 Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyPreciseCallStateChanged()V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->notifyUnknownConnection(Lcom/android/internal/telephony/Connection;)V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->onMMIDone(Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;)V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->sendErrorResponse(Landroid/os/Message;)V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->sendErrorResponse(Landroid/os/Message;Ljava/lang/Throwable;)V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->setCallForwardingOption(IILjava/lang/String;IILandroid/os/Message;)V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->setCallWaiting(ZLandroid/os/Message;)V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->setImsRegistered(Z)V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->setOnEcbModeExitResponse(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/imsphone/ImsPhone;->setServiceState(I)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->attach(Lcom/android/internal/telephony/Connection;Lcom/android/internal/telephony/Call$State;)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->attachFake(Lcom/android/internal/telephony/Connection;Lcom/android/internal/telephony/Call$State;)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->getConnections()Ljava/util/List;
 Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->getImsCall()Lcom/android/ims/ImsCall;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->hangup()V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->merge(Lcom/android/internal/telephony/imsphone/ImsPhoneCall;Lcom/android/internal/telephony/Call$State;)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCall;->onHangupLocal()V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->addConnection(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->clearDisconnected()V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->dial(Ljava/lang/String;ILandroid/os/Bundle;)Lcom/android/internal/telephony/Connection;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->dialPendingMO()V
 Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->findConnection(Lcom/android/ims/ImsCall;)Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;
 Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->getEcbmInterface()Lcom/android/ims/ImsEcbm;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->getUtInterface()Lcom/android/ims/ImsUtInterface;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->handleEcmTimer(I)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mAllowEmergencyVideoCalls:Z
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mBackgroundCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
 Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mCallExpectedToResume:Lcom/android/ims/ImsCall;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mConnections:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mForegroundCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mHandoverCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
 Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mImsCallListener:Lcom/android/ims/ImsCall$Listener;
 Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mImsManager:Lcom/android/ims/ImsManager;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mOnHoldToneId:I
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mOnHoldToneStarted:Z
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mPendingMO:Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mPendingUssd:Landroid/os/Message;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mPhone:Lcom/android/internal/telephony/imsphone/ImsPhone;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mRingingCall:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mSwitchingFgAndBgCalls:Z
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mSyncHold:Ljava/lang/Object;
 Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->mUssdSession:Lcom/android/ims/ImsCall;
 Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->processCallStateChange(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;I)V
 Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->processCallStateChange(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;IZ)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->removeConnection(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;)V
 Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->setVideoCallProvider(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;Lcom/android/ims/ImsCall;)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->switchAfterConferenceSuccess()V
-Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;->updatePhoneState()V
 Lcom/android/internal/telephony/imsphone/ImsPhoneConnection$MyHandler;-><init>(Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;Landroid/os/Looper;)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->acquireWakeLock()V
-Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->createWakeLock(Landroid/content/Context;)V
-Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->getCall()Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
-Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->getOwner()Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;
-Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->isMultiparty()Z
-Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mDisconnected:Z
 Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mImsCall:Lcom/android/ims/ImsCall;
-Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mOwner:Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker;
-Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->mParent:Lcom/android/internal/telephony/imsphone/ImsPhoneCall;
-Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->onDisconnect()Z
 Lcom/android/internal/telephony/imsphone/ImsPhoneConnection;->update(Lcom/android/ims/ImsCall;Lcom/android/internal/telephony/Call$State;)Z
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getCLIRMode()I
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getDialingNumber()Ljava/lang/String;
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getErrorMessage(Landroid/os/AsyncResult;)Ljava/lang/CharSequence;
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->getScString()Ljava/lang/CharSequence;
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isActivate()Z
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isDeactivate()Z
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isEmptyOrNull(Ljava/lang/CharSequence;)Z
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isErasure()Z
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isRegister()Z
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isSupportedOverImsPhone()Z
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->isTemporaryModeCLIR()Z
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->mPhone:Lcom/android/internal/telephony/imsphone/ImsPhone;
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->newFromDialString(Ljava/lang/String;Lcom/android/internal/telephony/imsphone/ImsPhone;)Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->processCode()V
-Lcom/android/internal/telephony/imsphone/ImsPhoneMmiCode;->serviceClassToCFString(I)Ljava/lang/CharSequence;
 Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;-><init>(Lcom/android/internal/telephony/InboundSmsHandler;Lcom/android/internal/telephony/InboundSmsTracker;)V
-Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;->mDeleteWhere:Ljava/lang/String;
-Lcom/android/internal/telephony/InboundSmsHandler$SmsBroadcastReceiver;->mDeleteWhereArgs:[Ljava/lang/String;
-Lcom/android/internal/telephony/InboundSmsHandler;->acknowledgeLastIncomingSms(ZILandroid/os/Message;)V
-Lcom/android/internal/telephony/InboundSmsHandler;->deleteFromRawTable(Ljava/lang/String;[Ljava/lang/String;I)V
-Lcom/android/internal/telephony/InboundSmsHandler;->dispatchIntent(Landroid/content/Intent;Ljava/lang/String;ILandroid/os/Bundle;Landroid/content/BroadcastReceiver;Landroid/os/UserHandle;)V
-Lcom/android/internal/telephony/InboundSmsHandler;->dispatchNormalMessage(Lcom/android/internal/telephony/SmsMessageBase;)I
-Lcom/android/internal/telephony/InboundSmsHandler;->getPhone()Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/InboundSmsHandler;->handleInjectSms(Landroid/os/AsyncResult;)V
-Lcom/android/internal/telephony/InboundSmsHandler;->handleNewSms(Landroid/os/AsyncResult;)V
-Lcom/android/internal/telephony/InboundSmsHandler;->handleSmsWhitelisting(Landroid/content/ComponentName;)Landroid/os/Bundle;
-Lcom/android/internal/telephony/InboundSmsHandler;->isSkipNotifyFlagSet(I)Z
-Lcom/android/internal/telephony/InboundSmsHandler;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/InboundSmsHandler;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/InboundSmsHandler;->mCellBroadcastHandler:Lcom/android/internal/telephony/CellBroadcastHandler;
-Lcom/android/internal/telephony/InboundSmsHandler;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/InboundSmsHandler;->mDeliveringState:Lcom/android/internal/telephony/InboundSmsHandler$DeliveringState;
-Lcom/android/internal/telephony/InboundSmsHandler;->mDeviceIdleController:Landroid/os/IDeviceIdleController;
-Lcom/android/internal/telephony/InboundSmsHandler;->mIdleState:Lcom/android/internal/telephony/InboundSmsHandler$IdleState;
-Lcom/android/internal/telephony/InboundSmsHandler;->mPhone:Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/InboundSmsHandler;->mResolver:Landroid/content/ContentResolver;
-Lcom/android/internal/telephony/InboundSmsHandler;->mUserManager:Landroid/os/UserManager;
-Lcom/android/internal/telephony/InboundSmsHandler;->mWaitingState:Lcom/android/internal/telephony/InboundSmsHandler$WaitingState;
-Lcom/android/internal/telephony/InboundSmsHandler;->mWakeLock:Landroid/os/PowerManager$WakeLock;
-Lcom/android/internal/telephony/InboundSmsHandler;->mWapPush:Lcom/android/internal/telephony/WapPushOverSms;
-Lcom/android/internal/telephony/InboundSmsHandler;->processMessagePart(Lcom/android/internal/telephony/InboundSmsTracker;)Z
-Lcom/android/internal/telephony/InboundSmsHandler;->showNewMessageNotification()V
-Lcom/android/internal/telephony/InboundSmsHandler;->writeInboxMessage(Landroid/content/Intent;)Landroid/net/Uri;
-Lcom/android/internal/telephony/InboundSmsTracker;->getFormat()Ljava/lang/String;
-Lcom/android/internal/telephony/InboundSmsTracker;->getIndexOffset()I
-Lcom/android/internal/telephony/IntRangeManager;->mRanges:Ljava/util/ArrayList;
 Lcom/android/internal/telephony/IPhoneStateListener$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneStateListener;
 Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/telephony/IPhoneSubInfo$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;
@@ -2603,91 +1982,6 @@
 Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/telephony/ITelephonyRegistry$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephonyRegistry;
 Lcom/android/internal/telephony/IWapPushManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IWapPushManager;
-Lcom/android/internal/telephony/MccTable$MccEntry;->mIso:Ljava/lang/String;
-Lcom/android/internal/telephony/MccTable;->countryCodeForMcc(I)Ljava/lang/String;
-Lcom/android/internal/telephony/MccTable;->defaultLanguageForMcc(I)Ljava/lang/String;
-Lcom/android/internal/telephony/MccTable;->defaultTimeZoneForMcc(I)Ljava/lang/String;
-Lcom/android/internal/telephony/MccTable;->entryForMcc(I)Lcom/android/internal/telephony/MccTable$MccEntry;
-Lcom/android/internal/telephony/MccTable;->getLocaleForLanguageCountry(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale;
-Lcom/android/internal/telephony/MccTable;->smallestDigitsMccForMnc(I)I
-Lcom/android/internal/telephony/MmiCode$State;->CANCELLED:Lcom/android/internal/telephony/MmiCode$State;
-Lcom/android/internal/telephony/MmiCode$State;->COMPLETE:Lcom/android/internal/telephony/MmiCode$State;
-Lcom/android/internal/telephony/MmiCode$State;->FAILED:Lcom/android/internal/telephony/MmiCode$State;
-Lcom/android/internal/telephony/MmiCode$State;->PENDING:Lcom/android/internal/telephony/MmiCode$State;
-Lcom/android/internal/telephony/MmiCode;->getPhone()Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/Phone;->dispose()V
-Lcom/android/internal/telephony/Phone;->exitEmergencyCallbackMode()V
-Lcom/android/internal/telephony/Phone;->getActiveApnTypes()[Ljava/lang/String;
-Lcom/android/internal/telephony/Phone;->getCallTracker()Lcom/android/internal/telephony/CallTracker;
-Lcom/android/internal/telephony/Phone;->getCellLocation()Landroid/telephony/CellLocation;
-Lcom/android/internal/telephony/Phone;->getContext()Landroid/content/Context;
-Lcom/android/internal/telephony/Phone;->getDataConnectionState()Lcom/android/internal/telephony/PhoneConstants$DataState;
-Lcom/android/internal/telephony/Phone;->getIccCard()Lcom/android/internal/telephony/IccCard;
-Lcom/android/internal/telephony/Phone;->getIccFileHandler()Lcom/android/internal/telephony/uicc/IccFileHandler;
-Lcom/android/internal/telephony/Phone;->getIccSerialNumber()Ljava/lang/String;
-Lcom/android/internal/telephony/Phone;->getIccSmsInterfaceManager()Lcom/android/internal/telephony/IccSmsInterfaceManager;
-Lcom/android/internal/telephony/Phone;->getImsPhone()Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/Phone;->getIsimRecords()Lcom/android/internal/telephony/uicc/IsimRecords;
-Lcom/android/internal/telephony/Phone;->getMsisdn()Ljava/lang/String;
-Lcom/android/internal/telephony/Phone;->getNai()Ljava/lang/String;
-Lcom/android/internal/telephony/Phone;->getPhoneId()I
-Lcom/android/internal/telephony/Phone;->getPhoneName()Ljava/lang/String;
-Lcom/android/internal/telephony/Phone;->getPhoneType()I
-Lcom/android/internal/telephony/Phone;->getServiceStateTracker()Lcom/android/internal/telephony/ServiceStateTracker;
-Lcom/android/internal/telephony/Phone;->getSmscAddress(Landroid/os/Message;)V
-Lcom/android/internal/telephony/Phone;->getState()Lcom/android/internal/telephony/PhoneConstants$State;
-Lcom/android/internal/telephony/Phone;->getSubId()I
-Lcom/android/internal/telephony/Phone;->getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/Phone;->getUiccCard()Lcom/android/internal/telephony/uicc/UiccCard;
-Lcom/android/internal/telephony/Phone;->getVideoState(Lcom/android/internal/telephony/Call;)I
-Lcom/android/internal/telephony/Phone;->invokeOemRilRequestRaw([BLandroid/os/Message;)V
-Lcom/android/internal/telephony/Phone;->invokeOemRilRequestStrings([Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/Phone;->isCspPlmnEnabled()Z
-Lcom/android/internal/telephony/Phone;->isUtEnabled()Z
-Lcom/android/internal/telephony/Phone;->isVideoEnabled()Z
-Lcom/android/internal/telephony/Phone;->isVolteEnabled()Z
-Lcom/android/internal/telephony/Phone;->isWifiCallingEnabled()Z
-Lcom/android/internal/telephony/Phone;->mCi:Lcom/android/internal/telephony/CommandsInterface;
-Lcom/android/internal/telephony/Phone;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/Phone;->mIccRecords:Ljava/util/concurrent/atomic/AtomicReference;
-Lcom/android/internal/telephony/Phone;->mImsPhone:Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/Phone;->mMmiRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/Phone;->mNotifier:Lcom/android/internal/telephony/PhoneNotifier;
-Lcom/android/internal/telephony/Phone;->mPhoneId:I
-Lcom/android/internal/telephony/Phone;->mSmsStorageMonitor:Lcom/android/internal/telephony/SmsStorageMonitor;
-Lcom/android/internal/telephony/Phone;->mUiccApplication:Ljava/util/concurrent/atomic/AtomicReference;
-Lcom/android/internal/telephony/Phone;->mUiccController:Lcom/android/internal/telephony/uicc/UiccController;
-Lcom/android/internal/telephony/Phone;->needsOtaServiceProvisioning()Z
-Lcom/android/internal/telephony/Phone;->notifyOtaspChanged(I)V
-Lcom/android/internal/telephony/Phone;->registerForDisconnect(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/Phone;->registerForEcmTimerReset(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/Phone;->registerForIncomingRing(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/Phone;->registerForMmiComplete(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/Phone;->registerForMmiInitiate(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/Phone;->registerForNewRingingConnection(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/Phone;->registerForPreciseCallStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/Phone;->registerForRingbackTone(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/Phone;->registerForServiceStateChanged(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/Phone;->registerForSimRecordsLoaded(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/Phone;->registerForUnknownConnection(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/Phone;->selectNetworkManually(Lcom/android/internal/telephony/OperatorInfo;ZLandroid/os/Message;)V
-Lcom/android/internal/telephony/Phone;->setNetworkSelectionModeAutomatic(Landroid/os/Message;)V
-Lcom/android/internal/telephony/Phone;->setOnEcbModeExitResponse(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/Phone;->setOnPostDialCharacter(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/Phone;->setPreferredNetworkType(ILandroid/os/Message;)V
-Lcom/android/internal/telephony/Phone;->setSmscAddress(Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/Phone;->unregisterForDisconnect(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/Phone;->unregisterForEcmTimerReset(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/Phone;->unregisterForIncomingRing(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/Phone;->unregisterForMmiComplete(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/Phone;->unregisterForMmiInitiate(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/Phone;->unregisterForNewRingingConnection(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/Phone;->unregisterForPreciseCallStateChanged(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/Phone;->unregisterForRingbackTone(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/Phone;->unregisterForServiceStateChanged(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/Phone;->unregisterForSimRecordsLoaded(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/Phone;->unregisterForUnknownConnection(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/Phone;->unsetOnEcbModeExitResponse(Landroid/os/Handler;)V
 Lcom/android/internal/telephony/PhoneConstants$DataState;->CONNECTED:Lcom/android/internal/telephony/PhoneConstants$DataState;
 Lcom/android/internal/telephony/PhoneConstants$DataState;->CONNECTING:Lcom/android/internal/telephony/PhoneConstants$DataState;
 Lcom/android/internal/telephony/PhoneConstants$DataState;->DISCONNECTED:Lcom/android/internal/telephony/PhoneConstants$DataState;
@@ -2701,152 +1995,7 @@
 Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_PAYPHONE:I
 Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_RESTRICTED:I
 Lcom/android/internal/telephony/PhoneConstants;->PRESENTATION_UNKNOWN:I
-Lcom/android/internal/telephony/PhoneFactory;->calculatePreferredNetworkType(Landroid/content/Context;I)I
-Lcom/android/internal/telephony/PhoneFactory;->getDefaultPhone()Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/PhoneFactory;->getDefaultSubscription()I
-Lcom/android/internal/telephony/PhoneFactory;->getPhone(I)Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/PhoneFactory;->getPhones()[Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/PhoneFactory;->makeDefaultPhone(Landroid/content/Context;)V
-Lcom/android/internal/telephony/PhoneFactory;->sCommandsInterface:Lcom/android/internal/telephony/CommandsInterface;
-Lcom/android/internal/telephony/PhoneFactory;->sContext:Landroid/content/Context;
-Lcom/android/internal/telephony/PhoneFactory;->sMadeDefaults:Z
-Lcom/android/internal/telephony/PhoneFactory;->sPhoneNotifier:Lcom/android/internal/telephony/PhoneNotifier;
-Lcom/android/internal/telephony/PhoneInternalInterface$DataActivityState;->NONE:Lcom/android/internal/telephony/PhoneInternalInterface$DataActivityState;
-Lcom/android/internal/telephony/PhoneInternalInterface;->PREFERRED_NT_MODE:I
-Lcom/android/internal/telephony/PhoneNotifier;->notifyMessageWaitingChanged(Lcom/android/internal/telephony/Phone;)V
-Lcom/android/internal/telephony/PhoneNotifier;->notifySignalStrength(Lcom/android/internal/telephony/Phone;)V
-Lcom/android/internal/telephony/PhoneStateIntentReceiver;-><init>(Landroid/content/Context;Landroid/os/Handler;)V
-Lcom/android/internal/telephony/PhoneStateIntentReceiver;->getSignalStrengthDbm()I
-Lcom/android/internal/telephony/PhoneStateIntentReceiver;->mSignalStrength:Landroid/telephony/SignalStrength;
-Lcom/android/internal/telephony/PhoneStateIntentReceiver;->mWants:I
-Lcom/android/internal/telephony/PhoneStateIntentReceiver;->notifyServiceState(I)V
-Lcom/android/internal/telephony/PhoneStateIntentReceiver;->notifySignalStrength(I)V
-Lcom/android/internal/telephony/PhoneStateIntentReceiver;->registerIntent()V
-Lcom/android/internal/telephony/PhoneStateIntentReceiver;->unregisterIntent()V
-Lcom/android/internal/telephony/PhoneSubInfoController;->getDefaultSubscription()I
-Lcom/android/internal/telephony/PhoneSubInfoController;->getPhone(I)Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/PhoneSubInfoController;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/PhoneSubInfoController;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/PhoneSubInfoController;->mPhone:[Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/PhoneSwitcher;->activate(I)V
-Lcom/android/internal/telephony/PhoneSwitcher;->deactivate(I)V
-Lcom/android/internal/telephony/PhoneSwitcher;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/PhoneSwitcher;->mMaxActivePhones:I
-Lcom/android/internal/telephony/PhoneSwitcher;->mNumPhones:I
-Lcom/android/internal/telephony/PhoneSwitcher;->mPhones:[Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/ProxyController;->completeRadioCapabilityTransaction()V
-Lcom/android/internal/telephony/ProxyController;->getInstance()Lcom/android/internal/telephony/ProxyController;
-Lcom/android/internal/telephony/ProxyController;->logd(Ljava/lang/String;)V
-Lcom/android/internal/telephony/ProxyController;->mOldRadioAccessFamily:[I
-Lcom/android/internal/telephony/ProxyController;->mRadioCapabilitySessionId:I
-Lcom/android/internal/telephony/ProxyController;->mSetRadioAccessFamilyStatus:[I
-Lcom/android/internal/telephony/ProxyController;->mUniqueIdGenerator:Ljava/util/concurrent/atomic/AtomicInteger;
-Lcom/android/internal/telephony/ProxyController;->sendRadioCapabilityRequest(IIIILjava/lang/String;II)V
-Lcom/android/internal/telephony/ProxyController;->sProxyController:Lcom/android/internal/telephony/ProxyController;
-Lcom/android/internal/telephony/RadioCapability;->getRadioAccessFamily()I
-Lcom/android/internal/telephony/RetryManager;->configure(Ljava/lang/String;)Z
-Lcom/android/internal/telephony/RetryManager;->getRetryTimer()I
-Lcom/android/internal/telephony/RetryManager;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/RetryManager;->mApnType:Ljava/lang/String;
-Lcom/android/internal/telephony/RetryManager;->mFailFastInterApnDelay:J
-Lcom/android/internal/telephony/RetryManager;->mInterApnDelay:J
-Lcom/android/internal/telephony/RetryManager;->mPhone:Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/RIL;-><init>(Landroid/content/Context;II)V
-Lcom/android/internal/telephony/RIL;-><init>(Landroid/content/Context;IILjava/lang/Integer;)V
-Lcom/android/internal/telephony/RIL;->acquireWakeLock(Lcom/android/internal/telephony/RILRequest;I)V
-Lcom/android/internal/telephony/RIL;->clearRequestList(IZ)V
-Lcom/android/internal/telephony/RIL;->clearWakeLock(I)Z
-Lcom/android/internal/telephony/RIL;->decrementWakeLock(Lcom/android/internal/telephony/RILRequest;)V
-Lcom/android/internal/telephony/RIL;->findAndRemoveRequestFromList(I)Lcom/android/internal/telephony/RILRequest;
-Lcom/android/internal/telephony/RIL;->getResponseForTimedOutRILRequest(Lcom/android/internal/telephony/RILRequest;)Ljava/lang/Object;
-Lcom/android/internal/telephony/RIL;->hangupForegroundResumeBackground(Landroid/os/Message;)V
-Lcom/android/internal/telephony/RIL;->hangupWaitingOrBackground(Landroid/os/Message;)V
-Lcom/android/internal/telephony/RIL;->invokeOemRilRequestRaw([BLandroid/os/Message;)V
-Lcom/android/internal/telephony/RIL;->makeStaticRadioCapability()Lcom/android/internal/telephony/RadioCapability;
-Lcom/android/internal/telephony/RIL;->mRequestList:Landroid/util/SparseArray;
-Lcom/android/internal/telephony/RIL;->mTestingEmergencyCall:Ljava/util/concurrent/atomic/AtomicBoolean;
-Lcom/android/internal/telephony/RIL;->mWakeLock:Landroid/os/PowerManager$WakeLock;
-Lcom/android/internal/telephony/RIL;->notifyRegistrantsCdmaInfoRec(Lcom/android/internal/telephony/cdma/CdmaInformationRecords;)V
-Lcom/android/internal/telephony/RIL;->notifyRegistrantsRilConnectionChanged(I)V
-Lcom/android/internal/telephony/RIL;->requestToString(I)Ljava/lang/String;
-Lcom/android/internal/telephony/RIL;->responseToString(I)Ljava/lang/String;
-Lcom/android/internal/telephony/RIL;->retToString(ILjava/lang/Object;)Ljava/lang/String;
-Lcom/android/internal/telephony/RIL;->riljLog(Ljava/lang/String;)V
-Lcom/android/internal/telephony/RIL;->setRadioPower(ZLandroid/os/Message;)V
-Lcom/android/internal/telephony/RIL;->unsljLog(I)V
-Lcom/android/internal/telephony/RIL;->unsljLogMore(ILjava/lang/String;)V
-Lcom/android/internal/telephony/RIL;->unsljLogRet(ILjava/lang/Object;)V
-Lcom/android/internal/telephony/RIL;->unsljLogvRet(ILjava/lang/Object;)V
 Lcom/android/internal/telephony/RILConstants;->PREFERRED_NETWORK_MODE:I
-Lcom/android/internal/telephony/RILRequest;->mRequest:I
-Lcom/android/internal/telephony/RILRequest;->mResult:Landroid/os/Message;
-Lcom/android/internal/telephony/RILRequest;->mSerial:I
-Lcom/android/internal/telephony/RILRequest;->obtain(ILandroid/os/Message;)Lcom/android/internal/telephony/RILRequest;
-Lcom/android/internal/telephony/RILRequest;->onError(ILjava/lang/Object;)V
-Lcom/android/internal/telephony/RILRequest;->release()V
-Lcom/android/internal/telephony/RILRequest;->serialString()Ljava/lang/String;
-Lcom/android/internal/telephony/ServiceStateTracker;->fixUnknownMcc(Ljava/lang/String;I)Ljava/lang/String;
-Lcom/android/internal/telephony/ServiceStateTracker;->getCurrentDataConnectionState()I
-Lcom/android/internal/telephony/ServiceStateTracker;->getDesiredPowerState()Z
-Lcom/android/internal/telephony/ServiceStateTracker;->getPhoneId()I
-Lcom/android/internal/telephony/ServiceStateTracker;->getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/ServiceStateTracker;->isConcurrentVoiceAndDataAllowed()Z
-Lcom/android/internal/telephony/ServiceStateTracker;->isGprsConsistent(II)Z
-Lcom/android/internal/telephony/ServiceStateTracker;->isImsRegistered()Z
-Lcom/android/internal/telephony/ServiceStateTracker;->isInHomeSidNid(II)Z
-Lcom/android/internal/telephony/ServiceStateTracker;->isInvalidOperatorNumeric(Ljava/lang/String;)Z
-Lcom/android/internal/telephony/ServiceStateTracker;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/ServiceStateTracker;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/ServiceStateTracker;->mCi:Lcom/android/internal/telephony/CommandsInterface;
-Lcom/android/internal/telephony/ServiceStateTracker;->mCr:Landroid/content/ContentResolver;
-Lcom/android/internal/telephony/ServiceStateTracker;->mCurDataSpn:Ljava/lang/String;
-Lcom/android/internal/telephony/ServiceStateTracker;->mCurPlmn:Ljava/lang/String;
-Lcom/android/internal/telephony/ServiceStateTracker;->mCurShowPlmn:Z
-Lcom/android/internal/telephony/ServiceStateTracker;->mCurShowSpn:Z
-Lcom/android/internal/telephony/ServiceStateTracker;->mCurSpn:Ljava/lang/String;
-Lcom/android/internal/telephony/ServiceStateTracker;->mDataRoamingOffRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/ServiceStateTracker;->mDataRoamingOnRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/ServiceStateTracker;->mDefaultRoamingIndicator:I
-Lcom/android/internal/telephony/ServiceStateTracker;->mDesiredPowerState:Z
-Lcom/android/internal/telephony/ServiceStateTracker;->mDeviceShuttingDown:Z
-Lcom/android/internal/telephony/ServiceStateTracker;->mEmergencyOnly:Z
-Lcom/android/internal/telephony/ServiceStateTracker;->mIccRecords:Lcom/android/internal/telephony/uicc/IccRecords;
-Lcom/android/internal/telephony/ServiceStateTracker;->mIntentReceiver:Landroid/content/BroadcastReceiver;
-Lcom/android/internal/telephony/ServiceStateTracker;->mIsSubscriptionFromRuim:Z
-Lcom/android/internal/telephony/ServiceStateTracker;->mMaxDataCalls:I
-Lcom/android/internal/telephony/ServiceStateTracker;->mNetworkAttachedRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/ServiceStateTracker;->mNewMaxDataCalls:I
-Lcom/android/internal/telephony/ServiceStateTracker;->mNewReasonDataDenied:I
-Lcom/android/internal/telephony/ServiceStateTracker;->mNewSS:Landroid/telephony/ServiceState;
-Lcom/android/internal/telephony/ServiceStateTracker;->mOnSubscriptionsChangedListener:Lcom/android/internal/telephony/ServiceStateTracker$SstSubscriptionsChangedListener;
-Lcom/android/internal/telephony/ServiceStateTracker;->mPhone:Lcom/android/internal/telephony/GsmCdmaPhone;
-Lcom/android/internal/telephony/ServiceStateTracker;->mPreferredNetworkType:I
-Lcom/android/internal/telephony/ServiceStateTracker;->mReasonDataDenied:I
-Lcom/android/internal/telephony/ServiceStateTracker;->mReportedGprsNoReg:Z
-Lcom/android/internal/telephony/ServiceStateTracker;->mRoamingIndicator:I
-Lcom/android/internal/telephony/ServiceStateTracker;->mSignalStrength:Landroid/telephony/SignalStrength;
-Lcom/android/internal/telephony/ServiceStateTracker;->mSpnUpdatePending:Z
-Lcom/android/internal/telephony/ServiceStateTracker;->mSS:Landroid/telephony/ServiceState;
-Lcom/android/internal/telephony/ServiceStateTracker;->mStartedGprsRegCheck:Z
-Lcom/android/internal/telephony/ServiceStateTracker;->mSubId:I
-Lcom/android/internal/telephony/ServiceStateTracker;->mSubscriptionController:Lcom/android/internal/telephony/SubscriptionController;
-Lcom/android/internal/telephony/ServiceStateTracker;->mSubscriptionManager:Landroid/telephony/SubscriptionManager;
-Lcom/android/internal/telephony/ServiceStateTracker;->mUiccApplcation:Lcom/android/internal/telephony/uicc/UiccCardApplication;
-Lcom/android/internal/telephony/ServiceStateTracker;->mUiccController:Lcom/android/internal/telephony/uicc/UiccController;
-Lcom/android/internal/telephony/ServiceStateTracker;->mVoiceRoamingOffRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/ServiceStateTracker;->mVoiceRoamingOnRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/ServiceStateTracker;->notifySignalStrength()Z
-Lcom/android/internal/telephony/ServiceStateTracker;->pollState()V
-Lcom/android/internal/telephony/ServiceStateTracker;->reRegisterNetwork(Landroid/os/Message;)V
-Lcom/android/internal/telephony/ServiceStateTracker;->resetServiceStateInIwlanMode()V
-Lcom/android/internal/telephony/ServiceStateTracker;->setOperatorIdd(Ljava/lang/String;)V
-Lcom/android/internal/telephony/ServiceStateTracker;->setRoamingType(Landroid/telephony/ServiceState;)V
-Lcom/android/internal/telephony/ServiceStateTracker;->setSignalStrengthDefaultValues()V
-Lcom/android/internal/telephony/ServiceStateTracker;->updateOtaspState()V
-Lcom/android/internal/telephony/ServiceStateTracker;->updatePhoneObject()V
-Lcom/android/internal/telephony/ServiceStateTracker;->updateRoamingState()V
-Lcom/android/internal/telephony/ServiceStateTracker;->updateSpnDisplay()V
-Lcom/android/internal/telephony/ServiceStateTracker;->useDataRegStateForDataOnlyDevices()V
 Lcom/android/internal/telephony/sip/SipPhone$SipCall;->hold()V
 Lcom/android/internal/telephony/sip/SipPhone$SipCall;->switchWith(Lcom/android/internal/telephony/sip/SipPhone$SipCall;)V
 Lcom/android/internal/telephony/sip/SipPhone$SipCall;->unhold()V
@@ -2870,100 +2019,14 @@
 Lcom/android/internal/telephony/SmsApplication;->isDefaultSmsApplication(Landroid/content/Context;Ljava/lang/String;)Z
 Lcom/android/internal/telephony/SmsApplication;->setDefaultApplication(Ljava/lang/String;Landroid/content/Context;)V
 Lcom/android/internal/telephony/SmsApplication;->shouldWriteMessageForPackage(Ljava/lang/String;Landroid/content/Context;)Z
-Lcom/android/internal/telephony/SmsBroadcastUndelivered;-><init>(Landroid/content/Context;Lcom/android/internal/telephony/gsm/GsmInboundSmsHandler;Lcom/android/internal/telephony/cdma/CdmaInboundSmsHandler;)V
-Lcom/android/internal/telephony/SMSDispatcher$ConfirmDialogListener;->mNegativeButton:Landroid/widget/Button;
-Lcom/android/internal/telephony/SMSDispatcher$ConfirmDialogListener;->mPositiveButton:Landroid/widget/Button;
-Lcom/android/internal/telephony/SMSDispatcher$ConfirmDialogListener;->mRememberUndoInstruction:Landroid/widget/TextView;
 Lcom/android/internal/telephony/SMSDispatcher$DataSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
 Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Ljava/util/ArrayList;[Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
-Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;->sendSmsByCarrierApp(Ljava/lang/String;Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSenderCallback;)V
 Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSenderCallback;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$MultipartSmsSender;)V
 Lcom/android/internal/telephony/SMSDispatcher$SmsSenderCallback;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsSender;)V
-Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->isMultipart()Z
-Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mAppInfo:Landroid/content/pm/PackageInfo;
-Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mData:Ljava/util/HashMap;
-Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mDeliveryIntent:Landroid/app/PendingIntent;
-Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mDestAddress:Ljava/lang/String;
-Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mMessageRef:I
-Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mMessageUri:Landroid/net/Uri;
-Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mPersistMessage:Z
-Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mSentIntent:Landroid/app/PendingIntent;
-Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->mTimestamp:J
-Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->onFailed(Landroid/content/Context;II)V
-Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->onSent(Landroid/content/Context;)V
-Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;->updateSentMessageStatus(Landroid/content/Context;I)V
 Lcom/android/internal/telephony/SMSDispatcher$TextSmsSender;-><init>(Lcom/android/internal/telephony/SMSDispatcher;Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
-Lcom/android/internal/telephony/SMSDispatcher;->calculateLength(Ljava/lang/CharSequence;Z)Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;
-Lcom/android/internal/telephony/SMSDispatcher;->checkCallerIsPhoneOrCarrierApp()V
-Lcom/android/internal/telephony/SMSDispatcher;->deliveryPendingList:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/SMSDispatcher;->dispose()V
-Lcom/android/internal/telephony/SMSDispatcher;->getCarrierAppPackageName()Ljava/lang/String;
-Lcom/android/internal/telephony/SMSDispatcher;->getMultipartMessageText(Ljava/util/ArrayList;)Ljava/lang/String;
-Lcom/android/internal/telephony/SMSDispatcher;->getNextConcatenatedRef()I
-Lcom/android/internal/telephony/SMSDispatcher;->getSubId()I
-Lcom/android/internal/telephony/SMSDispatcher;->handleConfirmShortCode(ZLcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
-Lcom/android/internal/telephony/SMSDispatcher;->mCi:Lcom/android/internal/telephony/CommandsInterface;
-Lcom/android/internal/telephony/SMSDispatcher;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/SMSDispatcher;->mPhone:Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/SMSDispatcher;->mResolver:Landroid/content/ContentResolver;
-Lcom/android/internal/telephony/SMSDispatcher;->mTelephonyManager:Landroid/telephony/TelephonyManager;
-Lcom/android/internal/telephony/SMSDispatcher;->processSendSmsResponse(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;II)V
-Lcom/android/internal/telephony/SMSDispatcher;->sendData(Ljava/lang/String;Ljava/lang/String;I[BLandroid/app/PendingIntent;Landroid/app/PendingIntent;)V
-Lcom/android/internal/telephony/SMSDispatcher;->sendMultipartSms(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
-Lcom/android/internal/telephony/SMSDispatcher;->sendSms(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
-Lcom/android/internal/telephony/SMSDispatcher;->sendSubmitPdu(Lcom/android/internal/telephony/SMSDispatcher$SmsTracker;)V
 Lcom/android/internal/telephony/SmsHeader$ConcatRef;-><init>()V
 Lcom/android/internal/telephony/SmsHeader$PortAddrs;-><init>()V
 Lcom/android/internal/telephony/SmsMessageBase;-><init>()V
-Lcom/android/internal/telephony/SmsResponse;-><init>(ILjava/lang/String;I)V
-Lcom/android/internal/telephony/SmsResponse;->mAckPdu:Ljava/lang/String;
-Lcom/android/internal/telephony/SmsResponse;->mErrorCode:I
-Lcom/android/internal/telephony/SmsResponse;->mMessageRef:I
-Lcom/android/internal/telephony/SmsStorageMonitor;->mCi:Lcom/android/internal/telephony/CommandsInterface;
-Lcom/android/internal/telephony/SmsUsageMonitor;-><init>(Landroid/content/Context;)V
-Lcom/android/internal/telephony/SmsUsageMonitor;->check(Ljava/lang/String;I)Z
-Lcom/android/internal/telephony/SubscriptionController;->broadcastDefaultDataSubIdChanged(I)V
-Lcom/android/internal/telephony/SubscriptionController;->colorArr:[I
-Lcom/android/internal/telephony/SubscriptionController;->enforceModifyPhoneState(Ljava/lang/String;)V
-Lcom/android/internal/telephony/SubscriptionController;->getActiveSubInfoCount(Ljava/lang/String;)I
-Lcom/android/internal/telephony/SubscriptionController;->getActiveSubscriptionInfo(ILjava/lang/String;)Landroid/telephony/SubscriptionInfo;
-Lcom/android/internal/telephony/SubscriptionController;->getActiveSubscriptionInfoList(Ljava/lang/String;)Ljava/util/List;
-Lcom/android/internal/telephony/SubscriptionController;->getDefaultDataSubId()I
-Lcom/android/internal/telephony/SubscriptionController;->getDefaultSmsSubId()I
-Lcom/android/internal/telephony/SubscriptionController;->getDefaultSubId()I
-Lcom/android/internal/telephony/SubscriptionController;->getDefaultVoiceSubId()I
-Lcom/android/internal/telephony/SubscriptionController;->getInstance()Lcom/android/internal/telephony/SubscriptionController;
-Lcom/android/internal/telephony/SubscriptionController;->getPhoneId(I)I
-Lcom/android/internal/telephony/SubscriptionController;->getSubId(I)[I
-Lcom/android/internal/telephony/SubscriptionController;->getSubIdUsingPhoneId(I)I
-Lcom/android/internal/telephony/SubscriptionController;->getSubInfo(Ljava/lang/String;Ljava/lang/Object;)Ljava/util/List;
-Lcom/android/internal/telephony/SubscriptionController;->getSubInfoRecord(Landroid/database/Cursor;)Landroid/telephony/SubscriptionInfo;
-Lcom/android/internal/telephony/SubscriptionController;->isActiveSubId(I)Z
-Lcom/android/internal/telephony/SubscriptionController;->isSubInfoReady()Z
-Lcom/android/internal/telephony/SubscriptionController;->logd(Ljava/lang/String;)V
-Lcom/android/internal/telephony/SubscriptionController;->logdl(Ljava/lang/String;)V
-Lcom/android/internal/telephony/SubscriptionController;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/SubscriptionController;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/SubscriptionController;->mDefaultPhoneId:I
-Lcom/android/internal/telephony/SubscriptionController;->mLock:Ljava/lang/Object;
-Lcom/android/internal/telephony/SubscriptionController;->notifySubscriptionInfoChanged()V
-Lcom/android/internal/telephony/SubscriptionController;->setDefaultDataSubId(I)V
-Lcom/android/internal/telephony/SubscriptionController;->setDefaultFallbackSubId(II)V
-Lcom/android/internal/telephony/SubscriptionController;->setDefaultSmsSubId(I)V
-Lcom/android/internal/telephony/SubscriptionController;->setDefaultVoiceSubId(I)V
-Lcom/android/internal/telephony/SubscriptionController;->setPlmnSpn(IZLjava/lang/String;ZLjava/lang/String;)Z
-Lcom/android/internal/telephony/SubscriptionController;->updateAllDataConnectionTrackers()V
-Lcom/android/internal/telephony/SubscriptionController;->validateSubId(I)V
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->broadcastSimStateChanged(ILjava/lang/String;Ljava/lang/String;)V
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->isAllIccIdQueryDone()Z
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->logd(Ljava/lang/String;)V
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mCurrentlyActiveUserId:I
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mIccId:[Ljava/lang/String;
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPackageManager:Landroid/content/pm/IPackageManager;
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->mPhone:[Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/SubscriptionInfoUpdater;->PROJECT_SIM_NUM:I
-Lcom/android/internal/telephony/TelephonyCapabilities;->supportsAdn(I)Z
 Lcom/android/internal/telephony/TelephonyProperties;->PROPERTY_ICC_OPERATOR_NUMERIC:Ljava/lang/String;
 Lcom/android/internal/telephony/test/InterpreterEx;-><init>(Ljava/lang/String;)V
 Lcom/android/internal/telephony/test/SimulatedCommands;->acceptCall(Landroid/os/Message;)V
@@ -2980,143 +2043,11 @@
 Lcom/android/internal/telephony/test/SimulatedGsmCallState;->releaseHeldOrUDUB()Z
 Lcom/android/internal/telephony/test/SimulatedGsmCallState;->separateCall(I)Z
 Lcom/android/internal/telephony/test/SimulatedGsmCallState;->switchActiveAndHeldOrWaiting()Z
-Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(IILjava/lang/String;Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(II[B)V
-Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(Ljava/lang/String;Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/AdnRecord;-><init>(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/AdnRecord;-><init>([B)V
-Lcom/android/internal/telephony/uicc/AdnRecord;->buildAdnString(I)[B
-Lcom/android/internal/telephony/uicc/AdnRecord;->CREATOR:Landroid/os/Parcelable$Creator;
-Lcom/android/internal/telephony/uicc/AdnRecord;->getEmails()[Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/AdnRecord;->getNumber()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/AdnRecord;->isEmpty()Z
-Lcom/android/internal/telephony/uicc/AdnRecord;->mAlphaTag:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/AdnRecord;->mEfid:I
-Lcom/android/internal/telephony/uicc/AdnRecord;->mEmails:[Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/AdnRecord;->mExtRecord:I
-Lcom/android/internal/telephony/uicc/AdnRecord;->mNumber:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/AdnRecord;->mRecordNumber:I
-Lcom/android/internal/telephony/uicc/AdnRecord;->setEmails([Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/AdnRecordCache;->extensionEfForEf(I)I
-Lcom/android/internal/telephony/uicc/AdnRecordCache;->getRecordsIfLoaded(I)Ljava/util/ArrayList;
-Lcom/android/internal/telephony/uicc/AdnRecordCache;->mAdnLikeWaiters:Landroid/util/SparseArray;
-Lcom/android/internal/telephony/uicc/AdnRecordCache;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler;
-Lcom/android/internal/telephony/uicc/AdnRecordCache;->mUserWriteResponse:Landroid/util/SparseArray;
-Lcom/android/internal/telephony/uicc/AdnRecordCache;->mUsimPhoneBookManager:Lcom/android/internal/telephony/gsm/UsimPhoneBookManager;
-Lcom/android/internal/telephony/uicc/AdnRecordCache;->reset()V
-Lcom/android/internal/telephony/uicc/AdnRecordCache;->sendErrorResponse(Landroid/os/Message;Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/AdnRecordCache;->updateAdnByIndex(ILcom/android/internal/telephony/uicc/AdnRecord;ILjava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/AdnRecordLoader;-><init>(Lcom/android/internal/telephony/uicc/IccFileHandler;)V
-Lcom/android/internal/telephony/uicc/AdnRecordLoader;->getEFPath(I)Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/AdnRecordLoader;->loadFromEF(IIILandroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/AdnRecordLoader;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler;
-Lcom/android/internal/telephony/uicc/AdnRecordLoader;->updateEF(Lcom/android/internal/telephony/uicc/AdnRecord;IIILjava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_DETECTED:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_PIN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_PUK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_READY:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_SUBSCRIPTION_PERSO:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->APPSTATE_UNKNOWN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
 Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_CSIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_ISIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_RUIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_SIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_UNKNOWN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->APPTYPE_USIM:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
 Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_NETWORK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_NETWORK_SUBSET:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_SERVICE_PROVIDER:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->PERSOSUBSTATE_UNKNOWN:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
 Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;->values()[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
 Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;-><init>()V
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;->AppTypeFromRILInt(I)Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
-Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;->app_type:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
-Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->CARDSTATE_ABSENT:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
-Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->CARDSTATE_ERROR:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
-Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->CARDSTATE_PRESENT:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
-Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;->isCardPresent()Z
-Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;->PINSTATE_DISABLED:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
-Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;->PINSTATE_ENABLED_BLOCKED:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
-Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;->PINSTATE_ENABLED_PERM_BLOCKED:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
-Lcom/android/internal/telephony/uicc/IccCardStatus;->mApplications:[Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;
-Lcom/android/internal/telephony/uicc/IccCardStatus;->mCardState:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
-Lcom/android/internal/telephony/uicc/IccCardStatus;->mCdmaSubscriptionAppIndex:I
-Lcom/android/internal/telephony/uicc/IccCardStatus;->mGsmUmtsSubscriptionAppIndex:I
-Lcom/android/internal/telephony/uicc/IccCardStatus;->mImsSubscriptionAppIndex:I
-Lcom/android/internal/telephony/uicc/IccCardStatus;->mUniversalPinState:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
-Lcom/android/internal/telephony/uicc/IccFileHandler$LoadLinearFixedContext;-><init>(IILandroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/IccFileHandler$LoadLinearFixedContext;->mRecordSize:I
-Lcom/android/internal/telephony/uicc/IccFileHandler$LoadLinearFixedContext;->results:Ljava/util/ArrayList;
-Lcom/android/internal/telephony/uicc/IccFileHandler;->getEFLinearRecordSize(ILandroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/IccFileHandler;->getEFLinearRecordSize(ILjava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/IccFileHandler;->getEFPath(I)Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixed(IILandroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixed(ILjava/lang/String;ILandroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixedAll(ILandroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFLinearFixedAll(ILjava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/IccFileHandler;->loadEFTransparent(ILandroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/IccFileHandler;->mAid:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccFileHandler;->mCi:Lcom/android/internal/telephony/CommandsInterface;
-Lcom/android/internal/telephony/uicc/IccFileHandler;->mParentApp:Lcom/android/internal/telephony/uicc/UiccCardApplication;
-Lcom/android/internal/telephony/uicc/IccFileHandler;->updateEFLinearFixed(II[BLjava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/IccFileHandler;->updateEFLinearFixed(ILjava/lang/String;I[BLjava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/IccFileHandler;->updateEFTransparent(I[BLandroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/IccIoResult;-><init>(IILjava/lang/String;)V
-Lcom/android/internal/telephony/uicc/IccIoResult;-><init>(II[B)V
-Lcom/android/internal/telephony/uicc/IccIoResult;->payload:[B
-Lcom/android/internal/telephony/uicc/IccIoResult;->success()Z
-Lcom/android/internal/telephony/uicc/IccIoResult;->sw1:I
-Lcom/android/internal/telephony/uicc/IccIoResult;->sw2:I
-Lcom/android/internal/telephony/uicc/IccRecords;->auth_rsp:Lcom/android/internal/telephony/uicc/IccIoResult;
-Lcom/android/internal/telephony/uicc/IccRecords;->getGid1()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccRecords;->getIccId()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccRecords;->getIccSimChallengeResponse(ILjava/lang/String;)Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccRecords;->getIMSI()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccRecords;->getMsisdnNumber()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccRecords;->getOperatorNumeric()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccRecords;->getRecordsLoaded()Z
-Lcom/android/internal/telephony/uicc/IccRecords;->getServiceProviderName()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccRecords;->getUsimServiceTable()Lcom/android/internal/telephony/uicc/UsimServiceTable;
-Lcom/android/internal/telephony/uicc/IccRecords;->handleRefresh(Lcom/android/internal/telephony/uicc/IccRefreshResponse;)V
-Lcom/android/internal/telephony/uicc/IccRecords;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/IccRecords;->mAdnCache:Lcom/android/internal/telephony/uicc/AdnRecordCache;
-Lcom/android/internal/telephony/uicc/IccRecords;->mCi:Lcom/android/internal/telephony/CommandsInterface;
-Lcom/android/internal/telephony/uicc/IccRecords;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/uicc/IccRecords;->mDestroyed:Ljava/util/concurrent/atomic/AtomicBoolean;
-Lcom/android/internal/telephony/uicc/IccRecords;->mFh:Lcom/android/internal/telephony/uicc/IccFileHandler;
-Lcom/android/internal/telephony/uicc/IccRecords;->mGid1:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccRecords;->mIccId:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccRecords;->mImsi:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccRecords;->mIsVoiceMailFixed:Z
-Lcom/android/internal/telephony/uicc/IccRecords;->mLock:Ljava/lang/Object;
-Lcom/android/internal/telephony/uicc/IccRecords;->mMncLength:I
-Lcom/android/internal/telephony/uicc/IccRecords;->mParentApp:Lcom/android/internal/telephony/uicc/UiccCardApplication;
-Lcom/android/internal/telephony/uicc/IccRecords;->mRecordsEventsRegistrants:Landroid/os/RegistrantList;
-Lcom/android/internal/telephony/uicc/IccRecords;->mRecordsToLoad:I
-Lcom/android/internal/telephony/uicc/IccRecords;->mSpn:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccRecords;->mTelephonyManager:Landroid/telephony/TelephonyManager;
-Lcom/android/internal/telephony/uicc/IccRecords;->mVoiceMailNum:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccRecords;->registerForNetworkSelectionModeAutomatic(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/uicc/IccRecords;->registerForNewSms(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/uicc/IccRecords;->registerForRecordsEvents(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/uicc/IccRecords;->registerForRecordsLoaded(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/uicc/IccRecords;->setMsisdnNumber(Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V
-Lcom/android/internal/telephony/uicc/IccRecords;->setVoiceCallForwardingFlag(IZLjava/lang/String;)V
-Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForNetworkSelectionModeAutomatic(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForNewSms(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForRecordsEvents(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/uicc/IccRecords;->unregisterForRecordsLoaded(Landroid/os/Handler;)V
 Lcom/android/internal/telephony/uicc/IccRefreshResponse;-><init>()V
-Lcom/android/internal/telephony/uicc/IccRefreshResponse;->aid:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccRefreshResponse;->efId:I
-Lcom/android/internal/telephony/uicc/IccRefreshResponse;->refreshResult:I
-Lcom/android/internal/telephony/uicc/IccServiceTable;->getTag()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IccServiceTable;->mServiceTable:[B
 Lcom/android/internal/telephony/uicc/IccUtils;->adnStringFieldToString([BII)Ljava/lang/String;
 Lcom/android/internal/telephony/uicc/IccUtils;->bcdToString([BII)Ljava/lang/String;
 Lcom/android/internal/telephony/uicc/IccUtils;->bytesToHexString([B)Ljava/lang/String;
@@ -3128,175 +2059,7 @@
 Lcom/android/internal/telephony/uicc/IccUtils;->networkNameToString([BII)Ljava/lang/String;
 Lcom/android/internal/telephony/uicc/IccUtils;->parseToBnW([BI)Landroid/graphics/Bitmap;
 Lcom/android/internal/telephony/uicc/IccUtils;->parseToRGB([BIZ)Landroid/graphics/Bitmap;
-Lcom/android/internal/telephony/uicc/IsimRecords;->getIsimDomain()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IsimRecords;->getIsimImpi()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IsimRecords;->getIsimImpu()[Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IsimUiccRecords;->auth_rsp:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IsimUiccRecords;->fetchIsimRecords()V
-Lcom/android/internal/telephony/uicc/IsimUiccRecords;->isimTlvToString([B)Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IsimUiccRecords;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimDomain:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimImpi:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimImpu:[Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimIst:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mIsimPcscf:[Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/IsimUiccRecords;->mLock:Ljava/lang/Object;
-Lcom/android/internal/telephony/uicc/RuimRecords;->adjstMinDigits(I)I
-Lcom/android/internal/telephony/uicc/RuimRecords;->fetchRuimRecords()V
-Lcom/android/internal/telephony/uicc/RuimRecords;->getAssetLanguages(Landroid/content/Context;)[Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/RuimRecords;->getCsimSpnDisplayCondition()Z
-Lcom/android/internal/telephony/uicc/RuimRecords;->getMdn()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/RuimRecords;->getMdnNumber()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/RuimRecords;->getRUIMOperatorNumeric()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/RuimRecords;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/RuimRecords;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/RuimRecords;->mEFli:[B
-Lcom/android/internal/telephony/uicc/RuimRecords;->mEFpl:[B
-Lcom/android/internal/telephony/uicc/RuimRecords;->mMin:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/RuimRecords;->mNai:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/RuimRecords;->onGetCSimEprlDone(Landroid/os/AsyncResult;)V
-Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->INIT:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
-Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->READ_SPN_3GPP:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
-Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->READ_SPN_CPHS:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
-Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->READ_SPN_SHORT_CPHS:Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
 Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;->values()[Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;
-Lcom/android/internal/telephony/uicc/SIMRecords;->fetchSimRecords()V
-Lcom/android/internal/telephony/uicc/SIMRecords;->getExtFromEf(I)I
-Lcom/android/internal/telephony/uicc/SIMRecords;->getMsisdnNumber()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/SIMRecords;->getOperatorNumeric()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/SIMRecords;->getSpnFsm(ZLandroid/os/AsyncResult;)V
-Lcom/android/internal/telephony/uicc/SIMRecords;->getVoiceMailNumber()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/SIMRecords;->isCphsMailboxEnabled()Z
-Lcom/android/internal/telephony/uicc/SIMRecords;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/SIMRecords;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/SIMRecords;->logv(Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/SIMRecords;->mEfCff:[B
-Lcom/android/internal/telephony/uicc/SIMRecords;->mEfCfis:[B
-Lcom/android/internal/telephony/uicc/SIMRecords;->mEfCPHS_MWI:[B
-Lcom/android/internal/telephony/uicc/SIMRecords;->mEfLi:[B
-Lcom/android/internal/telephony/uicc/SIMRecords;->mEfMWIS:[B
-Lcom/android/internal/telephony/uicc/SIMRecords;->mEfPl:[B
-Lcom/android/internal/telephony/uicc/SIMRecords;->mSpnDisplayCondition:I
-Lcom/android/internal/telephony/uicc/SIMRecords;->mUsimServiceTable:Lcom/android/internal/telephony/uicc/UsimServiceTable;
-Lcom/android/internal/telephony/uicc/SIMRecords;->mVmConfig:Lcom/android/internal/telephony/uicc/VoiceMailConstants;
-Lcom/android/internal/telephony/uicc/SIMRecords;->setVoiceCallForwardingFlag(IZLjava/lang/String;)V
-Lcom/android/internal/telephony/uicc/UiccCard;->getApplication(I)Lcom/android/internal/telephony/uicc/UiccCardApplication;
-Lcom/android/internal/telephony/uicc/UiccCard;->getApplicationByType(I)Lcom/android/internal/telephony/uicc/UiccCardApplication;
-Lcom/android/internal/telephony/uicc/UiccCard;->getApplicationIndex(I)Lcom/android/internal/telephony/uicc/UiccCardApplication;
-Lcom/android/internal/telephony/uicc/UiccCard;->getCardState()Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
-Lcom/android/internal/telephony/uicc/UiccCard;->getCarrierPackageNamesForIntent(Landroid/content/pm/PackageManager;Landroid/content/Intent;)Ljava/util/List;
-Lcom/android/internal/telephony/uicc/UiccCard;->getIccId()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/UiccCard;->getNumApplications()I
-Lcom/android/internal/telephony/uicc/UiccCard;->getOperatorBrandOverride()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/UiccCard;->isApplicationOnIcc(Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;)Z
-Lcom/android/internal/telephony/uicc/UiccCard;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/UiccCard;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/UiccCard;->mCardState:Lcom/android/internal/telephony/uicc/IccCardStatus$CardState;
-Lcom/android/internal/telephony/uicc/UiccCard;->mCi:Lcom/android/internal/telephony/CommandsInterface;
-Lcom/android/internal/telephony/uicc/UiccCard;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/uicc/UiccCard;->mLock:Ljava/lang/Object;
-Lcom/android/internal/telephony/uicc/UiccCard;->mPhoneId:I
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->dispose()V
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->getAid()Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->getAuthContext()I
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->getIccFileHandler()Lcom/android/internal/telephony/uicc/IccFileHandler;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->getIccRecords()Lcom/android/internal/telephony/uicc/IccRecords;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->getPersoSubState()Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->getPhoneId()I
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->getPin1State()Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->getState()Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->getType()Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->loge(Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->mAid:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->mAppState:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppState;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->mAppType:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$AppType;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->mCi:Lcom/android/internal/telephony/CommandsInterface;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->mDestroyed:Z
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->mLock:Ljava/lang/Object;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->mPersoSubState:Lcom/android/internal/telephony/uicc/IccCardApplicationStatus$PersoSubState;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->mPin1State:Lcom/android/internal/telephony/uicc/IccCardStatus$PinState;
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->registerForReady(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->unregisterForReady(Landroid/os/Handler;)V
-Lcom/android/internal/telephony/uicc/UiccCardApplication;->update(Lcom/android/internal/telephony/uicc/IccCardApplicationStatus;Landroid/content/Context;Lcom/android/internal/telephony/CommandsInterface;)V
-Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules$TLV;->length:Ljava/lang/Integer;
-Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules$TLV;->value:Ljava/lang/String;
-Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules;->mLoadedCallback:Landroid/os/Message;
-Lcom/android/internal/telephony/uicc/UiccCarrierPrivilegeRules;->mState:Ljava/util/concurrent/atomic/AtomicInteger;
-Lcom/android/internal/telephony/uicc/UiccController;->getIccFileHandler(II)Lcom/android/internal/telephony/uicc/IccFileHandler;
-Lcom/android/internal/telephony/uicc/UiccController;->getIccRecords(II)Lcom/android/internal/telephony/uicc/IccRecords;
-Lcom/android/internal/telephony/uicc/UiccController;->getInstance()Lcom/android/internal/telephony/uicc/UiccController;
-Lcom/android/internal/telephony/uicc/UiccController;->getUiccCard(I)Lcom/android/internal/telephony/uicc/UiccCard;
-Lcom/android/internal/telephony/uicc/UiccController;->getUiccCardApplication(II)Lcom/android/internal/telephony/uicc/UiccCardApplication;
-Lcom/android/internal/telephony/uicc/UiccController;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/uicc/UiccController;->mCis:[Lcom/android/internal/telephony/CommandsInterface;
-Lcom/android/internal/telephony/uicc/UiccController;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/uicc/UiccController;->mInstance:Lcom/android/internal/telephony/uicc/UiccController;
-Lcom/android/internal/telephony/uicc/UiccController;->mLock:Ljava/lang/Object;
-Lcom/android/internal/telephony/uicc/UiccController;->registerForIccChanged(Landroid/os/Handler;ILjava/lang/Object;)V
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->ALLOWED_CSG_LISTS_AND_INDICATIONS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->CFI_STATUS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->CSG_DISPLAY_CONTROL:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->FDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->MBDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->MSISDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->MWI_STATUS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->OPERATOR_CSG_LISTS_AND_INDICATIONS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->OPERATOR_PLMN_LIST:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->PLMN_NETWORK_NAME:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SDN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SM_OVER_IP:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SM_SERVICE_PARAMS:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SM_STORAGE:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;->SPN:Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;
-Lcom/android/internal/telephony/uicc/UsimServiceTable;->isAvailable(Lcom/android/internal/telephony/uicc/UsimServiceTable$UsimService;)Z
-Lcom/android/internal/telephony/uicc/VoiceMailConstants;-><init>()V
-Lcom/android/internal/telephony/UiccPhoneBookController;-><init>([Lcom/android/internal/telephony/Phone;)V
-Lcom/android/internal/telephony/UiccPhoneBookController;->getDefaultSubscription()I
-Lcom/android/internal/telephony/UiccPhoneBookController;->getIccPhoneBookInterfaceManager(I)Lcom/android/internal/telephony/IccPhoneBookInterfaceManager;
-Lcom/android/internal/telephony/UiccPhoneBookController;->mPhone:[Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/UiccSmsController;->copyMessageToIccEfForSubscriber(ILjava/lang/String;I[B[B)Z
-Lcom/android/internal/telephony/UiccSmsController;->disableCellBroadcastForSubscriber(III)Z
-Lcom/android/internal/telephony/UiccSmsController;->disableCellBroadcastRangeForSubscriber(IIII)Z
-Lcom/android/internal/telephony/UiccSmsController;->enableCellBroadcastForSubscriber(III)Z
-Lcom/android/internal/telephony/UiccSmsController;->enableCellBroadcastRangeForSubscriber(IIII)Z
-Lcom/android/internal/telephony/UiccSmsController;->getAllMessagesFromIccEfForSubscriber(ILjava/lang/String;)Ljava/util/List;
-Lcom/android/internal/telephony/UiccSmsController;->getIccSmsInterfaceManager(I)Lcom/android/internal/telephony/IccSmsInterfaceManager;
-Lcom/android/internal/telephony/UiccSmsController;->getImsSmsFormatForSubscriber(I)Ljava/lang/String;
-Lcom/android/internal/telephony/UiccSmsController;->getPreferredSmsSubscription()I
-Lcom/android/internal/telephony/UiccSmsController;->isImsSmsSupportedForSubscriber(I)Z
-Lcom/android/internal/telephony/UiccSmsController;->sendDataForSubscriber(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;I[BLandroid/app/PendingIntent;Landroid/app/PendingIntent;)V
-Lcom/android/internal/telephony/UiccSmsController;->sendErrorInPendingIntent(Landroid/app/PendingIntent;I)V
-Lcom/android/internal/telephony/UiccSmsController;->sendErrorInPendingIntents(Ljava/util/List;I)V
-Lcom/android/internal/telephony/UiccSmsController;->updateMessageOnIccEfForSubscriber(ILjava/lang/String;II[B)Z
-Lcom/android/internal/telephony/UUSInfo;->getDcs()I
-Lcom/android/internal/telephony/UUSInfo;->getType()I
-Lcom/android/internal/telephony/UUSInfo;->getUserData()[B
-Lcom/android/internal/telephony/WakeLockStateMachine;->log(Ljava/lang/String;)V
-Lcom/android/internal/telephony/WakeLockStateMachine;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/WakeLockStateMachine;->mIdleState:Lcom/android/internal/telephony/WakeLockStateMachine$IdleState;
-Lcom/android/internal/telephony/WakeLockStateMachine;->mPhone:Lcom/android/internal/telephony/Phone;
-Lcom/android/internal/telephony/WapPushOverSms;->dispatchWapPdu([BLandroid/content/BroadcastReceiver;Lcom/android/internal/telephony/InboundSmsHandler;)I
-Lcom/android/internal/telephony/WapPushOverSms;->getDeliveryOrReadReportThreadId(Landroid/content/Context;Lcom/google/android/mms/pdu/GenericPdu;)J
-Lcom/android/internal/telephony/WapPushOverSms;->isDuplicateNotification(Landroid/content/Context;Lcom/google/android/mms/pdu/NotificationInd;)Z
-Lcom/android/internal/telephony/WapPushOverSms;->isWapPushForMms([BLcom/android/internal/telephony/InboundSmsHandler;)Z
-Lcom/android/internal/telephony/WapPushOverSms;->mContext:Landroid/content/Context;
-Lcom/android/internal/telephony/WapPushOverSms;->mDeviceIdleController:Landroid/os/IDeviceIdleController;
-Lcom/android/internal/telephony/WapPushOverSms;->mWapPushManager:Lcom/android/internal/telephony/IWapPushManager;
-Lcom/android/internal/telephony/WspTypeDecoder;-><init>([B)V
-Lcom/android/internal/telephony/WspTypeDecoder;->decodeContentType(I)Z
-Lcom/android/internal/telephony/WspTypeDecoder;->decodeIntegerValue(I)Z
-Lcom/android/internal/telephony/WspTypeDecoder;->decodeShortInteger(I)Z
-Lcom/android/internal/telephony/WspTypeDecoder;->decodeTextString(I)Z
-Lcom/android/internal/telephony/WspTypeDecoder;->decodeUintvarInteger(I)Z
-Lcom/android/internal/telephony/WspTypeDecoder;->decodeValueLength(I)Z
-Lcom/android/internal/telephony/WspTypeDecoder;->decodeXWapApplicationId(I)Z
-Lcom/android/internal/telephony/WspTypeDecoder;->getContentParameters()Ljava/util/HashMap;
-Lcom/android/internal/telephony/WspTypeDecoder;->getDecodedDataLength()I
-Lcom/android/internal/telephony/WspTypeDecoder;->getValue32()J
-Lcom/android/internal/telephony/WspTypeDecoder;->getValueString()Ljava/lang/String;
-Lcom/android/internal/telephony/WspTypeDecoder;->mWspData:[B
-Lcom/android/internal/telephony/WspTypeDecoder;->seekXWapApplicationId(II)Z
 Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/util/ArrayUtils;->appendElement(Ljava/lang/Class;[Ljava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
 Lcom/android/internal/util/ArrayUtils;->appendInt([II)[I
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 56bf8fa..b039a60 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -139,6 +139,8 @@
 import com.android.internal.app.WindowDecorActionBar;
 import com.android.internal.policy.PhoneWindow;
 
+import dalvik.system.VMRuntime;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -2491,6 +2493,7 @@
             try {
                 ActivityTaskManager.getService().reportActivityFullyDrawn(
                         mToken, mRestoredFromBundle);
+                VMRuntime.getRuntime().notifyStartupCompleted();
             } catch (RemoteException e) {
             }
         }
@@ -8341,7 +8344,7 @@
         try {
             ActivityTaskManager.getService().setDisablePreviewScreenshots(mToken, disable);
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to call setDisablePreviewScreenshots", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -8362,7 +8365,7 @@
         try {
             ActivityTaskManager.getService().setShowWhenLocked(mToken, showWhenLocked);
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to call setShowWhenLocked", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -8386,7 +8389,7 @@
             ActivityTaskManager.getService().setInheritShowWhenLocked(
                     mToken, inheritShowWhenLocked);
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to call setInheritShowWhenLocked", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -8412,7 +8415,7 @@
         try {
             ActivityTaskManager.getService().setTurnScreenOn(mToken, turnScreenOn);
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to call setTurnScreenOn", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -8429,7 +8432,7 @@
         try {
             ActivityTaskManager.getService().registerRemoteAnimations(mToken, definition);
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to call registerRemoteAnimations", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index e2d868f..da9ea83 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -222,6 +222,13 @@
     private static final String KEY_AVOID_MOVE_TO_FRONT = "android.activity.avoidMoveToFront";
 
     /**
+     * See {@link #setFreezeRecentTasksReordering()}.
+     * @hide
+     */
+    private static final String KEY_FREEZE_RECENT_TASKS_REORDERING =
+            "android.activity.freezeRecentTasksReordering";
+
+    /**
      * Where the split-screen-primary stack should be positioned.
      * @hide
      */
@@ -324,6 +331,7 @@
     private boolean mTaskOverlay;
     private boolean mTaskOverlayCanResume;
     private boolean mAvoidMoveToFront;
+    private boolean mFreezeRecentTasksReordering;
     private AppTransitionAnimationSpec mAnimSpecs[];
     private int mRotationAnimationHint = -1;
     private Bundle mAppVerificationBundle;
@@ -946,6 +954,7 @@
         mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
         mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
         mAvoidMoveToFront = opts.getBoolean(KEY_AVOID_MOVE_TO_FRONT, false);
+        mFreezeRecentTasksReordering = opts.getBoolean(KEY_FREEZE_RECENT_TASKS_REORDERING, false);
         mSplitScreenCreateMode = opts.getInt(KEY_SPLIT_SCREEN_CREATE_MODE,
                 SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
         mDisallowEnterPictureInPictureWhileLaunching = opts.getBoolean(
@@ -1304,6 +1313,24 @@
         return mAvoidMoveToFront;
     }
 
+    /**
+     * Sets whether the launch of this activity should freeze the recent task list reordering until
+     * the next user interaction or timeout. This flag is only applied when starting an activity
+     * in recents.
+     * @hide
+     */
+    public void setFreezeRecentTasksReordering() {
+        mFreezeRecentTasksReordering = true;
+    }
+
+    /**
+     * @return whether the launch of this activity should freeze the recent task list reordering
+     * @hide
+     */
+    public boolean freezeRecentTasksReordering() {
+        return mFreezeRecentTasksReordering;
+    }
+
     /** @hide */
     public int getSplitScreenCreateMode() {
         return mSplitScreenCreateMode;
@@ -1502,6 +1529,9 @@
         if (mAvoidMoveToFront) {
             b.putBoolean(KEY_AVOID_MOVE_TO_FRONT, mAvoidMoveToFront);
         }
+        if (mFreezeRecentTasksReordering) {
+            b.putBoolean(KEY_FREEZE_RECENT_TASKS_REORDERING, mFreezeRecentTasksReordering);
+        }
         if (mSplitScreenCreateMode != SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT) {
             b.putInt(KEY_SPLIT_SCREEN_CREATE_MODE, mSplitScreenCreateMode);
         }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 91df05f..1066fc7 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2214,7 +2214,7 @@
         /**
          * @return The ops of the package.
          */
-        public List<OpEntry> getOps() {
+        public @NonNull List<OpEntry> getOps() {
             return mEntries;
         }
 
@@ -4371,7 +4371,8 @@
     @Deprecated
     @SystemApi
     @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
-    public List<PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
+    public @NonNull List<PackageOps> getOpsForPackage(int uid, @NonNull String packageName,
+            @Nullable int[] ops) {
         try {
             return mService.getOpsForPackage(uid, packageName, ops);
         } catch (RemoteException e) {
@@ -4639,8 +4640,8 @@
      * @param packageName The name of the application to monitor.
      * @param callback Where to report changes.
      */
-    public void startWatchingMode(String op, String packageName,
-            final OnOpChangedListener callback) {
+    public void startWatchingMode(@NonNull String op, @Nullable String packageName,
+            @NonNull final OnOpChangedListener callback) {
         startWatchingMode(strOpToOp(op), packageName, callback);
     }
 
@@ -4653,8 +4654,8 @@
      * @param flags Option flags: any combination of {@link #WATCH_FOREGROUND_CHANGES} or 0.
      * @param callback Where to report changes.
      */
-    public void startWatchingMode(String op, String packageName, int flags,
-            final OnOpChangedListener callback) {
+    public void startWatchingMode(@NonNull String op, @Nullable String packageName, int flags,
+            @NonNull final OnOpChangedListener callback) {
         startWatchingMode(strOpToOp(op), packageName, flags, callback);
     }
 
@@ -4716,7 +4717,7 @@
      * Stop monitoring that was previously started with {@link #startWatchingMode}.  All
      * monitoring associated with this callback will be removed.
      */
-    public void stopWatchingMode(OnOpChangedListener callback) {
+    public void stopWatchingMode(@NonNull OnOpChangedListener callback) {
         synchronized (mModeWatchers) {
             IAppOpsCallback cb = mModeWatchers.remove(callback);
             if (cb != null) {
@@ -4875,7 +4876,7 @@
      * {@hide}
      */
     @TestApi
-    public static int strOpToOp(String op) {
+    public static int strOpToOp(@NonNull String op) {
         Integer val = sOpStrToOp.get(op);
         if (val == null) {
             throw new IllegalArgumentException("Unknown operation string: " + op);
@@ -4910,7 +4911,7 @@
      * causing the app to crash).
      * @throws SecurityException If the app has been configured to crash on this op.
      */
-    public int unsafeCheckOp(String op, int uid, String packageName) {
+    public int unsafeCheckOp(@NonNull String op, int uid, @NonNull String packageName) {
         return checkOp(strOpToOp(op), uid, packageName);
     }
 
@@ -4918,7 +4919,7 @@
      * @deprecated Renamed to {@link #unsafeCheckOp(String, int, String)}.
      */
     @Deprecated
-    public int checkOp(String op, int uid, String packageName) {
+    public int checkOp(@NonNull String op, int uid, @NonNull String packageName) {
         return checkOp(strOpToOp(op), uid, packageName);
     }
 
@@ -4926,7 +4927,7 @@
      * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
      * returns {@link #MODE_ERRORED}.
      */
-    public int unsafeCheckOpNoThrow(String op, int uid, String packageName) {
+    public int unsafeCheckOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
         return checkOpNoThrow(strOpToOp(op), uid, packageName);
     }
 
@@ -4934,7 +4935,7 @@
      * @deprecated Renamed to {@link #unsafeCheckOpNoThrow(String, int, String)}.
      */
     @Deprecated
-    public int checkOpNoThrow(String op, int uid, String packageName) {
+    public int checkOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
         return checkOpNoThrow(strOpToOp(op), uid, packageName);
     }
 
@@ -4942,7 +4943,7 @@
      * Like {@link #checkOp} but returns the <em>raw</em> mode associated with the op.
      * Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}.
      */
-    public int unsafeCheckOpRaw(@NonNull String op, int uid, String packageName) {
+    public int unsafeCheckOpRaw(@NonNull String op, int uid, @NonNull String packageName) {
         try {
             return mService.checkOperationRaw(strOpToOp(op), uid, packageName);
         } catch (RemoteException e) {
@@ -4977,7 +4978,7 @@
      * causing the app to crash).
      * @throws SecurityException If the app has been configured to crash on this op.
      */
-    public int noteOp(String op, int uid, String packageName) {
+    public int noteOp(@NonNull String op, int uid, @NonNull String packageName) {
         return noteOp(strOpToOp(op), uid, packageName);
     }
 
@@ -4985,7 +4986,7 @@
      * Like {@link #noteOp} but instead of throwing a {@link SecurityException} it
      * returns {@link #MODE_ERRORED}.
      */
-    public int noteOpNoThrow(String op, int uid, String packageName) {
+    public int noteOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
         return noteOpNoThrow(strOpToOp(op), uid, packageName);
     }
 
@@ -5004,7 +5005,7 @@
      * causing the app to crash).
      * @throws SecurityException If the app has been configured to crash on this op.
      */
-    public int noteProxyOp(String op, String proxiedPackageName) {
+    public int noteProxyOp(@NonNull String op, @NonNull String proxiedPackageName) {
         return noteProxyOp(strOpToOp(op), proxiedPackageName);
     }
 
@@ -5015,7 +5016,7 @@
      * <p>This API requires the package with the {@code proxiedPackageName} to belongs to
      * {@link Binder#getCallingUid()}.
      */
-    public int noteProxyOpNoThrow(String op, String proxiedPackageName) {
+    public int noteProxyOpNoThrow(@NonNull String op, @NonNull String proxiedPackageName) {
         return noteProxyOpNoThrow(strOpToOp(op), proxiedPackageName);
     }
 
@@ -5051,7 +5052,7 @@
      * causing the app to crash).
      * @throws SecurityException If the app has been configured to crash on this op.
      */
-    public int startOp(String op, int uid, String packageName) {
+    public int startOp(@NonNull String op, int uid, @NonNull String packageName) {
         return startOp(strOpToOp(op), uid, packageName);
     }
 
@@ -5059,7 +5060,7 @@
      * Like {@link #startOp} but instead of throwing a {@link SecurityException} it
      * returns {@link #MODE_ERRORED}.
      */
-    public int startOpNoThrow(String op, int uid, String packageName) {
+    public int startOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
         return startOpNoThrow(strOpToOp(op), uid, packageName);
     }
 
@@ -5069,7 +5070,7 @@
      * or result; the parameters supplied here must be the exact same ones previously passed
      * in when starting the operation.
      */
-    public void finishOp(String op, int uid, String packageName) {
+    public void finishOp(@NonNull String op, int uid, @NonNull String packageName) {
         finishOp(strOpToOp(op), uid, packageName);
     }
 
@@ -5135,7 +5136,7 @@
      * @throws SecurityException if the package name doesn't belong to the given
      *             UID, or if ownership cannot be verified.
      */
-    public void checkPackage(int uid, String packageName) {
+    public void checkPackage(int uid, @NonNull String packageName) {
         try {
             if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) {
                 throw new SecurityException(
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index d3e3507..a226062 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1301,8 +1301,7 @@
     }
 
     @Override public Drawable getDefaultActivityIcon() {
-        return Resources.getSystem().getDrawable(
-            com.android.internal.R.drawable.sym_def_app_icon);
+        return mContext.getDrawable(com.android.internal.R.drawable.sym_def_app_icon);
     }
 
     @Override public Drawable getApplicationIcon(ApplicationInfo info) {
@@ -1440,7 +1439,7 @@
         if (density <= 0) {
             density = mContext.getResources().getDisplayMetrics().densityDpi;
         }
-        return Resources.getSystem().getDrawableForDensity(drawableId, density);
+        return mContext.getResources().getDrawableForDensity(drawableId, density);
     }
 
     private Drawable getManagedProfileIconForDensity(UserHandle user, int drawableId, int density) {
@@ -2469,7 +2468,7 @@
     }
 
     @Override
-    public void setAppDetailsActivityEnabled(String packageName, boolean enabled) {
+    public void setSyntheticAppDetailsActivityEnabled(String packageName, boolean enabled) {
         try {
             ComponentName componentName = new ComponentName(packageName,
                     PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME);
@@ -2483,7 +2482,7 @@
     }
 
     @Override
-    public boolean getAppDetailsActivityEnabled(String packageName) {
+    public boolean getSyntheticAppDetailsActivityEnabled(String packageName) {
         try {
             ComponentName componentName = new ComponentName(packageName,
                     PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 204fb6a..11b40c2 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1270,6 +1270,8 @@
 
     /**
      * Grants/revokes Notification Assistant access to {@code assistant} for current user.
+     * To grant access for a particular user, obtain this service by using the {@link Context}
+     * provided by {@link Context#createPackageContextAsUser}
      *
      * @param assistant Name of component to grant/revoke access or {@code null} to revoke access to
      *                  current assistant
@@ -1287,27 +1289,6 @@
         }
     }
 
-    /**
-     * Grants/revokes Notification Assistant access to {@code assistant} for given user.
-     *
-     * @param assistant Name of component to grant/revoke access or {@code null} to revoke access to
-     *                  current assistant
-     * @param user handle to associate assistant with
-     * @param granted Grant/revoke access
-     * @hide
-     */
-    @SystemApi
-    public void setNotificationAssistantAccessGrantedForUser(@Nullable ComponentName assistant,
-            @NonNull UserHandle user, boolean granted) {
-        INotificationManager service = getService();
-        try {
-            service.setNotificationAssistantAccessGrantedForUser(assistant, user.getIdentifier(),
-                    granted);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
     /** @hide */
     public List<ComponentName> getEnabledNotificationListeners(int userId) {
         INotificationManager service = getService();
@@ -1320,18 +1301,6 @@
 
     /** @hide */
     @SystemApi
-    public @Nullable ComponentName getAllowedNotificationAssistantForUser(
-            @NonNull UserHandle user) {
-        INotificationManager service = getService();
-        try {
-            return service.getAllowedNotificationAssistantForUser(user.getIdentifier());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /** @hide */
-    @SystemApi
     public @Nullable ComponentName getAllowedNotificationAssistant() {
         INotificationManager service = getService();
         try {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 90bc0a6..08e0880 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -104,11 +104,13 @@
 import android.net.IIpMemoryStore;
 import android.net.IIpSecService;
 import android.net.INetworkPolicyManager;
+import android.net.ITestNetworkManager;
 import android.net.IpMemoryStore;
 import android.net.IpSecManager;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkScoreManager;
 import android.net.NetworkWatchlistManager;
+import android.net.TestNetworkManager;
 import android.net.lowpan.ILowpanManager;
 import android.net.lowpan.LowpanManager;
 import android.net.nsd.INsdManager;
@@ -146,6 +148,7 @@
 import android.os.IncidentManager;
 import android.os.PowerManager;
 import android.os.RecoverySystem;
+import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
 import android.os.SystemUpdateManager;
@@ -357,6 +360,29 @@
                 return new IpSecManager(ctx, service);
             }});
 
+        registerService(
+                Context.TEST_NETWORK_SERVICE,
+                TestNetworkManager.class,
+                new StaticApplicationContextServiceFetcher<TestNetworkManager>() {
+                    @Override
+                    public TestNetworkManager createService(Context context)
+                            throws ServiceNotFoundException {
+                        IBinder csBinder =
+                                ServiceManager.getServiceOrThrow(Context.CONNECTIVITY_SERVICE);
+                        IConnectivityManager csMgr =
+                                IConnectivityManager.Stub.asInterface(csBinder);
+
+                        final IBinder tnBinder;
+                        try {
+                            tnBinder = csMgr.startOrGetTestNetworkService();
+                        } catch (RemoteException e) {
+                            throw new ServiceNotFoundException(Context.TEST_NETWORK_SERVICE);
+                        }
+                        ITestNetworkManager tnMgr = ITestNetworkManager.Stub.asInterface(tnBinder);
+                        return new TestNetworkManager(context, tnMgr);
+                    }
+                });
+
         registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
                 new StaticServiceFetcher<CountryDetector>() {
             @Override
@@ -1162,7 +1188,7 @@
                                 Context.CONTENT_SUGGESTIONS_SERVICE);
                         IContentSuggestionsManager service =
                                 IContentSuggestionsManager.Stub.asInterface(b);
-                        return new ContentSuggestionsManager(service);
+                        return new ContentSuggestionsManager(ctx.getUserId(), service);
                     }
                 });
 
diff --git a/core/java/android/app/admin/DevicePolicyEventLogger.java b/core/java/android/app/admin/DevicePolicyEventLogger.java
index c89d868..44ea218 100644
--- a/core/java/android/app/admin/DevicePolicyEventLogger.java
+++ b/core/java/android/app/admin/DevicePolicyEventLogger.java
@@ -178,7 +178,7 @@
     }
 
     /**
-     * Retrieves the package name of the admin application from the {@link ComponentName}.
+     * Sets the package name of the admin application from the {@link ComponentName}.
      */
     public DevicePolicyEventLogger setAdmin(@Nullable ComponentName componentName) {
         mAdminPackageName = (componentName != null ? componentName.getPackageName() : null);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f8ccb13..9a4e215 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3393,9 +3393,6 @@
      * explicitly querying the parent profile screen lock complexity via {@link
      * #getParentProfileInstance}.
      *
-     * <p>On devices not supporting {@link PackageManager#FEATURE_SECURE_LOCK_SCREEN} feature, the
-     * password is always empty and this method returns {@link #PASSWORD_COMPLEXITY_NONE}.
-     *
      * @throws IllegalStateException if the user is not unlocked.
      * @throws SecurityException if the calling application does not have the permission
      *                           {@link permission#REQUEST_PASSWORD_COMPLEXITY}
@@ -10628,10 +10625,10 @@
      * Returns the system-wide Private DNS host.
      *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with.
-     * @return The hostname used for Private DNS queries.
+     * @return The hostname used for Private DNS queries, null if none is set.
      * @throws SecurityException if the caller is not the device owner.
      */
-    public String getGlobalPrivateDnsHost(@NonNull ComponentName admin) {
+    public @Nullable String getGlobalPrivateDnsHost(@NonNull ComponentName admin) {
         throwIfParentInstance("setGlobalPrivateDns");
         if (mService == null) {
             return null;
@@ -10661,13 +10658,12 @@
     @SystemApi
     @RequiresPermission(value = android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS,
             conditional = true)
-    public void setProfileOwnerCanAccessDeviceIdsForUser(
-            @NonNull ComponentName who, @NonNull UserHandle userHandle) {
+    public void setProfileOwnerCanAccessDeviceIds(@NonNull ComponentName who) {
         if (mService == null) {
             return;
         }
         try {
-            mService.grantDeviceIdsAccessToProfileOwner(who, userHandle.getIdentifier());
+            mService.grantDeviceIdsAccessToProfileOwner(who, myUserId());
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
index b4d8977..1bb81b1 100644
--- a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
+++ b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java
@@ -20,11 +20,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.UserIdInt;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.util.SyncResultReceiver;
+
 import java.util.List;
 import java.util.concurrent.Executor;
 
@@ -44,12 +47,22 @@
 public final class ContentSuggestionsManager {
     private static final String TAG = ContentSuggestionsManager.class.getSimpleName();
 
+    /**
+     * Timeout for calls to system_server.
+     */
+    private static final int SYNC_CALLS_TIMEOUT_MS = 5000;
+
     @Nullable
     private final IContentSuggestionsManager mService;
 
+    @NonNull
+    private final int mUser;
+
     /** @hide */
-    public ContentSuggestionsManager(@Nullable IContentSuggestionsManager service) {
+    public ContentSuggestionsManager(
+            @UserIdInt int userId, @Nullable IContentSuggestionsManager service) {
         mService = service;
+        mUser = userId;
     }
 
     /**
@@ -60,14 +73,15 @@
      * @param imageContextRequestExtras sent with with request to provide implementation specific
      *                                  extra information.
      */
-    public void provideContextImage(int taskId, @NonNull Bundle imageContextRequestExtras) {
+    public void provideContextImage(
+            int taskId, @NonNull Bundle imageContextRequestExtras) {
         if (mService == null) {
             Log.e(TAG, "provideContextImage called, but no ContentSuggestionsManager configured");
             return;
         }
 
         try {
-            mService.provideContextImage(taskId, imageContextRequestExtras);
+            mService.provideContextImage(mUser, taskId, imageContextRequestExtras);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -96,7 +110,7 @@
 
         try {
             mService.suggestContentSelections(
-                    request, new SelectionsCallbackWrapper(callback, callbackExecutor));
+                    mUser, request, new SelectionsCallbackWrapper(callback, callbackExecutor));
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -123,7 +137,7 @@
 
         try {
             mService.classifyContentSelections(
-                    request, new ClassificationsCallbackWrapper(callback, callbackExecutor));
+                    mUser, request, new ClassificationsCallbackWrapper(callback, callbackExecutor));
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -135,20 +149,42 @@
      * @param requestId the id for the associated interaction
      * @param interaction to report back to the system content suggestions service.
      */
-    public void notifyInteraction(@NonNull String requestId, @NonNull Bundle interaction) {
+    public void notifyInteraction(
+            @NonNull String requestId, @NonNull Bundle interaction) {
         if (mService == null) {
             Log.e(TAG, "notifyInteraction called, but no ContentSuggestionsManager configured");
             return;
         }
 
         try {
-            mService.notifyInteraction(requestId, interaction);
+            mService.notifyInteraction(mUser, requestId, interaction);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
     }
 
     /**
+     * Indicates that Content Suggestions is available and enabled for the provided user. That is,
+     * has an implementation and not disabled through device management.
+     *
+     * @return {@code true} if Content Suggestions is enabled and available for the provided user.
+     */
+    public boolean isEnabled() {
+        if (mService == null) {
+            return false;
+        }
+
+        SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+        try {
+            mService.isEnabled(mUser, receiver);
+            return receiver.getIntResult() != 0;
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return false;
+    }
+
+    /**
      * Callback to receive content selections from
      *  {@link #suggestContentSelections(SelectionsRequest, Executor, SelectionsCallback)}.
      */
diff --git a/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
index 24f5ad8..b18a758 100644
--- a/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
+++ b/core/java/android/app/contentsuggestions/IContentSuggestionsManager.aidl
@@ -21,17 +21,23 @@
 import android.app.contentsuggestions.ClassificationsRequest;
 import android.app.contentsuggestions.SelectionsRequest;
 import android.os.Bundle;
+import android.os.UserHandle;
+import com.android.internal.os.IResultReceiver;
 
 /** @hide */
 oneway interface IContentSuggestionsManager {
     void provideContextImage(
+            int userId,
             int taskId,
             in Bundle imageContextRequestExtras);
     void suggestContentSelections(
+            int userId,
             in SelectionsRequest request,
             in ISelectionsCallback callback);
     void classifyContentSelections(
+            int userId,
             in ClassificationsRequest request,
             in IClassificationsCallback callback);
-    void notifyInteraction(in String requestId, in Bundle interaction);
+    void notifyInteraction(int userId, in String requestId, in Bundle interaction);
+    void isEnabled(int userId, in IResultReceiver receiver);
 }
diff --git a/core/java/android/app/prediction/AppPredictionContext.java b/core/java/android/app/prediction/AppPredictionContext.java
index 2da4671..b6f37f6 100644
--- a/core/java/android/app/prediction/AppPredictionContext.java
+++ b/core/java/android/app/prediction/AppPredictionContext.java
@@ -15,6 +15,7 @@
  */
 package android.app.prediction;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -49,18 +50,19 @@
         mExtras = extras;
     }
 
-    private AppPredictionContext(Parcel parcel) {
+    private AppPredictionContext(@NonNull Parcel parcel) {
         mUiSurface = parcel.readString();
         mPredictedTargetCount = parcel.readInt();
         mPackageName = parcel.readString();
         mExtras = parcel.readBundle();
     }
 
+    @NonNull
     public String getUiSurface() {
         return mUiSurface;
     }
 
-    public int getPredictedTargetCount() {
+    public @IntRange(from = 0) int getPredictedTargetCount() {
         return mPredictedTargetCount;
     }
 
@@ -91,7 +93,7 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString(mUiSurface);
         dest.writeInt(mPredictedTargetCount);
         dest.writeString(mPackageName);
@@ -144,7 +146,8 @@
         /**
          * Sets the number of prediction targets as a hint.
          */
-        public Builder setPredictedTargetCount(int predictedTargetCount) {
+        @NonNull
+        public Builder setPredictedTargetCount(@IntRange(from = 0) int predictedTargetCount) {
             mPredictedTargetCount = predictedTargetCount;
             return this;
         }
@@ -152,7 +155,8 @@
         /**
          * Sets the UI surface.
          */
-        public Builder setUiSurface(@Nullable String uiSurface) {
+        @NonNull
+        public Builder setUiSurface(@NonNull String uiSurface) {
             mUiSurface = uiSurface;
             return this;
         }
@@ -160,6 +164,7 @@
         /**
          * Sets the extras.
          */
+        @NonNull
         public Builder setExtras(@Nullable Bundle extras) {
             mExtras = extras;
             return this;
@@ -168,6 +173,7 @@
         /**
          * Builds a new context instance.
          */
+        @NonNull
         public AppPredictionContext build() {
             return new AppPredictionContext(mUiSurface, mPredictedTargetCount, mPackageName,
                     mExtras);
diff --git a/core/java/android/app/prediction/AppPredictionManager.java b/core/java/android/app/prediction/AppPredictionManager.java
index 99f78f1..45825cf 100644
--- a/core/java/android/app/prediction/AppPredictionManager.java
+++ b/core/java/android/app/prediction/AppPredictionManager.java
@@ -42,6 +42,7 @@
     /**
      * Creates a new app prediction session.
      */
+    @NonNull
     public AppPredictor createAppPredictionSession(
             @NonNull AppPredictionContext predictionContext) {
         return new AppPredictor(mContext, predictionContext);
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
index 12d6ce3..284327d 100644
--- a/core/java/android/app/prediction/AppPredictor.java
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -94,7 +94,7 @@
             mPredictionManager.createPredictionSession(predictionContext, mSessionId);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to create predictor", e);
-            return;
+            e.rethrowAsRuntimeException();
         }
 
         mCloseGuard.open("close");
@@ -112,6 +112,7 @@
             mPredictionManager.notifyAppTargetEvent(mSessionId, event);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to notify app target event", e);
+            e.rethrowAsRuntimeException();
         }
     }
 
@@ -129,6 +130,7 @@
                     new ParceledListSlice<>(targetIds));
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to notify location shown event", e);
+            e.rethrowAsRuntimeException();
         }
     }
 
@@ -155,6 +157,7 @@
             mRegisteredCallbacks.put(callback, callbackWrapper);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to register for prediction updates", e);
+            e.rethrowAsRuntimeException();
         }
     }
 
@@ -176,6 +179,7 @@
             mPredictionManager.unregisterPredictionUpdates(mSessionId, callbackWrapper);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to unregister for prediction updates", e);
+            e.rethrowAsRuntimeException();
         }
     }
 
@@ -194,6 +198,7 @@
             mPredictionManager.requestPredictionUpdate(mSessionId);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to request prediction update", e);
+            e.rethrowAsRuntimeException();
         }
     }
 
@@ -213,14 +218,13 @@
                     new CallbackWrapper(callbackExecutor, callback));
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to sort targets", e);
+            e.rethrowAsRuntimeException();
         }
     }
 
     /**
      * Destroys the client and unregisters the callback. Any method on this class after this call
      * with throw {@link IllegalStateException}.
-     *
-     * TODO(b/111701043): Add state check in other methods.
      */
     public void destroy() {
         if (!mIsClosed.getAndSet(true)) {
@@ -231,6 +235,7 @@
                 mPredictionManager.onDestroyPredictionSession(mSessionId);
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to notify app target event", e);
+                e.rethrowAsRuntimeException();
             }
         } else {
             throw new IllegalStateException("This client has already been destroyed.");
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
index 752c92b..6f09d34 100644
--- a/core/java/android/app/prediction/AppTarget.java
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -15,6 +15,7 @@
  */
 package android.app.prediction;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -134,14 +135,19 @@
      * Sets the rank of the for the target.
      * @hide
      */
-    public void setRank(int rank) {
+    public void setRank(@IntRange(from = 0) int rank) {
+        if (rank < 0) {
+            throw new IllegalArgumentException("rank cannot be a negative value");
+        }
         mRank = rank;
     }
 
     /**
-     * Returns the rank for the target.
+     * Returns the rank for the target. Rank of an AppTarget is a non-negative integer that
+     * represents the importance of this target compared to other candidate targets. A smaller value
+     * means higher importance in the list.
      */
-    public int getRank() {
+    public @IntRange(from = 0) int getRank() {
         return mRank;
     }
 
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
index 01452df..f6964f3 100644
--- a/core/java/android/app/prediction/AppTargetEvent.java
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -84,7 +84,7 @@
     /**
      * Returns the launch location.
      */
-    @NonNull
+    @Nullable
     public String getLaunchLocation() {
         return mLocation;
     }
@@ -92,8 +92,7 @@
     /**
      * Returns the action type.
      */
-    @NonNull
-    public int getAction() {
+    public @ActionType int getAction() {
         return mAction;
     }
 
@@ -152,7 +151,8 @@
         /**
          * Sets the launch location.
          */
-        public Builder setLaunchLocation(String location) {
+        @NonNull
+        public Builder setLaunchLocation(@Nullable String location) {
             mLocation = location;
             return this;
         }
@@ -160,6 +160,7 @@
         /**
          * Builds a new event instance.
          */
+        @NonNull
         public AppTargetEvent build() {
             return new AppTargetEvent(mTarget, mLocation, mAction);
         }
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 62b24e9..83c1d61 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -60,7 +60,7 @@
             in PendingIntent sessionEndCallbackIntent, String callingPackage);
     void unregisterUsageSessionObserver(int sessionObserverId, String callingPackage);
     void registerAppUsageLimitObserver(int observerId, in String[] packages, long timeLimitMs,
-            long timeRemainingMs, in PendingIntent callback, String callingPackage);
+            long timeUsedMs, in PendingIntent callback, String callingPackage);
     void unregisterAppUsageLimitObserver(int observerId, String callingPackage);
     void reportUsageStart(in IBinder activity, String token, String callingPackage);
     void reportPastUsageStart(in IBinder activity, String token, long timeAgoMs,
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index b3d01fd..b564c31 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -428,7 +428,6 @@
 
         /**
          * Indicates whether it is an instant app.
-         * STOPSHIP b/111407095: Add GTS tests for the newly added API method.
          * @hide
          */
         @SystemApi
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index cee6b87..a6ceeb1 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -660,6 +660,29 @@
         }
     }
 
+
+    /**
+     * @deprecated use {@link #registerUsageSessionObserver(int, String[], Duration, Duration,
+     *                                                      PendingIntent, PendingIntent)}.
+     *
+     * @hide
+     */
+    @Deprecated
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
+    // STOPSHIP b/128455269: remove this method
+    public void registerUsageSessionObserver(int sessionObserverId,
+            @NonNull String[] observedEntities, long timeLimit, @NonNull TimeUnit timeUnit,
+            long sessionThresholdTime,  @NonNull TimeUnit sessionThresholdTimeUnit,
+            @NonNull PendingIntent limitReachedCallbackIntent,
+            @Nullable PendingIntent sessionEndCallbackIntent) {
+        final Duration timeLimitDuration = Duration.ofMillis(timeUnit.toMillis(timeLimit));
+        final Duration sessionThresholdDuration =
+                Duration.ofMillis(sessionThresholdTimeUnit.toMillis(sessionThresholdTime));
+        registerUsageSessionObserver(sessionObserverId, observedEntities, timeLimitDuration,
+                sessionThresholdDuration, limitReachedCallbackIntent, sessionEndCallbackIntent);
+    }
+
     /**
      * Register a usage session observer that receives a callback on the provided {@code
      * limitReachedCallbackIntent} when the sum of usages of apps and tokens in the {@code
@@ -679,11 +702,8 @@
      *                         null and must include at least one package or token.
      * @param timeLimit The total time the set of apps can be used continuously before the {@code
      *                  limitReachedCallbackIntent} is delivered. Must be at least one minute.
-     * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
      * @param sessionThresholdTime The time that can take place between usage sessions before the
      *                             next session is considered a new session. Must be non-negative.
-     * @param sessionThresholdTimeUnit The unit for time specified in {@code sessionThreshold}.
-     *                                 Cannot be null.
      * @param limitReachedCallbackIntent The {@link PendingIntent} that will be dispatched when the
      *                                   usage limit is exceeded by the group of apps. The
      *                                   delivered Intent will also contain the extras {@link
@@ -703,14 +723,13 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
     public void registerUsageSessionObserver(int sessionObserverId,
-            @NonNull String[] observedEntities, long timeLimit, @NonNull TimeUnit timeUnit,
-            long sessionThresholdTime,  @NonNull TimeUnit sessionThresholdTimeUnit,
+            @NonNull String[] observedEntities, @NonNull Duration timeLimit,
+            @NonNull Duration sessionThresholdTime,
             @NonNull PendingIntent limitReachedCallbackIntent,
             @Nullable PendingIntent sessionEndCallbackIntent) {
         try {
             mService.registerUsageSessionObserver(sessionObserverId, observedEntities,
-                    timeUnit.toMillis(timeLimit),
-                    sessionThresholdTimeUnit.toMillis(sessionThresholdTime),
+                    timeLimit.toMillis(), sessionThresholdTime.toMillis(),
                     limitReachedCallbackIntent, sessionEndCallbackIntent,
                     mContext.getOpPackageName());
         } catch (RemoteException e) {
@@ -747,7 +766,7 @@
      */
     @Deprecated
     @UnsupportedAppUsage
-    // STOPSHIP b/126917290: remove this method once ag/6591106 is merged and it's not being used.
+    // STOPSHIP b/126917290: remove this method once b/126926550 is fixed.
     public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities,
             long timeLimit, @NonNull TimeUnit timeUnit, @Nullable PendingIntent callbackIntent) {
         final Duration timeLimitDuration = Duration.ofMillis(timeUnit.toMillis(timeLimit));
@@ -782,16 +801,17 @@
      *                         null and must include at least one package or token.
      * @param timeLimit The total time the set of apps can be in the foreground before the
      *                  {@code callbackIntent} is delivered. Must be at least one minute.
-     * @param timeRemaining The remaining time the set of apps can be in the foreground before the
-     *                      {@code callbackIntent} is delivered. Must be greater than
-     *                      {@code timeLimit}. Note: a limit of 0 can be set to indicate that the
-     *                      user has already exhausted the limit for a group, in which case,
-     *                      the given {@code callbackIntent} will be ignored.
+     * @param timeUsed The time that has already been used by the set of apps in
+     *                 {@code observedEntities}. Note: a time used equal to or greater than
+     *                 {@code timeLimit} can be set to indicate that the user has already exhausted
+     *                 the limit for a group, in which case, the given {@code callbackIntent} will
+     *                 be ignored.
      * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is
      *                       exceeded by the group of apps. The delivered Intent will also contain
      *                       the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and
      *                       {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is
-     *                       being registered with a {@code timeRemaining} of 0.
+     *                       being registered with a {@code timeUsed} equal to or greater than
+     *                       {@code timeLimit}.
      * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE
      *                           permissions.
      * @hide
@@ -801,11 +821,11 @@
             android.Manifest.permission.SUSPEND_APPS,
             android.Manifest.permission.OBSERVE_APP_USAGE})
     public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities,
-            @NonNull Duration timeLimit, @NonNull Duration timeRemaining,
+            @NonNull Duration timeLimit, @NonNull Duration timeUsed,
             @Nullable PendingIntent callbackIntent) {
         try {
             mService.registerAppUsageLimitObserver(observerId, observedEntities,
-                    timeLimit.toMillis(), timeRemaining.toMillis(), callbackIntent,
+                    timeLimit.toMillis(), timeUsed.toMillis(), callbackIntent,
                     mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index c4bf1eb..442b239 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -224,8 +224,10 @@
                         if (VDBG) Log.d(TAG, "Unbinding service...");
                         try {
                             mServiceLock.writeLock().lock();
-                            mService = null;
-                            mContext.unbindService(mConnection);
+                            if (mService != null) {
+                                mService = null;
+                                mContext.unbindService(mConnection);
+                            }
                         } catch (Exception re) {
                             Log.e(TAG, "", re);
                         } finally {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ab8c196..b8a741a 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -19,6 +19,7 @@
 
 import android.Manifest;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -3057,7 +3058,7 @@
      * permissions, or unable to start this CoC
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothServerSocket listenUsingL2capChannel()
+    public @NonNull BluetoothServerSocket listenUsingL2capChannel()
             throws IOException {
         BluetoothServerSocket socket =
                             new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true,
@@ -3115,7 +3116,7 @@
      * permissions, or unable to start this CoC
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothServerSocket listenUsingInsecureL2capChannel()
+    public @NonNull BluetoothServerSocket listenUsingInsecureL2capChannel()
             throws IOException {
         BluetoothServerSocket socket =
                             new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false,
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index f718415..fa2c9f8 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -17,6 +17,7 @@
 package android.bluetooth;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -2182,7 +2183,7 @@
      * permissions
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothSocket createL2capChannel(int psm) throws IOException {
+    public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException {
         if (!isBluetoothEnabled()) {
             Log.e(TAG, "createL2capChannel: Bluetooth is not enabled");
             throw new IOException();
@@ -2221,7 +2222,7 @@
      * permissions
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
+    public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
         if (!isBluetoothEnabled()) {
             Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled");
             throw new IOException();
diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java
index 58a2522..7c925a1 100644
--- a/core/java/android/bluetooth/BluetoothHidHost.java
+++ b/core/java/android/bluetooth/BluetoothHidHost.java
@@ -233,8 +233,10 @@
                         if (VDBG) Log.d(TAG, "Unbinding service...");
                         synchronized (mConnection) {
                             try {
-                                mService = null;
-                                mContext.unbindService(mConnection);
+                                if (mService != null) {
+                                    mService = null;
+                                    mContext.unbindService(mConnection);
+                                }
                             } catch (Exception re) {
                                 Log.e(TAG, "", re);
                             }
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index a601df0..359bec6 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -121,8 +121,10 @@
                         log("Unbinding service...");
                         synchronized (mConnection) {
                             try {
-                                mService = null;
-                                mContext.unbindService(mConnection);
+                                if (mService != null) {
+                                    mService = null;
+                                    mContext.unbindService(mConnection);
+                                }
                             } catch (Exception re) {
                                 Log.e(TAG, "", re);
                             }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0c76f3f..efb3bfc1 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -338,6 +338,15 @@
     public static final int BIND_ADJUST_BELOW_PERCEPTIBLE = 0x0100;
 
     /**
+     * Flag for {@link #bindService}: allow background activity starts from the bound service's
+     * process.
+     * This flag is only respected if the caller is holding
+     * {@link android.Manifest.permission#START_ACTIVITIES_FROM_BACKGROUND}.
+     * @hide
+     */
+    public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 0x00100000;
+
+    /**
      * @hide Flag for {@link #bindService}: the service being bound to represents a
      * protected system component, so must have association restrictions applied to it.
      * That is, a system config must have one or more allow-association tags limiting
@@ -3127,6 +3136,7 @@
             CONNECTIVITY_SERVICE,
             //@hide: IP_MEMORY_STORE_SERVICE,
             IPSEC_SERVICE,
+            TEST_NETWORK_SERVICE,
             //@hide: UPDATE_LOCK_SERVICE,
             //@hide: NETWORKMANAGEMENT_SERVICE,
             NETWORK_STATS_SERVICE,
@@ -3289,11 +3299,16 @@
      * {@link #USB_SERVICE}, {@link #WALLPAPER_SERVICE}, {@link #WIFI_P2P_SERVICE},
      * {@link #WIFI_SERVICE}, {@link #WIFI_AWARE_SERVICE}. For these services this method will
      * return <code>null</code>.  Generally, if you are running as an instant app you should always
-     * check whether the result of this method is null.
+     * check whether the result of this method is {@code null}.
+     *
+     * <p>Note: When implementing this method, keep in mind that new services can be added on newer
+     * Android releases, so if you're looking for just the explicit names mentioned above, make sure
+     * to return {@code null} when you don't recognize the name &mdash; if you throw a
+     * {@link RuntimeException} exception instead, you're app might break on new Android releases.
      *
      * @param name The name of the desired service.
      *
-     * @return The service or null if the name does not exist.
+     * @return The service or {@code null} if the name does not exist.
      *
      * @see #WINDOW_SERVICE
      * @see android.view.WindowManager
@@ -3367,7 +3382,9 @@
      * {@link android.app.UiModeManager}, {@link android.app.DownloadManager},
      * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler},
      * {@link android.app.usage.NetworkStatsManager}.
-     * </p><p>
+     * </p>
+     *
+     * <p>
      * Note: System services obtained via this API may be closely associated with
      * the Context in which they are obtained from.  In general, do not share the
      * service objects between various different contexts (Activities, Applications,
@@ -3379,11 +3396,13 @@
      * {@link #FINGERPRINT_SERVICE}, {@link #KEYGUARD_SERVICE}, {@link #SHORTCUT_SERVICE},
      * {@link #USB_SERVICE}, {@link #WALLPAPER_SERVICE}, {@link #WIFI_P2P_SERVICE},
      * {@link #WIFI_SERVICE}, {@link #WIFI_AWARE_SERVICE}. For these services this method will
-     * return <code>null</code>.  Generally, if you are running as an instant app you should always
-     * check whether the result of this method is null.
+     * return {@code null}. Generally, if you are running as an instant app you should always
+     * check whether the result of this method is {@code null}.
+     * </p>
      *
      * @param serviceClass The class of the desired service.
-     * @return The service or null if the class is not a supported system service.
+     * @return The service or {@code null} if the class is not a supported system service. Note:
+     * <b>never</b> throw a {@link RuntimeException} if the name is not supported.
      */
     @SuppressWarnings("unchecked")
     public final @Nullable <T> T getSystemService(@NonNull Class<T> serviceClass) {
@@ -3691,6 +3710,15 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a {@link
+     * android.net.TestNetworkManager} for building TUNs and limited-use Networks
+     *
+     * @see #getSystemService(String)
+     * @hide
+     */
+    @TestApi public static final String TEST_NETWORK_SERVICE = "test_network";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a {@link
      * android.os.IUpdateLock} for managing runtime sequences that
      * must not be interrupted by headless OTA application or similar.
      *
diff --git a/core/java/android/content/pm/AndroidHidlUpdater.java b/core/java/android/content/pm/AndroidHidlUpdater.java
index b7ae8f4..d0657e5 100644
--- a/core/java/android/content/pm/AndroidHidlUpdater.java
+++ b/core/java/android/content/pm/AndroidHidlUpdater.java
@@ -34,8 +34,14 @@
 
     @Override
     public void updatePackage(Package pkg) {
+        ApplicationInfo info = pkg.applicationInfo;
+
         // This was the default <= P and is maintained for backwards compatibility.
-        if (pkg.applicationInfo.targetSdkVersion <= Build.VERSION_CODES.P) {
+        boolean isLegacy = info.targetSdkVersion <= Build.VERSION_CODES.P;
+        // Only system apps use these libraries
+        boolean isSystem = info.isSystemApp() || info.isUpdatedSystemApp();
+
+        if (isLegacy && isSystem) {
             prefixRequiredLibrary(pkg, ANDROID_HIDL_BASE);
             prefixRequiredLibrary(pkg, ANDROID_HIDL_MANAGER);
         } else {
diff --git a/core/java/android/content/pm/PackageList.java b/core/java/android/content/pm/PackageList.java
index cfd99ab..f781758 100644
--- a/core/java/android/content/pm/PackageList.java
+++ b/core/java/android/content/pm/PackageList.java
@@ -45,16 +45,16 @@
     }
 
     @Override
-    public void onPackageAdded(String packageName) {
+    public void onPackageAdded(String packageName, int uid) {
         if (mWrappedObserver != null) {
-            mWrappedObserver.onPackageAdded(packageName);
+            mWrappedObserver.onPackageAdded(packageName, uid);
         }
     }
 
     @Override
-    public void onPackageRemoved(String packageName) {
+    public void onPackageRemoved(String packageName, int uid) {
         if (mWrappedObserver != null) {
-            mWrappedObserver.onPackageRemoved(packageName);
+            mWrappedObserver.onPackageRemoved(packageName, uid);
         }
     }
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d1ebcfd..99324ba 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1389,6 +1389,14 @@
      */
     public static final int INSTALL_FAILED_BAD_SIGNATURE = -118;
 
+    /**
+     * Installation failed return code: a new staged session was attempted to be committed while
+     * there is already one in-progress.
+     *
+     * @hide
+     */
+    public static final int INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS = -119;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "DELETE_" }, value = {
             DELETE_KEEP_DATA,
@@ -5866,34 +5874,37 @@
             @NonNull ComponentName componentName);
 
     /**
-     * Set the enabled setting for a package app settings activity.
+     * Set whether a synthetic app details activity will be generated if the app has no enabled
+     * launcher activity. Disabling this allows the app to have no launcher icon.
      *
      * @param packageName The package name of the app
-     * @param enabled The new enabled state for app details activity
+     * @param enabled The new enabled state for the synthetic app details activity.
      *
      * @hide
      */
     @RequiresPermission(value = android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE,
             conditional = true)
     @SystemApi
-    public void setAppDetailsActivityEnabled(@NonNull String packageName, boolean enabled) {
+    public void setSyntheticAppDetailsActivityEnabled(@NonNull String packageName,
+            boolean enabled) {
         throw new UnsupportedOperationException(
-                "setAppDetailsActivityEnabled not implemented");
+                "setSyntheticAppDetailsActivityEnabled not implemented");
     }
 
 
     /**
-     * Return the enabled setting for a package app settings activity.
+     * Return whether a synthetic app details activity will be generated if the app has no enabled
+     * launcher activity.
      *
      * @param packageName The package name of the app
-     * @return Returns the current enabled state for app settings activity.
+     * @return Returns the enabled state for the synthetic app details activity.
      *
      * @hide
      */
     @SystemApi
-    public boolean getAppDetailsActivityEnabled(@NonNull String packageName) {
+    public boolean getSyntheticAppDetailsActivityEnabled(@NonNull String packageName) {
         throw new UnsupportedOperationException(
-                "getAppDetailsActivityEnabled not implemented");
+                "getSyntheticAppDetailsActivityEnabled not implemented");
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 2c1842c..b3cc627 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -22,6 +22,7 @@
 import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.PackageManager.ApplicationInfoFlags;
 import android.content.pm.PackageManager.ComponentInfoFlags;
 import android.content.pm.PackageManager.PackageInfoFlags;
@@ -78,9 +79,9 @@
     /** Observer called whenever the list of packages changes */
     public interface PackageListObserver {
         /** A package was added to the system. */
-        void onPackageAdded(@NonNull String packageName);
+        void onPackageAdded(@NonNull String packageName, int uid);
         /** A package was removed from the system. */
-        void onPackageRemoved(@NonNull String packageName);
+        void onPackageRemoved(@NonNull String packageName, int uid);
     }
 
     /** Interface to override permission checks via composition */
@@ -925,4 +926,21 @@
      * @param provider the provider
      */
     public abstract void setDefaultHomeProvider(@NonNull DefaultHomeProvider provider);
+
+    /**
+     * Returns {@code true} if given {@code packageName} is an apex package.
+     */
+    public abstract boolean isApexPackage(String packageName);
+
+    /**
+     * Uninstalls given {@code packageName}.
+     *
+     * @param packageName apex package to uninstall.
+     * @param versionCode version of a package to uninstall.
+     * @param userId user to uninstall apex package for. Must be
+     *               {@link android.os.UserHandle#USER_ALL}, otherwise failure will be reported.
+     * @param intentSender a {@link IntentSender} to send result of an uninstall to.
+     */
+    public abstract void uninstallApex(String packageName, long versionCode, int userId,
+            IntentSender intentSender);
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ec42134..9d0ece0 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3993,8 +3993,6 @@
         setMaxAspectRatio(owner);
         setMinAspectRatio(owner);
 
-        PackageBackwardCompatibility.modifySharedLibraries(owner);
-
         if (hasDomainURLs(owner)) {
             owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
         } else {
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 2287243..df67117 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -600,15 +600,17 @@
             mTargetComponent = targetComponent;
         }
 
-        private ShareShortcutInfo(Parcel in) {
+        private ShareShortcutInfo(@NonNull Parcel in) {
             mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader());
             mTargetComponent = in.readParcelable(ComponentName.class.getClassLoader());
         }
 
+        @NonNull
         public ShortcutInfo getShortcutInfo() {
             return mShortcutInfo;
         }
 
+        @NonNull
         public ComponentName getTargetComponent() {
             return mTargetComponent;
         }
@@ -619,12 +621,12 @@
         }
 
         @Override
-        public void writeToParcel(Parcel dest, int flags) {
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
             dest.writeParcelable(mShortcutInfo, flags);
             dest.writeParcelable(mTargetComponent, flags);
         }
 
-        public static final @android.annotation.NonNull Parcelable.Creator<ShareShortcutInfo> CREATOR =
+        public static final @NonNull Parcelable.Creator<ShareShortcutInfo> CREATOR =
                 new Parcelable.Creator<ShareShortcutInfo>() {
                     public ShareShortcutInfo createFromParcel(Parcel in) {
                         return new ShareShortcutInfo(in);
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index a2e98cc..df4ae09 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -1,6 +1,12 @@
 {
   "imports": [
     {
+      "path": "cts/tests/tests/packageinstaller"
+    },
+    {
+      "path": "cts/hostsidetests/stagedinstall"
+    },
+    {
       "path": "system/apex/tests"
     }
   ]
diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS
index 29a339a..47dbf2d 100644
--- a/core/java/android/hardware/OWNERS
+++ b/core/java/android/hardware/OWNERS
@@ -1,2 +1,2 @@
 # Camera
-per-file *Camera* = cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,yinchiayeh@google.com,zhijunhe@google.com
+per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,yinchiayeh@google.com,zhijunhe@google.com,jchowdhary@google.com
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index 3602a33..6ea35f0 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -313,12 +313,17 @@
     public static final int FACE_ACQUIRED_START = 20;
 
     /**
+     * The sensor is dirty. The user should be informed to clean the sensor.
+     */
+    public static final int SENSOR_DIRTY = 21;
+
+    /**
      * Hardware vendors may extend this list if there are conditions that do not fall under one of
      * the above categories. Vendors are responsible for providing error strings for these errors.
      *
      * @hide
      */
-    public static final int FACE_ACQUIRED_VENDOR = 21;
+    public static final int FACE_ACQUIRED_VENDOR = 22;
 
     /**
      * @hide
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index f8b2a5b..7ae673c 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -85,8 +85,7 @@
          *
          * @hide
          */
-        @UnsupportedAppUsage
-        public Key(@NonNull String name, @NonNull String fallbackName, @NonNull Class<T> type) {
+        public Key(String name, String fallbackName, Class<T> type) {
             mKey = new CameraMetadataNative.Key<T>(name,  fallbackName, type);
         }
 
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 7382ac4..ba451e5 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -89,8 +89,7 @@
          *
          * @hide
          */
-        @UnsupportedAppUsage
-        public Key(@NonNull String name, @NonNull String fallbackName, @NonNull Class<T> type) {
+        public Key(String name, String fallbackName, Class<T> type) {
             mKey = new CameraMetadataNative.Key<T>(name, fallbackName, type);
         }
 
@@ -4252,7 +4251,6 @@
      * @see CaptureResult#SENSOR_TIMESTAMP
      * @hide
      */
-    @UnsupportedAppUsage
     public static final Key<long[]> STATISTICS_OIS_TIMESTAMPS =
             new Key<long[]>("android.statistics.oisTimestamps", long[].class);
 
@@ -4272,7 +4270,6 @@
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * @hide
      */
-    @UnsupportedAppUsage
     public static final Key<float[]> STATISTICS_OIS_X_SHIFTS =
             new Key<float[]>("android.statistics.oisXShifts", float[].class);
 
@@ -4292,7 +4289,6 @@
      * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
      * @hide
      */
-    @UnsupportedAppUsage
     public static final Key<float[]> STATISTICS_OIS_Y_SHIFTS =
             new Key<float[]>("android.statistics.oisYShifts", float[].class);
 
diff --git a/core/java/android/hardware/camera2/OWNERS b/core/java/android/hardware/camera2/OWNERS
index 18acfee..f48a95c 100644
--- a/core/java/android/hardware/camera2/OWNERS
+++ b/core/java/android/hardware/camera2/OWNERS
@@ -1,6 +1 @@
-cychen@google.com
-epeev@google.com
-etalvala@google.com
-shuzhenwang@google.com
-yinchiayeh@google.com
-zhijunhe@google.com
+include platform/frameworks/av:/camera/OWNERS
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index 92653d18..a7ff644 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -1761,7 +1761,7 @@
         TunerCallbackAdapter halCallback = new TunerCallbackAdapter(callback, handler);
         try {
             tuner = mService.openTuner(moduleId, config, withAudio, halCallback);
-        } catch (RemoteException | IllegalArgumentException ex) {
+        } catch (RemoteException | IllegalArgumentException | IllegalStateException ex) {
             Log.e(TAG, "Failed to open tuner", ex);
             return null;
         }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3f8410f..d08379f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -38,7 +38,6 @@
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.INetworkActivityListener;
 import android.os.INetworkManagementService;
@@ -75,6 +74,9 @@
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.RejectedExecutionException;
 
 /**
  * Class that answers queries about the state of network connectivity. It also
@@ -1813,23 +1815,26 @@
         public static final int MIN_INTERVAL = 10;
 
         private final Network mNetwork;
-        private final PacketKeepaliveCallback mCallback;
-        private final Looper mLooper;
-        private final Messenger mMessenger;
+        private final ISocketKeepaliveCallback mCallback;
+        private final ExecutorService mExecutor;
 
         private volatile Integer mSlot;
 
-        void stopLooper() {
-            mLooper.quit();
-        }
-
         @UnsupportedAppUsage
         public void stop() {
             try {
-                mService.stopKeepalive(mNetwork, mSlot);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error stopping packet keepalive: ", e);
-                stopLooper();
+                mExecutor.execute(() -> {
+                    try {
+                        if (mSlot != null) {
+                            mService.stopKeepalive(mNetwork, mSlot);
+                        }
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Error stopping packet keepalive: ", e);
+                        throw e.rethrowFromSystemServer();
+                    }
+                });
+            } catch (RejectedExecutionException e) {
+                // The internal executor has already stopped due to previous event.
             }
         }
 
@@ -1837,40 +1842,43 @@
             Preconditions.checkNotNull(network, "network cannot be null");
             Preconditions.checkNotNull(callback, "callback cannot be null");
             mNetwork = network;
-            mCallback = callback;
-            HandlerThread thread = new HandlerThread(TAG);
-            thread.start();
-            mLooper = thread.getLooper();
-            mMessenger = new Messenger(new Handler(mLooper) {
+            mExecutor = Executors.newSingleThreadExecutor();
+            mCallback = new ISocketKeepaliveCallback.Stub() {
                 @Override
-                public void handleMessage(Message message) {
-                    switch (message.what) {
-                        case NetworkAgent.EVENT_SOCKET_KEEPALIVE:
-                            int error = message.arg2;
-                            try {
-                                if (error == SUCCESS) {
-                                    if (mSlot == null) {
-                                        mSlot = message.arg1;
-                                        mCallback.onStarted();
-                                    } else {
-                                        mSlot = null;
-                                        stopLooper();
-                                        mCallback.onStopped();
-                                    }
-                                } else {
-                                    stopLooper();
-                                    mCallback.onError(error);
-                                }
-                            } catch (Exception e) {
-                                Log.e(TAG, "Exception in keepalive callback(" + error + ")", e);
-                            }
-                            break;
-                        default:
-                            Log.e(TAG, "Unhandled message " + Integer.toHexString(message.what));
-                            break;
-                    }
+                public void onStarted(int slot) {
+                    Binder.withCleanCallingIdentity(() ->
+                            mExecutor.execute(() -> {
+                                mSlot = slot;
+                                callback.onStarted();
+                            }));
                 }
-            });
+
+                @Override
+                public void onStopped() {
+                    Binder.withCleanCallingIdentity(() ->
+                            mExecutor.execute(() -> {
+                                mSlot = null;
+                                callback.onStopped();
+                            }));
+                    mExecutor.shutdown();
+                }
+
+                @Override
+                public void onError(int error) {
+                    Binder.withCleanCallingIdentity(() ->
+                            mExecutor.execute(() -> {
+                                mSlot = null;
+                                callback.onError(error);
+                            }));
+                    mExecutor.shutdown();
+                }
+
+                @Override
+                public void onDataReceived() {
+                    // PacketKeepalive is only used for Nat-T keepalive and as such does not invoke
+                    // this callback when data is received.
+                }
+            };
         }
     }
 
@@ -1887,12 +1895,11 @@
             InetAddress srcAddr, int srcPort, InetAddress dstAddr) {
         final PacketKeepalive k = new PacketKeepalive(network, callback);
         try {
-            mService.startNattKeepalive(network, intervalSeconds, k.mMessenger, new Binder(),
+            mService.startNattKeepalive(network, intervalSeconds, k.mCallback,
                     srcAddr.getHostAddress(), srcPort, dstAddr.getHostAddress());
         } catch (RemoteException e) {
             Log.e(TAG, "Error starting packet keepalive: ", e);
-            k.stopLooper();
-            return null;
+            throw e.rethrowFromSystemServer();
         }
         return k;
     }
@@ -2805,7 +2812,7 @@
          *         {@link #TETHER_ERROR_PROVISION_FAILED}, or
          *         {@link #TETHER_ERROR_ENTITLEMENT_UNKONWN}.
          */
-        void onEntitlementResult(@EntitlementResultCode int resultCode);
+        void onTetheringEntitlementResult(@EntitlementResultCode int resultCode);
     }
 
     /**
@@ -2855,7 +2862,7 @@
             protected void onReceiveResult(int resultCode, Bundle resultData) {
                 Binder.withCleanCallingIdentity(() ->
                             executor.execute(() -> {
-                                listener.onEntitlementResult(resultCode);
+                                listener.onTetheringEntitlementResult(resultCode);
                             }));
             }
         };
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 403b44d..24e6a85 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -27,6 +27,7 @@
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkRequest;
 import android.net.NetworkState;
+import android.net.ISocketKeepaliveCallback;
 import android.net.ProxyInfo;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -194,15 +195,15 @@
 
     void factoryReset();
 
-    void startNattKeepalive(in Network network, int intervalSeconds, in Messenger messenger,
-            in IBinder binder, String srcAddr, int srcPort, String dstAddr);
+    void startNattKeepalive(in Network network, int intervalSeconds,
+            in ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr);
 
     void startNattKeepaliveWithFd(in Network network, in FileDescriptor fd, int resourceId,
-            int intervalSeconds, in Messenger messenger, in IBinder binder, String srcAddr,
+            int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr,
             String dstAddr);
 
     void startTcpKeepalive(in Network network, in FileDescriptor fd, int intervalSeconds,
-            in Messenger messenger, in IBinder binder);
+            in ISocketKeepaliveCallback cb);
 
     void stopKeepalive(in Network network, int slot);
 
@@ -219,4 +220,6 @@
 
     void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);
     void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);
+
+    IBinder startOrGetTestNetworkService();
 }
diff --git a/core/java/android/net/ISocketKeepaliveCallback.aidl b/core/java/android/net/ISocketKeepaliveCallback.aidl
new file mode 100644
index 0000000..020fbca
--- /dev/null
+++ b/core/java/android/net/ISocketKeepaliveCallback.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2019, 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.net;
+
+/**
+ * Callback to provide status changes of keepalive offload.
+ *
+ * @hide
+ */
+oneway interface ISocketKeepaliveCallback
+{
+    /** The keepalive was successfully started. */
+    void onStarted(int slot);
+    /** The keepalive was successfully stopped. */
+    void onStopped();
+    /** The keepalive was stopped because of an error. */
+    void onError(int error);
+    /** The keepalive on a TCP socket was stopped because the socket received data. */
+    void onDataReceived();
+}
diff --git a/core/java/android/net/NattSocketKeepalive.java b/core/java/android/net/NattSocketKeepalive.java
index 88631ae..84da294 100644
--- a/core/java/android/net/NattSocketKeepalive.java
+++ b/core/java/android/net/NattSocketKeepalive.java
@@ -17,7 +17,6 @@
 package android.net;
 
 import android.annotation.NonNull;
-import android.os.Binder;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -52,24 +51,30 @@
 
     @Override
     void startImpl(int intervalSec) {
-        try {
-            mService.startNattKeepaliveWithFd(mNetwork, mFd, mResourceId, intervalSec, mMessenger,
-                    new Binder(), mSource.getHostAddress(), mDestination.getHostAddress());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error starting packet keepalive: ", e);
-            stopLooper();
-        }
+        mExecutor.execute(() -> {
+            try {
+                mService.startNattKeepaliveWithFd(mNetwork, mFd, mResourceId, intervalSec,
+                        mCallback,
+                        mSource.getHostAddress(), mDestination.getHostAddress());
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error starting socket keepalive: ", e);
+                throw e.rethrowFromSystemServer();
+            }
+        });
     }
 
     @Override
     void stopImpl() {
-        try {
-            if (mSlot != null) {
-                mService.stopKeepalive(mNetwork, mSlot);
+        mExecutor.execute(() -> {
+            try {
+                if (mSlot != null) {
+                    mService.stopKeepalive(mNetwork, mSlot);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error stopping socket keepalive: ", e);
+                throw e.rethrowFromSystemServer();
             }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error stopping packet keepalive: ", e);
-            stopLooper();
-        }
+        });
+
     }
 }
diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java
index 07728be..0e768df 100644
--- a/core/java/android/net/SocketKeepalive.java
+++ b/core/java/android/net/SocketKeepalive.java
@@ -20,13 +20,8 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.Process;
-import android.util.Log;
+import android.os.Binder;
+import android.os.RemoteException;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -152,10 +147,9 @@
 
     @NonNull final IConnectivityManager mService;
     @NonNull final Network mNetwork;
-    @NonNull private final Executor mExecutor;
-    @NonNull private final SocketKeepalive.Callback mCallback;
-    @NonNull private final Looper mLooper;
-    @NonNull final Messenger mMessenger;
+    @NonNull final Executor mExecutor;
+    @NonNull final ISocketKeepaliveCallback mCallback;
+    // TODO: remove slot since mCallback could be used to identify which keepalive to stop.
     @Nullable Integer mSlot;
 
     SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network,
@@ -163,53 +157,53 @@
         mService = service;
         mNetwork = network;
         mExecutor = executor;
-        mCallback = callback;
-        // TODO: 1. Use other thread modeling instead of create one thread for every instance to
-        //          reduce the memory cost.
-        //       2. support restart.
-        //       3. Fix race condition which caused by rapidly start and stop.
-        HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND
-                + Process.THREAD_PRIORITY_LESS_FAVORABLE);
-        thread.start();
-        mLooper = thread.getLooper();
-        mMessenger = new Messenger(new Handler(mLooper) {
+        mCallback = new ISocketKeepaliveCallback.Stub() {
             @Override
-            public void handleMessage(Message message) {
-                switch (message.what) {
-                    case NetworkAgent.EVENT_SOCKET_KEEPALIVE:
-                        final int status = message.arg2;
-                        try {
-                            if (status == SUCCESS) {
-                                if (mSlot == null) {
-                                    mSlot = message.arg1;
-                                    mExecutor.execute(() -> mCallback.onStarted());
-                                } else {
-                                    mSlot = null;
-                                    stopLooper();
-                                    mExecutor.execute(() -> mCallback.onStopped());
-                                }
-                            } else if (status == DATA_RECEIVED) {
-                                stopLooper();
-                                mExecutor.execute(() -> mCallback.onDataReceived());
-                            } else {
-                                stopLooper();
-                                mExecutor.execute(() -> mCallback.onError(status));
-                            }
-                        } catch (Exception e) {
-                            Log.e(TAG, "Exception in keepalive callback(" + status + ")", e);
-                        }
-                        break;
-                    default:
-                        Log.e(TAG, "Unhandled message " + Integer.toHexString(message.what));
-                        break;
-                }
+            public void onStarted(int slot) {
+                Binder.withCleanCallingIdentity(() ->
+                        mExecutor.execute(() -> {
+                            mSlot = slot;
+                            callback.onStarted();
+                        }));
             }
-        });
+
+            @Override
+            public void onStopped() {
+                Binder.withCleanCallingIdentity(() ->
+                        executor.execute(() -> {
+                            mSlot = null;
+                            callback.onStopped();
+                        }));
+            }
+
+            @Override
+            public void onError(int error) {
+                Binder.withCleanCallingIdentity(() ->
+                        executor.execute(() -> {
+                            mSlot = null;
+                            callback.onError(error);
+                        }));
+            }
+
+            @Override
+            public void onDataReceived() {
+                Binder.withCleanCallingIdentity(() ->
+                        executor.execute(() -> {
+                            mSlot = null;
+                            callback.onDataReceived();
+                        }));
+            }
+        };
     }
 
     /**
      * Request that keepalive be started with the given {@code intervalSec}. See
-     * {@link SocketKeepalive}.
+     * {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an exception
+     * when invoking start or stop of the {@link SocketKeepalive}, a {@link RemoteException} will be
+     * thrown into the {@code executor}. This is typically not important to catch because the remote
+     * party is the system, so if it is not in shape to communicate through binder the system is
+     * probably going down anyway. If the caller cares regardless, it can use a custom
+     * {@link Executor} to catch the {@link RemoteException}.
      *
      * @param intervalSec The target interval in seconds between keepalive packet transmissions.
      *                    The interval should be between 10 seconds and 3600 seconds, otherwise
@@ -222,12 +216,6 @@
 
     abstract void startImpl(int intervalSec);
 
-    /** @hide */
-    protected void stopLooper() {
-        // TODO: remove this after changing thread modeling.
-        mLooper.quit();
-    }
-
     /**
      * Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
      * before using the object. See {@link SocketKeepalive}.
@@ -245,7 +233,6 @@
     @Override
     public final void close() {
         stop();
-        stopLooper();
     }
 
     /**
@@ -259,7 +246,8 @@
         public void onStopped() {}
         /** An error occurred. */
         public void onError(@ErrorCode int error) {}
-        /** The keepalive on a TCP socket was stopped because the socket received data. */
+        /** The keepalive on a TCP socket was stopped because the socket received data. This is
+         * never called for UDP sockets. */
         public void onDataReceived() {}
     }
 }
diff --git a/core/java/android/net/TcpSocketKeepalive.java b/core/java/android/net/TcpSocketKeepalive.java
index f691a0d..26cc8ff 100644
--- a/core/java/android/net/TcpSocketKeepalive.java
+++ b/core/java/android/net/TcpSocketKeepalive.java
@@ -17,7 +17,6 @@
 package android.net;
 
 import android.annotation.NonNull;
-import android.os.Binder;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -56,24 +55,28 @@
      */
     @Override
     void startImpl(int intervalSec) {
-        try {
-            final FileDescriptor fd = mSocket.getFileDescriptor$();
-            mService.startTcpKeepalive(mNetwork, fd, intervalSec, mMessenger, new Binder());
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error starting packet keepalive: ", e);
-            stopLooper();
-        }
+        mExecutor.execute(() -> {
+            try {
+                final FileDescriptor fd = mSocket.getFileDescriptor$();
+                mService.startTcpKeepalive(mNetwork, fd, intervalSec, mCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error starting packet keepalive: ", e);
+                throw e.rethrowFromSystemServer();
+            }
+        });
     }
 
     @Override
     void stopImpl() {
-        try {
-            if (mSlot != null) {
-                mService.stopKeepalive(mNetwork, mSlot);
+        mExecutor.execute(() -> {
+            try {
+                if (mSlot != null) {
+                    mService.stopKeepalive(mNetwork, mSlot);
+                }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error stopping packet keepalive: ", e);
+                throw e.rethrowFromSystemServer();
             }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error stopping packet keepalive: ", e);
-            stopLooper();
-        }
+        });
     }
 }
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 672624c..f87abde 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -28,6 +28,8 @@
 
 import com.android.internal.util.Preconditions;
 
+import libcore.io.IoUtils;
+
 import java.io.FileDescriptor;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -124,6 +126,8 @@
      * <p>The bugreport artifacts will be copied over to the given file descriptors only if the
      * user consents to sharing with the calling app.
      *
+     * <p>{@link BugreportManager} takes ownership of {@code bugreportFd} and {@code screenshotFd}.
+     *
      * @param bugreportFd file to write the bugreport. This should be opened in write-only,
      *     append mode.
      * @param screenshotFd file to write the screenshot, if necessary. This should be opened
@@ -137,12 +141,13 @@
             @NonNull BugreportParams params,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull BugreportCallback callback) {
-        Preconditions.checkNotNull(bugreportFd);
-        Preconditions.checkNotNull(params);
-        Preconditions.checkNotNull(executor);
-        Preconditions.checkNotNull(callback);
-        DumpstateListener dsListener = new DumpstateListener(executor, callback);
         try {
+            Preconditions.checkNotNull(bugreportFd);
+            Preconditions.checkNotNull(params);
+            Preconditions.checkNotNull(executor);
+            Preconditions.checkNotNull(callback);
+
+            DumpstateListener dsListener = new DumpstateListener(executor, callback);
             // Note: mBinder can get callingUid from the binder transaction.
             mBinder.startBugreport(-1 /* callingUid */,
                     mContext.getOpPackageName(),
@@ -152,6 +157,12 @@
                     params.getMode(), dsListener);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
+        } finally {
+            // We can close the file descriptors here because binder would have duped them.
+            IoUtils.closeQuietly(bugreportFd);
+            if (screenshotFd != null) {
+                IoUtils.closeQuietly(screenshotFd);
+            }
         }
     }
 
@@ -171,7 +182,7 @@
         private final Executor mExecutor;
         private final BugreportCallback mCallback;
 
-        DumpstateListener(Executor executor, @Nullable BugreportCallback callback) {
+        DumpstateListener(Executor executor, BugreportCallback callback) {
             mExecutor = executor;
             mCallback = callback;
         }
@@ -209,8 +220,6 @@
                 });
             } finally {
                 Binder.restoreCallingIdentity(identity);
-                // The bugreport has finished. Let's shutdown the service to minimize its footprint.
-                cancelBugreport();
             }
         }
 
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 483c41a..a0d88ee 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -48,7 +48,7 @@
     boolean isInteractive();
     boolean isPowerSaveMode();
     PowerSaveState getPowerSaveState(int serviceType);
-    boolean setPowerSaveMode(boolean mode);
+    boolean setPowerSaveModeEnabled(boolean mode);
     boolean setDynamicPowerSavings(boolean dynamicPowerSavingsEnabled, int disableThreshold);
     boolean setAdaptivePowerSavePolicy(in BatterySaverPolicyConfig config);
     boolean setAdaptivePowerSaveEnabled(boolean enabled);
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 7a8727c..ed1d8a5 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -372,7 +372,11 @@
     /**
      * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
      * The returned ParcelFileDescriptor now owns the given fd, and will be
-     * responsible for closing it.  You must not close the fd yourself.
+     * responsible for closing it.
+     * <p>
+     * <strong>WARNING:</strong> You must not close the fd yourself after
+     * this call, and ownership of the file descriptor must have been
+     * released prior to the call to this function.
      *
      * @param fd The native fd that the ParcelFileDescriptor should adopt.
      *
@@ -391,6 +395,16 @@
      * ParcelFileDescriptor holds a dup of the original FileDescriptor in
      * the Socket, so you must still close the Socket as well as the new
      * ParcelFileDescriptor.
+     * <p>
+     * <strong>WARNING:</strong> Prior to API level 29, this function would not
+     * actually dup the Socket's FileDescriptor, and would take a
+     * reference to the its internal FileDescriptor instead. If the Socket
+     * gets garbage collected before the ParcelFileDescriptor, this may
+     * lead to the ParcelFileDescriptor being unexpectedly closed. To avoid
+     * this, the following pattern can be used:
+     * <pre>{@code
+     *    ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket).dup();
+     * }</pre>
      *
      * @param socket The Socket whose FileDescriptor is used to create
      *               a new ParcelFileDescriptor.
@@ -414,6 +428,16 @@
      * new ParcelFileDescriptor holds a dup of the original FileDescriptor in
      * the DatagramSocket, so you must still close the DatagramSocket as well
      * as the new ParcelFileDescriptor.
+     * <p>
+     * <strong>WARNING:</strong> Prior to API level 29, this function would not
+     * actually dup the DatagramSocket's FileDescriptor, and would take a
+     * reference to the its internal FileDescriptor instead. If the DatagramSocket
+     * gets garbage collected before the ParcelFileDescriptor, this may
+     * lead to the ParcelFileDescriptor being unexpectedly closed. To avoid
+     * this, the following pattern can be used:
+     * <pre>{@code
+     *    ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket).dup();
+     * }</pre>
      *
      * @param datagramSocket The DatagramSocket whose FileDescriptor is used
      *               to create a new ParcelFileDescriptor.
@@ -651,6 +675,9 @@
      * Return the native fd int for this ParcelFileDescriptor.  The
      * ParcelFileDescriptor still owns the fd, and it still must be closed
      * through this API.
+     * <p>
+     * <strong>WARNING:</strong> Do not call close on the return value of this
+     * function or pass it to a function that assumes ownership of the fd.
      */
     public int getFd() {
         if (mWrapped != null) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 728b215..fdc5157 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1419,9 +1419,9 @@
             android.Manifest.permission.DEVICE_POWER,
             android.Manifest.permission.POWER_SAVER
     })
-    public boolean setPowerSaveMode(boolean mode) {
+    public boolean setPowerSaveModeEnabled(boolean mode) {
         try {
-            return mService.setPowerSaveMode(mode);
+            return mService.setPowerSaveModeEnabled(mode);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index ff551d4..6f0a1f2 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -21,12 +21,12 @@
 import android.content.pm.ApplicationInfo;
 import android.net.LocalSocket;
 import android.net.LocalSocketAddress;
-import android.provider.DeviceConfig;
 import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.Zygote;
+import com.android.internal.os.ZygoteConfig;
 
 import java.io.BufferedWriter;
 import java.io.DataInputStream;
@@ -147,7 +147,7 @@
         final DataInputStream mZygoteInputStream;
         final BufferedWriter mZygoteOutputWriter;
 
-        private final List<String> mABIList;
+        private final List<String> mAbiList;
 
         private boolean mClosed;
 
@@ -162,7 +162,7 @@
             this.mZygoteSessionSocket = zygoteSessionSocket;
             this.mZygoteInputStream = zygoteInputStream;
             this.mZygoteOutputWriter = zygoteOutputWriter;
-            this.mABIList = abiList;
+            this.mAbiList = abiList;
         }
 
         /**
@@ -215,7 +215,7 @@
         }
 
         boolean matches(String abi) {
-            return mABIList.contains(abi);
+            return mAbiList.contains(abi);
         }
 
         public void close() {
@@ -338,7 +338,7 @@
         try {
             return startViaZygote(processClass, niceName, uid, gid, gids,
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
-                    abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/false,
+                    abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
                     packageName, packagesForUid, sandboxId,
                     useUsapPool, zygoteArgs);
         } catch (ZygoteStartFailedEx ex) {
@@ -374,7 +374,7 @@
         byte[] bytes = new byte[numBytes];
         inputStream.readFully(bytes);
 
-        String rawList = new String(bytes, StandardCharsets.US_ASCII);
+        final String rawList = new String(bytes, StandardCharsets.US_ASCII);
 
         return Arrays.asList(rawList.split(","));
     }
@@ -659,16 +659,13 @@
     private boolean fetchUsapPoolEnabledProp() {
         boolean origVal = mUsapPoolEnabled;
 
-        final String propertyString =
-                Zygote.getSystemProperty(
-                        DeviceConfig.RuntimeNative.USAP_POOL_ENABLED,
-                        USAP_POOL_ENABLED_DEFAULT);
+        final String propertyString = Zygote.getConfigurationProperty(
+                ZygoteConfig.USAP_POOL_ENABLED, USAP_POOL_ENABLED_DEFAULT);
 
         if (!propertyString.isEmpty()) {
-            mUsapPoolEnabled =
-                    Zygote.getSystemPropertyBoolean(
-                            DeviceConfig.RuntimeNative.USAP_POOL_ENABLED,
-                            Boolean.parseBoolean(USAP_POOL_ENABLED_DEFAULT));
+            mUsapPoolEnabled = Zygote.getConfigurationPropertyBoolean(
+                    ZygoteConfig.USAP_POOL_ENABLED,
+                    Boolean.parseBoolean(USAP_POOL_ENABLED_DEFAULT));
         }
 
         if (origVal != mUsapPoolEnabled) {
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index f114b12..25f67f8 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -191,4 +191,6 @@
     String translateAppToSystem(String path, int pid, int uid) = 81;
     String translateSystemToApp(String path, int pid, int uid) = 82;
     void commitChanges() = 83;
+    boolean supportsCheckpoint() = 84;
+    void startCheckpoint(int numTries) = 85;
 }
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index e6564664..32511e9 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -19,6 +19,7 @@
 
 import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
+import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.UnsupportedAppUsage;
 import android.app.AlertDialog;
@@ -354,6 +355,7 @@
      * @return the DecorView for the current dialog window, if it exists.
      * If the window does not exist, null is returned.
      */
+    @Nullable
     private View getDecorView() {
         if (mDialog != null && mDialog.getWindow() != null) {
             return mDialog.getWindow().getDecorView();
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 17fc108..6d32f8c 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -31,6 +31,7 @@
 import android.net.Uri;
 import android.provider.Settings.ResetMode;
 import android.util.ArrayMap;
+import android.util.Log;
 import android.util.Pair;
 
 import com.android.internal.annotations.GuardedBy;
@@ -77,6 +78,14 @@
             "activity_manager_native_boot";
 
     /**
+     * Namespace for AttentionManagerService related features.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
+
+    /**
      * Namespace for autofill feature that provides suggestions across all apps when
      * the user interacts with input fields.
      *
@@ -130,6 +139,14 @@
     public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
 
     /**
+     * Namespace for attention-based features provided by on-device machine intelligence.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
+
+    /**
      * Namespace for all media native related features.
      *
      * @hide
@@ -146,6 +163,25 @@
     public static final String NAMESPACE_NETD_NATIVE = "netd_native";
 
     /**
+     * Namespace for all runtime related features that don't require a reboot to become active.
+     * There are no feature flags using NAMESPACE_RUNTIME.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_RUNTIME = "runtime";
+
+    /**
+     * Namespace for all runtime related features that require system properties for accessing
+     * the feature flags from C++ or Java language code. One example is the app image startup
+     * cache feature use_app_image_startup_cache.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
+
+    /**
      * Namespace for all runtime native boot related features. Boot in this case refers to the
      * fact that the properties only take affect after rebooting the device.
      *
@@ -171,79 +207,6 @@
     public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
 
     /**
-     * Namespace for all runtime related features.
-     *
-     * @hide
-     */
-    @SystemApi
-    public interface Runtime {
-        String NAMESPACE = "runtime";
-
-        /**
-         * Whether or not we use the precompiled layout.
-         */
-        String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled";
-    }
-
-    /**
-     * Namespace for all runtime native related features.
-     *
-     * @hide
-     */
-    @SystemApi
-    public interface RuntimeNative {
-        String NAMESPACE = "runtime_native";
-
-        /**
-         * Zygote flags. See {@link com.internal.os.Zygote}.
-         */
-
-        /**
-         * If {@code true}, enables the unspecialized app process (USAP) pool feature.
-         *
-         * @hide for internal use only
-         */
-        String USAP_POOL_ENABLED = "usap_pool_enabled";
-
-        /**
-         * The maximum number of processes to keep in the USAP pool.
-         *
-         * @hide for internal use only
-         */
-        String USAP_POOL_SIZE_MAX = "usap_pool_size_max";
-
-        /**
-         * The minimum number of processes to keep in the USAP pool.
-         *
-         * @hide for internal use only
-         */
-        String USAP_POOL_SIZE_MIN = "usap_pool_size_min";
-
-        /**
-         * The threshold used to determine if the pool should be refilled.
-         *
-         * @hide for internal use only
-         */
-        String USAP_POOL_REFILL_THRESHOLD = "usap_refill_threshold";
-    }
-
-    /**
-     * Namespace for attention-based features provided by on-device machine intelligence.
-     *
-     * @hide
-     */
-    @SystemApi
-    public interface IntelligenceAttention {
-        String NAMESPACE = "intelligence_attention";
-
-        /** If {@code true}, enables the attention features. */
-        String ATTENTION_ENABLED = "attention_enabled";
-
-        /** Settings for the attention features. */
-        String ATTENTION_SETTINGS = "attention_settings";
-    }
-
-    /**
      * Privacy related properties definitions.
      *
      * @hide
@@ -298,22 +261,6 @@
     }
 
     /**
-     * Namespace for {@link AttentionManagerService} related features.
-     *
-     * @hide
-     */
-    @SystemApi
-    public interface AttentionManagerService {
-        String NAMESPACE = "attention_manager_service";
-
-        /** If {@code true}, enables {@link AttentionManagerService} features. */
-        String SERVICE_ENABLED = "service_enabled";
-
-        /** Allows a CTS to inject a fake implementation. */
-        String COMPONENT_NAME = "component_name";
-    }
-
-    /**
      * Namespace for Rollback.
      *
      * @hide
@@ -402,6 +349,7 @@
             new ArrayMap<>();
     @GuardedBy("sLock")
     private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>();
+    private static final String TAG = "DeviceConfig";
 
     // Should never be invoked
     private DeviceConfig() {
@@ -418,7 +366,7 @@
     @SystemApi
     @TestApi
     @RequiresPermission(READ_DEVICE_CONFIG)
-    public static String getProperty(String namespace, String name) {
+    public static String getProperty(@NonNull String namespace, @NonNull String name) {
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
         String compositeName = createCompositeName(namespace, name);
         return Settings.Config.getString(contentResolver, compositeName);
@@ -437,7 +385,8 @@
     @SystemApi
     @TestApi
     @RequiresPermission(READ_DEVICE_CONFIG)
-    public static String getString(String namespace, String name, String defaultValue) {
+    public static String getString(@NonNull String namespace, @NonNull String name,
+            @Nullable String defaultValue) {
         String value = getProperty(namespace, name);
         return value != null ? value : defaultValue;
     }
@@ -455,7 +404,8 @@
     @SystemApi
     @TestApi
     @RequiresPermission(READ_DEVICE_CONFIG)
-    public static boolean getBoolean(String namespace, String name, boolean defaultValue) {
+    public static boolean getBoolean(@NonNull String namespace, @NonNull String name,
+            boolean defaultValue) {
         String value = getProperty(namespace, name);
         return value != null ? Boolean.parseBoolean(value) : defaultValue;
     }
@@ -473,11 +423,15 @@
     @SystemApi
     @TestApi
     @RequiresPermission(READ_DEVICE_CONFIG)
-    public static int getInt(String namespace, String name, int defaultValue) {
+    public static int getInt(@NonNull String namespace, @NonNull String name, int defaultValue) {
         String value = getProperty(namespace, name);
+        if (value == null) {
+            return defaultValue;
+        }
         try {
             return Integer.parseInt(value);
         } catch (NumberFormatException e) {
+            Log.e(TAG, "Parsing integer failed for " + namespace + ":" + name);
             return defaultValue;
         }
     }
@@ -495,11 +449,15 @@
     @SystemApi
     @TestApi
     @RequiresPermission(READ_DEVICE_CONFIG)
-    public static long getLong(String namespace, String name, long defaultValue) {
+    public static long getLong(@NonNull String namespace, @NonNull String name, long defaultValue) {
         String value = getProperty(namespace, name);
+        if (value == null) {
+            return defaultValue;
+        }
         try {
             return Long.parseLong(value);
         } catch (NumberFormatException e) {
+            Log.e(TAG, "Parsing long failed for " + namespace + ":" + name);
             return defaultValue;
         }
     }
@@ -517,13 +475,16 @@
     @SystemApi
     @TestApi
     @RequiresPermission(READ_DEVICE_CONFIG)
-    public static float getFloat(String namespace, String name, float defaultValue) {
+    public static float getFloat(@NonNull String namespace, @NonNull String name,
+            float defaultValue) {
         String value = getProperty(namespace, name);
+        if (value == null) {
+            return defaultValue;
+        }
         try {
             return Float.parseFloat(value);
         } catch (NumberFormatException e) {
-            return defaultValue;
-        } catch (NullPointerException e) {
+            Log.e(TAG, "Parsing float failed for " + namespace + ":" + name);
             return defaultValue;
         }
     }
@@ -550,10 +511,10 @@
     @SystemApi
     @TestApi
     @RequiresPermission(WRITE_DEVICE_CONFIG)
-    public static boolean setProperty(
-            String namespace, String name, String value, boolean makeDefault) {
-        ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
+    public static boolean setProperty(@NonNull String namespace, @NonNull String name,
+            @Nullable String value, boolean makeDefault) {
         String compositeName = createCompositeName(namespace, name);
+        ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
         return Settings.Config.putString(contentResolver, compositeName, value, makeDefault);
     }
 
@@ -696,11 +657,14 @@
         }
     }
 
-    private static String createCompositeName(String namespace, String name) {
+    private static String createCompositeName(@NonNull String namespace, @NonNull String name) {
+        Preconditions.checkNotNull(namespace);
+        Preconditions.checkNotNull(name);
         return namespace + "/" + name;
     }
 
-    private static Uri createNamespaceUri(String namespace) {
+    private static Uri createNamespaceUri(@NonNull String namespace) {
+        Preconditions.checkNotNull(namespace);
         return CONTENT_URI.buildUpon().appendPath(namespace).build();
     }
 
@@ -712,7 +676,8 @@
      * @param namespace The namespace to increment the count for.
      */
     @GuardedBy("sLock")
-    private static void incrementNamespace(String namespace) {
+    private static void incrementNamespace(@NonNull String namespace) {
+        Preconditions.checkNotNull(namespace);
         Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace);
         if (namespaceCount != null) {
             sNamespaces.put(namespace, new Pair<>(namespaceCount.first, namespaceCount.second + 1));
@@ -721,7 +686,9 @@
             ContentObserver contentObserver = new ContentObserver(null) {
                 @Override
                 public void onChange(boolean selfChange, Uri uri) {
-                    handleChange(uri);
+                    if (uri != null) {
+                        handleChange(uri);
+                    }
                 }
             };
             ActivityThread.currentApplication().getContentResolver()
@@ -738,7 +705,8 @@
      * @param namespace The namespace to decrement the count for.
      */
     @GuardedBy("sLock")
-    private static void decrementNamespace(String namespace) {
+    private static void decrementNamespace(@NonNull String namespace) {
+        Preconditions.checkNotNull(namespace);
         Pair<ContentObserver, Integer> namespaceCount = sNamespaces.get(namespace);
         if (namespaceCount == null) {
             // This namespace is not registered and does not need to be decremented
@@ -753,7 +721,8 @@
         }
     }
 
-    private static void handleChange(Uri uri) {
+    private static void handleChange(@NonNull Uri uri) {
+        Preconditions.checkNotNull(uri);
         List<String> pathSegments = uri.getPathSegments();
         // pathSegments(0) is "config"
         final String namespace = pathSegments.get(1);
@@ -809,7 +778,8 @@
          * @param name      The name of the property which has changed.
          * @param value     The new value of the property which has changed.
          */
-        void onPropertyChanged(String namespace, String name, String value);
+        void onPropertyChanged(@NonNull String namespace, @NonNull String name,
+                @Nullable String value);
     }
 
     /**
@@ -911,9 +881,13 @@
         public int getInt(@NonNull String name, int defaultValue) {
             Preconditions.checkNotNull(name);
             String value = mMap.get(name);
+            if (value == null) {
+                return defaultValue;
+            }
             try {
                 return Integer.parseInt(value);
             } catch (NumberFormatException e) {
+                Log.e(TAG, "Parsing int failed for " + name);
                 return defaultValue;
             }
         }
@@ -929,9 +903,13 @@
         public long getLong(@NonNull String name, long defaultValue) {
             Preconditions.checkNotNull(name);
             String value = mMap.get(name);
+            if (value == null) {
+                return defaultValue;
+            }
             try {
                 return Long.parseLong(value);
             } catch (NumberFormatException e) {
+                Log.e(TAG, "Parsing long failed for " + name);
                 return defaultValue;
             }
         }
@@ -947,11 +925,13 @@
         public float getFloat(@NonNull String name, float defaultValue) {
             Preconditions.checkNotNull(name);
             String value = mMap.get(name);
+            if (value == null) {
+                return defaultValue;
+            }
             try {
                 return Float.parseFloat(value);
             } catch (NumberFormatException e) {
-                return defaultValue;
-            } catch (NullPointerException e) {
+                Log.e(TAG, "Parsing float failed for " + name);
                 return defaultValue;
             }
         }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4836e6c..df5da6c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5590,6 +5590,15 @@
         private static final Validator ALLOW_MOCK_LOCATION_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * Setting to indicate that on device captions are enabled.
+         *
+         * @hide
+         */
+        public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled";
+
+        private static final Validator ODI_CAPTIONS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
          * On Android 8.0 (API level 26) and higher versions of the platform,
          * a 64-bit number (expressed as a hexadecimal string), unique to
          * each combination of app-signing key, user, and device.
@@ -6335,7 +6344,6 @@
          * Number of times the user has manually clicked the ringer toggle
          * @hide
          */
-        @SystemApi
         public static final String MANUAL_RINGER_TOGGLE_COUNT = "manual_ringer_toggle_count";
 
         private static final Validator MANUAL_RINGER_TOGGLE_COUNT_VALIDATOR =
@@ -8508,9 +8516,15 @@
         @SystemApi
         public static final String VOLUME_HUSH_GESTURE = "volume_hush_gesture";
 
-        /** @hide */ public static final int VOLUME_HUSH_OFF = 0;
-        /** @hide */ public static final int VOLUME_HUSH_VIBRATE = 1;
-        /** @hide */ public static final int VOLUME_HUSH_MUTE = 2;
+        /** @hide */
+        @SystemApi
+        public static final int VOLUME_HUSH_OFF = 0;
+        /** @hide */
+        @SystemApi
+        public static final int VOLUME_HUSH_VIBRATE = 1;
+        /** @hide */
+        @SystemApi
+        public static final int VOLUME_HUSH_MUTE = 2;
 
         private static final Validator VOLUME_HUSH_GESTURE_VALIDATOR =
                 NON_NEGATIVE_INTEGER_VALIDATOR;
@@ -8950,6 +8964,7 @@
             VALIDATORS.put(SILENCE_TIMER_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
             VALIDATORS.put(SILENCE_CALL_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
             VALIDATORS.put(SILENCE_NOTIFICATION_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
+            VALIDATORS.put(ODI_CAPTIONS_ENABLED, ODI_CAPTIONS_ENABLED_VALIDATOR);
         }
 
         /**
@@ -9038,27 +9053,12 @@
          * @return true if the provider is enabled
          *
          * @deprecated use {@link LocationManager#isProviderEnabled(String)}
+         * @removed no longer supported
          */
         @Deprecated
-        public static final boolean isLocationProviderEnabled(ContentResolver cr, String provider) {
-            return isLocationProviderEnabledForUser(cr, provider, cr.getUserId());
-        }
-
-        /**
-         * Helper method for determining if a location provider is enabled.
-         * @param cr the content resolver to use
-         * @param provider the location provider to query
-         * @param userId the userId to query
-         * @return true if the provider is enabled
-         *
-         * @deprecated use {@link LocationManager#isProviderEnabled(String)}
-         * @hide
-         */
-        @Deprecated
-        public static final boolean isLocationProviderEnabledForUser(
-                ContentResolver cr, String provider, int userId) {
+        public static boolean isLocationProviderEnabled(ContentResolver cr, String provider) {
             String allowedProviders = Settings.Secure.getStringForUser(cr,
-                    LOCATION_PROVIDERS_ALLOWED, userId);
+                    LOCATION_PROVIDERS_ALLOWED, cr.getUserId());
             return TextUtils.delimitedStringContains(allowedProviders, ',', provider);
         }
 
@@ -9067,42 +9067,12 @@
          * @param cr the content resolver to use
          * @param provider the location provider to enable or disable
          * @param enabled true if the provider should be enabled
-         * @deprecated This API is deprecated. It requires WRITE_SECURE_SETTINGS permission to
-         *             change location settings.
+         * @deprecated This API is deprecated
+         * @removed no longer supported
          */
         @Deprecated
-        public static final void setLocationProviderEnabled(ContentResolver cr,
+        public static void setLocationProviderEnabled(ContentResolver cr,
                 String provider, boolean enabled) {
-            setLocationProviderEnabledForUser(cr, provider, enabled, cr.getUserId());
-        }
-
-        /**
-         * Thread-safe method for enabling or disabling a single location provider.
-         *
-         * @param cr the content resolver to use
-         * @param provider the location provider to enable or disable
-         * @param enabled true if the provider should be enabled
-         * @param userId the userId for which to enable/disable providers
-         * @return true if the value was set, false on database errors
-         *
-         * @deprecated use {@link LocationManager#setProviderEnabledForUser(String, boolean, int)}
-         * @hide
-         */
-        @Deprecated
-        public static final boolean setLocationProviderEnabledForUser(ContentResolver cr,
-                String provider, boolean enabled, int userId) {
-            synchronized (mLocationSettingsLock) {
-                // to ensure thread safety, we write the provider name with a '+' or '-'
-                // and let the SettingsProvider handle it rather than reading and modifying
-                // the list of enabled providers.
-                if (enabled) {
-                    provider = "+" + provider;
-                } else {
-                    provider = "-" + provider;
-                }
-                return putStringForUser(cr, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, provider,
-                        userId);
-            }
         }
     }
 
@@ -11508,6 +11478,7 @@
          * service_min_restart_time_between     (long)
          * service_max_inactivity               (long)
          * service_bg_start_timeout             (long)
+         * service_bg_activity_start_timeout    (long)
          * process_start_async                  (boolean)
          * </pre>
          *
@@ -12007,6 +11978,8 @@
          * notification_conversation_action_types_default   (String[])
          * lang_id_threshold_override                       (float)
          * template_intent_factory_enabled                  (boolean)
+         * translate_in_classification_enabled              (boolean)
+         * detect_language_from_text_enabled                (boolean)
          * </pre>
          *
          * <p>
diff --git a/core/java/android/service/appprediction/AppPredictionService.java b/core/java/android/service/appprediction/AppPredictionService.java
index d012851..ff13e03 100644
--- a/core/java/android/service/appprediction/AppPredictionService.java
+++ b/core/java/android/service/appprediction/AppPredictionService.java
@@ -141,7 +141,8 @@
     }
 
     @Override
-    public final IBinder onBind(Intent intent) {
+    @NonNull
+    public final IBinder onBind(@NonNull Intent intent) {
         // TODO(b/111701043): Verify that the action is valid
         return mInterface.asBinder();
     }
diff --git a/core/java/android/service/attention/AttentionService.java b/core/java/android/service/attention/AttentionService.java
index 24d74ff..32f4ea9 100644
--- a/core/java/android/service/attention/AttentionService.java
+++ b/core/java/android/service/attention/AttentionService.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
@@ -111,8 +112,9 @@
         }
     };
 
+    @Nullable
     @Override
-    public final IBinder onBind(Intent intent) {
+    public final IBinder onBind(@NonNull Intent intent) {
         if (SERVICE_INTERFACE.equals(intent.getAction())) {
             return mBinder;
         }
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index cd54930..19e216a 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -405,7 +405,6 @@
         private void update(@NonNull AutofillId focusedId, @NonNull AutofillValue focusedValue,
                 @NonNull IFillCallback callback) {
             synchronized (mLock) {
-                // TODO(b/123099468): should we close the popupwindow if the focused id changed?
                 mFocusedId = focusedId;
                 mFocusedValue = focusedValue;
                 if (mCallback != null) {
diff --git a/core/java/android/service/contentcapture/ActivityEvent.java b/core/java/android/service/contentcapture/ActivityEvent.java
index 7ac380d..5407c1d 100644
--- a/core/java/android/service/contentcapture/ActivityEvent.java
+++ b/core/java/android/service/contentcapture/ActivityEvent.java
@@ -47,10 +47,16 @@
      */
     public static final int TYPE_ACTIVITY_PAUSED = Event.ACTIVITY_PAUSED;
 
+    /**
+     * The activity stopped.
+     */
+    public static final int TYPE_ACTIVITY_STOPPED = Event.ACTIVITY_STOPPED;
+
     /** @hide */
     @IntDef(prefix = { "TYPE_" }, value = {
             TYPE_ACTIVITY_RESUMED,
-            TYPE_ACTIVITY_PAUSED
+            TYPE_ACTIVITY_PAUSED,
+            TYPE_ACTIVITY_STOPPED
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ActivityEventType{}
@@ -89,6 +95,8 @@
                 return "ACTIVITY_RESUMED";
             case TYPE_ACTIVITY_PAUSED:
                 return "ACTIVITY_PAUSED";
+            case TYPE_ACTIVITY_STOPPED:
+                return "ACTIVITY_STOPPED";
             default:
                 return "UKNOWN_TYPE: " + type;
         }
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 192abd5..6f4114d 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -102,9 +102,10 @@
 
         @Override
         public void onSessionStarted(ContentCaptureContext context, String sessionId, int uid,
-                IResultReceiver clientReceiver) {
+                IResultReceiver clientReceiver, int initialState) {
             mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnCreateSession,
-                    ContentCaptureService.this, context, sessionId, uid, clientReceiver));
+                    ContentCaptureService.this, context, sessionId, uid, clientReceiver,
+                    initialState));
         }
 
         @Override
@@ -335,7 +336,7 @@
     // so we don't need to create a temporary InteractionSessionId for each event.
 
     private void handleOnCreateSession(@NonNull ContentCaptureContext context,
-            @NonNull String sessionId, int uid, IResultReceiver clientReceiver) {
+            @NonNull String sessionId, int uid, IResultReceiver clientReceiver, int initialState) {
         mSessionUids.put(sessionId, uid);
         onCreateContentCaptureSession(context, new ContentCaptureSessionId(sessionId));
 
@@ -348,7 +349,7 @@
             stateFlags |= ContentCaptureSession.STATE_BY_APP;
         }
         if (stateFlags == 0) {
-            stateFlags = ContentCaptureSession.STATE_ACTIVE;
+            stateFlags = initialState;
         } else {
             stateFlags |= ContentCaptureSession.STATE_DISABLED;
 
diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl
index f32432f..6be7a80 100644
--- a/core/java/android/service/contentcapture/IContentCaptureService.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl
@@ -36,7 +36,7 @@
     void onConnected(IBinder callback, boolean verbose, boolean debug);
     void onDisconnected();
     void onSessionStarted(in ContentCaptureContext context, String sessionId, int uid,
-                          in IResultReceiver clientReceiver);
+                          in IResultReceiver clientReceiver, int initialState);
     void onSessionFinished(String sessionId);
     void onActivitySnapshot(String sessionId, in SnapshotData snapshotData);
     void onUserDataRemovalRequest(in UserDataRemovalRequest request);
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index a46d047..2288106 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -113,15 +113,27 @@
     public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION =
             "android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
 
-    /** @see android.telephony.euicc.EuiccManager#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED */
+    /**
+     * @see android.telephony.euicc.EuiccManager#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED. This is
+     * a protected intent that can only be sent by the system, and requires the
+     * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission.
+     */
     public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED =
             "android.service.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED";
 
-    /** @see android.telephony.euicc.EuiccManager#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED */
+    /**
+     * @see android.telephony.euicc.EuiccManager#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED. This is
+     * a protected intent that can only be sent by the system, and requires the
+     * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission.
+     */
     public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED =
             "android.service.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED";
 
-    /** @see android.telephony.euicc.EuiccManager#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED */
+    /**
+     * @see android.telephony.euicc.EuiccManager#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED. This is
+     * a protected intent that can only be sent by the system, and requires the
+     * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission.
+     */
     public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED =
             "android.service.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED";
 
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index fb6dc22..bf0ef94 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -2192,26 +2192,26 @@
      */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     public static class TabStops {
-        private int[] mStops;
+        private float[] mStops;
         private int mNumStops;
-        private int mIncrement;
+        private float mIncrement;
 
-        public TabStops(int increment, Object[] spans) {
+        public TabStops(float increment, Object[] spans) {
             reset(increment, spans);
         }
 
-        void reset(int increment, Object[] spans) {
+        void reset(float increment, Object[] spans) {
             this.mIncrement = increment;
 
             int ns = 0;
             if (spans != null) {
-                int[] stops = this.mStops;
+                float[] stops = this.mStops;
                 for (Object o : spans) {
                     if (o instanceof TabStopSpan) {
                         if (stops == null) {
-                            stops = new int[10];
+                            stops = new float[10];
                         } else if (ns == stops.length) {
-                            int[] nstops = new int[ns * 2];
+                            float[] nstops = new float[ns * 2];
                             for (int i = 0; i < ns; ++i) {
                                 nstops[i] = stops[i];
                             }
@@ -2233,9 +2233,9 @@
         float nextTab(float h) {
             int ns = this.mNumStops;
             if (ns > 0) {
-                int[] stops = this.mStops;
+                float[] stops = this.mStops;
                 for (int i = 0; i < ns; ++i) {
-                    int stop = stops[i];
+                    float stop = stops[i];
                     if (stop > h) {
                         return stop;
                     }
@@ -2244,7 +2244,10 @@
             return nextDefaultStop(h, mIncrement);
         }
 
-        public static float nextDefaultStop(float h, int inc) {
+        /**
+         * Returns the position of next tab stop.
+         */
+        public static float nextDefaultStop(float h, float inc) {
             return ((int) ((h + inc) / inc)) * inc;
         }
     }
@@ -2582,7 +2585,7 @@
         ALIGN_RIGHT,
     }
 
-    private static final int TAB_INCREMENT = 20;
+    private static final float TAB_INCREMENT = 20;
 
     /** @hide */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 9fefc83..69cfc03 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -737,14 +737,14 @@
                 }
             }
             // tab stop locations
-            int[] variableTabStops = null;
+            float[] variableTabStops = null;
             if (spanned != null) {
                 TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
                         paraEnd, TabStopSpan.class);
                 if (spans.length > 0) {
-                    int[] stops = new int[spans.length];
+                    float[] stops = new float[spans.length];
                     for (int i = 0; i < spans.length; i++) {
-                        stops[i] = spans[i].getTabStop();
+                        stops[i] = (float) spans[i].getTabStop();
                     }
                     Arrays.sort(stops, 0, stops.length);
                     variableTabStops = stops;
@@ -1422,7 +1422,7 @@
     private static final int START_HYPHEN_MASK = 0x18; // 0b11000
     private static final int END_HYPHEN_MASK = 0x7;  // 0b00111
 
-    private static final int TAB_INCREMENT = 20; // same as Layout, but that's private
+    private static final float TAB_INCREMENT = 20; // same as Layout, but that's private
 
     private static final char CHAR_NEW_LINE = '\n';
 
diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java
index 13ac9ff..98f58be 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -46,10 +46,10 @@
  * <p>
  * For example, an <code>ImagedSpan</code> can be used like this:
  * <pre>
- * SpannableString string = SpannableString("Bottom: span.\nBaseline: span.");
+ * SpannableString string = new SpannableString("Bottom: span.\nBaseline: span.");
  * // using the default alignment: ALIGN_BOTTOM
- * string.setSpan(ImageSpan(this, R.mipmap.ic_launcher), 7, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- * string.setSpan(ImageSpan(this, R.mipmap.ic_launcher, DynamicDrawableSpan.ALIGN_BASELINE),
+ * string.setSpan(new ImageSpan(this, R.mipmap.ic_launcher), 7, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ * string.setSpan(new ImageSpan(this, R.mipmap.ic_launcher, DynamicDrawableSpan.ALIGN_BASELINE),
  * 22, 23, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  * </pre>
  * <img src="{@docRoot}reference/android/images/text/style/imagespan.png" />
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index aee1d6a..c1504ae 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -60,6 +60,7 @@
         DEFAULT_FLAGS.put(GLOBAL_ACTIONS_GRID_ENABLED, "true");
         DEFAULT_FLAGS.put(GLOBAL_ACTIONS_PANEL_ENABLED, "true");
         DEFAULT_FLAGS.put("settings_wifi_details_saved_screen", "false");
+        DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false");
     }
 
     /**
diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS
index 86ed122..98297fb 100644
--- a/core/java/android/util/OWNERS
+++ b/core/java/android/util/OWNERS
@@ -1,2 +1,3 @@
 per-file FeatureFlagUtils.java = sbasi@google.com
 per-file FeatureFlagUtils.java = zhfan@google.com
+per-file FeatureFlagUtils.java = asapperstein@google.com
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 2e27737..35cf129 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -83,6 +83,10 @@
     private static final boolean DEBUG = false;
 
     private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex";
+    /**
+     * Whether or not we use the precompiled layout.
+     */
+    private static final String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled";
 
     /** Empty stack trace used to avoid log spam in re-throw exceptions. */
     private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
@@ -416,15 +420,15 @@
         String usePrecompiledLayout = null;
         try {
             usePrecompiledLayout = DeviceConfig.getProperty(
-                    DeviceConfig.Runtime.NAMESPACE,
-                    DeviceConfig.Runtime.USE_PRECOMPILED_LAYOUT);
+                    DeviceConfig.NAMESPACE_RUNTIME,
+                    USE_PRECOMPILED_LAYOUT);
         } catch (Exception e) {
           // May be caused by permission errors reading the property (i.e. instant apps).
         }
         boolean enabled = false;
         if (TextUtils.isEmpty(usePrecompiledLayout)) {
             enabled = SystemProperties.getBoolean(
-                    DeviceConfig.Runtime.USE_PRECOMPILED_LAYOUT,
+                    USE_PRECOMPILED_LAYOUT,
                     false);
         } else {
             enabled = Boolean.parseBoolean(usePrecompiledLayout);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7fcce6d..b857f1e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -17197,6 +17197,7 @@
      * and {@link #setTranslationY(float)} (float)}} instead.
      *
      * @param matrix The matrix, null indicates that the matrix should be cleared.
+     * @see #getAnimationMatrix()
      */
     public void setAnimationMatrix(@Nullable Matrix matrix) {
         invalidateViewProperty(true, false);
@@ -17207,6 +17208,22 @@
     }
 
     /**
+     * Return the current transformation matrix of the view. This is used in animation frameworks,
+     * such as {@link android.transition.Transition}. Returns <code>null</code> when there is no
+     * transformation provided by {@link #setAnimationMatrix(Matrix)}.
+     * Application developers should use transformation methods like {@link #setRotation(float)},
+     * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}}
+     * and {@link #setTranslationY(float)} (float)}} instead.
+     *
+     * @return the Matrix, null indicates there is no transformation
+     * @see #setAnimationMatrix(Matrix)
+     */
+    @Nullable
+    public Matrix getAnimationMatrix() {
+        return mRenderNode.getAnimationMatrix();
+    }
+
+    /**
      * Returns the current StateListAnimator if exists.
      *
      * @return StateListAnimator or null if it does not exists
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4dc20d4..4964ee1 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4284,35 +4284,38 @@
     }
 
     /**
-     * Returns the index of the child to draw for this iteration. Override this
+     * Converts drawing order position to container position. Override this
      * if you want to change the drawing order of children. By default, it
-     * returns i.
+     * returns drawingPosition.
      * <p>
      * NOTE: In order for this method to be called, you must enable child ordering
      * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
      *
-     * @param i The current iteration.
-     * @return The index of the child to draw this iteration.
+     * @param drawingPosition the drawing order position.
+     * @return the container position of a child for this drawing order position.
      *
      * @see #setChildrenDrawingOrderEnabled(boolean)
      * @see #isChildrenDrawingOrderEnabled()
      */
-    protected int getChildDrawingOrder(int childCount, int i) {
-        return i;
+    protected int getChildDrawingOrder(int childCount, int drawingPosition) {
+        return drawingPosition;
     }
 
     /**
-     * The public version of getChildDrawingOrder().
+     * Converts drawing order position to container position.
+     * <p>
+     * Children are not necessarily drawn in the order in which they appear in the container.
+     * ViewGroups can enable a custom ordering via {@link #setChildrenDrawingOrderEnabled(boolean)}.
+     * This method returns the container position of a child that appears in the given position
+     * in the current drawing order.
      *
-     * Returns the index of the child to draw for this iteration.
-     *
-     * @param i The current iteration.
-     * @return The index of the child to draw this iteration.
+     * @param drawingPosition the drawing order position.
+     * @return the container position of a child for this drawing order position.
      *
      * @see #getChildDrawingOrder(int, int)}
      */
-    public final int getChildDrawingOrder(int i) {
-        return getChildDrawingOrder(getChildCount(), i);
+    public final int getChildDrawingOrder(int drawingPosition) {
+        return getChildDrawingOrder(getChildCount(), drawingPosition);
     }
 
     private boolean hasChildWithZ() {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9222bd6..a28d662 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1213,15 +1213,12 @@
 
         boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
 
-        // Allow debug.hwui.force_dark to override the target SDK check
-        if (useAutoDark && !SystemProperties.getBoolean("debug.hwui.force_dark", false)) {
-            useAutoDark = mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q;
-        }
-
         if (useAutoDark) {
+            boolean forceDarkAllowedDefault =
+                    SystemProperties.getBoolean("debug.hwui.force_dark", false);
             TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
             useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true)
-                    && a.getBoolean(R.styleable.Theme_forceDarkAllowed, true);
+                    && a.getBoolean(R.styleable.Theme_forceDarkAllowed, forceDarkAllowedDefault);
             a.recycle();
         }
 
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index 8fa29f3..2c79299 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -47,20 +47,20 @@
 
     /** @hide */
     @TestApi
-    public AutofillId(@NonNull AutofillId parent, int virtualChildId) {
-        this(FLAG_IS_VIRTUAL_INT, parent.mViewId, virtualChildId, NO_SESSION);
+    public AutofillId(@NonNull AutofillId hostId, int virtualChildId) {
+        this(FLAG_IS_VIRTUAL_INT, hostId.mViewId, virtualChildId, NO_SESSION);
     }
 
     /** @hide */
     @TestApi
-    public AutofillId(int parentId, int virtualChildId) {
-        this(FLAG_IS_VIRTUAL_INT, parentId, virtualChildId, NO_SESSION);
+    public AutofillId(int hostId, int virtualChildId) {
+        this(FLAG_IS_VIRTUAL_INT, hostId, virtualChildId, NO_SESSION);
     }
 
     /** @hide */
     @TestApi
-    public AutofillId(@NonNull AutofillId parent, long virtualChildId, int sessionId) {
-        this(FLAG_IS_VIRTUAL_LONG | FLAG_HAS_SESSION, parent.mViewId, virtualChildId, sessionId);
+    public AutofillId(@NonNull AutofillId hostId, long virtualChildId, int sessionId) {
+        this(FLAG_IS_VIRTUAL_LONG | FLAG_HAS_SESSION, hostId.mViewId, virtualChildId, sessionId);
     }
 
     private AutofillId(int flags, int parentId, long virtualChildId, int sessionId) {
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 0c0a555..604cce5 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -20,6 +20,7 @@
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.view.autofill.Helper.sDebug;
 import static android.view.autofill.Helper.sVerbose;
+import static android.view.autofill.Helper.toList;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.IntDef;
@@ -1872,10 +1873,6 @@
         }
     }
 
-    private <T> ArrayList<T> toList(@Nullable Set<T> set) {
-        return set == null ? null : new ArrayList<T>(set);
-    }
-
     /**
      * Notifies that a non-autofillable view was entered because the activity is whitelisted for
      * augmented autofill.
@@ -2211,12 +2208,17 @@
      *  when the service failed to fullfil the request, or {@link #STATE_DISABLED_BY_SERVICE}
      *  (because the autofill service or {@link #STATE_DISABLED_BY_SERVICE} (because the autofill
      *  service disabled further autofill requests for the activity).
+     * @param autofillableIds list of ids that could trigger autofill, use to not handle a new
+     *  session when they're entered.
      */
-    private void setSessionFinished(int newState) {
+    private void setSessionFinished(int newState, @Nullable List<AutofillId> autofillableIds) {
         synchronized (mLock) {
             if (sVerbose) {
                 Log.v(TAG, "setSessionFinished(): from " + getStateAsStringLocked() + " to "
-                        + getStateAsString(newState));
+                        + getStateAsString(newState) + "; autofillableIds=" + autofillableIds);
+            }
+            if (autofillableIds != null) {
+                mEnteredIds = new ArraySet<>(autofillableIds);
             }
             if (newState == STATE_UNKNOWN_COMPAT_MODE || newState == STATE_UNKNOWN_FAILED) {
                 resetSessionLocked(/* resetEnteredIds= */ true);
@@ -2328,7 +2330,7 @@
 
         if (sessionFinishedState != 0) {
             // Callback call was "hijacked" to also update the session state.
-            setSessionFinished(sessionFinishedState);
+            setSessionFinished(sessionFinishedState, /* autofillableIds= */ null);
         }
     }
 
@@ -3114,10 +3116,10 @@
         }
 
         @Override
-        public void setSessionFinished(int newState) {
+        public void setSessionFinished(int newState, List<AutofillId> autofillableIds) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
-                afm.post(() -> afm.setSessionFinished(newState));
+                afm.post(() -> afm.setSessionFinished(newState, autofillableIds));
             }
         }
 
diff --git a/core/java/android/view/autofill/Helper.java b/core/java/android/view/autofill/Helper.java
index 48d0dbb..2f12bb2 100644
--- a/core/java/android/view/autofill/Helper.java
+++ b/core/java/android/view/autofill/Helper.java
@@ -19,7 +19,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Set;
 
 /** @hide */
 public final class Helper {
@@ -62,7 +64,8 @@
     }
 
     /**
-     * Convers a collaction of {@link AutofillId AutofillIds} to an array.
+     * Converts a collaction of {@link AutofillId AutofillIds} to an array.
+     *
      * @param collection The collection.
      * @return The array.
      */
@@ -75,6 +78,14 @@
         return array;
     }
 
+    /**
+     * Converts a Set to a List.
+     */
+    @Nullable
+    public static <T> ArrayList<T> toList(@Nullable Set<T> set) {
+        return set == null ? null : new ArrayList<T>(set);
+    }
+
     private Helper() {
         throw new UnsupportedOperationException("contains static members only");
     }
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 63394b4..85def7f 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -98,8 +98,10 @@
      *
      * @param newState STATE_FINISHED (because the autofill service returned a null
      * FillResponse) or STATE_UNKNOWN (because the session was removed).
+     * @param autofillableIds list of ids that could trigger autofill, use to not handle a new
+     * session when they're entered.
      */
-   void setSessionFinished(int newState);
+   void setSessionFinished(int newState, in List<AutofillId> autofillableIds);
 
    /**
     * Gets a reference to the binder object that can be used by the Augmented Autofill service.
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index b9dc0dd..019ebff 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -71,10 +71,21 @@
     @TestApi
     public static final int FLAG_DISABLED_BY_FLAG_SECURE = 0x2;
 
+    /**
+     * Flag used when the event is sent because the Android System reconnected to the service (for
+     * example, after its process died).
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int FLAG_RECONNECTED = 0x4;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "FLAG_" }, value = {
             FLAG_DISABLED_BY_APP,
-            FLAG_DISABLED_BY_FLAG_SECURE
+            FLAG_DISABLED_BY_FLAG_SECURE,
+            FLAG_RECONNECTED
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface ContextCreationFlags{}
@@ -126,6 +137,17 @@
         mDisplayId = Display.INVALID_DISPLAY;
     }
 
+    /** @hide */
+    public ContentCaptureContext(@Nullable ContentCaptureContext original, int extraFlags) {
+        mHasClientContext = original.mHasClientContext;
+        mExtras = original.mExtras;
+        mId = original.mId;
+        mComponentName = original.mComponentName;
+        mTaskId = original.mTaskId;
+        mFlags = original.mFlags | extraFlags;
+        mDisplayId = original.mDisplayId;
+    }
+
     /**
      * Gets the (optional) extras set by the app (through {@link Builder#setExtras(Bundle)}).
      *
@@ -199,8 +221,8 @@
     /**
      * Gets the flags associated with this context.
      *
-     * @return any combination of {@link #FLAG_DISABLED_BY_FLAG_SECURE} and
-     * {@link #FLAG_DISABLED_BY_APP}.
+     * @return any combination of {@link #FLAG_DISABLED_BY_FLAG_SECURE},
+     * {@link #FLAG_DISABLED_BY_APP} and {@link #FLAG_RECONNECTED}.
      *
      * @hide
      */
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index 67d3629..8188e05 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -303,6 +303,47 @@
         return mText;
     }
 
+    /**
+     * Merges event of the same type, either {@link #TYPE_VIEW_TEXT_CHANGED}
+     * or {@link #TYPE_VIEW_DISAPPEARED}.
+     *
+     * @hide
+     */
+    public void mergeEvent(@NonNull ContentCaptureEvent event) {
+        Preconditions.checkNotNull(event);
+        final int eventType = event.getType();
+        if (mType != eventType) {
+            Log.e(TAG, "mergeEvent(" + getTypeAsString(eventType) + ") cannot be merged "
+                    + "with different eventType=" + getTypeAsString(mType));
+            return;
+        }
+
+        if (eventType == TYPE_VIEW_DISAPPEARED) {
+            final List<AutofillId> ids = event.getIds();
+            final AutofillId id = event.getId();
+            if (ids != null) {
+                if (id != null) {
+                    Log.w(TAG, "got TYPE_VIEW_DISAPPEARED event with both id and ids: " + event);
+                }
+                for (int i = 0; i < ids.size(); i++) {
+                    addAutofillId(ids.get(i));
+                }
+                return;
+            }
+            if (id != null) {
+                addAutofillId(id);
+                return;
+            }
+            throw new IllegalArgumentException("mergeEvent(): got "
+                    + "TYPE_VIEW_DISAPPEARED event with neither id or ids: " + event);
+        } else if (eventType == TYPE_VIEW_TEXT_CHANGED) {
+            setText(event.getText());
+        } else {
+            Log.e(TAG, "mergeEvent(" + getTypeAsString(eventType)
+                    + ") does not support this event type.");
+        }
+    }
+
     /** @hide */
     public void dump(@NonNull PrintWriter pw) {
         pw.print("type="); pw.print(getTypeAsString(mType));
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 1f0971e..6d41b28 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -127,6 +127,20 @@
      */
     public static final int STATE_NOT_WHITELISTED = 0x200;
 
+    /**
+     * Session is disabled because the service died.
+     *
+     * @hide
+     */
+    public static final int STATE_SERVICE_DIED = 0x400;
+
+    /**
+     * Session is enabled, after the service died and came back to live.
+     *
+     * @hide
+     */
+    public static final int STATE_SERVICE_RESURRECTED = 0x800;
+
     private static final int INITIAL_CHILDREN_CAPACITY = 5;
 
     /** @hide */
@@ -139,6 +153,8 @@
     public static final int FLUSH_REASON_SESSION_FINISHED = 4;
     /** @hide */
     public static final int FLUSH_REASON_IDLE_TIMEOUT = 5;
+    /** @hide */
+    public static final int FLUSH_REASON_TEXT_CHANGE_TIMEOUT = 6;
 
     /** @hide */
     @IntDef(prefix = { "FLUSH_REASON_" }, value = {
@@ -146,7 +162,8 @@
             FLUSH_REASON_VIEW_ROOT_ENTERED,
             FLUSH_REASON_SESSION_STARTED,
             FLUSH_REASON_SESSION_FINISHED,
-            FLUSH_REASON_IDLE_TIMEOUT
+            FLUSH_REASON_IDLE_TIMEOUT,
+            FLUSH_REASON_TEXT_CHANGE_TIMEOUT
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FlushReason{}
@@ -375,7 +392,8 @@
      *
      * <p>Should only be called by views that handle their own virtual view hierarchy.
      *
-     * @param hostId id of the view hosting the virtual hierarchy.
+     * @param hostId id of the non-virtual view hosting the virtual view hierarchy (it can be
+     * obtained by calling {@link ViewStructure#getAutofillId()}).
      * @param virtualIds ids of the virtual children.
      *
      * @throws IllegalArgumentException if the {@code hostId} is an autofill id for a virtual view.
@@ -383,7 +401,7 @@
      */
     public final void notifyViewsDisappeared(@NonNull AutofillId hostId,
             @NonNull long[] virtualIds) {
-        Preconditions.checkArgument(hostId.isNonVirtual(), "parent cannot be virtual");
+        Preconditions.checkArgument(hostId.isNonVirtual(), "hostId cannot be virtual: %s", hostId);
         Preconditions.checkArgument(!ArrayUtils.isEmpty(virtualIds), "virtual ids cannot be empty");
         if (!isContentCaptureEnabled()) return;
 
@@ -428,18 +446,18 @@
      * Creates a new {@link AutofillId} for a virtual child, so it can be used to uniquely identify
      * the children in the session.
      *
-     * @param parentId id of the virtual view parent (it can be obtained by calling
-     * {@link ViewStructure#getAutofillId()} on the parent).
+     * @param hostId id of the non-virtual view hosting the virtual view hierarchy (it can be
+     * obtained by calling {@link ViewStructure#getAutofillId()}).
      * @param virtualChildId id of the virtual child, relative to the parent.
      *
      * @return if for the virtual child
      *
      * @throws IllegalArgumentException if the {@code parentId} is a virtual child id.
      */
-    public @NonNull AutofillId newAutofillId(@NonNull AutofillId parentId, long virtualChildId) {
-        Preconditions.checkNotNull(parentId);
-        Preconditions.checkArgument(parentId.isNonVirtual(), "virtual ids cannot have children");
-        return new AutofillId(parentId, virtualChildId, getIdAsInt());
+    public @NonNull AutofillId newAutofillId(@NonNull AutofillId hostId, long virtualChildId) {
+        Preconditions.checkNotNull(hostId);
+        Preconditions.checkArgument(hostId.isNonVirtual(), "hostId cannot be virtual: %s", hostId);
+        return new AutofillId(hostId, virtualChildId, getIdAsInt());
     }
 
     /**
@@ -510,6 +528,8 @@
                 return "FINISHED";
             case FLUSH_REASON_IDLE_TIMEOUT:
                 return "IDLE";
+            case FLUSH_REASON_TEXT_CHANGE_TIMEOUT:
+                return "TEXT_CHANGE";
             default:
                 return "UNKOWN-" + reason;
         }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index dce8ebe..666af59 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -125,9 +125,20 @@
     // Used just for debugging purposes (on dump)
     private long mNextFlush;
 
+    /**
+     * Whether the next buffer flush is queued by a text changed event.
+     */
+    private boolean mNextFlushForTextChanged = false;
+
     @Nullable
     private final LocalLog mFlushHistory;
 
+    /**
+     * Binder object used to update the session state.
+     */
+    @NonNull
+    private final IResultReceiver.Stub mSessionStateReceiver;
+
     protected MainContentCaptureSession(@NonNull Context context,
             @NonNull ContentCaptureManager manager, @NonNull Handler handler,
             @NonNull IContentCaptureManager systemServerInterface) {
@@ -138,6 +149,26 @@
 
         final int logHistorySize = mManager.mOptions.logHistorySize;
         mFlushHistory = logHistorySize > 0 ? new LocalLog(logHistorySize) : null;
+
+        mSessionStateReceiver = new IResultReceiver.Stub() {
+            @Override
+            public void send(int resultCode, Bundle resultData) {
+                final IBinder binder;
+                if (resultData != null) {
+                    binder = resultData.getBinder(EXTRA_BINDER);
+                    if (binder == null) {
+                        Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result");
+                        mHandler.post(() -> resetSession(
+                                STATE_DISABLED | STATE_INTERNAL_ERROR));
+                        return;
+                    }
+                } else {
+                    binder = null;
+                }
+                mHandler.post(() -> onSessionStarted(resultCode, binder));
+            }
+        };
+
     }
 
     @Override
@@ -185,24 +216,7 @@
 
         try {
             mSystemServerInterface.startSession(mApplicationToken, component, mId, flags,
-                    new IResultReceiver.Stub() {
-                        @Override
-                        public void send(int resultCode, Bundle resultData) {
-                            final IBinder binder;
-                            if (resultData != null) {
-                                binder = resultData.getBinder(EXTRA_BINDER);
-                                if (binder == null) {
-                                    Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result");
-                                    mHandler.post(() -> resetSession(
-                                            STATE_DISABLED | STATE_INTERNAL_ERROR));
-                                    return;
-                                }
-                            } else {
-                                binder = null;
-                            }
-                            mHandler.post(() -> onSessionStarted(resultCode, binder));
-                        }
-                    });
+                    mSessionStateReceiver);
         } catch (RemoteException e) {
             Log.w(TAG, "Error starting session for " + component.flattenToShortString() + ": " + e);
         }
@@ -216,8 +230,7 @@
 
     /**
      * Callback from {@code system_server} after call to
-     * {@link IContentCaptureManager#startSession(IBinder, ComponentName, String, int,
-     * IResultReceiver)}
+     * {@link IContentCaptureManager#startSession(IBinder, ComponentName, String, int, IBinder)}
      *
      * @param resultCode session state
      * @param binder handle to {@code IContentCaptureDirectManager}
@@ -227,8 +240,9 @@
         if (binder != null) {
             mDirectServiceInterface = IContentCaptureDirectManager.Stub.asInterface(binder);
             mDirectServiceVulture = () -> {
-                Log.w(TAG, "Destroying session " + mId + " because service died");
-                destroy();
+                Log.w(TAG, "Keeping session " + mId + " when service died");
+                mState = STATE_SERVICE_DIED;
+                mDisabled.set(true);
             };
             try {
                 binder.linkToDeath(mDirectServiceVulture, 0);
@@ -295,8 +309,7 @@
                     Log.v(TAG, "Buffering VIEW_TEXT_CHANGED event, updated text="
                             + getSanitizedString(event.getText()));
                 }
-                // TODO(b/124107816): should call lastEvent.merge(event) instead
-                lastEvent.setText(event.getText());
+                lastEvent.mergeEvent(event);
                 addEvent = false;
             }
         }
@@ -309,7 +322,7 @@
                     Log.v(TAG, "Buffering TYPE_VIEW_DISAPPEARED events for session "
                             + lastEvent.getSessionId());
                 }
-                mergeViewsDisappearedEvent(lastEvent, event);
+                lastEvent.mergeEvent(event);
                 addEvent = false;
             }
         }
@@ -323,7 +336,21 @@
         final boolean bufferEvent = numberEvents < maxBufferSize;
 
         if (bufferEvent && !forceFlush) {
-            scheduleFlush(FLUSH_REASON_IDLE_TIMEOUT, /* checkExisting= */ true);
+            final int flushReason;
+            if (eventType == TYPE_VIEW_TEXT_CHANGED) {
+                mNextFlushForTextChanged = true;
+                flushReason = FLUSH_REASON_TEXT_CHANGE_TIMEOUT;
+            } else {
+                if (mNextFlushForTextChanged) {
+                    if (sVerbose) {
+                        Log.i(TAG, "Not scheduling flush because next flush is for text changed");
+                    }
+                    return;
+                }
+
+                flushReason = FLUSH_REASON_IDLE_TIMEOUT;
+            }
+            scheduleFlush(flushReason, /* checkExisting= */ true);
             return;
         }
 
@@ -357,30 +384,6 @@
         flush(flushReason);
     }
 
-    // TODO(b/124107816): should be ContentCaptureEvent Event.merge(event) instead (which would
-    // replace the addAutofillId() method - we would also need unit tests on ContentCaptureEventTest
-    // to check these scenarios)
-    private void mergeViewsDisappearedEvent(@NonNull ContentCaptureEvent lastEvent,
-            @NonNull ContentCaptureEvent event) {
-        final List<AutofillId> ids = event.getIds();
-        final AutofillId id = event.getId();
-        if (ids != null) {
-            if (id != null) {
-                Log.w(TAG, "got TYPE_VIEW_DISAPPEARED event with both id and ids: " + event);
-            }
-            for (int i = 0; i < ids.size(); i++) {
-                lastEvent.addAutofillId(ids.get(i));
-            }
-            return;
-        }
-        if (id != null) {
-            lastEvent.addAutofillId(id);
-            return;
-        }
-        throw new IllegalArgumentException(
-                "got TYPE_VIEW_DISAPPEARED event with neither id or ids: " + event);
-    }
-
     @UiThread
     private boolean hasStarted() {
         return mState != UNKNOWN_STATE;
@@ -408,14 +411,25 @@
             // "Renew" the flush message by removing the previous one
             mHandler.removeMessages(MSG_FLUSH);
         }
-        final int idleFlushingFrequencyMs = mManager.mOptions.idleFlushingFrequencyMs;
-        mNextFlush = System.currentTimeMillis() + idleFlushingFrequencyMs;
+
+        final int flushFrequencyMs;
+        if (reason == FLUSH_REASON_IDLE_TIMEOUT) {
+            flushFrequencyMs = mManager.mOptions.idleFlushingFrequencyMs;
+        } else if (reason == FLUSH_REASON_TEXT_CHANGE_TIMEOUT) {
+            flushFrequencyMs = mManager.mOptions.textChangeFlushingFrequencyMs;
+        } else {
+            Log.e(TAG, "handleScheduleFlush(" + getDebugState(reason) + "): not called with a "
+                    + "timeout reason.");
+            return;
+        }
+
+        mNextFlush = System.currentTimeMillis() + flushFrequencyMs;
         if (sVerbose) {
             Log.v(TAG, "handleScheduleFlush(): scheduled to flush in "
-                    + idleFlushingFrequencyMs + "ms: " + TimeUtils.logTimeOfDay(mNextFlush));
+                    + flushFrequencyMs + "ms: " + TimeUtils.logTimeOfDay(mNextFlush));
         }
         // Post using a Runnable directly to trim a few μs from PooledLambda.obtainMessage()
-        mHandler.postDelayed(() -> flushIfNeeded(reason), MSG_FLUSH, idleFlushingFrequencyMs);
+        mHandler.postDelayed(() -> flushIfNeeded(reason), MSG_FLUSH, flushFrequencyMs);
     }
 
     @UiThread
@@ -464,6 +478,10 @@
         try {
             mHandler.removeMessages(MSG_FLUSH);
 
+            if (reason == FLUSH_REASON_TEXT_CHANGE_TIMEOUT) {
+                mNextFlushForTextChanged = false;
+            }
+
             final ParceledListSlice<ContentCaptureEvent> events = clearEvents();
             mDirectServiceInterface.sendEvents(events);
         } catch (RemoteException e) {
@@ -641,8 +659,14 @@
                     pw.println();
                 }
             }
+            pw.print(prefix); pw.print("mNextFlushForTextChanged: ");
+            pw.println(mNextFlushForTextChanged);
             pw.print(prefix); pw.print("flush frequency: ");
-            pw.println(mManager.mOptions.idleFlushingFrequencyMs);
+            if (mNextFlushForTextChanged) {
+                pw.println(mManager.mOptions.textChangeFlushingFrequencyMs);
+            } else {
+                pw.println(mManager.mOptions.idleFlushingFrequencyMs);
+            }
             pw.print(prefix); pw.print("next flush: ");
             TimeUtils.formatDuration(mNextFlush - System.currentTimeMillis(), pw);
             pw.print(" ("); pw.print(TimeUtils.logTimeOfDay(mNextFlush)); pw.println(")");
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index e63a406..5e00425 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2559,6 +2559,12 @@
         mPendingEventPool.release(p);
     }
 
+    /**
+     * Show IME picker popup window.
+     *
+     * <p>Requires the {@link PackageManager#FEATURE_INPUT_METHODS} feature which can be detected
+     * using {@link PackageManager#hasSystemFeature(String)}.
+     */
     public void showInputMethodPicker() {
         synchronized (mH) {
             showInputMethodPickerLocked();
diff --git a/core/java/android/view/inspector/IntEnumMapping.java b/core/java/android/view/inspector/IntEnumMapping.java
deleted file mode 100644
index 147bb46..0000000
--- a/core/java/android/view/inspector/IntEnumMapping.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.inspector;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.SparseArray;
-
-import java.util.Objects;
-
-/**
- * Maps the values of an {@code int} property to strings for properties that encode an enumeration.
- *
- * An {@link InspectionCompanion} may provide an instance of this class to a {@link PropertyMapper}
- * for flag values packed into primitive {@code int} properties.
- *
- * This class is an immutable wrapper for {@link SparseArray}, and must be constructed by a
- * {@link Builder}.
- *
- * @see PropertyMapper#mapIntEnum(String, int, IntEnumMapping)
- */
-public final class IntEnumMapping {
-    private final SparseArray<String> mValues;
-
-    /**
-     * Get the name for the given property value
-     *
-     * @param value The value of the property
-     * @return The name of the value in the enumeration, or null if no value is defined
-     */
-    @Nullable
-    public String get(int value) {
-        return mValues.get(value);
-    }
-
-    /**
-     * Create a new instance from a builder.
-     *
-     * This constructor is private, use {@link Builder#build()} instead.
-     *
-     * @param builder A builder to create from
-     */
-    private IntEnumMapping(Builder builder) {
-        mValues = builder.mValues.clone();
-    }
-
-    /**
-     * A builder for {@link IntEnumMapping}.
-     */
-    public static final class Builder {
-        @NonNull
-        private SparseArray<String> mValues;
-        private boolean mMustCloneValues = false;
-
-        public Builder() {
-            mValues = new SparseArray<>();
-        }
-
-        /**
-         * Add a new enumerated value.
-         *
-         * @param name The string name of the enumeration value
-         * @param value The {@code int} value of the enumeration value
-         * @return This builder
-         */
-        @NonNull
-        public Builder addValue(@NonNull String name, int value) {
-            // Save an allocation, only re-clone if the builder is used again after building
-            if (mMustCloneValues) {
-                mValues = mValues.clone();
-            }
-
-            mValues.put(value, Objects.requireNonNull(name));
-            return this;
-        }
-
-        /**
-         * Build a new {@link IntEnumMapping} from this builder.
-         *
-         * @return A new mapping
-         */
-        @NonNull
-        public IntEnumMapping build() {
-            mMustCloneValues = true;
-            return new IntEnumMapping(this);
-        }
-    }
-}
diff --git a/core/java/android/view/inspector/IntFlagMapping.java b/core/java/android/view/inspector/IntFlagMapping.java
index 2409081..f501329 100644
--- a/core/java/android/view/inspector/IntFlagMapping.java
+++ b/core/java/android/view/inspector/IntFlagMapping.java
@@ -21,6 +21,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 
@@ -35,22 +36,20 @@
  * it by bitwise anding it with the mask and comparing the result against the target, that is,
  * {@code (value & mask) == target}.
  *
- * This class is immutable, and must be constructed by a {@link Builder}.
- *
- * @see PropertyMapper#mapIntFlag(String, int, IntFlagMapping)
+ * @see PropertyMapper#mapIntFlag(String, int, java.util.function.IntFunction)
  */
 public final class IntFlagMapping {
-    private final Flag[] mFlags;
+    private final List<Flag> mFlags = new ArrayList<>();
 
     /**
-     * Get an array of the names of enabled flags for a given property value.
+     * Get a set of the names of enabled flags for a given property value.
      *
      * @param value The value of the property
      * @return The names of the enabled flags, empty if no flags enabled
      */
     @NonNull
     public Set<String> get(int value) {
-        final Set<String> enabledFlagNames = new HashSet<>(mFlags.length);
+        final Set<String> enabledFlagNames = new HashSet<>(mFlags.size());
 
         for (Flag flag : mFlags) {
             if (flag.isEnabledFor(value)) {
@@ -62,70 +61,14 @@
     }
 
     /**
-     * Create a new instance from a builder.
+     * Add a mutually exclusive flag to the map.
      *
-     * This constructor is private, use {@link Builder#build()} instead.
-     *
-     * @param builder A builder to create from
+     * @param mask The bit mask to compare to and with a value
+     * @param target The target value to compare the masked value with
+     * @param name The name of the flag to include if enabled
      */
-    private IntFlagMapping(Builder builder) {
-        mFlags = builder.mFlags.toArray(new Flag[builder.mFlags.size()]);
-    }
-
-    /**
-     * A builder for {@link IntFlagMapping}.
-     */
-    public static final class Builder {
-        private ArrayList<Flag> mFlags;
-
-        public Builder() {
-            mFlags = new ArrayList<>();
-        }
-
-        /**
-         * Add a new flag without a mask.
-         *
-         * The target value will be used as a mask, to handle the common case where flag values
-         * are not mutually exclusive. The flag will be considered enabled for a property value if
-         * the result of bitwise anding the target and the value equals the target, that is:
-         * {@code (value & target) == target}.
-         *
-         * @param name The name of the flag
-         * @param target The value to compare against
-         * @return This builder
-         */
-        @NonNull
-        public Builder addFlag(@NonNull String name, int target) {
-            mFlags.add(new Flag(name, target, target));
-            return this;
-        }
-
-        /**
-         * Add a new flag with a mask.
-         *
-         * The flag will be considered enabled for a property value if the result of bitwise anding
-         * the value and the mask equals the target, that is: {@code (value & mask) == target}.
-         *
-         * @param name The name of the flag
-         * @param target The value to compare against
-         * @param mask A bit mask
-         * @return This builder
-         */
-        @NonNull
-        public Builder addFlag(@NonNull String name, int target, int mask) {
-            mFlags.add(new Flag(name, target, mask));
-            return this;
-        }
-
-        /**
-         * Build a new {@link IntFlagMapping} from this builder.
-         *
-         * @return A new mapping
-         */
-        @NonNull
-        public IntFlagMapping build() {
-            return new IntFlagMapping(this);
-        }
+    public void add(int mask, int target, @NonNull String name) {
+        mFlags.add(new Flag(mask, target, name));
     }
 
     /**
@@ -136,10 +79,10 @@
         private final int mTarget;
         private final int mMask;
 
-        private Flag(@NonNull String name, int target, int mask) {
-            mName = Objects.requireNonNull(name);
+        private Flag(int mask, int target, @NonNull String name) {
             mTarget = target;
             mMask = mask;
+            mName = Objects.requireNonNull(name);
         }
 
         /**
diff --git a/core/java/android/view/inspector/PropertyMapper.java b/core/java/android/view/inspector/PropertyMapper.java
index 54d99df..cbc690e 100644
--- a/core/java/android/view/inspector/PropertyMapper.java
+++ b/core/java/android/view/inspector/PropertyMapper.java
@@ -19,6 +19,9 @@
 import android.annotation.AttrRes;
 import android.annotation.NonNull;
 
+import java.util.Set;
+import java.util.function.IntFunction;
+
 /**
  * An interface for mapping the string names of inspectable properties to integer identifiers.
  *
@@ -154,7 +157,7 @@
     int mapIntEnum(
             @NonNull String name,
             @AttrRes int attributeId,
-            @NonNull IntEnumMapping mapping);
+            @NonNull IntFunction<String> mapping);
 
     /**
      * Map a string name to an integer ID for an attribute that contains resource IDs.
@@ -178,7 +181,7 @@
     int mapIntFlag(
             @NonNull String name,
             @AttrRes int attributeId,
-            @NonNull IntFlagMapping mapping);
+            @NonNull IntFunction<Set<String>> mapping);
     /**
      * Thrown from a map method if a property name is already mapped as different type.
      */
diff --git a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
index ddbff7b..9c268f2 100644
--- a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
+++ b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
@@ -23,10 +23,13 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Pair;
+import android.view.textclassifier.intent.LabeledIntent;
+import android.view.textclassifier.intent.TemplateIntentFactory;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import com.google.android.textclassifier.ActionsSuggestionsModel;
+import com.google.android.textclassifier.RemoteActionTemplate;
 
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -46,6 +49,7 @@
  */
 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
 public final class ActionsSuggestionsHelper {
+    private static final String TAG = "ActionsSuggestions";
     private static final int USER_LOCAL = 0;
     private static final int FIRST_NON_LOCAL_USER = 1;
 
@@ -82,9 +86,12 @@
             long referenceTime = message.getReferenceTime() == null
                     ? 0
                     : message.getReferenceTime().toInstant().toEpochMilli();
+            String timeZone = message.getReferenceTime() == null
+                    ? null
+                    : message.getReferenceTime().getZone().getId();
             nativeMessages.push(new ActionsSuggestionsModel.ConversationMessage(
                     personEncoder.encode(message.getAuthor()),
-                    message.getText().toString(), referenceTime,
+                    message.getText().toString(), referenceTime, timeZone,
                     languageDetector.apply(message.getText())));
         }
         return nativeMessages.toArray(
@@ -114,8 +121,33 @@
     }
 
     /**
-     * Returns a {@link android.view.textclassifier.LabeledIntent.TitleChooser} for
-     * conversation actions use case.
+     * Generated labeled intent from an action suggestion and return the resolved result.
+     */
+    @Nullable
+    public static LabeledIntent.Result createLabeledIntentResult(
+            Context context,
+            TemplateIntentFactory templateIntentFactory,
+            ActionsSuggestionsModel.ActionSuggestion nativeSuggestion) {
+        RemoteActionTemplate[] remoteActionTemplates =
+                nativeSuggestion.getRemoteActionTemplates();
+        if (remoteActionTemplates == null) {
+            Log.w(TAG, "createRemoteAction: Missing template for type "
+                    + nativeSuggestion.getActionType());
+            return null;
+        }
+        List<LabeledIntent> labeledIntents = templateIntentFactory.create(remoteActionTemplates);
+        if (labeledIntents.isEmpty()) {
+            return null;
+        }
+        // Given that we only support implicit intent here, we should expect there is just one
+        // intent for each action type.
+        LabeledIntent.TitleChooser titleChooser =
+                ActionsSuggestionsHelper.createTitleChooser(nativeSuggestion.getActionType());
+        return labeledIntents.get(0).resolve(context, titleChooser, null);
+    }
+
+    /**
+     * Returns a {@link LabeledIntent.TitleChooser} for conversation actions use case.
      */
     @Nullable
     public static LabeledIntent.TitleChooser createTitleChooser(String actionType) {
diff --git a/core/java/android/view/textclassifier/ConversationAction.java b/core/java/android/view/textclassifier/ConversationAction.java
index 2b952a3..f2d878a 100644
--- a/core/java/android/view/textclassifier/ConversationAction.java
+++ b/core/java/android/view/textclassifier/ConversationAction.java
@@ -92,10 +92,15 @@
      */
     public static final String TYPE_SHARE_LOCATION = "share_location";
 
+    // TODO: Make this public API
     /** @hide **/
     public static final String TYPE_ADD_CONTACT = "add_contact";
 
-    public static final @android.annotation.NonNull Creator<ConversationAction> CREATOR =
+    // TODO: Make this public API
+    /** @hide **/
+    public static final String TYPE_COPY = "copy";
+
+    public static final @NonNull Creator<ConversationAction> CREATOR =
             new Creator<ConversationAction>() {
                 @Override
                 public ConversationAction createFromParcel(Parcel in) {
diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java
index df548ae..eadad28 100644
--- a/core/java/android/view/textclassifier/ExtrasUtils.java
+++ b/core/java/android/view/textclassifier/ExtrasUtils.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.app.RemoteAction;
 import android.content.Intent;
+import android.icu.util.ULocale;
 import android.os.Bundle;
 
 import java.util.ArrayList;
@@ -27,8 +28,10 @@
  * Utility class for inserting and retrieving data in TextClassifier request/response extras.
  * @hide
  */
+// TODO: Make this a TestApi for CTS testing.
 public final class ExtrasUtils {
 
+    private static final String ENTITIES_EXTRAS = "entities-extras";
     private static final String ACTION_INTENT = "action-intent";
     private static final String ACTIONS_INTENTS = "actions-intents";
     private static final String FOREIGN_LANGUAGE = "foreign-language";
@@ -36,6 +39,7 @@
     private static final String SCORE = "score";
     private static final String MODEL_VERSION = "model-version";
     private static final String MODEL_NAME = "model-name";
+    private static final String TEXT_LANGUAGES = "text-languages";
 
     private ExtrasUtils() {}
 
@@ -55,6 +59,8 @@
     /**
      * Stores {@code extra} as foreign language information in TextClassifier response object's
      * extras {@code container}.
+     *
+     * @see #getForeignLanguageExtra(TextClassification)
      */
     static void putForeignLanguageExtra(Bundle container, Bundle extra) {
         container.putParcelable(FOREIGN_LANGUAGE, extra);
@@ -63,13 +69,68 @@
     /**
      * Returns foreign language detection information contained in the TextClassification object.
      * responses.
+     *
+     * @see #putForeignLanguageExtra(Bundle, Bundle)
      */
     @Nullable
-    public static Bundle getForeignLanguageExtra(TextClassification classification) {
+    public static Bundle getForeignLanguageExtra(@Nullable TextClassification classification) {
+        if (classification == null) {
+            return null;
+        }
         return classification.getExtras().getBundle(FOREIGN_LANGUAGE);
     }
 
     /**
+     * @see #getTopLanguage(Intent)
+     */
+    static void putTopLanguageScores(Bundle container, EntityConfidence languageScores) {
+        final int maxSize = Math.min(3, languageScores.getEntities().size());
+        final String[] languages = languageScores.getEntities().subList(0, maxSize)
+                .toArray(new String[0]);
+        final float[] scores = new float[languages.length];
+        for (int i = 0; i < languages.length; i++) {
+            scores[i] = languageScores.getConfidenceScore(languages[i]);
+        }
+        container.putStringArray(ENTITY_TYPE, languages);
+        container.putFloatArray(SCORE, scores);
+    }
+
+    /**
+     * @see #putTopLanguageScores(Bundle, EntityConfidence)
+     */
+    @Nullable
+    public static ULocale getTopLanguage(@Nullable Intent intent) {
+        if (intent == null) {
+            return null;
+        }
+        final Bundle tcBundle = intent.getBundleExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER);
+        if (tcBundle == null) {
+            return null;
+        }
+        final Bundle textLanguagesExtra = tcBundle.getBundle(TEXT_LANGUAGES);
+        if (textLanguagesExtra == null) {
+            return null;
+        }
+        final String[] languages = textLanguagesExtra.getStringArray(ENTITY_TYPE);
+        final float[] scores = textLanguagesExtra.getFloatArray(SCORE);
+        if (languages == null || scores == null
+                || languages.length == 0 || languages.length != scores.length) {
+            return null;
+        }
+        int highestScoringIndex = 0;
+        for (int i = 1; i < languages.length; i++) {
+            if (scores[highestScoringIndex] < scores[i]) {
+                highestScoringIndex = i;
+            }
+        }
+        return ULocale.forLanguageTag(languages[highestScoringIndex]);
+    }
+
+    public static void putTextLanguagesExtra(Bundle container, Bundle extra) {
+        container.putBundle(TEXT_LANGUAGES, extra);
+    }
+
+    /**
      * Stores {@code actionIntents} information in TextClassifier response object's extras
      * {@code container}.
      */
@@ -94,10 +155,37 @@
     }
 
     /**
+     * Stores {@code entities} information in TextClassifier response object's extras
+     * {@code container}.
+     *
+     * @see {@link #getCopyText(Bundle)}
+     */
+    public static void putEntitiesExtras(Bundle container, @Nullable Bundle entitiesExtras) {
+        container.putParcelable(ENTITIES_EXTRAS, entitiesExtras);
+    }
+
+    /**
+     * Returns {@code entities} information contained in a TextClassifier response object.
+     *
+     * @see {@link #putEntitiesExtras(Bundle, Bundle)}
+     */
+    @Nullable
+    public static String getCopyText(Bundle container) {
+        Bundle entitiesExtras = container.getParcelable(ENTITIES_EXTRAS);
+        if (entitiesExtras == null) {
+            return null;
+        }
+        return entitiesExtras.getString("text");
+    }
+
+    /**
      * Returns {@code actionIntents} information contained in the TextClassification object.
      */
     @Nullable
-    public static ArrayList<Intent> getActionsIntents(TextClassification classification) {
+    public static ArrayList<Intent> getActionsIntents(@Nullable TextClassification classification) {
+        if (classification == null) {
+            return null;
+        }
         return classification.getExtras().getParcelableArrayList(ACTIONS_INTENTS);
     }
 
@@ -106,7 +194,11 @@
      * action string, {@code intentAction}.
      */
     @Nullable
-    public static RemoteAction findAction(TextClassification classification, String intentAction) {
+    public static RemoteAction findAction(
+            @Nullable TextClassification classification, @Nullable String intentAction) {
+        if (classification == null || intentAction == null) {
+            return null;
+        }
         final ArrayList<Intent> actionIntents = getActionsIntents(classification);
         if (actionIntents != null) {
             final int size = actionIntents.size();
@@ -124,7 +216,7 @@
      * Returns the first "translate" action found in the {@code classification} object.
      */
     @Nullable
-    public static RemoteAction findTranslateAction(TextClassification classification) {
+    public static RemoteAction findTranslateAction(@Nullable TextClassification classification) {
         return findAction(classification, Intent.ACTION_TRANSLATE);
     }
 
@@ -132,7 +224,10 @@
      * Returns the entity type contained in the {@code extra}.
      */
     @Nullable
-    public static String getEntityType(Bundle extra) {
+    public static String getEntityType(@Nullable Bundle extra) {
+        if (extra == null) {
+            return null;
+        }
         return extra.getString(ENTITY_TYPE);
     }
 
@@ -141,14 +236,21 @@
      */
     @Nullable
     public static float getScore(Bundle extra) {
-        return extra.getFloat(SCORE, -1);
+        final int defaultValue = -1;
+        if (extra == null) {
+            return defaultValue;
+        }
+        return extra.getFloat(SCORE, defaultValue);
     }
 
     /**
      * Returns the model name contained in the {@code extra}.
      */
     @Nullable
-    public static String getModelName(Bundle extra) {
+    public static String getModelName(@Nullable Bundle extra) {
+        if (extra == null) {
+            return null;
+        }
         return extra.getString(MODEL_NAME);
     }
 }
diff --git a/core/java/android/view/textclassifier/Log.java b/core/java/android/view/textclassifier/Log.java
index 5c60c09..03ed496 100644
--- a/core/java/android/view/textclassifier/Log.java
+++ b/core/java/android/view/textclassifier/Log.java
@@ -22,8 +22,10 @@
  * To enable full log:
  * 1. adb shell setprop log.tag.androidtc VERBOSE
  * 2. adb shell stop && adb shell start
+ *
+ * @hide
  */
-final class Log {
+public final class Log {
 
     /**
      * true: Enables full logging.
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index 125b0d3..876e5cc 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -48,6 +48,9 @@
  * notification_conversation_action_types_default   (String[])
  * lang_id_threshold_override                       (float)
  * template_intent_factory_enabled                  (boolean)
+ * translate_in_classification_enabled              (boolean)
+ * detect_languages_from_text_enabled               (boolean)
+ * lang_id_context_settings                         (float[])
  * </pre>
  *
  * <p>
@@ -56,12 +59,14 @@
  *
  * Example of setting the values for testing.
  * adb shell settings put global text_classifier_constants \
- *      model_dark_launch_enabled=true,smart_selection_enabled=true,\
- *      entity_list_default=phone:address
+ *      model_dark_launch_enabled=true,smart_selection_enabled=true, \
+ *      entity_list_default=phone:address, \
+ *      lang_id_context_settings=20:1.0:0.4
  * @hide
  */
 public final class TextClassificationConstants {
-    private static final String LOG_TAG = "TextClassificationConstants";
+
+    private static final String LOG_TAG = TextClassifier.DEFAULT_LOG_TAG;
 
     /**
      * Whether the smart linkify feature is enabled.
@@ -139,13 +144,38 @@
     private static final String NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT =
             "notification_conversation_action_types_default";
     /**
-     * Threshold in classifyText to consider a text is in a foreign language.
+     * Threshold to accept a suggested language from LangID model.
      */
     private static final String LANG_ID_THRESHOLD_OVERRIDE = "lang_id_threshold_override";
     /**
      * Whether to enable {@link android.view.textclassifier.TemplateIntentFactory}.
      */
     private static final String TEMPLATE_INTENT_FACTORY_ENABLED = "template_intent_factory_enabled";
+    /**
+     * Whether to enable "translate" action in classifyText.
+     */
+    private static final String TRANSLATE_IN_CLASSIFICATION_ENABLED =
+            "translate_in_classification_enabled";
+    /**
+     * Whether to detect the languages of the text in request by using langId for the native
+     * model.
+     */
+    private static final String DETECT_LANGUAGES_FROM_TEXT_ENABLED =
+            "detect_languages_from_text_enabled";
+    /**
+     * A colon(:) separated string that specifies the configuration to use when including
+     * surrounding context text in language detection queries.
+     * <p>
+     * Format= minimumTextSize<int>:penalizeRatio<float>:textScoreRatio<float>
+     * <p>
+     * e.g. 20:1.0:0.4
+     * <p>
+     * Accept all text lengths with minimumTextSize=0
+     * <p>
+     * Reject all text less than minimumTextSize with penalizeRatio=0
+     * @see {@code TextClassifierImpl#detectLanguages(String, int, int)} for reference.
+     */
+    private static final String LANG_ID_CONTEXT_SETTINGS = "lang_id_context_settings";
 
     private static final boolean LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
     private static final boolean SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
@@ -179,15 +209,20 @@
                     .add(ConversationAction.TYPE_VIEW_CALENDAR)
                     .add(ConversationAction.TYPE_VIEW_MAP)
                     .add(ConversationAction.TYPE_ADD_CONTACT)
+                    .add(ConversationAction.TYPE_COPY)
                     .toString();
     /**
      * < 0  : Not set. Use value from LangId model.
      * 0 - 1: Override value in LangId model.
-     * > 1  : Effectively turns off the foreign language detection. Scores should never be > 1.
+     *
      * @see EntityConfidence
      */
     private static final float LANG_ID_THRESHOLD_OVERRIDE_DEFAULT = -1f;
     private static final boolean TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT = true;
+    private static final boolean TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT = true;
+    private static final boolean DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT = true;
+    private static final String LANG_ID_CONTEXT_SETTINGS_DEFAULT =
+            new StringJoiner(STRING_LIST_DELIMITER).add("20").add("1.0").add("0.4").toString();
 
     private final boolean mSystemTextClassifierEnabled;
     private final boolean mLocalTextClassifierEnabled;
@@ -207,6 +242,9 @@
     private final List<String> mNotificationConversationActionTypesDefault;
     private final float mLangIdThresholdOverride;
     private final boolean mTemplateIntentFactoryEnabled;
+    private final boolean mTranslateInClassificationEnabled;
+    private final boolean mDetectLanguagesFromTextEnabled;
+    private final float[] mLangIdContextSettings;
 
     private TextClassificationConstants(@Nullable String settings) {
         ConfigParser configParser = new ConfigParser(settings);
@@ -254,9 +292,10 @@
                 configParser.getInt(
                         GENERATE_LINKS_LOG_SAMPLE_RATE,
                         GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT);
-        mEntityListDefault = parseStringList(configParser.getString(
-                ENTITY_LIST_DEFAULT,
-                ENTITY_LIST_DEFAULT_VALUE));
+        mEntityListDefault = parseStringList(
+                configParser.getString(
+                        ENTITY_LIST_DEFAULT,
+                        ENTITY_LIST_DEFAULT_VALUE));
         mEntityListNotEditable = parseStringList(
                 configParser.getString(
                         ENTITY_LIST_NOT_EDITABLE,
@@ -277,9 +316,22 @@
                 configParser.getFloat(
                         LANG_ID_THRESHOLD_OVERRIDE,
                         LANG_ID_THRESHOLD_OVERRIDE_DEFAULT);
-        mTemplateIntentFactoryEnabled = configParser.getBoolean(
-                TEMPLATE_INTENT_FACTORY_ENABLED,
-                TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT);
+        mTemplateIntentFactoryEnabled =
+                configParser.getBoolean(
+                        TEMPLATE_INTENT_FACTORY_ENABLED,
+                        TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT);
+        mTranslateInClassificationEnabled =
+                configParser.getBoolean(
+                        TRANSLATE_IN_CLASSIFICATION_ENABLED,
+                        TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT);
+        mDetectLanguagesFromTextEnabled =
+                configParser.getBoolean(
+                        DETECT_LANGUAGES_FROM_TEXT_ENABLED,
+                        DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT);
+        mLangIdContextSettings = parseFloatArray(
+                configParser,
+                LANG_ID_CONTEXT_SETTINGS,
+                LANG_ID_CONTEXT_SETTINGS_DEFAULT);
     }
 
     /** Load from a settings string. */
@@ -359,10 +411,43 @@
         return mTemplateIntentFactoryEnabled;
     }
 
+    public boolean isTranslateInClassificationEnabled() {
+        return mTranslateInClassificationEnabled;
+    }
+
+    public boolean isDetectLanguagesFromTextEnabled() {
+        return mDetectLanguagesFromTextEnabled;
+    }
+
+    public float[] getLangIdContextSettings() {
+        return mLangIdContextSettings;
+    }
+
     private static List<String> parseStringList(String listStr) {
         return Collections.unmodifiableList(Arrays.asList(listStr.split(STRING_LIST_DELIMITER)));
     }
 
+    private static float[] parseFloatArray(
+            ConfigParser configParser, String key, String defaultStr) {
+        final String str = configParser.getString(key, defaultStr);
+        final String[] defaultSplit = defaultStr.split(STRING_LIST_DELIMITER);
+        String[] split = str.split(STRING_LIST_DELIMITER);
+        if (split.length != defaultSplit.length) {
+            Log.v(LOG_TAG, "Error parsing " + key + " flag. Using defaults.");
+            split = defaultSplit;
+        }
+        final float[] result = new float[split.length];
+        for (int i = 0; i < split.length; i++) {
+            try {
+                result[i] = Float.parseFloat(split[i]);
+            } catch (NumberFormatException e) {
+                Log.v(LOG_TAG, "Error parsing part of " + key + " flag. Using defaults.");
+                result[i] = Float.parseFloat(defaultSplit[i]);
+            }
+        }
+        return result;
+    }
+
     void dump(IndentingPrintWriter pw) {
         pw.println("TextClassificationConstants:");
         pw.increaseIndent();
@@ -385,6 +470,9 @@
                 mNotificationConversationActionTypesDefault);
         pw.printPair("getLangIdThresholdOverride", mLangIdThresholdOverride);
         pw.printPair("isTemplateIntentFactoryEnabled", mTemplateIntentFactoryEnabled);
+        pw.printPair("isTranslateInClassificationEnabled", mTranslateInClassificationEnabled);
+        pw.printPair("isDetectLanguageFromTextEnabled", mDetectLanguagesFromTextEnabled);
+        pw.printPair("getLangIdContextSettings", Arrays.toString(mLangIdContextSettings));
         pw.decreaseIndent();
         pw.println();
     }
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index a4e5502..ac8a429 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -33,11 +33,13 @@
 import android.text.util.Linkify.LinkifyMask;
 import android.util.ArrayMap;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.text.BreakIterator;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -644,11 +646,14 @@
      *  <li>Provides validation of input parameters to TextClassifier methods
      * </ul>
      *
-     * Intended to be used only in this package.
+     * Intended to be used only for TextClassifier purposes.
      * @hide
      */
     final class Utils {
 
+        @GuardedBy("WORD_ITERATOR")
+        private static final BreakIterator WORD_ITERATOR = BreakIterator.getWordInstance();
+
         /**
          * @throws IllegalArgumentException if text is null; startIndex is negative;
          *      endIndex is greater than text.length() or is not greater than startIndex;
@@ -666,6 +671,47 @@
         }
 
         /**
+         * Returns the substring of {@code text} that contains at least text from index
+         * {@code start} <i>(inclusive)</i> to index {@code end} <i><(exclusive)/i> with the goal of
+         * returning text that is at least {@code minimumLength}. If {@code text} is not long
+         * enough, this will return {@code text}. This method returns text at word boundaries.
+         *
+         * @param text the source text
+         * @param start the start index of text that must be included
+         * @param end the end index of text that must be included
+         * @param minimumLength minimum length of text to return if {@code text} is long enough
+         */
+        public static String getSubString(
+                String text, int start, int end, int minimumLength) {
+            Preconditions.checkArgument(start >= 0);
+            Preconditions.checkArgument(end <= text.length());
+            Preconditions.checkArgument(start <= end);
+
+            if (text.length() < minimumLength) {
+                return text;
+            }
+
+            final int length = end - start;
+            if (length >= minimumLength) {
+                return text.substring(start, end);
+            }
+
+            final int offset = (minimumLength - length) / 2;
+            int iterStart = Math.max(0, Math.min(start - offset, text.length() - minimumLength));
+            int iterEnd = Math.min(text.length(), iterStart + minimumLength);
+
+            synchronized (WORD_ITERATOR) {
+                WORD_ITERATOR.setText(text);
+                iterStart = WORD_ITERATOR.isBoundary(iterStart)
+                        ? iterStart : Math.max(0, WORD_ITERATOR.preceding(iterStart));
+                iterEnd = WORD_ITERATOR.isBoundary(iterEnd)
+                        ? iterEnd : Math.max(iterEnd, WORD_ITERATOR.following(iterEnd));
+                WORD_ITERATOR.setText("");
+                return text.substring(iterStart, iterEnd);
+            }
+        }
+
+        /**
          * Generates links using legacy {@link Linkify}.
          */
         public static TextLinks generateLegacyLinks(@NonNull TextLinks.Request request) {
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 35cd678..8f5f0a37 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -21,10 +21,19 @@
 import android.annotation.WorkerThread;
 import android.app.RemoteAction;
 import android.content.Context;
+import android.content.Intent;
 import android.icu.util.ULocale;
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.ParcelFileDescriptor;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Pair;
+import android.view.textclassifier.intent.ClassificationIntentFactory;
+import android.view.textclassifier.intent.LabeledIntent;
+import android.view.textclassifier.intent.LegacyClassificationIntentFactory;
+import android.view.textclassifier.intent.TemplateClassificationIntentFactory;
+import android.view.textclassifier.intent.TemplateIntentFactory;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
@@ -33,6 +42,7 @@
 import com.google.android.textclassifier.ActionsSuggestionsModel;
 import com.google.android.textclassifier.AnnotatorModel;
 import com.google.android.textclassifier.LangIdModel;
+import com.google.android.textclassifier.LangIdModel.LanguageResult;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -41,11 +51,12 @@
 import java.time.ZonedDateTime;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
+import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Default implementation of the {@link TextClassifier} interface.
@@ -85,19 +96,19 @@
 
     private final Object mLock = new Object();
 
-    @GuardedBy("mLock") // Do not access outside this lock.
+    @GuardedBy("mLock")
     private ModelFileManager.ModelFile mAnnotatorModelInUse;
-    @GuardedBy("mLock") // Do not access outside this lock.
+    @GuardedBy("mLock")
     private AnnotatorModel mAnnotatorImpl;
 
-    @GuardedBy("mLock") // Do not access outside this lock.
+    @GuardedBy("mLock")
     private ModelFileManager.ModelFile mLangIdModelInUse;
-    @GuardedBy("mLock") // Do not access outside this lock.
+    @GuardedBy("mLock")
     private LangIdModel mLangIdImpl;
 
-    @GuardedBy("mLock") // Do not access outside this lock.
+    @GuardedBy("mLock")
     private ModelFileManager.ModelFile mActionModelInUse;
-    @GuardedBy("mLock") // Do not access outside this lock.
+    @GuardedBy("mLock")
     private ActionsSuggestionsModel mActionsImpl;
 
     private final SelectionSessionLogger mSessionLogger = new SelectionSessionLogger();
@@ -110,7 +121,7 @@
     private final ModelFileManager mLangIdModelFileManager;
     private final ModelFileManager mActionsModelFileManager;
 
-    private final IntentFactory mIntentFactory;
+    private final ClassificationIntentFactory mClassificationIntentFactory;
     private final TemplateIntentFactory mTemplateIntentFactory;
 
     public TextClassifierImpl(
@@ -142,10 +153,10 @@
                         ActionsSuggestionsModel::getLocales));
 
         mTemplateIntentFactory = new TemplateIntentFactory();
-        mIntentFactory = mSettings.isTemplateIntentFactoryEnabled()
+        mClassificationIntentFactory = mSettings.isTemplateIntentFactoryEnabled()
                 ? new TemplateClassificationIntentFactory(
-                mTemplateIntentFactory, new LegacyIntentFactory())
-                : new LegacyIntentFactory();
+                mTemplateIntentFactory, new LegacyClassificationIntentFactory())
+                : new LegacyClassificationIntentFactory();
     }
 
     public TextClassifierImpl(Context context, TextClassificationConstants settings) {
@@ -164,6 +175,7 @@
             if (string.length() > 0
                     && rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) {
                 final String localesString = concatenateLocales(request.getDefaultLocales());
+                final String detectLanguageTags = detectLanguageTagsFromText(request.getText());
                 final ZonedDateTime refTime = ZonedDateTime.now();
                 final AnnotatorModel annotatorImpl =
                         getAnnotatorImpl(request.getDefaultLocales());
@@ -175,7 +187,7 @@
                 } else {
                     final int[] startEnd = annotatorImpl.suggestSelection(
                             string, request.getStartIndex(), request.getEndIndex(),
-                            new AnnotatorModel.SelectionOptions(localesString));
+                            new AnnotatorModel.SelectionOptions(localesString, detectLanguageTags));
                     start = startEnd[0];
                     end = startEnd[1];
                 }
@@ -189,7 +201,8 @@
                                     new AnnotatorModel.ClassificationOptions(
                                             refTime.toInstant().toEpochMilli(),
                                             refTime.getZone().getId(),
-                                            localesString),
+                                            localesString,
+                                            detectLanguageTags),
                                     // Passing null here to suppress intent generation
                                     // TODO: Use an explicit flag to suppress it.
                                     /* appContext */ null,
@@ -227,6 +240,7 @@
             final String string = request.getText().toString();
             if (string.length() > 0 && rangeLength <= mSettings.getClassifyTextMaxRangeLength()) {
                 final String localesString = concatenateLocales(request.getDefaultLocales());
+                final String detectLanguageTags = detectLanguageTagsFromText(request.getText());
                 final ZonedDateTime refTime = request.getReferenceTime() != null
                         ? request.getReferenceTime() : ZonedDateTime.now();
                 final AnnotatorModel.ClassificationResult[] results =
@@ -236,9 +250,10 @@
                                         new AnnotatorModel.ClassificationOptions(
                                                 refTime.toInstant().toEpochMilli(),
                                                 refTime.getZone().getId(),
-                                                localesString),
+                                                localesString,
+                                                detectLanguageTags),
                                         mContext,
-                                        getResourceLocaleString()
+                                        getResourceLocalesString()
                                 );
                 if (results.length > 0) {
                     return createClassificationResult(
@@ -274,8 +289,10 @@
             final ZonedDateTime refTime = ZonedDateTime.now();
             final Collection<String> entitiesToIdentify = request.getEntityConfig() != null
                     ? request.getEntityConfig().resolveEntityListModifications(
-                    getEntitiesForHints(request.getEntityConfig().getHints()))
+                            getEntitiesForHints(request.getEntityConfig().getHints()))
                     : mSettings.getEntityListDefault();
+            final String localesString = concatenateLocales(request.getDefaultLocales());
+            final String detectLanguageTags = detectLanguageTagsFromText(request.getText());
             final AnnotatorModel annotatorImpl =
                     getAnnotatorImpl(request.getDefaultLocales());
             final AnnotatorModel.AnnotatedSpan[] annotations =
@@ -284,7 +301,8 @@
                             new AnnotatorModel.AnnotationOptions(
                                     refTime.toInstant().toEpochMilli(),
                                     refTime.getZone().getId(),
-                                    concatenateLocales(request.getDefaultLocales())));
+                                    localesString,
+                                    detectLanguageTags));
             for (AnnotatorModel.AnnotatedSpan span : annotations) {
                 final AnnotatorModel.ClassificationResult[] results =
                         span.getClassification();
@@ -292,7 +310,7 @@
                         || !entitiesToIdentify.contains(results[0].getCollection())) {
                     continue;
                 }
-                final Map<String, Float> entityScores = new HashMap<>();
+                final Map<String, Float> entityScores = new ArrayMap<>();
                 for (int i = 0; i < results.length; i++) {
                     entityScores.put(results[i].getCollection(), results[i].getScore());
                 }
@@ -386,8 +404,8 @@
                 return mFallback.suggestConversationActions(request);
             }
             ActionsSuggestionsModel.ConversationMessage[] nativeMessages =
-                    ActionsSuggestionsHelper.toNativeMessages(request.getConversation(),
-                            this::detectLanguageTagsFromText);
+                    ActionsSuggestionsHelper.toNativeMessages(
+                            request.getConversation(), this::detectLanguageTagsFromText);
             if (nativeMessages.length == 0) {
                 return mFallback.suggestConversationActions(request);
             }
@@ -399,7 +417,7 @@
                             nativeConversation,
                             null,
                             mContext,
-                            getResourceLocaleString());
+                            getResourceLocalesString());
             return createConversationActionResult(request, nativeSuggestions);
         } catch (Throwable t) {
             // Avoid throwing from this method. Log the error.
@@ -428,21 +446,20 @@
             if (!expectedTypes.contains(actionType)) {
                 continue;
             }
-            List<LabeledIntent> labeledIntents =
-                    mTemplateIntentFactory.create(nativeSuggestion.getRemoteActionTemplates());
-            Bundle extras = new Bundle();
+            LabeledIntent.Result labeledIntentResult =
+                    ActionsSuggestionsHelper.createLabeledIntentResult(
+                            mContext,
+                            mTemplateIntentFactory,
+                            nativeSuggestion);
             RemoteAction remoteAction = null;
-            // Given that we only support implicit intent here, we should expect there is just one
-            // intent for each action type.
-            if (!labeledIntents.isEmpty()) {
-                LabeledIntent.TitleChooser titleChooser =
-                        ActionsSuggestionsHelper.createTitleChooser(actionType);
-                LabeledIntent.Result result = labeledIntents.get(0).resolve(mContext, titleChooser);
-                if (result != null) {
-                    remoteAction = result.remoteAction;
-                    ExtrasUtils.putActionIntent(extras, result.resolvedIntent);
-                }
+            Bundle extras = new Bundle();
+            if (labeledIntentResult != null) {
+                remoteAction = labeledIntentResult.remoteAction;
+                ExtrasUtils.putActionIntent(extras, labeledIntentResult.resolvedIntent);
             }
+            ExtrasUtils.putEntitiesExtras(
+                    extras,
+                    TemplateIntentFactory.nameVariantsToBundle(nativeSuggestion.getEntityData()));
             conversationActions.add(
                     new ConversationAction.Builder(actionType)
                             .setConfidenceScore(nativeSuggestion.getScore())
@@ -463,19 +480,28 @@
 
     @Nullable
     private String detectLanguageTagsFromText(CharSequence text) {
+        if (!mSettings.isDetectLanguagesFromTextEnabled()) {
+            return null;
+        }
+        final float threshold = getLangIdThreshold();
+        if (threshold < 0 || threshold > 1) {
+            Log.w(LOG_TAG,
+                    "[detectLanguageTagsFromText] unexpected threshold is found: " + threshold);
+            return null;
+        }
         TextLanguage.Request request = new TextLanguage.Request.Builder(text).build();
         TextLanguage textLanguage = detectLanguage(request);
         int localeHypothesisCount = textLanguage.getLocaleHypothesisCount();
         List<String> languageTags = new ArrayList<>();
         for (int i = 0; i < localeHypothesisCount; i++) {
             ULocale locale = textLanguage.getLocale(i);
-            if (textLanguage.getConfidenceScore(locale) < getForeignLanguageThreshold()) {
+            if (textLanguage.getConfidenceScore(locale) < threshold) {
                 break;
             }
             languageTags.add(locale.toLanguageTag());
         }
         if (languageTags.isEmpty()) {
-            return LocaleList.getDefault().toLanguageTags();
+            return null;
         }
         return String.join(",", languageTags);
     }
@@ -600,97 +626,194 @@
             }
         }
 
-        final Bundle foreignLanguageBundle = detectForeignLanguage(classifiedText);
+        final Pair<Bundle, Bundle> languagesBundles = generateLanguageBundles(text, start, end);
+        final Bundle textLanguagesBundle = languagesBundles.first;
+        final Bundle foreignLanguageBundle = languagesBundles.second;
         builder.setForeignLanguageExtra(foreignLanguageBundle);
 
         boolean isPrimaryAction = true;
-        List<LabeledIntent> labeledIntents = mIntentFactory.create(
+        final List<LabeledIntent> labeledIntents = mClassificationIntentFactory.create(
                 mContext,
                 classifiedText,
                 foreignLanguageBundle != null,
                 referenceTime,
                 highestScoringResult);
-        LabeledIntent.TitleChooser titleChooser =
+        final LabeledIntent.TitleChooser titleChooser =
                 (labeledIntent, resolveInfo) -> labeledIntent.titleWithoutEntity;
+
         for (LabeledIntent labeledIntent : labeledIntents) {
-            LabeledIntent.Result result = labeledIntent.resolve(mContext, titleChooser);
+            final LabeledIntent.Result result =
+                    labeledIntent.resolve(mContext, titleChooser, textLanguagesBundle);
             if (result == null) {
                 continue;
             }
+
+            final Intent intent = result.resolvedIntent;
             final RemoteAction action = result.remoteAction;
             if (isPrimaryAction) {
                 // For O backwards compatibility, the first RemoteAction is also written to the
                 // legacy API fields.
                 builder.setIcon(action.getIcon().loadDrawable(mContext));
                 builder.setLabel(action.getTitle().toString());
-                builder.setIntent(result.resolvedIntent);
+                builder.setIntent(intent);
                 builder.setOnClickListener(TextClassification.createIntentOnClickListener(
-                        TextClassification.createPendingIntent(mContext,
-                                result.resolvedIntent, labeledIntent.requestCode)));
+                        TextClassification.createPendingIntent(
+                                mContext, intent, labeledIntent.requestCode)));
                 isPrimaryAction = false;
             }
-            builder.addAction(action, result.resolvedIntent);
+            builder.addAction(action, intent);
         }
 
         return builder.setId(createId(text, start, end)).build();
     }
 
     /**
-     * Returns a bundle with the language and confidence score if it finds the text to be
-     * in a foreign language. Otherwise returns null. This algorithm defines what the system thinks
-     * is a foreign language.
+     * Returns a bundle pair with language detection information for extras.
+     * <p>
+     * Pair.first = textLanguagesBundle - A bundle containing information about all detected
+     * languages in the text. May be null if language detection fails or is disabled. This is
+     * typically expected to be added to a textClassifier generated remote action intent.
+     * See {@link ExtrasUtils#putTextLanguagesExtra(Bundle, Bundle)}.
+     * See {@link ExtrasUtils#getTopLanguage(Intent)}.
+     * <p>
+     * Pair.second = foreignLanguageBundle - A bundle with the language and confidence score if the
+     * system finds the text to be in a foreign language. Otherwise is null.
+     * See {@link TextClassification.Builder#setForeignLanguageExtra(Bundle)}.
+     *
+     * @param context the context of the text to detect languages for
+     * @param start the start index of the text
+     * @param end the end index of the text
      */
     // TODO: Revisit this algorithm.
     // TODO: Consider making this public API.
-    @Nullable
-    private Bundle detectForeignLanguage(String text) {
+    private Pair<Bundle, Bundle> generateLanguageBundles(String context, int start, int end) {
+        if (!mSettings.isTranslateInClassificationEnabled()) {
+            return null;
+        }
         try {
-            final float threshold = getForeignLanguageThreshold();
-            if (threshold > 1) {
-                Log.v(LOG_TAG, "Foreign language detection disabled.");
-                return null;
+            final float threshold = getLangIdThreshold();
+            if (threshold < 0 || threshold > 1) {
+                Log.w(LOG_TAG,
+                        "[detectForeignLanguage] unexpected threshold is found: " + threshold);
+                return Pair.create(null, null);
             }
 
-            final LangIdModel langId = getLangIdImpl();
-            final LangIdModel.LanguageResult[] langResults = langId.detectLanguages(text);
-            if (langResults.length <= 0) {
-                return null;
+            final EntityConfidence languageScores = detectLanguages(context, start, end);
+            if (languageScores.getEntities().isEmpty()) {
+                return Pair.create(null, null);
             }
 
-            LangIdModel.LanguageResult highestScoringResult = langResults[0];
-            for (int i = 1; i < langResults.length; i++) {
-                if (langResults[i].getScore() > highestScoringResult.getScore()) {
-                    highestScoringResult = langResults[i];
-                }
-            }
-            if (highestScoringResult.getScore() < threshold) {
-                return null;
+            final Bundle textLanguagesBundle = new Bundle();
+            ExtrasUtils.putTopLanguageScores(textLanguagesBundle, languageScores);
+
+            final String language = languageScores.getEntities().get(0);
+            final float score = languageScores.getConfidenceScore(language);
+            if (score < threshold) {
+                return Pair.create(textLanguagesBundle, null);
             }
 
-            Log.v(LOG_TAG, String.format("Language detected: <%s:%s>",
-                    highestScoringResult.getLanguage(), highestScoringResult.getScore()));
+            Log.v(LOG_TAG, String.format(
+                    Locale.US, "Language detected: <%s:%.2f>", language, score));
 
-            final Locale detected = new Locale(highestScoringResult.getLanguage());
+            final Locale detected = new Locale(language);
             final LocaleList deviceLocales = LocaleList.getDefault();
             final int size = deviceLocales.size();
             for (int i = 0; i < size; i++) {
                 if (deviceLocales.get(i).getLanguage().equals(detected.getLanguage())) {
-                    return null;
+                    return Pair.create(textLanguagesBundle, null);
                 }
             }
-            return ExtrasUtils.createForeignLanguageExtra(
-                    detected.getLanguage(), highestScoringResult.getScore(), langId.getVersion());
+            final Bundle foreignLanguageBundle = ExtrasUtils.createForeignLanguageExtra(
+                    detected.getLanguage(), score, getLangIdImpl().getVersion());
+            return Pair.create(textLanguagesBundle, foreignLanguageBundle);
         } catch (Throwable t) {
-            Log.e(LOG_TAG, "Error detecting foreign text. Ignored.", t);
+            Log.e(LOG_TAG, "Error generating language bundles.", t);
         }
-        return null;
+        return Pair.create(null, null);
     }
 
-    private float getForeignLanguageThreshold() {
+    /**
+     * Detect the language of a piece of text by taking surrounding text into consideration.
+     *
+     * @param text text providing context for the text for which its language is to be detected
+     * @param start the start index of the text to detect its language
+     * @param end the end index of the text to detect its language
+     */
+    // TODO: Revisit this algorithm.
+    private EntityConfidence detectLanguages(String text, int start, int end)
+            throws FileNotFoundException {
+        Preconditions.checkArgument(start >= 0);
+        Preconditions.checkArgument(end <= text.length());
+        Preconditions.checkArgument(start <= end);
+
+        final float[] langIdContextSettings = mSettings.getLangIdContextSettings();
+        // The minimum size of text to prefer for detection.
+        final int minimumTextSize = (int) langIdContextSettings[0];
+        // For reducing the score when text is less than the preferred size.
+        final float penalizeRatio = langIdContextSettings[1];
+        // Original detection score to surrounding text detection score ratios.
+        final float subjectTextScoreRatio = langIdContextSettings[2];
+        final float moreTextScoreRatio = 1f - subjectTextScoreRatio;
+        Log.v(LOG_TAG,
+                String.format(Locale.US, "LangIdContextSettings: "
+                        + "minimumTextSize=%d, penalizeRatio=%.2f, "
+                        + "subjectTextScoreRatio=%.2f, moreTextScoreRatio=%.2f",
+                        minimumTextSize, penalizeRatio, subjectTextScoreRatio, moreTextScoreRatio));
+
+        if (end - start < minimumTextSize && penalizeRatio <= 0) {
+            return new EntityConfidence(Collections.emptyMap());
+        }
+
+        final String subject = text.substring(start, end);
+        final EntityConfidence scores = detectLanguages(subject);
+
+        if (subject.length() >= minimumTextSize
+                || subject.length() == text.length()
+                || subjectTextScoreRatio * penalizeRatio >= 1) {
+            return scores;
+        }
+
+        final EntityConfidence moreTextScores;
+        if (moreTextScoreRatio >= 0) {
+            // Attempt to grow the detection text to be at least minimumTextSize long.
+            final String moreText = Utils.getSubString(text, start, end, minimumTextSize);
+            moreTextScores = detectLanguages(moreText);
+        } else {
+            moreTextScores = new EntityConfidence(Collections.emptyMap());
+        }
+
+        // Combine the original detection scores with the those returned after including more text.
+        final Map<String, Float> newScores = new ArrayMap<>();
+        final Set<String> languages = new ArraySet<>();
+        languages.addAll(scores.getEntities());
+        languages.addAll(moreTextScores.getEntities());
+        for (String language : languages) {
+            final float score = (subjectTextScoreRatio * scores.getConfidenceScore(language)
+                    + moreTextScoreRatio * moreTextScores.getConfidenceScore(language))
+                    * penalizeRatio;
+            newScores.put(language, score);
+        }
+        return new EntityConfidence(newScores);
+    }
+
+    /**
+     * Detect languages for the specified text.
+     */
+    private EntityConfidence detectLanguages(String text) throws FileNotFoundException {
+        final LangIdModel langId = getLangIdImpl();
+        final LangIdModel.LanguageResult[] langResults = langId.detectLanguages(text);
+        final Map<String, Float> languagesMap = new ArrayMap<>();
+        for (LanguageResult langResult : langResults) {
+            languagesMap.put(langResult.getLanguage(), langResult.getScore());
+        }
+        return new EntityConfidence(languagesMap);
+    }
+
+    private float getLangIdThreshold() {
         try {
             return mSettings.getLangIdThresholdOverride() >= 0
                     ? mSettings.getLangIdThresholdOverride()
-                    : getLangIdImpl().getTranslateThreshold();
+                    : getLangIdImpl().getLangIdThreshold();
         } catch (FileNotFoundException e) {
             final float defaultThreshold = 0.5f;
             Log.v(LOG_TAG, "Using default foreign language threshold: " + defaultThreshold);
@@ -746,15 +869,14 @@
     }
 
     /**
-     * Returns the locale string for the current resources configuration.
+     * Returns the locales string for the current resources configuration.
      */
-    private String getResourceLocaleString() {
-        // TODO: Pass the locale list once it is supported in native side.
+    private String getResourceLocalesString() {
         try {
-            return mContext.getResources().getConfiguration().getLocales().get(0).toLanguageTag();
+            return mContext.getResources().getConfiguration().getLocales().toLanguageTags();
         } catch (NullPointerException e) {
             // NPE is unexpected. Erring on the side of caution.
-            return LocaleList.getDefault().get(0).toLanguageTag();
+            return LocaleList.getDefault().toLanguageTags();
         }
     }
 }
diff --git a/core/java/android/view/textclassifier/IntentFactory.java b/core/java/android/view/textclassifier/intent/ClassificationIntentFactory.java
similarity index 89%
rename from core/java/android/view/textclassifier/IntentFactory.java
rename to core/java/android/view/textclassifier/intent/ClassificationIntentFactory.java
index 722c812..b034846 100644
--- a/core/java/android/view/textclassifier/IntentFactory.java
+++ b/core/java/android/view/textclassifier/intent/ClassificationIntentFactory.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
 
 import android.annotation.Nullable;
 import android.content.Context;
@@ -27,7 +27,7 @@
 /**
  * @hide
  */
-public interface IntentFactory {
+public interface ClassificationIntentFactory {
 
     /**
      * Return a list of LabeledIntent from the classification result.
@@ -51,8 +51,7 @@
                 new Intent(Intent.ACTION_TRANSLATE)
                         // TODO: Probably better to introduce a "translate" scheme instead of
                         // using EXTRA_TEXT.
-                        .putExtra(Intent.EXTRA_TEXT, text)
-                        .putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true),
+                        .putExtra(Intent.EXTRA_TEXT, text),
                 text.hashCode()));
     }
 }
diff --git a/core/java/android/view/textclassifier/LabeledIntent.java b/core/java/android/view/textclassifier/intent/LabeledIntent.java
similarity index 81%
rename from core/java/android/view/textclassifier/LabeledIntent.java
rename to core/java/android/view/textclassifier/intent/LabeledIntent.java
index d2897b2..11d64f1 100644
--- a/core/java/android/view/textclassifier/LabeledIntent.java
+++ b/core/java/android/view/textclassifier/intent/LabeledIntent.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
 
 import android.annotation.Nullable;
 import android.app.PendingIntent;
@@ -24,7 +24,12 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Icon;
+import android.os.Bundle;
 import android.text.TextUtils;
+import android.view.textclassifier.ExtrasUtils;
+import android.view.textclassifier.Log;
+import android.view.textclassifier.TextClassification;
+import android.view.textclassifier.TextClassifier;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
@@ -85,10 +90,16 @@
 
     /**
      * Return the resolved result.
+     *
+     * @param context the context to resolve the result's intent and action
+     * @param titleChooser for choosing an action title
+     * @param textLanguagesBundle containing language detection information
      */
     @Nullable
     public Result resolve(
-            Context context, @Nullable TitleChooser titleChooser) {
+            Context context,
+            @Nullable TitleChooser titleChooser,
+            @Nullable Bundle textLanguagesBundle) {
         final PackageManager pm = context.getPackageManager();
         final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
 
@@ -104,6 +115,10 @@
         }
         Intent resolvedIntent = new Intent(intent);
         resolvedIntent.setComponent(new ComponentName(packageName, className));
+        resolvedIntent.putExtra(
+                TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER,
+                getFromTextClassifierExtra(textLanguagesBundle));
+
         boolean shouldShowIcon = false;
         Icon icon = null;
         if (!"android".equals(packageName)) {
@@ -115,25 +130,32 @@
         }
         if (icon == null) {
             // RemoteAction requires that there be an icon.
-            icon = Icon.createWithResource("android",
-                    com.android.internal.R.drawable.ic_more_items);
+            icon = Icon.createWithResource(
+                    "android", com.android.internal.R.drawable.ic_more_items);
         }
         final PendingIntent pendingIntent =
                 TextClassification.createPendingIntent(context, resolvedIntent, requestCode);
-        if (titleChooser == null) {
-            titleChooser = DEFAULT_TITLE_CHOOSER;
-        }
+        titleChooser = titleChooser == null ? DEFAULT_TITLE_CHOOSER : titleChooser;
         CharSequence title = titleChooser.chooseTitle(this, resolveInfo);
         if (TextUtils.isEmpty(title)) {
             Log.w(TAG, "Custom titleChooser return null, fallback to the default titleChooser");
             title = DEFAULT_TITLE_CHOOSER.chooseTitle(this, resolveInfo);
         }
-        final RemoteAction action =
-                new RemoteAction(icon, title, description, pendingIntent);
+        final RemoteAction action = new RemoteAction(icon, title, description, pendingIntent);
         action.setShouldShowIcon(shouldShowIcon);
         return new Result(resolvedIntent, action);
     }
 
+    private Bundle getFromTextClassifierExtra(@Nullable Bundle textLanguagesBundle) {
+        if (textLanguagesBundle != null) {
+            final Bundle bundle = new Bundle();
+            ExtrasUtils.putTextLanguagesExtra(bundle, textLanguagesBundle);
+            return bundle;
+        } else {
+            return Bundle.EMPTY;
+        }
+    }
+
     /**
      * Data class that holds the result.
      */
diff --git a/core/java/android/view/textclassifier/LegacyIntentFactory.java b/core/java/android/view/textclassifier/intent/LegacyClassificationIntentFactory.java
similarity index 96%
rename from core/java/android/view/textclassifier/LegacyIntentFactory.java
rename to core/java/android/view/textclassifier/intent/LegacyClassificationIntentFactory.java
index ea9229d..7916791 100644
--- a/core/java/android/view/textclassifier/LegacyIntentFactory.java
+++ b/core/java/android/view/textclassifier/intent/LegacyClassificationIntentFactory.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
 
 import static java.time.temporal.ChronoUnit.MILLIS;
 
@@ -29,6 +29,8 @@
 import android.provider.Browser;
 import android.provider.CalendarContract;
 import android.provider.ContactsContract;
+import android.view.textclassifier.Log;
+import android.view.textclassifier.TextClassifier;
 
 import com.google.android.textclassifier.AnnotatorModel;
 
@@ -44,14 +46,12 @@
  * Creates intents based on the classification type.
  * @hide
  */
-public final class LegacyIntentFactory implements IntentFactory {
+public final class LegacyClassificationIntentFactory implements ClassificationIntentFactory {
 
-    private static final String TAG = "LegacyIntentFactory";
+    private static final String TAG = "LegacyClassificationIntentFactory";
     private static final long MIN_EVENT_FUTURE_MILLIS = TimeUnit.MINUTES.toMillis(5);
     private static final long DEFAULT_EVENT_DURATION = TimeUnit.HOURS.toMillis(1);
 
-    public LegacyIntentFactory() {}
-
     @NonNull
     @Override
     public List<LabeledIntent> create(Context context, String text, boolean foreignText,
@@ -96,10 +96,8 @@
                 break;
         }
         if (foreignText) {
-            IntentFactory.insertTranslateAction(actions, context, text);
+            ClassificationIntentFactory.insertTranslateAction(actions, context, text);
         }
-        actions.forEach(
-                action -> action.intent.putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true));
         return actions;
     }
 
diff --git a/core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java b/core/java/android/view/textclassifier/intent/TemplateClassificationIntentFactory.java
similarity index 82%
rename from core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java
rename to core/java/android/view/textclassifier/intent/TemplateClassificationIntentFactory.java
index ed0259f..111fc6a 100644
--- a/core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java
+++ b/core/java/android/view/textclassifier/intent/TemplateClassificationIntentFactory.java
@@ -13,14 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.view.textclassifier.Log;
+import android.view.textclassifier.TextClassifier;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 
 import com.google.android.textclassifier.AnnotatorModel;
@@ -36,19 +37,19 @@
  * @hide
  */
 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public final class TemplateClassificationIntentFactory implements IntentFactory {
+public final class TemplateClassificationIntentFactory implements ClassificationIntentFactory {
     private static final String TAG = TextClassifier.DEFAULT_LOG_TAG;
     private final TemplateIntentFactory mTemplateIntentFactory;
-    private final IntentFactory mFallback;
+    private final ClassificationIntentFactory mFallback;
 
     public TemplateClassificationIntentFactory(TemplateIntentFactory templateIntentFactory,
-            IntentFactory fallback) {
+            ClassificationIntentFactory fallback) {
         mTemplateIntentFactory = Preconditions.checkNotNull(templateIntentFactory);
         mFallback = Preconditions.checkNotNull(fallback);
     }
 
     /**
-     * Returns a list of {@link android.view.textclassifier.LabeledIntent}
+     * Returns a list of {@link LabeledIntent}
      * that are constructed from the classification result.
      */
     @NonNull
@@ -63,15 +64,16 @@
             return Collections.emptyList();
         }
         RemoteActionTemplate[] remoteActionTemplates = classification.getRemoteActionTemplates();
-        if (ArrayUtils.isEmpty(remoteActionTemplates)) {
+        if (remoteActionTemplates == null) {
             // RemoteActionTemplate is missing, fallback.
-            Log.w(TAG, "RemoteActionTemplate is missing, fallback to LegacyIntentFactory.");
+            Log.w(TAG, "RemoteActionTemplate is missing, fallback to"
+                    + " LegacyClassificationIntentFactory.");
             return mFallback.create(context, text, foreignText, referenceTime, classification);
         }
         final List<LabeledIntent> labeledIntents =
                 mTemplateIntentFactory.create(remoteActionTemplates);
         if (foreignText) {
-            IntentFactory.insertTranslateAction(labeledIntents, context, text.trim());
+            ClassificationIntentFactory.insertTranslateAction(labeledIntents, context, text.trim());
         }
         return labeledIntents;
     }
diff --git a/core/java/android/view/textclassifier/TemplateIntentFactory.java b/core/java/android/view/textclassifier/intent/TemplateIntentFactory.java
similarity index 87%
rename from core/java/android/view/textclassifier/TemplateIntentFactory.java
rename to core/java/android/view/textclassifier/intent/TemplateIntentFactory.java
index 0696d98..59cd7ab 100644
--- a/core/java/android/view/textclassifier/TemplateIntentFactory.java
+++ b/core/java/android/view/textclassifier/intent/TemplateIntentFactory.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -21,15 +21,15 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.text.TextUtils;
+import android.view.textclassifier.Log;
+import android.view.textclassifier.TextClassifier;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
 
 import com.google.android.textclassifier.NamedVariant;
 import com.google.android.textclassifier.RemoteActionTemplate;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 
 /**
@@ -41,11 +41,14 @@
 public final class TemplateIntentFactory {
     private static final String TAG = TextClassifier.DEFAULT_LOG_TAG;
 
-    @NonNull
+    /**
+     * Constructs and returns a list of {@link LabeledIntent} based on the given templates.
+     */
+    @Nullable
     public List<LabeledIntent> create(
-            @Nullable RemoteActionTemplate[] remoteActionTemplates) {
-        if (ArrayUtils.isEmpty(remoteActionTemplates)) {
-            return Collections.emptyList();
+            @NonNull RemoteActionTemplate[] remoteActionTemplates) {
+        if (remoteActionTemplates.length == 0) {
+            return new ArrayList<>();
         }
         final List<LabeledIntent> labeledIntents = new ArrayList<>();
         for (RemoteActionTemplate remoteActionTemplate : remoteActionTemplates) {
@@ -63,8 +66,6 @@
                                     ? LabeledIntent.DEFAULT_REQUEST_CODE
                                     : remoteActionTemplate.requestCode));
         }
-        labeledIntents.forEach(
-                action -> action.intent.putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true));
         return labeledIntents;
     }
 
@@ -108,11 +109,14 @@
                 }
             }
         }
-        intent.putExtras(createExtras(remoteActionTemplate.extras));
+        intent.putExtras(nameVariantsToBundle(remoteActionTemplate.extras));
         return intent;
     }
 
-    private static Bundle createExtras(NamedVariant[] namedVariants) {
+    /**
+     * Converts an array of {@link NamedVariant} to a Bundle and returns it.
+     */
+    public static Bundle nameVariantsToBundle(@Nullable NamedVariant[] namedVariants) {
         if (namedVariants == null) {
             return Bundle.EMPTY;
         }
@@ -142,7 +146,8 @@
                     break;
                 default:
                     Log.w(TAG,
-                            "Unsupported type found in createExtras : " + namedVariant.getType());
+                            "Unsupported type found in nameVariantsToBundle : "
+                                    + namedVariant.getType());
             }
         }
         return bundle;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 528a6a8..6d88530 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -448,7 +448,8 @@
 
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
             try {
-                new WebViewDelegate().addWebViewAssetPath(initialApplication);
+                initialApplication.getAssets().addAssetPathAsSharedLibrary(
+                        webViewContext.getApplicationInfo().sourceDir);
                 ClassLoader clazzLoader = webViewContext.getClassLoader();
 
                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 89e205c..8785251 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.annotation.DrawableRes;
+import android.annotation.IntDef;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Resources.Theme;
@@ -44,6 +45,8 @@
 
 import com.android.internal.R;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 
 /**
@@ -1259,9 +1262,20 @@
     }
 
     /**
+     * The valid input method modes for the {@link AutoCompleteTextView}:
+     *
+     * {@hide}
+     */
+    @IntDef({ListPopupWindow.INPUT_METHOD_FROM_FOCUSABLE,
+            ListPopupWindow.INPUT_METHOD_NEEDED,
+            ListPopupWindow.INPUT_METHOD_NOT_NEEDED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InputMethodMode {}
+
+    /**
      * Returns the input method mode used by the auto complete dropdown.
      */
-    public int getInputMethodMode() {
+    public @InputMethodMode int getInputMethodMode() {
         return mPopup.getInputMethodMode();
     }
 
@@ -1277,7 +1291,7 @@
      * {@link ListPopupWindow#INPUT_METHOD_NOT_NEEDED}. The auto-complete suggestions are always
      * displayed, even if the suggestions cover/hide the input method.
      */
-    public void setInputMethodMode(int mode) {
+    public void setInputMethodMode(@InputMethodMode int mode) {
         mPopup.setInputMethodMode(mode);
     }
 
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 25e5dd3..16b903d 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -702,7 +702,7 @@
 
             mPopup.setWidth(widthSpec);
             mPopup.setHeight(heightSpec);
-            mPopup.setClipToScreenEnabled(true);
+            mPopup.setIsClippedToScreen(true);
 
             // use outside touchable to dismiss drop down when touching outside of it, so
             // only set this if the dropdown is not always visible
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 2798296..20fc0b1 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -886,9 +886,9 @@
      * containing window<p/>
      *
      * @return true if popup will be clipped to the screen instead of the window, false otherwise
-     *
-     * @see #setClipToScreenEnabled(boolean)
+     * @deprecated Use {@link #isClippedToScreen()} instead
      */
+    @Deprecated
     public boolean isClipToScreenEnabled() {
         return mClipToScreen;
     }
@@ -900,11 +900,37 @@
      * the next time the popup is shown or through a manual call to one of
      * the {@link #update()} methods.</p>
      *
+     * @deprecated Use {@link #setIsClippedToScreen(boolean)} instead
+     */
+    @Deprecated
+    public void setClipToScreenEnabled(boolean enabled) {
+        mClipToScreen = enabled;
+    }
+
+    /**
+     * <p>Indicates whether this popup will be clipped to the screen and not to the
+     * containing window<p/>
+     *
+     * @return true if popup will be clipped to the screen instead of the window, false otherwise
+     *
+     * @see #setIsClippedToScreen(boolean)
+     */
+    public boolean isClippedToScreen() {
+        return mClipToScreen;
+    }
+
+    /**
+     * <p>Clip this popup window to the screen, but not to the containing window.</p>
+     *
+     * <p>If the popup is showing, calling this method will take effect only
+     * the next time the popup is shown or through a manual call to one of
+     * the {@link #update()} methods.</p>
+     *
      * @param enabled true to clip to the screen.
      *
-     * @see #isClipToScreenEnabled()
+     * @see #isClippedToScreen()
      */
-    public void setClipToScreenEnabled(boolean enabled) {
+    public void setIsClippedToScreen(boolean enabled) {
         mClipToScreen = enabled;
     }
 
@@ -961,8 +987,9 @@
      *
      * @return true if the window will always be positioned in screen coordinates.
      *
-     * @see #setLayoutInScreenEnabled(boolean)
+     * @deprecated Use {@link #isLaidOutInScreen()} instead
      */
+    @Deprecated
     public boolean isLayoutInScreenEnabled() {
         return mLayoutInScreen;
     }
@@ -973,14 +1000,39 @@
      * This will cause the popup to be positioned in absolute screen coordinates.</p>
      *
      * @param enabled true if the popup should always be positioned in screen coordinates
-     *
-     * @see #isLayoutInScreenEnabled()
+     * @deprecated Use {@link #setIsLaidOutInScreen(boolean)} instead
      */
+    @Deprecated
     public void setLayoutInScreenEnabled(boolean enabled) {
         mLayoutInScreen = enabled;
     }
 
     /**
+     * <p>Indicates whether the popup window will be forced into using absolute screen coordinates
+     * for positioning.</p>
+     *
+     * @return true if the window will always be positioned in screen coordinates.
+     *
+     * @see #setIsLaidOutInScreen(boolean)
+     */
+    public boolean isLaidOutInScreen() {
+        return mLayoutInScreen;
+    }
+
+    /**
+     * <p>Allows the popup window to force the flag
+     * {@link WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN}, overriding default behavior.
+     * This will cause the popup to be positioned in absolute screen coordinates.</p>
+     *
+     * @param enabled true if the popup should always be positioned in screen coordinates
+     *
+     * @see #isLaidOutInScreen()
+     */
+    public void setIsLaidOutInScreen(boolean enabled) {
+        mLayoutInScreen = enabled;
+    }
+
+    /**
      * <p>Indicates whether the popup window will be attached in the decor frame of its parent
      * window.
      *
@@ -1016,7 +1068,7 @@
      * This will cause the popup to inset its content to account for system windows overlaying
      * the screen, such as the status bar.
      *
-     * <p>This will often be combined with {@link #setLayoutInScreenEnabled(boolean)}.
+     * <p>This will often be combined with {@link #setIsLaidOutInScreen(boolean)}.
      *
      * @param enabled true if the popup's views should inset content to account for system windows,
      *                the way that decor views behave for full-screen windows.
@@ -2114,7 +2166,7 @@
      *     <li>{@link #setTouchable(boolean)}</li>
      *     <li>{@link #setAnimationStyle(int)}</li>
      *     <li>{@link #setTouchModal(boolean)} (boolean)}</li>
-     *     <li>{@link #setClipToScreenEnabled(boolean)}</li>
+     *     <li>{@link #setIsClippedToScreen(boolean)}</li>
      * </ul>
      */
     public void update() {
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 91928b5..f250666 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -42,7 +42,6 @@
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
 import android.content.ServiceConnection;
-import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.pm.LabeledIntent;
 import android.content.pm.LauncherApps;
@@ -65,7 +64,6 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
@@ -75,7 +73,6 @@
 import android.os.ResultReceiver;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.storage.StorageManager;
 import android.provider.DocumentsContract;
 import android.provider.Downloads;
 import android.provider.OpenableColumns;
@@ -114,7 +111,6 @@
 
 import com.google.android.collect.Lists;
 
-import java.io.File;
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.util.ArrayList;
@@ -188,10 +184,7 @@
     private Drawable mChooserRowLayer;
     private int mChooserRowServiceSpacing;
 
-    private SharedPreferences mPinnedSharedPrefs;
-    private static final float PINNED_TARGET_SCORE_BOOST = 1000.f;
     private static final float CALLER_TARGET_SCORE_BOOST = 900.f;
-    private static final String PINNED_SHARED_PREFS_NAME = "chooser_pin_settings";
     private static final String TARGET_DETAILS_FRAGMENT_TAG = "targetDetailsFragment";
 
     private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>();
@@ -236,7 +229,6 @@
                     mServiceConnections.remove(sri.connection);
                     if (mServiceConnections.isEmpty()) {
                         sendVoiceChoicesIfNeeded();
-                        mChooserListAdapter.setShowServiceTargets(true);
                     }
                     break;
 
@@ -250,7 +242,6 @@
                     unbindRemainingServices();
                     sendVoiceChoicesIfNeeded();
                     mChooserListAdapter.completeServiceTargetLoading();
-                    mChooserListAdapter.setShowServiceTargets(true);
                     break;
 
                 case SHORTCUT_MANAGER_SHARE_TARGET_RESULT:
@@ -265,7 +256,6 @@
 
                 case SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED:
                     sendVoiceChoicesIfNeeded();
-                    mChooserListAdapter.setShowServiceTargets(true);
                     break;
 
                 default:
@@ -321,9 +311,7 @@
         // Do not allow the title to be changed when sharing content
         CharSequence title = null;
         if (target != null) {
-            String targetAction = target.getAction();
-            if (!(Intent.ACTION_SEND.equals(targetAction) || Intent.ACTION_SEND_MULTIPLE.equals(
-                    targetAction))) {
+            if (!isSendAction(target)) {
                 title = intent.getCharSequenceExtra(Intent.EXTRA_TITLE);
             } else {
                 Log.w(TAG, "Ignoring intent's EXTRA_TITLE, deprecated in P. You may wish to set a"
@@ -390,7 +378,6 @@
             mCallerChooserTargets = targets;
         }
 
-        mPinnedSharedPrefs = getPinnedSharedPrefs(this);
         setRetainInOnStop(intent.getBooleanExtra(EXTRA_PRIVATE_RETAIN_IN_ON_STOP, false));
         super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
                 null, false);
@@ -446,6 +433,11 @@
         mChooserRowServiceSpacing = getResources()
                                         .getDimensionPixelSize(R.dimen.chooser_service_spacing);
 
+        // expand/shrink direct share 4 -> 8 viewgroup
+        if (mResolverDrawerLayout != null && isSendAction(target)) {
+            mResolverDrawerLayout.setOnScrollChangeListener(this::handleScroll);
+        }
+
         if (DEBUG) {
             Log.d(TAG, "System Time Cost is " + systemCost);
         }
@@ -461,34 +453,6 @@
                 .getUserInfo(UserHandle.myUserId()).isManagedProfile();
     }
 
-    /**
-     * Override method to add content preview area, specific to the chooser activity.
-     */
-    @Override
-    public void setHeader() {
-        super.setHeader();
-
-        Intent targetIntent = getTargetIntent();
-        if (targetIntent == null) {
-            return;
-        }
-
-        String action = targetIntent.getAction();
-        if (!(Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action))) {
-            return;
-        }
-
-        if (mChooserListAdapter == null || mChooserListAdapter.getCount() == 0) {
-            return;
-        }
-
-        int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
-
-        getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
-                .setSubtype(previewType));
-        displayContentPreview(previewType, targetIntent);
-    }
-
     private void onCopyButtonClicked(View v) {
         Intent targetIntent = getTargetIntent();
         if (targetIntent == null) {
@@ -548,46 +512,56 @@
 
     private void updateLayoutWidth(int layoutResourceId, int width) {
         View view = findViewById(layoutResourceId);
-        LayoutParams params = view.getLayoutParams();
-        params.width = width;
-        view.setLayoutParams(params);
-    }
-
-    private void displayContentPreview(@ContentPreviewType int previewType, Intent targetIntent) {
-        switch (previewType) {
-            case CONTENT_PREVIEW_TEXT:
-                displayTextContentPreview(targetIntent);
-                break;
-            case CONTENT_PREVIEW_IMAGE:
-                displayImageContentPreview(targetIntent);
-                break;
-            case CONTENT_PREVIEW_FILE:
-                displayFileContentPreview(targetIntent);
-                break;
-            default:
-                Log.e(TAG, "Unexpected content preview type: " + previewType);
+        if (view != null && view.getLayoutParams() != null) {
+            LayoutParams params = view.getLayoutParams();
+            params.width = width;
+            view.setLayoutParams(params);
         }
     }
 
-    private void displayTextContentPreview(Intent targetIntent) {
-        ViewGroup contentPreviewLayout = findViewById(R.id.content_preview_text_area);
-        contentPreviewLayout.setVisibility(View.VISIBLE);
+    private ViewGroup displayContentPreview(@ContentPreviewType int previewType,
+            Intent targetIntent, LayoutInflater layoutInflater, ViewGroup convertView,
+            ViewGroup parent) {
+        switch (previewType) {
+            case CONTENT_PREVIEW_TEXT:
+                return displayTextContentPreview(targetIntent, layoutInflater, convertView, parent);
+            case CONTENT_PREVIEW_IMAGE:
+                return displayImageContentPreview(targetIntent, layoutInflater, convertView,
+                        parent);
+            case CONTENT_PREVIEW_FILE:
+                return displayFileContentPreview(targetIntent, layoutInflater, convertView, parent);
+            default:
+                Log.e(TAG, "Unexpected content preview type: " + previewType);
+        }
 
-        findViewById(R.id.copy_button).setOnClickListener(this::onCopyButtonClicked);
+        return null;
+    }
+
+    private ViewGroup displayTextContentPreview(Intent targetIntent, LayoutInflater layoutInflater,
+            ViewGroup convertView, ViewGroup parent) {
+        ViewGroup contentPreviewLayout =
+                convertView != null ? convertView : (ViewGroup) layoutInflater.inflate(
+                        R.layout.chooser_grid_preview_text, parent, false);
+
+        contentPreviewLayout.findViewById(R.id.copy_button).setOnClickListener(
+                this::onCopyButtonClicked);
 
         CharSequence sharingText = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT);
         if (sharingText == null) {
-            findViewById(R.id.content_preview_text_layout).setVisibility(View.GONE);
+            contentPreviewLayout.findViewById(R.id.content_preview_text_layout).setVisibility(
+                    View.GONE);
         } else {
-            TextView textView = findViewById(R.id.content_preview_text);
+            TextView textView = contentPreviewLayout.findViewById(R.id.content_preview_text);
             textView.setText(sharingText);
         }
 
         String previewTitle = targetIntent.getStringExtra(Intent.EXTRA_TITLE);
         if (TextUtils.isEmpty(previewTitle)) {
-            findViewById(R.id.content_preview_title_layout).setVisibility(View.GONE);
+            contentPreviewLayout.findViewById(R.id.content_preview_title_layout).setVisibility(
+                    View.GONE);
         } else {
-            TextView previewTitleView = findViewById(R.id.content_preview_title);
+            TextView previewTitleView = contentPreviewLayout.findViewById(
+                    R.id.content_preview_title);
             previewTitleView.setText(previewTitle);
 
             ClipData previewData = targetIntent.getClipData();
@@ -599,7 +573,8 @@
                 }
             }
 
-            ImageView previewThumbnailView = findViewById(R.id.content_preview_thumbnail);
+            ImageView previewThumbnailView = contentPreviewLayout.findViewById(
+                    R.id.content_preview_thumbnail);
             if (previewThumbnail == null) {
                 previewThumbnailView.setVisibility(View.GONE);
             } else {
@@ -611,16 +586,20 @@
                 }
             }
         }
+
+        return contentPreviewLayout;
     }
 
-    private void displayImageContentPreview(Intent targetIntent) {
-        ViewGroup contentPreviewLayout = findViewById(R.id.content_preview_image_area);
-        contentPreviewLayout.setVisibility(View.VISIBLE);
+    private ViewGroup displayImageContentPreview(Intent targetIntent, LayoutInflater layoutInflater,
+            ViewGroup convertView, ViewGroup parent) {
+        ViewGroup contentPreviewLayout =
+                convertView != null ? convertView : (ViewGroup) layoutInflater.inflate(
+                        R.layout.chooser_grid_preview_image, parent, false);
 
         String action = targetIntent.getAction();
         if (Intent.ACTION_SEND.equals(action)) {
             Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
-            loadUriIntoView(R.id.content_preview_image_1_large, uri);
+            loadUriIntoView(R.id.content_preview_image_1_large, uri, contentPreviewLayout);
         } else {
             ContentResolver resolver = getContentResolver();
 
@@ -636,23 +615,28 @@
                 Log.i(TAG, "Attempted to display image preview area with zero"
                         + " available images detected in EXTRA_STREAM list");
                 contentPreviewLayout.setVisibility(View.GONE);
-                return;
+                return contentPreviewLayout;
             }
 
-            loadUriIntoView(R.id.content_preview_image_1_large, imageUris.get(0));
+            loadUriIntoView(R.id.content_preview_image_1_large, imageUris.get(0),
+                    contentPreviewLayout);
 
             if (imageUris.size() == 2) {
-                loadUriIntoView(R.id.content_preview_image_2_large, imageUris.get(1));
+                loadUriIntoView(R.id.content_preview_image_2_large, imageUris.get(1),
+                        contentPreviewLayout);
             } else if (imageUris.size() > 2) {
-                loadUriIntoView(R.id.content_preview_image_2_small, imageUris.get(1));
+                loadUriIntoView(R.id.content_preview_image_2_small, imageUris.get(1),
+                        contentPreviewLayout);
                 RoundedRectImageView imageView = loadUriIntoView(
-                        R.id.content_preview_image_3_small, imageUris.get(2));
+                        R.id.content_preview_image_3_small, imageUris.get(2), contentPreviewLayout);
 
                 if (imageUris.size() > 3) {
                     imageView.setExtraImageCount(imageUris.size() - 3);
                 }
             }
         }
+
+        return contentPreviewLayout;
     }
 
     private static class FileInfo {
@@ -711,18 +695,21 @@
         return new FileInfo(fileName, hasThumbnail);
     }
 
-    private void displayFileContentPreview(Intent targetIntent) {
-        ViewGroup contentPreviewLayout = findViewById(R.id.content_preview_file_area);
-        contentPreviewLayout.setVisibility(View.VISIBLE);
+    private ViewGroup displayFileContentPreview(Intent targetIntent, LayoutInflater layoutInflater,
+            ViewGroup convertView, ViewGroup parent) {
+
+        ViewGroup contentPreviewLayout =
+                convertView != null ? convertView : (ViewGroup) layoutInflater.inflate(
+                        R.layout.chooser_grid_preview_file, parent, false);
 
         // TODO(b/120417119): Disable file copy until after moving to sysui,
         // due to permissions issues
-        findViewById(R.id.file_copy_button).setVisibility(View.GONE);
+        contentPreviewLayout.findViewById(R.id.file_copy_button).setVisibility(View.GONE);
 
         String action = targetIntent.getAction();
         if (Intent.ACTION_SEND.equals(action)) {
             Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM);
-            loadFileUriIntoView(uri);
+            loadFileUriIntoView(uri, contentPreviewLayout);
         } else {
             List<Uri> uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
             int uriCount = uris.size();
@@ -732,42 +719,46 @@
                 Log.i(TAG,
                         "Appears to be no uris available in EXTRA_STREAM, removing "
                                 + "preview area");
-                return;
+                return contentPreviewLayout;
             } else if (uriCount == 1) {
-                loadFileUriIntoView(uris.get(0));
+                loadFileUriIntoView(uris.get(0), contentPreviewLayout);
             } else {
                 FileInfo fileInfo = extractFileInfo(uris.get(0), getContentResolver());
                 int remUriCount = uriCount - 1;
                 String fileName = getResources().getQuantityString(R.plurals.file_count,
                         remUriCount, fileInfo.name, remUriCount);
 
-                TextView fileNameView = findViewById(R.id.content_preview_filename);
+                TextView fileNameView = contentPreviewLayout.findViewById(
+                        R.id.content_preview_filename);
                 fileNameView.setText(fileName);
 
-                ImageView fileIconView = findViewById(R.id.content_preview_file_icon);
+                ImageView fileIconView = contentPreviewLayout.findViewById(
+                        R.id.content_preview_file_icon);
                 fileIconView.setVisibility(View.VISIBLE);
                 fileIconView.setImageResource(R.drawable.ic_file_copy);
             }
         }
+
+        return contentPreviewLayout;
     }
 
-    private void loadFileUriIntoView(Uri uri) {
+    private void loadFileUriIntoView(Uri uri, View parent) {
         FileInfo fileInfo = extractFileInfo(uri, getContentResolver());
 
-        TextView fileNameView = findViewById(R.id.content_preview_filename);
+        TextView fileNameView = parent.findViewById(R.id.content_preview_filename);
         fileNameView.setText(fileInfo.name);
 
         if (fileInfo.hasThumbnail) {
-            loadUriIntoView(R.id.content_preview_file_thumbnail, uri);
+            loadUriIntoView(R.id.content_preview_file_thumbnail, uri, parent);
         } else {
-            ImageView fileIconView = findViewById(R.id.content_preview_file_icon);
+            ImageView fileIconView = parent.findViewById(R.id.content_preview_file_icon);
             fileIconView.setVisibility(View.VISIBLE);
             fileIconView.setImageResource(R.drawable.ic_doc_generic);
         }
     }
 
-    private RoundedRectImageView loadUriIntoView(int imageResourceId, Uri uri) {
-        RoundedRectImageView imageView = findViewById(imageResourceId);
+    private RoundedRectImageView loadUriIntoView(int imageResourceId, Uri uri, View parent) {
+        RoundedRectImageView imageView = parent.findViewById(imageResourceId);
         Bitmap bmp = loadThumbnail(uri, new Size(200, 200));
         if (bmp != null) {
             imageView.setVisibility(View.VISIBLE);
@@ -822,22 +813,6 @@
         return CONTENT_PREVIEW_TEXT;
     }
 
-    static SharedPreferences getPinnedSharedPrefs(Context context) {
-        // The code below is because in the android:ui process, no one can hear you scream.
-        // The package info in the context isn't initialized in the way it is for normal apps,
-        // so the standard, name-based context.getSharedPreferences doesn't work. Instead, we
-        // build the path manually below using the same policy that appears in ContextImpl.
-        // This fails silently under the hood if there's a problem, so if we find ourselves in
-        // the case where we don't have access to credential encrypted storage we just won't
-        // have our pinned target info.
-        final File prefsFile = new File(new File(
-                Environment.getDataUserCePackageDirectory(StorageManager.UUID_PRIVATE_INTERNAL,
-                        context.getUserId(), context.getPackageName()),
-                "shared_prefs"),
-                PINNED_SHARED_PREFS_NAME + ".xml");
-        return context.getSharedPreferences(prefsFile, MODE_PRIVATE);
-    }
-
     @Override
     protected void onDestroy() {
         super.onDestroy();
@@ -933,17 +908,14 @@
         }
 
         ComponentName name = ri.activityInfo.getComponentName();
-        boolean pinned = mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
         ResolverTargetActionsDialogFragment f =
                 new ResolverTargetActionsDialogFragment(ri.loadLabel(getPackageManager()),
-                        name, pinned);
+                        name);
         f.show(getFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG);
     }
 
     private void modifyTargetIntent(Intent in) {
-        final String action = in.getAction();
-        if (Intent.ACTION_SEND.equals(action) ||
-                Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+        if (isSendAction(in)) {
             in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
                     Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
         }
@@ -998,15 +970,15 @@
             switch (mChooserListAdapter.getPositionTargetType(which)) {
                 case ChooserListAdapter.TARGET_CALLER:
                     cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET;
+                    value -= mChooserListAdapter.getSelectableServiceTargetCount();
                     break;
                 case ChooserListAdapter.TARGET_SERVICE:
                     cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET;
-                    value -= mChooserListAdapter.getCallerTargetCount();
                     break;
                 case ChooserListAdapter.TARGET_STANDARD:
                     cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET;
                     value -= mChooserListAdapter.getCallerTargetCount()
-                            + mChooserListAdapter.getServiceTargetCount();
+                            + mChooserListAdapter.getSelectableServiceTargetCount();
                     break;
             }
 
@@ -1392,11 +1364,6 @@
         }
 
         @Override
-        boolean isComponentPinned(ComponentName name) {
-            return mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
-        }
-
-        @Override
         boolean isComponentFiltered(ComponentName name) {
             if (mFilteredComponentNames == null) {
                 return false;
@@ -1414,11 +1381,8 @@
             if (target == null) {
                 return CALLER_TARGET_SCORE_BOOST;
             }
-            float score = super.getScore(target);
-            if (target.isPinned()) {
-                score += PINNED_TARGET_SCORE_BOOST;
-            }
-            return score;
+
+            return super.getScore(target);
         }
     }
 
@@ -1515,10 +1479,6 @@
             return null;
         }
 
-        public boolean isPinned() {
-            return false;
-        }
-
         public float getModifiedScore() {
             return 0.1f;
         }
@@ -1749,10 +1709,11 @@
             }
             return results;
         }
+    }
 
-        @Override
-        public boolean isPinned() {
-            return mSourceInfo != null ? mSourceInfo.isPinned() : false;
+    private void handleScroll(View view, int x, int y, int oldx, int oldy) {
+        if (mChooserRowAdapter != null) {
+            mChooserRowAdapter.handleScroll(view, y, oldy);
         }
     }
 
@@ -1762,12 +1723,14 @@
         public static final int TARGET_SERVICE = 1;
         public static final int TARGET_STANDARD = 2;
 
-        private static final int MAX_SERVICE_TARGETS = 4;
+        private static final int MAX_SUGGESTED_APP_TARGETS = 4;
         private static final int MAX_TARGETS_PER_SERVICE = 2;
 
+        private static final int MAX_SERVICE_TARGETS = 8;
+
         // Reserve spots for incoming direct share targets by adding placeholders
         private ChooserTargetInfo mPlaceHolderTargetInfo = new PlaceHolderTargetInfo();
-        private List<ChooserTargetInfo> mServiceTargets;
+        private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
         private final List<TargetInfo> mCallerTargets = new ArrayList<>();
         private boolean mShowServiceTargets;
 
@@ -1786,7 +1749,7 @@
             super(context, payloadIntents, null, rList, launchedFromUid, filterLastUsed,
                     resolverListController);
 
-            mServiceTargets = createPlaceHolders();
+            createPlaceHolders();
 
             if (initialIntents != null) {
                 final PackageManager pm = getPackageManager();
@@ -1840,12 +1803,11 @@
             }
         }
 
-        private List<ChooserTargetInfo> createPlaceHolders() {
-            List<ChooserTargetInfo> list = new ArrayList<>();
+        private void createPlaceHolders() {
+            mServiceTargets.clear();
             for (int i = 0; i < MAX_SERVICE_TARGETS; i++) {
-                list.add(mPlaceHolderTargetInfo);
+                mServiceTargets.add(mPlaceHolderTargetInfo);
             }
-            return list;
         }
 
         @Override
@@ -1855,11 +1817,6 @@
         }
 
         @Override
-        public boolean isComponentPinned(ComponentName name) {
-            return mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
-        }
-
-        @Override
         public View onCreateView(ViewGroup parent) {
             return mInflater.inflate(
                     com.android.internal.R.layout.resolve_grid_item, parent, false);
@@ -1913,7 +1870,7 @@
         }
 
         public int getCallerTargetCount() {
-            return mCallerTargets.size();
+            return Math.min(mCallerTargets.size(), MAX_SUGGESTED_APP_TARGETS);
         }
 
         /**
@@ -1930,7 +1887,11 @@
         }
 
         public int getServiceTargetCount() {
-            return Math.min(mServiceTargets.size(), MAX_SERVICE_TARGETS);
+            if (isSendAction(getTargetIntent())) {
+                return Math.min(mServiceTargets.size(), MAX_SERVICE_TARGETS);
+            }
+
+            return 0;
         }
 
         public int getStandardTargetCount() {
@@ -1940,18 +1901,18 @@
         public int getPositionTargetType(int position) {
             int offset = 0;
 
-            final int callerTargetCount = getCallerTargetCount();
-            if (position < callerTargetCount) {
-                return TARGET_CALLER;
-            }
-            offset += callerTargetCount;
-
             final int serviceTargetCount = getServiceTargetCount();
-            if (position - offset < serviceTargetCount) {
+            if (position < serviceTargetCount) {
                 return TARGET_SERVICE;
             }
             offset += serviceTargetCount;
 
+            final int callerTargetCount = getCallerTargetCount();
+            if (position - offset < callerTargetCount) {
+                return TARGET_CALLER;
+            }
+            offset += callerTargetCount;
+
             final int standardTargetCount = super.getCount();
             if (position - offset < standardTargetCount) {
                 return TARGET_STANDARD;
@@ -1969,19 +1930,19 @@
         public TargetInfo targetInfoForPosition(int position, boolean filtered) {
             int offset = 0;
 
-            final int callerTargetCount = getCallerTargetCount();
-            if (position < callerTargetCount) {
-                return mCallerTargets.get(position);
-            }
-            offset += callerTargetCount;
-
             final int serviceTargetCount = filtered ? getServiceTargetCount() :
                                                getSelectableServiceTargetCount();
-            if (position - offset < serviceTargetCount) {
-                return mServiceTargets.get(position - offset);
+            if (position < serviceTargetCount) {
+                return mServiceTargets.get(position);
             }
             offset += serviceTargetCount;
 
+            final int callerTargetCount = getCallerTargetCount();
+            if (position - offset < callerTargetCount) {
+                return mCallerTargets.get(position - offset);
+            }
+            offset += callerTargetCount;
+
             return filtered ? super.getItem(position - offset)
                     : getDisplayInfoAt(position - offset);
         }
@@ -1995,7 +1956,7 @@
             if (mTargetsNeedPruning && targets.size() > 0) {
                 // First proper update since we got an onListRebuilt() with (transient) 0 items.
                 // Clear out the target list and rebuild.
-                mServiceTargets = createPlaceHolders();
+                createPlaceHolders();
                 mTargetsNeedPruning = false;
 
                 // Add back any app-supplied direct share targets that may have been
@@ -2037,26 +1998,6 @@
         }
 
         /**
-         * Set to true to reveal all service targets at once.
-         */
-        public void setShowServiceTargets(boolean show) {
-            // mShowServiceTargets is only flipped once to show direct share targets. But after the
-            // initial display the list can be re-sorted and the user will see the target list
-            // change. This will log the initial show and the subsequent shuffle to help us get
-            // accurate timing of the UX.
-            if (show) {
-                getMetricsLogger().write(
-                        new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN_DIRECT_TARGET)
-                                .setSubtype(mShowServiceTargets ? MetricsEvent.PREVIOUSLY_VISIBLE
-                                        : MetricsEvent.PREVIOUSLY_HIDDEN));
-            }
-            if (show != mShowServiceTargets) {
-                mShowServiceTargets = show;
-                notifyDataSetChanged();
-            }
-        }
-
-        /**
          * Calling this marks service target loading complete, and will attempt to no longer
          * update the direct share area.
          */
@@ -2099,12 +2040,34 @@
         }
     }
 
+    private boolean isSendAction(Intent targetIntent) {
+        if (targetIntent == null) {
+            return false;
+        }
+
+        String action = targetIntent.getAction();
+        if (action == null) {
+            return false;
+        }
+
+        if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+            return true;
+        }
+
+        return false;
+    }
+
     class ChooserRowAdapter extends BaseAdapter {
         private ChooserListAdapter mChooserListAdapter;
         private final LayoutInflater mLayoutInflater;
-        private final int mColumnCount = 4;
         private int mAnimationCount = 0;
 
+        private DirectShareViewHolder mDirectShareViewHolder;
+
+        private static final int VIEW_TYPE_DIRECT_SHARE = 0;
+        private static final int VIEW_TYPE_NORMAL = 1;
+        private static final int VIEW_TYPE_CONTENT_PREVIEW = 2;
+
         public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) {
             mChooserListAdapter = wrappedAdapter;
             mLayoutInflater = LayoutInflater.from(ChooserActivity.this);
@@ -2124,24 +2087,47 @@
             });
         }
 
+        private int getMaxTargetsPerRow() {
+            // this will soon hold logic for portrait/landscape
+            return 4;
+        }
+
         @Override
         public int getCount() {
             return (int) (
-                    getCallerTargetRowCount()
+                    getContentPreviewRowCount()
+                            + getCallerTargetRowCount()
                             + getServiceTargetRowCount()
                             + Math.ceil(
-                            (float) mChooserListAdapter.getStandardTargetCount() / mColumnCount)
+                            (float) mChooserListAdapter.getStandardTargetCount()
+                                    / getMaxTargetsPerRow())
             );
         }
 
+        public int getContentPreviewRowCount() {
+            if (!isSendAction(getTargetIntent())) {
+                return 0;
+            }
+
+            if (mChooserListAdapter == null || mChooserListAdapter.getCount() == 0) {
+                return 0;
+            }
+
+            return 1;
+        }
+
         public int getCallerTargetRowCount() {
             return (int) Math.ceil(
-                    (float) mChooserListAdapter.getCallerTargetCount() / mColumnCount);
+                    (float) mChooserListAdapter.getCallerTargetCount() / getMaxTargetsPerRow());
         }
 
-        // There can be at most one row of service targets.
+        // There can be at most one row in the listview, that is internally
+        // a ViewGroup with 2 rows
         public int getServiceTargetRowCount() {
-            return 1;
+            if (isSendAction(getTargetIntent())) {
+                return 1;
+            }
+            return 0;
         }
 
         @Override
@@ -2158,29 +2144,70 @@
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
             final RowViewHolder holder;
+            int viewType = getItemViewType(position);
+
+            if (viewType == VIEW_TYPE_CONTENT_PREVIEW) {
+                return createContentPreviewView(convertView, parent);
+            }
+
             if (convertView == null) {
-                holder = createViewHolder(parent);
+                holder = createViewHolder(viewType, parent);
             } else {
                 holder = (RowViewHolder) convertView.getTag();
             }
-            bindViewHolder(position, holder);
 
-            return holder.row;
+            bindViewHolder(position, holder,
+                    viewType == VIEW_TYPE_DIRECT_SHARE
+                            ? ChooserListAdapter.MAX_SERVICE_TARGETS : getMaxTargetsPerRow());
+
+            return holder.getViewGroup();
         }
 
-        RowViewHolder createViewHolder(ViewGroup parent) {
-            final ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row,
-                    parent, false);
-            final RowViewHolder holder = new RowViewHolder(row, mColumnCount);
-            final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        @Override
+        public int getItemViewType(int position) {
+            if (position == 0 && getContentPreviewRowCount() == 1) {
+                return VIEW_TYPE_CONTENT_PREVIEW;
+            }
 
-            for (int i = 0; i < mColumnCount; i++) {
-                final View v = mChooserListAdapter.createView(row);
+            final int start = getFirstRowPosition(position);
+            final int startType = mChooserListAdapter.getPositionTargetType(start);
+
+            if (startType == ChooserListAdapter.TARGET_SERVICE) {
+                return VIEW_TYPE_DIRECT_SHARE;
+            }
+
+            return VIEW_TYPE_NORMAL;
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return 3;
+        }
+
+        private ViewGroup createContentPreviewView(View convertView, ViewGroup parent) {
+            Intent targetIntent = getTargetIntent();
+            int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
+
+            if (convertView == null) {
+                getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
+                        .setSubtype(previewType));
+            }
+
+            return displayContentPreview(previewType, targetIntent, mLayoutInflater,
+                    (ViewGroup) convertView, parent);
+        }
+
+        private RowViewHolder loadViewsIntoRow(RowViewHolder holder) {
+            final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            int columnCount = holder.getColumnCount();
+
+            for (int i = 0; i < columnCount; i++) {
+                final View v = mChooserListAdapter.createView(holder.getRow(i));
                 final int column = i;
                 v.setOnClickListener(new OnClickListener() {
                     @Override
                     public void onClick(View v) {
-                        startSelected(holder.itemIndices[column], false, true);
+                        startSelected(holder.getItemIndex(column), false, true);
                     }
                 });
                 v.setOnLongClickListener(new OnLongClickListener() {
@@ -2188,12 +2215,11 @@
                     public boolean onLongClick(View v) {
                         showTargetDetails(
                                 mChooserListAdapter.resolveInfoForPosition(
-                                        holder.itemIndices[column], true));
+                                        holder.getItemIndex(column), true));
                         return true;
                     }
                 });
-                row.addView(v);
-                holder.cells[i] = v;
+                ViewGroup row = holder.addView(i, v);
 
                 // Force height to be a given so we don't have visual disruption during scaling.
                 LayoutParams lp = v.getLayoutParams();
@@ -2204,47 +2230,75 @@
                 } else {
                     lp.height = v.getMeasuredHeight();
                 }
-                if (i != (mColumnCount - 1)) {
-                    row.addView(new Space(ChooserActivity.this),
-                            new LinearLayout.LayoutParams(0, 0, 1));
-                }
             }
 
+            final ViewGroup viewGroup = holder.getViewGroup();
+
             // Pre-measure so we can scale later.
             holder.measure();
-            LayoutParams lp = row.getLayoutParams();
+            LayoutParams lp = viewGroup.getLayoutParams();
             if (lp == null) {
-                lp = new LayoutParams(LayoutParams.MATCH_PARENT, holder.measuredRowHeight);
-                row.setLayoutParams(lp);
+                lp = new LayoutParams(LayoutParams.MATCH_PARENT, holder.getMeasuredRowHeight());
+                viewGroup.setLayoutParams(lp);
             } else {
-                lp.height = holder.measuredRowHeight;
+                lp.height = holder.getMeasuredRowHeight();
             }
-            row.setTag(holder);
+
+            viewGroup.setTag(holder);
+
             return holder;
         }
 
-        void bindViewHolder(int rowPosition, RowViewHolder holder) {
+        RowViewHolder createViewHolder(int viewType, ViewGroup parent) {
+            if (viewType == VIEW_TYPE_DIRECT_SHARE) {
+                ViewGroup parentGroup = (ViewGroup) mLayoutInflater.inflate(
+                        R.layout.chooser_row_direct_share, parent, false);
+                ViewGroup row1 = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row,
+                        parentGroup, false);
+                ViewGroup row2 = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row,
+                        parentGroup, false);
+                parentGroup.addView(row1);
+                parentGroup.addView(row2);
+
+                mDirectShareViewHolder = new DirectShareViewHolder(parentGroup,
+                        Lists.newArrayList(row1, row2), getMaxTargetsPerRow());
+                loadViewsIntoRow(mDirectShareViewHolder);
+
+                return mDirectShareViewHolder;
+            } else {
+                ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row, parent,
+                        false);
+                RowViewHolder holder = new SingleRowViewHolder(row, getMaxTargetsPerRow());
+                loadViewsIntoRow(holder);
+
+                return holder;
+            }
+        }
+
+        void bindViewHolder(int rowPosition, RowViewHolder holder, int columnCount) {
             final int start = getFirstRowPosition(rowPosition);
             final int startType = mChooserListAdapter.getPositionTargetType(start);
 
             final int lastStartType = mChooserListAdapter.getPositionTargetType(
                     getFirstRowPosition(rowPosition - 1));
 
-            if (startType != lastStartType || rowPosition == 0) {
-                holder.row.setBackground(mChooserRowLayer);
-                setVertPadding(holder, mChooserRowServiceSpacing, 0);
+            final ViewGroup row = holder.getViewGroup();
+
+            if (startType != lastStartType || rowPosition == getContentPreviewRowCount()) {
+                row.setBackground(mChooserRowLayer);
+                setVertPadding(row, mChooserRowServiceSpacing, 0);
             } else {
-                holder.row.setBackground(null);
-                setVertPadding(holder, 0, 0);
+                row.setBackground(null);
+                setVertPadding(row, 0, 0);
             }
 
-            int end = start + mColumnCount - 1;
+            int end = start + columnCount - 1;
             while (mChooserListAdapter.getPositionTargetType(end) != startType && end >= start) {
                 end--;
             }
 
             if (end == start && mChooserListAdapter.getItem(start) instanceof EmptyTargetInfo) {
-                final TextView textView = holder.row.findViewById(R.id.chooser_row_text_option);
+                final TextView textView = row.findViewById(R.id.chooser_row_text_option);
 
                 if (textView.getVisibility() != View.VISIBLE) {
                     textView.setAlpha(0.0f);
@@ -2269,12 +2323,12 @@
                 }
             }
 
-            for (int i = 0; i < mColumnCount; i++) {
-                final View v = holder.cells[i];
+            for (int i = 0; i < columnCount; i++) {
+                final View v = holder.getView(i);
                 if (start + i <= end) {
                     setCellVisibility(holder, i, View.VISIBLE);
-                    holder.itemIndices[i] = start + i;
-                    mChooserListAdapter.bindView(holder.itemIndices[i], v);
+                    holder.setItemIndex(i, start + i);
+                    mChooserListAdapter.bindView(holder.getItemIndex(i), v);
                 } else {
                     setCellVisibility(holder, i, View.INVISIBLE);
                 }
@@ -2282,13 +2336,13 @@
         }
 
         private void setCellVisibility(RowViewHolder holder, int i, int visibility) {
-            final View v = holder.cells[i];
+            final View v = holder.getView(i);
             if (visibility == View.VISIBLE) {
-                holder.cellVisibility[i] = true;
+                holder.setViewVisibility(i, true);
                 v.setVisibility(visibility);
                 v.setAlpha(1.0f);
-            } else if (visibility == View.INVISIBLE && holder.cellVisibility[i]) {
-                holder.cellVisibility[i] = false;
+            } else if (visibility == View.INVISIBLE && holder.getViewVisibility(i)) {
+                holder.setViewVisibility(i, false);
 
                 ValueAnimator fadeAnim = ObjectAnimator.ofFloat(v, "alpha", 1.0f, 0f);
                 fadeAnim.setDuration(NO_DIRECT_SHARE_ANIM_IN_MILLIS);
@@ -2302,49 +2356,222 @@
             }
         }
 
-        private void setVertPadding(RowViewHolder holder, int top, int bottom) {
-            holder.row.setPadding(holder.row.getPaddingLeft(), top,
-                    holder.row.getPaddingRight(), bottom);
+        private void setVertPadding(ViewGroup row, int top, int bottom) {
+            row.setPadding(row.getPaddingLeft(), top, row.getPaddingRight(), bottom);
         }
 
         int getFirstRowPosition(int row) {
-            final int callerCount = mChooserListAdapter.getCallerTargetCount();
-            final int callerRows = (int) Math.ceil((float) callerCount / mColumnCount);
-
-            if (row < callerRows) {
-                return row * mColumnCount;
-            }
+            row -= getContentPreviewRowCount();
 
             final int serviceCount = mChooserListAdapter.getServiceTargetCount();
-            final int serviceRows = (int) Math.ceil((float) serviceCount / mColumnCount);
+            final int serviceRows = (int) Math.ceil((float) serviceCount
+                    / ChooserListAdapter.MAX_SERVICE_TARGETS);
+            if (row < serviceRows) {
+                return row * getMaxTargetsPerRow();
+            }
 
+            final int callerCount = mChooserListAdapter.getCallerTargetCount();
+            final int callerRows = (int) Math.ceil((float) callerCount / getMaxTargetsPerRow());
             if (row < callerRows + serviceRows) {
-                return callerCount + (row - callerRows) * mColumnCount;
+                return serviceCount + (row - serviceRows) * getMaxTargetsPerRow();
             }
 
             return callerCount + serviceCount
-                    + (row - callerRows - serviceRows) * mColumnCount;
+                    + (row - callerRows - serviceRows) * getMaxTargetsPerRow();
+        }
+
+        public void handleScroll(View v, int y, int oldy) {
+            if (mDirectShareViewHolder != null) {
+                mDirectShareViewHolder.handleScroll(mAdapterView, y, oldy, getMaxTargetsPerRow());
+            }
         }
     }
 
-    static class RowViewHolder {
-        public final View[] cells;
-        public final boolean [] cellVisibility;
-        public final ViewGroup row;
-        int measuredRowHeight;
-        int[] itemIndices;
+    abstract class RowViewHolder {
+        protected int mMeasuredRowHeight;
+        private int[] mItemIndices;
+        protected final View[] mCells;
+        private final boolean[] mCellVisibility;
+        private final int mColumnCount;
 
-        public RowViewHolder(ViewGroup row, int cellCount) {
-            this.row = row;
-            this.cells = new View[cellCount];
-            this.cellVisibility = new boolean[cellCount];
-            this.itemIndices = new int[cellCount];
+        RowViewHolder(int cellCount) {
+            this.mCells = new View[cellCount];
+            this.mItemIndices = new int[cellCount];
+            this.mCellVisibility = new boolean[cellCount];
+            this.mColumnCount = cellCount;
+        }
+
+        abstract ViewGroup addView(int index, View v);
+
+        abstract ViewGroup getViewGroup();
+
+        abstract ViewGroup getRow(int index);
+
+        public int getColumnCount() {
+            return mColumnCount;
+        }
+
+        public void setViewVisibility(int index, boolean visibility) {
+            mCellVisibility[index] = visibility;
+        }
+
+        public boolean getViewVisibility(int index) {
+            return mCellVisibility[index];
         }
 
         public void measure() {
             final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-            row.measure(spec, spec);
-            measuredRowHeight = row.getMeasuredHeight();
+            getViewGroup().measure(spec, spec);
+            mMeasuredRowHeight = getViewGroup().getMeasuredHeight();
+        }
+
+        public int getMeasuredRowHeight() {
+            return mMeasuredRowHeight;
+        }
+
+        protected void addSpacer(ViewGroup row) {
+            row.addView(new Space(ChooserActivity.this),
+                    new LinearLayout.LayoutParams(0, 0, 1));
+        }
+
+        public void setItemIndex(int itemIndex, int listIndex) {
+            mItemIndices[itemIndex] = listIndex;
+        }
+
+        public int getItemIndex(int itemIndex) {
+            return mItemIndices[itemIndex];
+        }
+
+        public View getView(int index) {
+            return mCells[index];
+        }
+    }
+
+    class SingleRowViewHolder extends RowViewHolder {
+        private final ViewGroup mRow;
+
+        SingleRowViewHolder(ViewGroup row, int cellCount) {
+            super(cellCount);
+
+            this.mRow = row;
+        }
+
+        public ViewGroup getViewGroup() {
+            return mRow;
+        }
+
+        public ViewGroup getRow(int index) {
+            return mRow;
+        }
+
+        public ViewGroup addView(int index, View v) {
+            mRow.addView(v);
+            mCells[index] = v;
+
+            if (index != (mCells.length - 1)) {
+                addSpacer(mRow);
+            }
+
+            return mRow;
+        }
+    }
+
+    class DirectShareViewHolder extends RowViewHolder {
+        private final ViewGroup mParent;
+        private final List<ViewGroup> mRows;
+        private int mCellCountPerRow;
+
+        private boolean mHideDirectShareExpansion = false;
+        private int mDirectShareMinHeight = 0;
+        private int mDirectShareCurrHeight = 0;
+        private int mDirectShareMaxHeight = 0;
+
+        DirectShareViewHolder(ViewGroup parent, List<ViewGroup> rows, int cellCountPerRow) {
+            super(rows.size() * cellCountPerRow);
+
+            this.mParent = parent;
+            this.mRows = rows;
+            this.mCellCountPerRow = cellCountPerRow;
+        }
+
+        public ViewGroup addView(int index, View v) {
+            ViewGroup row = getRow(index);
+            row.addView(v);
+            mCells[index] = v;
+
+            if (index % mCellCountPerRow != (mCellCountPerRow - 1)) {
+                addSpacer(row);
+            }
+
+            return row;
+        }
+
+        public ViewGroup getViewGroup() {
+            return mParent;
+        }
+
+        public ViewGroup getRow(int index) {
+            return mRows.get(index / mCellCountPerRow);
+        }
+
+        public void measure() {
+            final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            getRow(0).measure(spec, spec);
+            getRow(1).measure(spec, spec);
+
+            // uses ChooserActiivty state variables to track height
+            mDirectShareMinHeight = getRow(0).getMeasuredHeight();
+            mDirectShareCurrHeight = mDirectShareCurrHeight > 0
+                                         ? mDirectShareCurrHeight : mDirectShareMinHeight;
+            mDirectShareMaxHeight = 2 * mDirectShareMinHeight;
+        }
+
+        public int getMeasuredRowHeight() {
+            return mDirectShareCurrHeight;
+        }
+
+        public void handleScroll(AbsListView view, int y, int oldy, int maxTargetsPerRow) {
+            // only expand if we have more than 4 targets, and delay that decision until
+            // they start to scroll
+            if (mHideDirectShareExpansion) {
+                return;
+            }
+
+            if (mChooserListAdapter.getSelectableServiceTargetCount() <= maxTargetsPerRow) {
+                mHideDirectShareExpansion = true;
+                return;
+            }
+
+            int yDiff = (int) ((oldy - y) * 0.7f);
+
+            int prevHeight = mDirectShareCurrHeight;
+            mDirectShareCurrHeight = Math.min(mDirectShareCurrHeight + yDiff,
+                    mDirectShareMaxHeight);
+            mDirectShareCurrHeight = Math.max(mDirectShareCurrHeight, mDirectShareMinHeight);
+            yDiff = mDirectShareCurrHeight - prevHeight;
+
+            if (view == null || view.getChildCount() == 0) {
+                return;
+            }
+
+            int index = mChooserRowAdapter.getContentPreviewRowCount();
+
+            ViewGroup expansionGroup = (ViewGroup) view.getChildAt(index);
+            int widthSpec = MeasureSpec.makeMeasureSpec(expansionGroup.getWidth(),
+                    MeasureSpec.EXACTLY);
+            int heightSpec = MeasureSpec.makeMeasureSpec(mDirectShareCurrHeight,
+                    MeasureSpec.EXACTLY);
+            expansionGroup.measure(widthSpec, heightSpec);
+            expansionGroup.getLayoutParams().height = expansionGroup.getMeasuredHeight();
+            expansionGroup.layout(expansionGroup.getLeft(), expansionGroup.getTop(),
+                    expansionGroup.getRight(),
+                    expansionGroup.getTop() + expansionGroup.getMeasuredHeight());
+
+            // reposition list items
+            int items = view.getChildCount();
+            for (int i = index + 1; i < items; i++) {
+                view.getChildAt(i).offsetTopAndBottom(yDiff);
+            }
         }
     }
 
@@ -2519,13 +2746,13 @@
             final int chooserTargetRows = mChooserRowAdapter.getServiceTargetRowCount();
             int offset = 0;
             for (int i = 0; i < chooserTargetRows; i++) {
-                final int pos = mChooserRowAdapter.getCallerTargetRowCount() + i;
+                final int pos = mChooserRowAdapter.getContentPreviewRowCount() + i;
                 final int vt = mChooserRowAdapter.getItemViewType(pos);
                 if (vt != mCachedViewType) {
                     mCachedView = null;
                 }
                 final View v = mChooserRowAdapter.getView(pos, mCachedView, mListView);
-                int height = ((RowViewHolder) (v.getTag())).measuredRowHeight;
+                int height = ((RowViewHolder) (v.getTag())).getMeasuredRowHeight();
 
                 offset += (int) (height);
 
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 011cc04..12942ab 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -42,6 +42,8 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -49,6 +51,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.PatternMatcher;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.StrictMode;
 import android.os.UserHandle;
@@ -56,7 +59,6 @@
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.text.TextUtils;
-import android.util.IconDrawableFactory;
 import android.util.Log;
 import android.util.Slog;
 import android.view.LayoutInflater;
@@ -99,7 +101,7 @@
 
     protected ResolveListAdapter mAdapter;
     private boolean mSafeForwardingMode;
-    private AbsListView mAdapterView;
+    protected AbsListView mAdapterView;
     private Button mAlwaysButton;
     private Button mOnceButton;
     private Button mSettingsButton;
@@ -131,7 +133,7 @@
     /** See {@link #setRetainInOnStop}. */
     private boolean mRetainInOnStop;
 
-    IconDrawableFactory mIconFactory;
+    SimpleIconFactory mSimpleIconFactory;
 
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
         @Override public void onSomePackagesChanged() {
@@ -309,7 +311,11 @@
         // as to mitigate Intent Capturing vulnerability
         mSupportsAlwaysUseOption = supportsAlwaysUseOption && !mUseLayoutForBrowsables;
 
-        mIconFactory = IconDrawableFactory.newInstance(this, true);
+        final int iconSize = getResources().getDimensionPixelSize(R.dimen.resolver_icon_size);
+        final int badgeSize = getResources().getDimensionPixelSize(R.dimen.resolver_badge_size);
+        mSimpleIconFactory = new SimpleIconFactory(this, mIconDpi, iconSize, badgeSize);
+        mSimpleIconFactory.setWrapperBackgroundColor(Color.WHITE);
+
         if (configureContentView(mIntents, initialIntents, rList)) {
             return;
         }
@@ -494,6 +500,7 @@
         }
     }
 
+    @Nullable
     Drawable getIcon(Resources res, int resId) {
         Drawable result;
         try {
@@ -505,26 +512,52 @@
         return result;
     }
 
+    /**
+     * Loads the icon for the provided ResolveInfo. Defaults to using the application icon over
+     * any IntentFilter or Activity icon to increase user understanding, with an exception for
+     * applications that hold the right permission. Always attempts to use icon resources over
+     * PackageManager loading mechanisms so badging can be done by iconloader.
+     */
     Drawable loadIconForResolveInfo(ResolveInfo ri) {
-        Drawable dr;
-        try {
-            if (ri.resolvePackageName != null && ri.icon != 0) {
-                dr = getIcon(mPm.getResourcesForApplication(ri.resolvePackageName), ri.icon);
-                if (dr != null) {
-                    return mIconFactory.getShadowedIcon(dr);
+        Drawable dr = null;
+
+        // Allow for app icon override given the right permission
+        if (PackageManager.PERMISSION_GRANTED == mPm.checkPermission(
+                android.Manifest.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON,
+                ri.activityInfo.applicationInfo.packageName)) {
+            try {
+                if (ri.resolvePackageName != null && ri.icon != 0) {
+                    dr = getIcon(mPm.getResourcesForApplication(ri.resolvePackageName), ri.icon);
                 }
-            }
-            final int iconRes = ri.getIconResource();
-            if (iconRes != 0) {
-                dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.packageName), iconRes);
-                if (dr != null) {
-                    return mIconFactory.getShadowedIcon(dr);
+                if (dr == null) {
+                    final int iconRes = ri.getIconResource();
+                    if (iconRes != 0) {
+                        dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.packageName),
+                                iconRes);
+                    }
                 }
+            } catch (NameNotFoundException e) {
+                Log.e(TAG, "SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON permission granted but "
+                        + "couldn't find resources for package", e);
             }
-        } catch (NameNotFoundException e) {
-            Log.e(TAG, "Couldn't find resources for package", e);
         }
-        return mIconFactory.getBadgedIcon(ri.activityInfo.applicationInfo);
+
+        // Use app icons for better user association
+        if (dr == null) {
+            try {
+                dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.applicationInfo),
+                        ri.activityInfo.applicationInfo.icon);
+            } catch (NameNotFoundException ignore) {
+            }
+        }
+
+        // Fall back to ApplicationInfo#loadIcon if nothing has been loaded
+        if (dr == null) {
+            dr = ri.activityInfo.applicationInfo.loadIcon(mPm);
+        }
+
+        return new BitmapDrawable(this.getResources(),
+                mSimpleIconFactory.createUserBadgedIconBitmap(dr, Process.myUserHandle()));
     }
 
     @Override
@@ -1177,7 +1210,6 @@
         private final CharSequence mExtendedInfo;
         private final Intent mResolvedIntent;
         private final List<Intent> mSourceIntents = new ArrayList<>();
-        private boolean mPinned;
 
         public DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel,
                 CharSequence pInfo, Intent pOrigIntent) {
@@ -1204,7 +1236,6 @@
             mExtendedInfo = other.mExtendedInfo;
             mResolvedIntent = new Intent(other.mResolvedIntent);
             mResolvedIntent.fillIn(fillInIntent, flags);
-            mPinned = other.mPinned;
         }
 
         public ResolveInfo getResolveInfo() {
@@ -1304,15 +1335,6 @@
             activity.startActivityAsUser(mResolvedIntent, options, user);
             return false;
         }
-
-        @Override
-        public boolean isPinned() {
-            return mPinned;
-        }
-
-        public void setPinned(boolean pinned) {
-            mPinned = pinned;
-        }
     }
 
     /**
@@ -1414,11 +1436,6 @@
          * @return the list of supported source intents deduped against this single target
          */
         List<Intent> getAllSourceIntents();
-
-        /**
-         * @return true if this target should be pinned to the front by the request of the user
-         */
-        boolean isPinned();
     }
 
     public class ResolveListAdapter extends BaseAdapter {
@@ -1776,7 +1793,6 @@
             final Intent replaceIntent = getReplacementIntent(add.activityInfo, intent);
             final DisplayResolveInfo dri = new DisplayResolveInfo(intent, add, roLabel,
                     extraInfo, replaceIntent);
-            dri.setPinned(rci.isPinned());
             addResolveInfo(dri);
             if (replaceIntent == intent) {
                 // Only add alternates if we didn't get a specific replacement from
@@ -1921,10 +1937,6 @@
             return !TextUtils.isEmpty(info.getExtendedInfo());
         }
 
-        public boolean isComponentPinned(ComponentName name) {
-            return false;
-        }
-
         public final void bindView(int position, View view) {
             onBindView(view, getItem(position));
         }
@@ -1967,7 +1979,6 @@
     @VisibleForTesting
     public static final class ResolvedComponentInfo {
         public final ComponentName name;
-        private boolean mPinned;
         private final List<Intent> mIntents = new ArrayList<>();
         private final List<ResolveInfo> mResolveInfos = new ArrayList<>();
 
@@ -2010,14 +2021,6 @@
             }
             return -1;
         }
-
-        public boolean isPinned() {
-            return mPinned;
-        }
-
-        public void setPinned(boolean pinned) {
-            mPinned = pinned;
-        }
     }
 
     static class ViewHolder {
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index f61a03b..b9f67e6 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -325,30 +325,18 @@
             }
         }
 
-        final boolean lPinned = lhsp.isPinned();
-        final boolean rPinned = rhsp.isPinned();
+        if (mStats != null) {
+            final ResolverTarget lhsTarget = mTargetsDict.get(new ComponentName(
+                    lhs.activityInfo.packageName, lhs.activityInfo.name));
+            final ResolverTarget rhsTarget = mTargetsDict.get(new ComponentName(
+                    rhs.activityInfo.packageName, rhs.activityInfo.name));
 
-        if (lPinned && !rPinned) {
-            return -1;
-        } else if (!lPinned && rPinned) {
-            return 1;
-        }
-
-        // Pinned items stay stable within a normal lexical sort and ignore scoring.
-        if (!lPinned && !rPinned) {
-            if (mStats != null) {
-                final ResolverTarget lhsTarget = mTargetsDict.get(new ComponentName(
-                        lhs.activityInfo.packageName, lhs.activityInfo.name));
-                final ResolverTarget rhsTarget = mTargetsDict.get(new ComponentName(
-                        rhs.activityInfo.packageName, rhs.activityInfo.name));
-
-                if (lhsTarget != null && rhsTarget != null) {
-                    final int selectProbabilityDiff = Float.compare(
+            if (lhsTarget != null && rhsTarget != null) {
+                final int selectProbabilityDiff = Float.compare(
                         rhsTarget.getSelectProbability(), lhsTarget.getSelectProbability());
 
-                    if (selectProbabilityDiff != 0) {
-                        return selectProbabilityDiff > 0 ? 1 : -1;
-                    }
+                if (selectProbabilityDiff != 0) {
+                    return selectProbabilityDiff > 0 ? 1 : -1;
                 }
             }
         }
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 61aeca6..f48102a 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -30,14 +30,13 @@
 import android.content.pm.ResolveInfo;
 import android.os.RemoteException;
 import android.util.Log;
-import com.android.internal.annotations.GuardedBy;
+
 import com.android.internal.annotations.VisibleForTesting;
 
-import java.lang.InterruptedException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.concurrent.CountDownLatch;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 
 /**
  * A helper for the ResolverActivity that exposes methods to retrieve, filter and sort its list of
@@ -147,7 +146,6 @@
                         newInfo.activityInfo.packageName, newInfo.activityInfo.name);
                 final ResolverActivity.ResolvedComponentInfo rci =
                         new ResolverActivity.ResolvedComponentInfo(name, intent, newInfo);
-                rci.setPinned(isComponentPinned(name));
                 into.add(rci);
             }
         }
@@ -270,10 +268,6 @@
                 && ai.name.equals(b.name.getClassName());
     }
 
-    boolean isComponentPinned(ComponentName name) {
-        return false;
-    }
-
     boolean isComponentFiltered(ComponentName componentName) {
         return false;
     }
diff --git a/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java b/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java
index 8156f79..a49240c 100644
--- a/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java
+++ b/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java
@@ -23,7 +23,6 @@
 import android.content.ComponentName;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.SharedPreferences;
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.Settings;
@@ -36,34 +35,27 @@
 public class ResolverTargetActionsDialogFragment extends DialogFragment
         implements DialogInterface.OnClickListener {
     private static final String NAME_KEY = "componentName";
-    private static final String PINNED_KEY = "pinned";
     private static final String TITLE_KEY = "title";
 
     // Sync with R.array.resolver_target_actions_* resources
-    private static final int TOGGLE_PIN_INDEX = 0;
-    private static final int APP_INFO_INDEX = 1;
+    private static final int APP_INFO_INDEX = 0;
 
     public ResolverTargetActionsDialogFragment() {
     }
 
-    public ResolverTargetActionsDialogFragment(CharSequence title, ComponentName name,
-            boolean pinned) {
+    public ResolverTargetActionsDialogFragment(CharSequence title, ComponentName name) {
         Bundle args = new Bundle();
         args.putCharSequence(TITLE_KEY, title);
         args.putParcelable(NAME_KEY, name);
-        args.putBoolean(PINNED_KEY, pinned);
         setArguments(args);
     }
 
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         final Bundle args = getArguments();
-        final int itemRes = args.getBoolean(PINNED_KEY, false)
-                ? R.array.resolver_target_actions_unpin
-                : R.array.resolver_target_actions_pin;
         return new Builder(getContext())
                 .setCancelable(true)
-                .setItems(itemRes, this)
+                .setItems(R.array.resolver_target_actions, this)
                 .setTitle(args.getCharSequence(TITLE_KEY))
                 .create();
     }
@@ -73,19 +65,6 @@
         final Bundle args = getArguments();
         ComponentName name = args.getParcelable(NAME_KEY);
         switch (which) {
-            case TOGGLE_PIN_INDEX:
-                SharedPreferences sp = ChooserActivity.getPinnedSharedPrefs(getContext());
-                final String key = name.flattenToString();
-                boolean currentVal = sp.getBoolean(name.flattenToString(), false);
-                if (currentVal) {
-                    sp.edit().remove(key).apply();
-                } else {
-                    sp.edit().putBoolean(key, true).apply();
-                }
-
-                // Force the chooser to requery and resort things
-                getActivity().recreate();
-                break;
             case APP_INFO_INDEX:
                 Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                         .setData(Uri.fromParts("package", name.getPackageName(), null))
diff --git a/core/java/com/android/internal/app/SimpleIconFactory.java b/core/java/com/android/internal/app/SimpleIconFactory.java
new file mode 100644
index 0000000..eb1530e
--- /dev/null
+++ b/core/java/com/android/internal/app/SimpleIconFactory.java
@@ -0,0 +1,609 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import static android.graphics.Paint.DITHER_FLAG;
+import static android.graphics.Paint.FILTER_BITMAP_FLAG;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
+import android.graphics.BlurMaskFilter.Blur;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableWrapper;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.AttributeSet;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+
+import java.nio.ByteBuffer;
+
+
+/**
+ * @deprecated Use the Launcher3 Iconloaderlib at packages/apps/Launcher3/iconloaderlib. This class
+ * is a temporary fork of Iconloader. It combines all necessary methods to render app icons that are
+ * possibly badged. It is intended to be used only by Sharesheet for the Q release.
+ */
+@Deprecated
+public class SimpleIconFactory {
+
+    private static final int DEFAULT_WRAPPER_BACKGROUND = Color.WHITE;
+    private static final float BLUR_FACTOR = 0.5f / 48;
+
+    private Context mContext;
+    private Canvas mCanvas;
+    private PackageManager mPm;
+
+    private int mFillResIconDpi;
+    private int mIconBitmapSize;
+    private int mBadgeBitmapSize;
+    private int mWrapperBackgroundColor;
+
+    private Drawable mWrapperIcon;
+    private final Rect mOldBounds = new Rect();
+
+    /**
+     * @deprecated Do not use, functionality will be replaced by iconloader lib eventually.
+     */
+    @Deprecated
+    SimpleIconFactory(Context context, int fillResIconDpi, int iconBitmapSize,
+            int badgeBitmapSize) {
+        mContext = context.getApplicationContext();
+        mPm = mContext.getPackageManager();
+        mIconBitmapSize = iconBitmapSize;
+        mBadgeBitmapSize = badgeBitmapSize;
+        mFillResIconDpi = fillResIconDpi;
+
+        mCanvas = new Canvas();
+        mCanvas.setDrawFilter(new PaintFlagsDrawFilter(DITHER_FLAG, FILTER_BITMAP_FLAG));
+
+        // Normalizer init
+        // Use twice the icon size as maximum size to avoid scaling down twice.
+        mMaxSize = iconBitmapSize * 2;
+        mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);
+        mScaleCheckCanvas = new Canvas(mBitmap);
+        mPixels = new byte[mMaxSize * mMaxSize];
+        mLeftBorder = new float[mMaxSize];
+        mRightBorder = new float[mMaxSize];
+        mBounds = new Rect();
+        mAdaptiveIconBounds = new Rect();
+        mAdaptiveIconScale = SCALE_NOT_INITIALIZED;
+
+        // Shadow generator init
+        mDefaultBlurMaskFilter = new BlurMaskFilter(iconBitmapSize * BLUR_FACTOR,
+                Blur.NORMAL);
+    }
+
+    /**
+     * Sets the background color used for wrapped adaptive icon
+     *
+     * @deprecated Do not use, functionality will be replaced by iconloader lib eventually.
+     */
+    @Deprecated
+    void setWrapperBackgroundColor(int color) {
+        mWrapperBackgroundColor = (Color.alpha(color) < 255) ? DEFAULT_WRAPPER_BACKGROUND : color;
+    }
+
+    /**
+     * Creates bitmap using the source drawable and various parameters.
+     * The bitmap is visually normalized with other icons and has enough spacing to add shadow.
+     *
+     * @param icon                      source of the icon associated with a user that has no badge,
+     *                                  likely user 0
+     * @param user                      info can be used for a badge
+     * @return a bitmap suitable for disaplaying as an icon at various system UIs.
+     *
+     * @deprecated Do not use, functionality will be replaced by iconloader lib eventually.
+     */
+    @Deprecated
+    Bitmap createUserBadgedIconBitmap(@Nullable Drawable icon, UserHandle user) {
+        float [] scale = new float[1];
+
+        // If no icon is provided use the system default
+        if (icon == null) {
+            icon = getFullResDefaultActivityIcon(mFillResIconDpi);
+        }
+        icon = normalizeAndWrapToAdaptiveIcon(icon, null, scale);
+        Bitmap bitmap = createIconBitmap(icon, scale[0]);
+        if (icon instanceof AdaptiveIconDrawable) {
+            mCanvas.setBitmap(bitmap);
+            recreateIcon(Bitmap.createBitmap(bitmap), mCanvas);
+            mCanvas.setBitmap(null);
+        }
+
+        final Bitmap result;
+        if (user != null && !Process.myUserHandle().equals(user)) {
+            BitmapDrawable drawable = new FixedSizeBitmapDrawable(bitmap);
+            Drawable badged = mPm.getUserBadgedIcon(drawable, user);
+            if (badged instanceof BitmapDrawable) {
+                result = ((BitmapDrawable) badged).getBitmap();
+            } else {
+                result = createIconBitmap(badged, 1f);
+            }
+        } else {
+            result = bitmap;
+        }
+
+        return result;
+    }
+
+    /**
+     * Creates bitmap using the source drawable and flattened pre-rendered app icon.
+     * The bitmap is visually normalized with other icons and has enough spacing to add shadow.
+     *
+     * @param icon                      source of the icon associated with a user that has no badge
+     * @param renderedAppIcon           pre-rendered app icon to use as a badge, likely the output
+     *                                  of createUserBadgedIconBitmap for user 0
+     * @return a bitmap suitable for disaplaying as an icon at various system UIs.
+     *
+     * @deprecated Do not use, functionality will be replaced by iconloader lib eventually.
+     */
+    @Deprecated
+    public Bitmap createAppBadgedIconBitmap(@Nullable Drawable icon, Bitmap renderedAppIcon) {
+        // Flatten the passed in icon
+        float [] scale = new float[1];
+
+        // If no icon is provided use the system default
+        if (icon == null) {
+            icon = getFullResDefaultActivityIcon(mFillResIconDpi);
+        }
+        icon = normalizeAndWrapToAdaptiveIcon(icon, null, scale);
+        Bitmap bitmap = createIconBitmap(icon, scale[0]);
+        if (icon instanceof AdaptiveIconDrawable) {
+            mCanvas.setBitmap(bitmap);
+            recreateIcon(Bitmap.createBitmap(bitmap), mCanvas);
+            mCanvas.setBitmap(null);
+        }
+
+        // Now scale down and apply the badge to the bottom right corner of the flattened icon
+        renderedAppIcon = Bitmap.createScaledBitmap(renderedAppIcon, mBadgeBitmapSize,
+                mBadgeBitmapSize, false);
+
+        // Paint the provided badge on top of the flattened icon
+        mCanvas.setBitmap(bitmap);
+        mCanvas.drawBitmap(renderedAppIcon, mIconBitmapSize - mBadgeBitmapSize,
+                mIconBitmapSize - mBadgeBitmapSize, null);
+        mCanvas.setBitmap(null);
+
+        return bitmap;
+    }
+
+    private static Drawable getFullResDefaultActivityIcon(int iconDpi) {
+        return Resources.getSystem().getDrawableForDensity(android.R.mipmap.sym_def_app_icon,
+                iconDpi);
+    }
+
+    private Bitmap createIconBitmap(Drawable icon, float scale) {
+        return createIconBitmap(icon, scale, mIconBitmapSize);
+    }
+
+    /**
+     * @param icon drawable that should be flattened to a bitmap
+     * @param scale the scale to apply before drawing {@param icon} on the canvas
+     */
+    private Bitmap createIconBitmap(Drawable icon, float scale, int size) {
+        Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+
+        mCanvas.setBitmap(bitmap);
+        mOldBounds.set(icon.getBounds());
+
+        if (icon instanceof AdaptiveIconDrawable) {
+            int offset = Math.max((int) Math.ceil(BLUR_FACTOR * size),
+                    Math.round(size * (1 - scale) / 2));
+            icon.setBounds(offset, offset, size - offset, size - offset);
+            icon.draw(mCanvas);
+        } else {
+            if (icon instanceof BitmapDrawable) {
+                BitmapDrawable bitmapDrawable = (BitmapDrawable) icon;
+                Bitmap b = bitmapDrawable.getBitmap();
+                if (bitmap != null && b.getDensity() == Bitmap.DENSITY_NONE) {
+                    bitmapDrawable.setTargetDensity(mContext.getResources().getDisplayMetrics());
+                }
+            }
+            int width = size;
+            int height = size;
+
+            int intrinsicWidth = icon.getIntrinsicWidth();
+            int intrinsicHeight = icon.getIntrinsicHeight();
+            if (intrinsicWidth > 0 && intrinsicHeight > 0) {
+                // Scale the icon proportionally to the icon dimensions
+                final float ratio = (float) intrinsicWidth / intrinsicHeight;
+                if (intrinsicWidth > intrinsicHeight) {
+                    height = (int) (width / ratio);
+                } else if (intrinsicHeight > intrinsicWidth) {
+                    width = (int) (height * ratio);
+                }
+            }
+            final int left = (size - width) / 2;
+            final int top = (size - height) / 2;
+            icon.setBounds(left, top, left + width, top + height);
+            mCanvas.save();
+            mCanvas.scale(scale, scale, size / 2, size / 2);
+            icon.draw(mCanvas);
+            mCanvas.restore();
+
+        }
+
+        icon.setBounds(mOldBounds);
+        mCanvas.setBitmap(null);
+        return bitmap;
+    }
+
+    private Drawable normalizeAndWrapToAdaptiveIcon(Drawable icon, RectF outIconBounds,
+            float[] outScale) {
+        float scale = 1f;
+
+        if (mWrapperIcon == null) {
+            mWrapperIcon = mContext.getDrawable(
+                    R.drawable.iconfactory_adaptive_icon_drawable_wrapper).mutate();
+        }
+
+        AdaptiveIconDrawable dr = (AdaptiveIconDrawable) mWrapperIcon;
+        dr.setBounds(0, 0, 1, 1);
+        scale = getScale(icon, outIconBounds);
+        if (!(icon instanceof AdaptiveIconDrawable)) {
+            FixedScaleDrawable fsd = ((FixedScaleDrawable) dr.getForeground());
+            fsd.setDrawable(icon);
+            fsd.setScale(scale);
+            icon = dr;
+            scale = getScale(icon, outIconBounds);
+
+            ((ColorDrawable) dr.getBackground()).setColor(mWrapperBackgroundColor);
+        }
+
+        outScale[0] = scale;
+        return icon;
+    }
+
+
+    /* Normalization block */
+
+    private static final float SCALE_NOT_INITIALIZED = 0;
+    // Ratio of icon visible area to full icon size for a square shaped icon
+    private static final float MAX_SQUARE_AREA_FACTOR = 375.0f / 576;
+    // Ratio of icon visible area to full icon size for a circular shaped icon
+    private static final float MAX_CIRCLE_AREA_FACTOR = 380.0f / 576;
+
+    private static final float CIRCLE_AREA_BY_RECT = (float) Math.PI / 4;
+
+    // Slope used to calculate icon visible area to full icon size for any generic shaped icon.
+    private static final float LINEAR_SCALE_SLOPE =
+            (MAX_CIRCLE_AREA_FACTOR - MAX_SQUARE_AREA_FACTOR) / (1 - CIRCLE_AREA_BY_RECT);
+
+    private static final int MIN_VISIBLE_ALPHA = 40;
+
+    private float mAdaptiveIconScale;
+    private final Rect mAdaptiveIconBounds;
+    private final Rect mBounds;
+    private final int mMaxSize;
+    private final byte[] mPixels;
+    private final float[] mLeftBorder;
+    private final float[] mRightBorder;
+    private final Bitmap mBitmap;
+    private final Canvas mScaleCheckCanvas;
+
+    /**
+     * Returns the amount by which the {@param d} should be scaled (in both dimensions) so that it
+     * matches the design guidelines for a launcher icon.
+     *
+     * We first calculate the convex hull of the visible portion of the icon.
+     * This hull then compared with the bounding rectangle of the hull to find how closely it
+     * resembles a circle and a square, by comparing the ratio of the areas. Note that this is not
+     * an ideal solution but it gives satisfactory result without affecting the performance.
+     *
+     * This closeness is used to determine the ratio of hull area to the full icon size.
+     * Refer {@link #MAX_CIRCLE_AREA_FACTOR} and {@link #MAX_SQUARE_AREA_FACTOR}
+     *
+     * @param outBounds optional rect to receive the fraction distance from each edge.
+     */
+    private synchronized float getScale(@NonNull Drawable d, @Nullable RectF outBounds) {
+        if (d instanceof AdaptiveIconDrawable) {
+            if (mAdaptiveIconScale != SCALE_NOT_INITIALIZED) {
+                if (outBounds != null) {
+                    outBounds.set(mAdaptiveIconBounds);
+                }
+                return mAdaptiveIconScale;
+            }
+        }
+        int width = d.getIntrinsicWidth();
+        int height = d.getIntrinsicHeight();
+        if (width <= 0 || height <= 0) {
+            width = width <= 0 || width > mMaxSize ? mMaxSize : width;
+            height = height <= 0 || height > mMaxSize ? mMaxSize : height;
+        } else if (width > mMaxSize || height > mMaxSize) {
+            int max = Math.max(width, height);
+            width = mMaxSize * width / max;
+            height = mMaxSize * height / max;
+        }
+
+        mBitmap.eraseColor(Color.TRANSPARENT);
+        d.setBounds(0, 0, width, height);
+        d.draw(mScaleCheckCanvas);
+
+        ByteBuffer buffer = ByteBuffer.wrap(mPixels);
+        buffer.rewind();
+        mBitmap.copyPixelsToBuffer(buffer);
+
+        // Overall bounds of the visible icon.
+        int topY = -1;
+        int bottomY = -1;
+        int leftX = mMaxSize + 1;
+        int rightX = -1;
+
+        // Create border by going through all pixels one row at a time and for each row find
+        // the first and the last non-transparent pixel. Set those values to mLeftBorder and
+        // mRightBorder and use -1 if there are no visible pixel in the row.
+
+        // buffer position
+        int index = 0;
+        // buffer shift after every row, width of buffer = mMaxSize
+        int rowSizeDiff = mMaxSize - width;
+        // first and last position for any row.
+        int firstX, lastX;
+
+        for (int y = 0; y < height; y++) {
+            firstX = lastX = -1;
+            for (int x = 0; x < width; x++) {
+                if ((mPixels[index] & 0xFF) > MIN_VISIBLE_ALPHA) {
+                    if (firstX == -1) {
+                        firstX = x;
+                    }
+                    lastX = x;
+                }
+                index++;
+            }
+            index += rowSizeDiff;
+
+            mLeftBorder[y] = firstX;
+            mRightBorder[y] = lastX;
+
+            // If there is at least one visible pixel, update the overall bounds.
+            if (firstX != -1) {
+                bottomY = y;
+                if (topY == -1) {
+                    topY = y;
+                }
+
+                leftX = Math.min(leftX, firstX);
+                rightX = Math.max(rightX, lastX);
+            }
+        }
+
+        if (topY == -1 || rightX == -1) {
+            // No valid pixels found. Do not scale.
+            return 1;
+        }
+
+        convertToConvexArray(mLeftBorder, 1, topY, bottomY);
+        convertToConvexArray(mRightBorder, -1, topY, bottomY);
+
+        // Area of the convex hull
+        float area = 0;
+        for (int y = 0; y < height; y++) {
+            if (mLeftBorder[y] <= -1) {
+                continue;
+            }
+            area += mRightBorder[y] - mLeftBorder[y] + 1;
+        }
+
+        // Area of the rectangle required to fit the convex hull
+        float rectArea = (bottomY + 1 - topY) * (rightX + 1 - leftX);
+        float hullByRect = area / rectArea;
+
+        float scaleRequired;
+        if (hullByRect < CIRCLE_AREA_BY_RECT) {
+            scaleRequired = MAX_CIRCLE_AREA_FACTOR;
+        } else {
+            scaleRequired = MAX_SQUARE_AREA_FACTOR + LINEAR_SCALE_SLOPE * (1 - hullByRect);
+        }
+        mBounds.left = leftX;
+        mBounds.right = rightX;
+
+        mBounds.top = topY;
+        mBounds.bottom = bottomY;
+
+        if (outBounds != null) {
+            outBounds.set(((float) mBounds.left) / width, ((float) mBounds.top) / height,
+                    1 - ((float) mBounds.right) / width,
+                    1 - ((float) mBounds.bottom) / height);
+        }
+        float areaScale = area / (width * height);
+        // Use sqrt of the final ratio as the images is scaled across both width and height.
+        float scale = areaScale > scaleRequired ? (float) Math.sqrt(scaleRequired / areaScale) : 1;
+        if (d instanceof AdaptiveIconDrawable && mAdaptiveIconScale == SCALE_NOT_INITIALIZED) {
+            mAdaptiveIconScale = scale;
+            mAdaptiveIconBounds.set(mBounds);
+        }
+        return scale;
+    }
+
+    /**
+     * Modifies {@param xCoordinates} to represent a convex border. Fills in all missing values
+     * (except on either ends) with appropriate values.
+     * @param xCoordinates map of x coordinate per y.
+     * @param direction 1 for left border and -1 for right border.
+     * @param topY the first Y position (inclusive) with a valid value.
+     * @param bottomY the last Y position (inclusive) with a valid value.
+     */
+    private static void convertToConvexArray(
+            float[] xCoordinates, int direction, int topY, int bottomY) {
+        int total = xCoordinates.length;
+        // The tangent at each pixel.
+        float[] angles = new float[total - 1];
+
+        int first = topY; // First valid y coordinate
+        int last = -1;    // Last valid y coordinate which didn't have a missing value
+
+        float lastAngle = Float.MAX_VALUE;
+
+        for (int i = topY + 1; i <= bottomY; i++) {
+            if (xCoordinates[i] <= -1) {
+                continue;
+            }
+            int start;
+
+            if (lastAngle == Float.MAX_VALUE) {
+                start = first;
+            } else {
+                float currentAngle = (xCoordinates[i] - xCoordinates[last]) / (i - last);
+                start = last;
+                // If this position creates a concave angle, keep moving up until we find a
+                // position which creates a convex angle.
+                if ((currentAngle - lastAngle) * direction < 0) {
+                    while (start > first) {
+                        start--;
+                        currentAngle = (xCoordinates[i] - xCoordinates[start]) / (i - start);
+                        if ((currentAngle - angles[start]) * direction >= 0) {
+                            break;
+                        }
+                    }
+                }
+            }
+
+            // Reset from last check
+            lastAngle = (xCoordinates[i] - xCoordinates[start]) / (i - start);
+            // Update all the points from start.
+            for (int j = start; j < i; j++) {
+                angles[j] = lastAngle;
+                xCoordinates[j] = xCoordinates[start] + lastAngle * (j - start);
+            }
+            last = i;
+        }
+    }
+
+    /* Shadow generator block */
+
+    private static final float KEY_SHADOW_DISTANCE = 1f / 48;
+    private static final int KEY_SHADOW_ALPHA = 61;
+    private static final int AMBIENT_SHADOW_ALPHA = 30;
+
+    private Paint mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+    private Paint mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+    private BlurMaskFilter mDefaultBlurMaskFilter;
+
+    private synchronized void recreateIcon(Bitmap icon, Canvas out) {
+        recreateIcon(icon, mDefaultBlurMaskFilter, AMBIENT_SHADOW_ALPHA, KEY_SHADOW_ALPHA, out);
+    }
+
+    private synchronized void recreateIcon(Bitmap icon, BlurMaskFilter blurMaskFilter,
+            int ambientAlpha, int keyAlpha, Canvas out) {
+        int[] offset = new int[2];
+        mBlurPaint.setMaskFilter(blurMaskFilter);
+        Bitmap shadow = icon.extractAlpha(mBlurPaint, offset);
+
+        // Draw ambient shadow
+        mDrawPaint.setAlpha(ambientAlpha);
+        out.drawBitmap(shadow, offset[0], offset[1], mDrawPaint);
+
+        // Draw key shadow
+        mDrawPaint.setAlpha(keyAlpha);
+        out.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconBitmapSize,
+                mDrawPaint);
+
+        // Draw the icon
+        mDrawPaint.setAlpha(255); // TODO if b/128609682 not fixed by launch use .setAlpha(254)
+        out.drawBitmap(icon, 0, 0, mDrawPaint);
+    }
+
+    /* Classes */
+
+    /**
+     * Extension of {@link DrawableWrapper} which scales the child drawables by a fixed amount.
+     */
+    public static class FixedScaleDrawable extends DrawableWrapper {
+
+        private static final float LEGACY_ICON_SCALE = .7f * .6667f;
+        private float mScaleX, mScaleY;
+
+        public FixedScaleDrawable() {
+            super(new ColorDrawable());
+            mScaleX = LEGACY_ICON_SCALE;
+            mScaleY = LEGACY_ICON_SCALE;
+        }
+
+        @Override
+        public void draw(@NonNull Canvas canvas) {
+            int saveCount = canvas.save();
+            canvas.scale(mScaleX, mScaleY,
+                    getBounds().exactCenterX(), getBounds().exactCenterY());
+            super.draw(canvas);
+            canvas.restoreToCount(saveCount);
+        }
+
+        @Override
+        public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) { }
+
+        @Override
+        public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) { }
+
+        /**
+         * Sets the scale associated with this drawable
+         * @param scale
+         */
+        public void setScale(float scale) {
+            float h = getIntrinsicHeight();
+            float w = getIntrinsicWidth();
+            mScaleX = scale * LEGACY_ICON_SCALE;
+            mScaleY = scale * LEGACY_ICON_SCALE;
+            if (h > w && w > 0) {
+                mScaleX *= w / h;
+            } else if (w > h && h > 0) {
+                mScaleY *= h / w;
+            }
+        }
+    }
+
+    /**
+     * An extension of {@link BitmapDrawable} which returns the bitmap pixel size as intrinsic size.
+     * This allows the badging to be done based on the action bitmap size rather than
+     * the scaled bitmap size.
+     */
+    private static class FixedSizeBitmapDrawable extends BitmapDrawable {
+
+        FixedSizeBitmapDrawable(Bitmap bitmap) {
+            super(null, bitmap);
+        }
+
+        @Override
+        public int getIntrinsicHeight() {
+            return getBitmap().getWidth();
+        }
+
+        @Override
+        public int getIntrinsicWidth() {
+            return getBitmap().getWidth();
+        }
+    }
+
+}
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 2e709de..eb881de 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -614,6 +614,7 @@
                 if (remoteService != null) {
                     // TODO(b/117779333): we should probably ignore it if service is destroyed.
                     Slog.w(mTag, "timed out after " + service.getRemoteRequestMillis() + " ms");
+                    remoteService.finishRequest(this);
                     onTimeout(remoteService);
                 } else {
                     Slog.w(mTag, "timed out (no service)");
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java
index 6a9db10..248e026 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java
@@ -198,8 +198,8 @@
      *
      * <p>This function will crawl through all process {@code proc} directories found by the pattern
      * {@code /proc/[0-9]*}, and then check the UID using {@code /proc/$PID/status}. This takes
-     * approximately 500ms on a Pixel 2. Therefore, this method can be computationally expensive,
-     * and should not be called more than once an hour.
+     * approximately 500ms on a 2017 device. Therefore, this method can be computationally
+     * expensive, and should not be called more than once an hour.
      *
      * <p>Data is only collected for UIDs passing the predicate supplied in {@link
      * #setUidPredicate}.
@@ -283,7 +283,7 @@
                 if (threadCpuUsage == null) {
                     continue;
                 }
-                if (mMinimumTotalCpuUsageMillis < totalCpuUsage(threadCpuUsage.usageTimesMillis)) {
+                if (mMinimumTotalCpuUsageMillis > totalCpuUsage(threadCpuUsage.usageTimesMillis)) {
                     if (filteredThreadsCpuUsage == null) {
                         filteredThreadsCpuUsage = new int[mFrequenciesKhz.length];
                     }
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index 2442d0b..8b25e2d 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -66,7 +66,7 @@
      */
     public final KernelWakelockStats readKernelWakelockStats(KernelWakelockStats staleStats) {
         byte[] buffer = new byte[32*1024];
-        int len;
+        int len = 0;
         boolean wakeup_sources;
         final long startTime = SystemClock.uptimeMillis();
 
@@ -87,7 +87,11 @@
                 }
             }
 
-            len = is.read(buffer);
+            int cnt;
+            while ((cnt = is.read(buffer, len, buffer.length - len)) > 0) {
+                len += cnt;
+            }
+
             is.close();
         } catch (java.io.IOException e) {
             Slog.wtf(TAG, "failed to read kernel wakelocks", e);
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 70d8b45..992ddd8 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -408,11 +408,11 @@
      * TODO (chriswailes): Cache the system property location in native code and then write a JNI
      *                     function to fetch it.
      */
-    public static String getSystemProperty(String propertyName, String defaultValue) {
+    public static String getConfigurationProperty(String propertyName, String defaultValue) {
         return SystemProperties.get(
                 String.join(".",
                         "persist.device_config",
-                        DeviceConfig.RuntimeNative.NAMESPACE,
+                        DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
                         propertyName),
                 defaultValue);
     }
@@ -433,12 +433,14 @@
      *
      * TODO (chriswailes): Cache the system property location in native code and then write a JNI
      *                     function to fetch it.
+     * TODO (chriswailes): Move into ZygoteConfig.java once the necessary CL lands (go/ag/6580627)
      */
-    public static boolean getSystemPropertyBoolean(String propertyName, Boolean defaultValue) {
+    public static boolean getConfigurationPropertyBoolean(
+            String propertyName, Boolean defaultValue) {
         return SystemProperties.getBoolean(
                 String.join(".",
                         "persist.device_config",
-                        DeviceConfig.RuntimeNative.NAMESPACE,
+                        DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
                         propertyName),
                 defaultValue);
     }
diff --git a/core/java/com/android/internal/os/ZygoteConfig.java b/core/java/com/android/internal/os/ZygoteConfig.java
new file mode 100644
index 0000000..c8ff51e
--- /dev/null
+++ b/core/java/com/android/internal/os/ZygoteConfig.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+/**
+ * Flag names for configuring the zygote.
+ *
+ * @hide
+ */
+public class ZygoteConfig {
+
+    /** If {@code true}, enables the unspecialized app process (USAP) pool feature */
+    public static final String USAP_POOL_ENABLED = "blastula_pool_enabled";
+
+    /** The threshold used to determine if the pool should be refilled */
+    public static final String USAP_POOL_REFILL_THRESHOLD = "blastula_refill_threshold";
+
+    /** The maximum number of processes to keep in the USAP pool */
+    public static final String USAP_POOL_SIZE_MAX = "blastula_pool_size_max";
+
+    /** The minimum number of processes to keep in the USAP pool */
+    public static final String USAP_POOL_SIZE_MIN = "blastula_pool_size_min";
+}
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index 4aff912..3f3aba9 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -22,7 +22,6 @@
 import android.net.LocalSocket;
 import android.os.SystemClock;
 import android.os.Trace;
-import android.provider.DeviceConfig;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.StructPollfd;
@@ -242,44 +241,33 @@
 
     private void fetchUsapPoolPolicyProps() {
         if (mUsapPoolSupported) {
-            final String usapPoolSizeMaxPropString =
-                    Zygote.getSystemProperty(
-                            DeviceConfig.RuntimeNative.USAP_POOL_SIZE_MAX,
-                            USAP_POOL_SIZE_MAX_DEFAULT);
+            final String usapPoolSizeMaxPropString = Zygote.getConfigurationProperty(
+                    ZygoteConfig.USAP_POOL_SIZE_MAX, USAP_POOL_SIZE_MAX_DEFAULT);
 
             if (!usapPoolSizeMaxPropString.isEmpty()) {
-                mUsapPoolSizeMax =
-                        Integer.min(
-                                Integer.parseInt(usapPoolSizeMaxPropString),
-                                USAP_POOL_SIZE_MAX_LIMIT);
+                mUsapPoolSizeMax = Integer.min(Integer.parseInt(
+                        usapPoolSizeMaxPropString), USAP_POOL_SIZE_MAX_LIMIT);
             }
 
-            final String usapPoolSizeMinPropString =
-                    Zygote.getSystemProperty(
-                            DeviceConfig.RuntimeNative.USAP_POOL_SIZE_MIN,
-                            USAP_POOL_SIZE_MIN_DEFAULT);
+            final String usapPoolSizeMinPropString = Zygote.getConfigurationProperty(
+                    ZygoteConfig.USAP_POOL_SIZE_MIN, USAP_POOL_SIZE_MIN_DEFAULT);
 
             if (!usapPoolSizeMinPropString.isEmpty()) {
-                mUsapPoolSizeMin =
-                        Integer.max(
-                                Integer.parseInt(usapPoolSizeMinPropString),
-                                USAP_POOL_SIZE_MIN_LIMIT);
+                mUsapPoolSizeMin = Integer.max(
+                        Integer.parseInt(usapPoolSizeMinPropString), USAP_POOL_SIZE_MIN_LIMIT);
             }
 
-            final String usapPoolRefillThresholdPropString =
-                    Zygote.getSystemProperty(
-                            DeviceConfig.RuntimeNative.USAP_POOL_REFILL_THRESHOLD,
-                            Integer.toString(mUsapPoolSizeMax / 2));
+            final String usapPoolRefillThresholdPropString = Zygote.getConfigurationProperty(
+                    ZygoteConfig.USAP_POOL_REFILL_THRESHOLD,
+                    Integer.toString(mUsapPoolSizeMax / 2));
 
             if (!usapPoolRefillThresholdPropString.isEmpty()) {
-                mUsapPoolRefillThreshold =
-                        Integer.min(
-                                Integer.parseInt(usapPoolRefillThresholdPropString),
-                                mUsapPoolSizeMax);
+                mUsapPoolRefillThreshold = Integer.min(
+                        Integer.parseInt(usapPoolRefillThresholdPropString),
+                        mUsapPoolSizeMax);
             }
 
             // Sanity check
-
             if (mUsapPoolSizeMin >= mUsapPoolSizeMax) {
                 Log.w(TAG, "The max size of the USAP pool must be greater than the minimum size."
                         + "  Restoring default values.");
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 42fb1f5..bb7423a 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -33,7 +33,6 @@
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
 import android.util.Size;
-import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -593,7 +592,7 @@
             refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
             preparePopupContent();
             // We need to specify the position in window coordinates.
-            // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
+            // TODO: Consider to use PopupWindow.setIsLaidOutInScreen(true) so that we can
             // specify the popup position in screen coordinates.
             mPopupWindow.showAtLocation(
                     mParent, Gravity.NO_GRAVITY, mCoordsOnWindow.x, mCoordsOnWindow.y);
@@ -661,7 +660,7 @@
             refreshCoordinatesAndOverflowDirection(contentRectOnScreen);
             preparePopupContent();
             // We need to specify the position in window coordinates.
-            // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can
+            // TODO: Consider to use PopupWindow.setIsLaidOutInScreen(true) so that we can
             // specify the popup position in screen coordinates.
             mPopupWindow.update(
                     mCoordsOnWindow.x, mCoordsOnWindow.y,
@@ -755,7 +754,7 @@
             // and screen coordiantes, where the offset between them should be equal to the window
             // origin, and 2) we can use an arbitrary for this calculation while calculating the
             // location of the rootview is supposed to be least expensive.
-            // TODO: Consider to use PopupWindow.setLayoutInScreenEnabled(true) so that we can avoid
+            // TODO: Consider to use PopupWindow.setIsLaidOutInScreen(true) so that we can avoid
             // the following calculation.
             mParent.getRootView().getLocationOnScreen(mTmpCoords);
             int rootViewLeftOnScreen = mTmpCoords[0];
@@ -1722,7 +1721,7 @@
     private static PopupWindow createPopupWindow(ViewGroup content) {
         ViewGroup popupContentHolder = new LinearLayout(content.getContext());
         PopupWindow popupWindow = new PopupWindow(popupContentHolder);
-        // TODO: Use .setLayoutInScreenEnabled(true) instead of .setClippingEnabled(false)
+        // TODO: Use .setIsLaidOutInScreen(true) instead of .setClippingEnabled(false)
         // unless FLAG_LAYOUT_IN_SCREEN has any unintentional side-effects.
         popupWindow.setClippingEnabled(false);
         popupWindow.setWindowLayoutType(
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index ee8637d8..9722fcb 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -502,6 +502,7 @@
                         new LogMaker(MetricsEvent.ACTION_SHARESHEET_COLLAPSED_CHANGED)
                         .setSubtype(isCollapsedNew ? 1 : 0));
             }
+            onScrollChanged(0, (int) newPos, 0, (int) (newPos - dy));
             postInvalidateOnAnimation();
             return dy;
         }
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 958bb18..561dcad 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -938,6 +938,7 @@
                         } else {
                             mBugreportWhitelistedPackages.add(pkgname);
                         }
+                        XmlUtils.skipCurrentTag(parser);
                     } break;
                     default: {
                         Slog.w(TAG, "Tag " + name + " is unknown in "
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 8f00759..e0b7629 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -206,13 +206,14 @@
     // The caller needs to have already set the alpha type properly, so the
     // native SkBitmap stays in sync with the Java Bitmap.
     assert_premultiplied(bitmap->info(), isPremultiplied);
+    bool fromMalloc = bitmap->pixelStorageType() == PixelStorageType::Heap;
     BitmapWrapper* bitmapWrapper = new BitmapWrapper(bitmap);
     if (!isMutable) {
         bitmapWrapper->bitmap().setImmutable();
     }
     jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
             reinterpret_cast<jlong>(bitmapWrapper), bitmap->width(), bitmap->height(), density,
-            isPremultiplied, ninePatchChunk, ninePatchInsets);
+            isPremultiplied, ninePatchChunk, ninePatchInsets, fromMalloc);
 
     if (env->ExceptionCheck() != 0) {
         ALOGE("*** Uncaught exception returned from Java call!\n");
@@ -1224,7 +1225,7 @@
 {
     gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
     gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
-    gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
+    gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;Z)V");
     gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
     gBitmap_getAllocationByteCountMethodID = GetMethodIDOrDie(env, gBitmap_class, "getAllocationByteCount", "()I");
     return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 4ba4540..47b1548 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -507,18 +507,9 @@
                 ninePatchChunk, ninePatchInsets, -1);
     }
 
-    // Speculative fix for b/112551574. It doesn't seem like |b| can be null. If it is, print some
-    // info that might be helpful to diagnose.
-    Bitmap* b = defaultAllocator.getStorageObjAndReset();
-    if (!b) {
-        ALOGW("defaultAllocator has no storage object!");
-        ALOGW("\tjavaBitmap: %s", (javaBitmap == nullptr ? "null" : "present"));
-        ALOGW("\tisHardware: %s", (isHardware ? "true" : "false"));
-        ALOGW("\twillScale: %s", (willScale ? "true" : "false"));
-        return nullptr;
-    }
     // now create the java bitmap
-    return bitmap::createBitmap(env, b, bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1);
+    return bitmap::createBitmap(env, defaultAllocator.getStorageObjAndReset(),
+            bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1);
 }
 
 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index cd7346e..cd5c734 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -723,13 +723,17 @@
         obj->setStyle(style);
     }
 
-    static void setColor(jlong paintHandle, jlong colorSpaceHandle,
-            jfloat r, jfloat g, jfloat b, jfloat a) {
+    static void setColorLong(jlong paintHandle, jlong colorSpaceHandle,
+            jlong colorLong) {
+        SkColor4f color = GraphicsJNI::convertColorLong(colorLong);
         sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
-        SkColor4f color = SkColor4f{r, g, b, a};
         reinterpret_cast<Paint*>(paintHandle)->setColor4f(color, cs.get());
     }
 
+    static void setColor(jlong paintHandle, jint color) {
+        reinterpret_cast<Paint*>(paintHandle)->setColor(color);
+    }
+
     static void setAlpha(jlong paintHandle, jint a) {
         reinterpret_cast<Paint*>(paintHandle)->setAlpha(a);
     }
@@ -991,9 +995,9 @@
 
     static void setShadowLayer(jlong paintHandle, jfloat radius,
                                jfloat dx, jfloat dy, jlong colorSpaceHandle,
-                               jfloat r, jfloat g, jfloat b, jfloat a) {
+                               jlong colorLong) {
+        SkColor4f color = GraphicsJNI::convertColorLong(colorLong);
         sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
-        SkColor4f color = SkColor4f{r, g, b, a};
 
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         if (radius <= 0) {
@@ -1082,7 +1086,8 @@
     {"nSetDither","(JZ)V", (void*) PaintGlue::setDither},
     {"nGetStyle","(J)I", (void*) PaintGlue::getStyle},
     {"nSetStyle","(JI)V", (void*) PaintGlue::setStyle},
-    {"nSetColor","(JJFFFF)V", (void*) PaintGlue::setColor},
+    {"nSetColor","(JI)V", (void*) PaintGlue::setColor},
+    {"nSetColor","(JJJ)V", (void*) PaintGlue::setColorLong},
     {"nSetAlpha","(JI)V", (void*) PaintGlue::setAlpha},
     {"nGetStrokeWidth","(J)F", (void*) PaintGlue::getStrokeWidth},
     {"nSetStrokeWidth","(JF)V", (void*) PaintGlue::setStrokeWidth},
@@ -1125,7 +1130,7 @@
     {"nGetUnderlineThickness","(J)F", (void*) PaintGlue::getUnderlineThickness},
     {"nGetStrikeThruPosition","(J)F", (void*) PaintGlue::getStrikeThruPosition},
     {"nGetStrikeThruThickness","(J)F", (void*) PaintGlue::getStrikeThruThickness},
-    {"nSetShadowLayer", "(JFFFJFFFF)V", (void*)PaintGlue::setShadowLayer},
+    {"nSetShadowLayer", "(JFFFJJ)V", (void*)PaintGlue::setShadowLayer},
     {"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer},
     {"nEqualsForTextMeasurement", "(JJ)Z", (void*)PaintGlue::equalsForTextMeasurement},
 };
diff --git a/core/jni/android/graphics/text/LineBreaker.cpp b/core/jni/android/graphics/text/LineBreaker.cpp
index c23f1e9..a23f99a 100644
--- a/core/jni/android/graphics/text/LineBreaker.cpp
+++ b/core/jni/android/graphics/text/LineBreaker.cpp
@@ -80,13 +80,13 @@
         jfloat firstWidth,
         jint firstWidthLineCount,
         jfloat restWidth,
-        jintArray variableTabStops,
-        jint defaultTabStop,
+        jfloatArray variableTabStops,
+        jfloat defaultTabStop,
         jint indentsOffset) {
     minikin::android::StaticLayoutNative* builder = toNative(nativePtr);
 
     ScopedCharArrayRO text(env, javaText);
-    ScopedNullableIntArrayRO tabStops(env, variableTabStops);
+    ScopedNullableFloatArrayRO tabStops(env, variableTabStops);
 
     minikin::U16StringPiece u16Text(text.get(), length);
     minikin::MeasuredText* measuredText = reinterpret_cast<minikin::MeasuredText*>(measuredTextPtr);
@@ -151,8 +151,8 @@
         "F"  // firstWidth
         "I"  // firstWidthLineCount
         "F"  // restWidth
-        "[I"  // variableTabStops
-        "I"  // defaultTabStop
+        "[F"  // variableTabStops
+        "F"  // defaultTabStop
         "I"  // indentsOffset
         ")J", (void*) nComputeLineBreaks},
 
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index ce5512b..9f9fbf9 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -338,6 +338,19 @@
     return renderNode->stagingProperties().hasOverlappingRendering();
 }
 
+static jboolean android_view_RenderNode_getAnimationMatrix(jlong renderNodePtr, jlong outMatrixPtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr);
+
+    const SkMatrix* animationMatrix = renderNode->stagingProperties().getAnimationMatrix();
+
+    if (animationMatrix) {
+        *outMatrix = *animationMatrix;
+        return JNI_TRUE;
+    }
+    return JNI_FALSE;
+}
+
 static jboolean android_view_RenderNode_getClipToBounds(jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     return renderNode->stagingProperties().getClipToBounds();
@@ -649,6 +662,7 @@
     { "nSetLayerPaint",        "(JJ)Z",  (void*) android_view_RenderNode_setLayerPaint },
     { "nSetStaticMatrix",      "(JJ)Z",  (void*) android_view_RenderNode_setStaticMatrix },
     { "nSetAnimationMatrix",   "(JJ)Z",  (void*) android_view_RenderNode_setAnimationMatrix },
+    { "nGetAnimationMatrix",   "(JJ)Z",  (void*) android_view_RenderNode_getAnimationMatrix },
     { "nSetClipToBounds",      "(JZ)Z",  (void*) android_view_RenderNode_setClipToBounds },
     { "nGetClipToBounds",      "(J)Z",   (void*) android_view_RenderNode_getClipToBounds },
     { "nSetClipBounds",        "(JIIII)Z", (void*) android_view_RenderNode_setClipBounds },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index c6f62ca..009a6ca 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -352,7 +352,7 @@
   }
 
   if (usaps_removed > 0) {
-    if (write(gUsapPoolEventFD, &usaps_removed, sizeof(usaps_removed)) == -1) {
+    if (TEMP_FAILURE_RETRY(write(gUsapPoolEventFD, &usaps_removed, sizeof(usaps_removed))) == -1) {
       // If this write fails something went terribly wrong.  We will now kill
       // the zygote and let the system bring it back up.
       async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
diff --git a/core/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto
index 21717d8..a82326f 100644
--- a/core/proto/android/server/connectivity/data_stall_event.proto
+++ b/core/proto/android/server/connectivity/data_stall_event.proto
@@ -25,6 +25,7 @@
     VALID = 1;
     INVALID = 2;
     PORTAL = 3;
+    PARTIAL = 4;
 }
 
 enum ApBand {
@@ -86,4 +87,4 @@
     repeated int32 dns_return_code = 1;
     // Indicate the timestamp of the dns event.
     repeated int64 dns_time = 2;
-}
\ No newline at end of file
+}
diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
index 49221b4..589a6a7 100644
--- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto
+++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
@@ -136,11 +136,13 @@
 
   SEPARATE_PROFILE_CHALLENGE_CHANGED = 110;
   SET_GLOBAL_SETTING = 111;
-  PM_IS_INSTALLER_DEVICE_OWNER_OR_AFFILIATED_PROFILE_OWNER = 112;
-  PM_UNINSTALL = 113;
+  INSTALL_PACKAGE = 112;
+  UNINSTALL_PACKAGE = 113;
   WIFI_SERVICE_ADD_NETWORK_SUGGESTIONS = 114;
   WIFI_SERVICE_ADD_OR_UPDATE_NETWORK = 115;
   QUERY_SUMMARY_FOR_DEVICE = 116;
   REMOVE_CROSS_PROFILE_WIDGET_PROVIDER = 117;
   ESTABLISH_VPN = 118;
+  SET_NETWORK_LOGGING_ENABLED = 119;
+  RETRIEVE_NETWORK_LOGS = 120;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ea300aa..c7417bf 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -867,6 +867,7 @@
         android:label="@string/permgrouplab_visual"
         android:description="@string/permgroupdesc_visual"
         android:request="@string/permgrouprequest_visual"
+        android:requestDetail="@string/permgrouprequestdetail_visual"
         android:priority="920" />
 
     <!-- Allows an application to read the user's shared images collection. -->
@@ -1516,6 +1517,13 @@
     <permission android:name="android.permission.MANAGE_IPSEC_TUNNELS"
         android:protectionLevel="signature|appop" />
 
+    <!-- @hide Allows apps to create and manage Test Networks.
+         <p>Granted only to shell. CTS tests will use
+         UiAutomation.AdoptShellPermissionIdentity() to gain access.
+    -->
+    <permission android:name="android.permission.MANAGE_TEST_NETWORKS"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi @hide Allows applications to read Wi-Fi credential.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_WIFI_CREDENTIAL"
diff --git a/packages/SystemUI/res/layout/assistant_handle.xml b/core/res/res/drawable/iconfactory_adaptive_icon_drawable_wrapper.xml
similarity index 68%
rename from packages/SystemUI/res/layout/assistant_handle.xml
rename to core/res/res/drawable/iconfactory_adaptive_icon_drawable_wrapper.xml
index a952ca5..3dd276d 100644
--- a/packages/SystemUI/res/layout/assistant_handle.xml
+++ b/core/res/res/drawable/iconfactory_adaptive_icon_drawable_wrapper.xml
@@ -15,11 +15,10 @@
   ~ limitations under the License
   -->
 
-<com.android.systemui.statusbar.phone.NavigationHandle
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/assistant_handle"
-    android:layout_width="@dimen/navigation_assistant_handle_width"
-    android:layout_height="match_parent"
-    android:layout_weight="0"
-/>
-
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@color/white"/>
+    <foreground>
+        <drawable
+            class="com.android.internal.app.SimpleIconFactory$FixedScaleDrawable"/>
+    </foreground>
+</adaptive-icon>
\ No newline at end of file
diff --git a/core/res/res/drawable/sym_def_app_icon_background.xml b/core/res/res/drawable/sym_def_app_icon_background.xml
index 5755210..17b592f 100644
--- a/core/res/res/drawable/sym_def_app_icon_background.xml
+++ b/core/res/res/drawable/sym_def_app_icon_background.xml
@@ -5,7 +5,7 @@
     android:viewportHeight="108.0"
     android:viewportWidth="108.0"
     xmlns:android="http://schemas.android.com/apk/res/android">
-    <path android:fillColor="@android:color/material_deep_teal_500"
+    <path android:fillColor="@android:color/accent_device_default_light"
         android:pathData="M0,0h108v108h-108z"
         android:strokeColor="#66FFFFFF" android:strokeWidth="0.8"/>
     <path android:fillColor="#00000000" android:pathData="M19,0L19,108"
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 10798ad..2860ee4 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -70,209 +70,6 @@
                   android:layout_centerHorizontal="true"/>
     </RelativeLayout>
 
-    <!-- The following 3 layouts are mutually exclusive. One of them will be
-         set VISIBLE programatically, when the optimal preview type can be 
-         determined by inspecting the data being shared. This path was chosen
-         b/c inflating layouts in code had sizing problems with this widget. -->
-
-    <!-- Layout Option 1: Supporting up to 3 images for preview -->
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:background="?attr/colorBackgroundFloating">
-        <RelativeLayout
-            android:id="@+id/content_preview_image_area"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal"
-            android:paddingBottom="@dimen/chooser_view_spacing"
-            android:visibility="gone"
-            android:background="?attr/colorBackgroundFloating">
-
-            <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
-                  android:id="@+id/content_preview_image_1_large"
-                  android:visibility="gone"
-                  android:layout_width="120dp"
-                  android:layout_height="140dp"
-                  android:layout_alignParentTop="true"
-                  android:adjustViewBounds="true"
-                  android:gravity="center"
-                  android:scaleType="centerCrop"/>
-
-            <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
-                  android:id="@+id/content_preview_image_2_large"
-                  android:visibility="gone"
-                  android:layout_width="120dp"
-                  android:layout_height="140dp"
-                  android:layout_alignParentTop="true"
-                  android:layout_toRightOf="@id/content_preview_image_1_large"
-                  android:layout_marginLeft="10dp"
-                  android:adjustViewBounds="true"
-                  android:gravity="center"
-                  android:scaleType="centerCrop"/>
-
-            <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
-                  android:id="@+id/content_preview_image_2_small"
-                  android:visibility="gone"
-                  android:layout_width="120dp"
-                  android:layout_height="65dp"
-                  android:layout_alignParentTop="true"
-                  android:layout_toRightOf="@id/content_preview_image_1_large"
-                  android:layout_marginLeft="10dp"
-                  android:adjustViewBounds="true"
-                  android:gravity="center"
-                  android:scaleType="centerCrop"/>
-
-            <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
-                  android:id="@+id/content_preview_image_3_small"
-                  android:visibility="gone"
-                  android:layout_width="120dp"
-                  android:layout_height="65dp"
-                  android:layout_below="@id/content_preview_image_2_small"
-                  android:layout_toRightOf="@id/content_preview_image_1_large"
-                  android:layout_marginLeft="10dp"
-                  android:layout_marginTop="10dp"
-                  android:adjustViewBounds="true"
-                  android:gravity="center"
-                  android:scaleType="centerCrop"/>
-
-        </RelativeLayout>
-    </LinearLayout>
-
-    <!-- Layout Option 2: Text preview, with optional title and thumbnail -->
-    <LinearLayout
-        android:id="@+id/content_preview_text_area"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:paddingBottom="@dimen/chooser_view_spacing"
-        android:visibility="gone"
-        android:background="?attr/colorBackgroundFloating">
-
-        <LinearLayout
-            android:layout_width="@dimen/chooser_preview_width"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:orientation="horizontal"
-            android:paddingLeft="@dimen/chooser_edge_margin_normal"
-            android:paddingRight="@dimen/chooser_edge_margin_normal"
-            android:layout_marginBottom="@dimen/chooser_view_spacing"
-            android:id="@+id/content_preview_text_layout">
-            <TextView
-                android:id="@+id/content_preview_text"
-                android:layout_width="0dp"
-                android:layout_weight="1"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:ellipsize="end"
-                android:gravity="start|top"
-                android:paddingRight="24dp"
-                android:maxLines="2"/>
-            <Button
-                android:id="@+id/copy_button"
-                android:layout_width="24dp"
-                android:layout_height="24dp"
-                android:gravity="center"
-                android:layout_gravity="center_vertical"
-                android:background="@drawable/ic_content_copy_gm2"/>
-        </LinearLayout>
-
-        <!-- Required sub-layout so we can get the nice rounded corners-->
-        <!-- around this section -->
-        <LinearLayout
-            android:layout_width="@dimen/chooser_preview_width"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:orientation="horizontal"
-            android:layout_marginLeft="@dimen/chooser_edge_margin_thin"
-            android:layout_marginRight="@dimen/chooser_edge_margin_thin"
-            android:minHeight="80dp"
-            android:background="@drawable/chooser_content_preview_rounded"
-            android:id="@+id/content_preview_title_layout">
-
-            <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
-                  android:id="@+id/content_preview_thumbnail"
-                  android:layout_width="75dp"
-                  android:layout_height="75dp"
-                  android:layout_marginRight="16dp"
-                  android:adjustViewBounds="true"
-                  android:layout_gravity="center_vertical"
-                  android:gravity="center"
-                  android:scaleType="centerCrop"/>
-
-            <TextView
-                android:id="@+id/content_preview_title"
-                android:layout_width="0dp"
-                android:layout_weight="1"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:ellipsize="end"
-                android:maxLines="2"
-                android:textAppearance="?attr/textAppearanceMedium"/>
-        </LinearLayout>
-    </LinearLayout>
-
-    <!-- Layout Option 3: File preview, icon, filename, copy-->
-    <LinearLayout
-        android:id="@+id/content_preview_file_area"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:paddingBottom="@dimen/chooser_view_spacing"
-        android:visibility="gone"
-        android:background="?attr/colorBackgroundFloating">
-
-        <LinearLayout
-            android:layout_width="@dimen/chooser_preview_width"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:orientation="horizontal"
-            android:paddingLeft="@dimen/chooser_edge_margin_normal"
-            android:paddingRight="@dimen/chooser_edge_margin_normal"
-            android:layout_marginBottom="@dimen/chooser_view_spacing"
-            android:id="@+id/content_preview_file_layout">
-
-            <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
-                  android:id="@+id/content_preview_file_thumbnail"
-                  android:layout_width="75dp"
-                  android:layout_height="75dp"
-                  android:layout_marginRight="16dp"
-                  android:adjustViewBounds="true"
-                  android:layout_gravity="center_vertical"
-                  android:gravity="center"
-                  android:scaleType="centerCrop"
-                  android:visibility="gone"/>
-            <ImageView
-                  android:id="@+id/content_preview_file_icon"
-                  android:layout_width="36dp"
-                  android:layout_height="36dp"
-                  android:layout_marginRight="16dp"
-                  android:adjustViewBounds="true"
-                  android:layout_gravity="center_vertical"
-                  android:gravity="center"
-                  android:scaleType="fitCenter"
-                  android:visibility="gone"/>
-            <TextView
-                android:id="@+id/content_preview_filename"
-                android:layout_width="0dp"
-                android:layout_weight="1"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical"
-                android:ellipsize="middle"
-                android:gravity="start|top"
-                android:paddingRight="24dp"
-                android:singleLine="true"/>
-            <Button
-                android:id="@+id/file_copy_button"
-                android:layout_width="24dp"
-                android:layout_height="24dp"
-                android:gravity="center"
-                android:layout_gravity="center_vertical"
-                android:background="@drawable/ic_content_copy_gm2"/>
-        </LinearLayout>
-    </LinearLayout>
-
     <ListView
         android:layout_width="match_parent"
         android:layout_height="match_parent"
diff --git a/core/res/res/layout/chooser_grid_preview_file.xml b/core/res/res/layout/chooser_grid_preview_file.xml
new file mode 100644
index 0000000..27c6041
--- /dev/null
+++ b/core/res/res/layout/chooser_grid_preview_file.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 2019, 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.
+*/
+-->
+<!-- Layout Option: File preview, icon, filename, copy-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content_preview_file_area"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:paddingBottom="@dimen/chooser_view_spacing"
+    android:background="?attr/colorBackgroundFloating">
+
+  <LinearLayout
+      android:layout_width="@dimen/chooser_preview_width"
+      android:layout_height="wrap_content"
+      android:layout_gravity="center"
+      android:orientation="horizontal"
+      android:paddingLeft="@dimen/chooser_edge_margin_normal"
+      android:paddingRight="@dimen/chooser_edge_margin_normal"
+      android:layout_marginBottom="@dimen/chooser_view_spacing"
+      android:id="@+id/content_preview_file_layout">
+
+    <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
+          android:id="@+id/content_preview_file_thumbnail"
+          android:layout_width="75dp"
+          android:layout_height="75dp"
+          android:layout_marginRight="16dp"
+          android:adjustViewBounds="true"
+          android:layout_gravity="center_vertical"
+          android:gravity="center"
+          android:scaleType="centerCrop"
+          android:visibility="gone"/>
+    <ImageView
+        android:id="@+id/content_preview_file_icon"
+        android:layout_width="36dp"
+        android:layout_height="36dp"
+        android:layout_marginRight="16dp"
+        android:adjustViewBounds="true"
+        android:layout_gravity="center_vertical"
+        android:gravity="center"
+        android:scaleType="fitCenter"
+        android:visibility="gone"/>
+    <TextView
+        android:id="@+id/content_preview_filename"
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:ellipsize="middle"
+        android:gravity="start|top"
+        android:paddingRight="24dp"
+        android:singleLine="true"/>
+    <Button
+        android:id="@+id/file_copy_button"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:gravity="center"
+        android:layout_gravity="center_vertical"
+        android:background="@drawable/ic_content_copy_gm2"/>
+  </LinearLayout>
+</LinearLayout>
+
diff --git a/core/res/res/layout/chooser_grid_preview_image.xml b/core/res/res/layout/chooser_grid_preview_image.xml
new file mode 100644
index 0000000..ad31e0d
--- /dev/null
+++ b/core/res/res/layout/chooser_grid_preview_image.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 2019, 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.
+*/
+-->
+<!-- Layout Option: Supporting up to 3 images for preview -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:background="?attr/colorBackgroundFloating">
+  <RelativeLayout
+      android:id="@+id/content_preview_image_area"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_gravity="center_horizontal"
+      android:paddingBottom="@dimen/chooser_view_spacing"
+      android:background="?attr/colorBackgroundFloating">
+
+    <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
+          android:id="@+id/content_preview_image_1_large"
+          android:visibility="gone"
+          android:layout_width="120dp"
+          android:layout_height="140dp"
+          android:layout_alignParentTop="true"
+          android:adjustViewBounds="true"
+          android:gravity="center"
+          android:scaleType="centerCrop"/>
+
+    <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
+          android:id="@+id/content_preview_image_2_large"
+          android:visibility="gone"
+          android:layout_width="120dp"
+          android:layout_height="140dp"
+          android:layout_alignParentTop="true"
+          android:layout_toRightOf="@id/content_preview_image_1_large"
+          android:layout_marginLeft="10dp"
+          android:adjustViewBounds="true"
+          android:gravity="center"
+          android:scaleType="centerCrop"/>
+
+    <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
+          android:id="@+id/content_preview_image_2_small"
+          android:visibility="gone"
+          android:layout_width="120dp"
+          android:layout_height="65dp"
+          android:layout_alignParentTop="true"
+          android:layout_toRightOf="@id/content_preview_image_1_large"
+          android:layout_marginLeft="10dp"
+          android:adjustViewBounds="true"
+          android:gravity="center"
+          android:scaleType="centerCrop"/>
+
+    <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
+          android:id="@+id/content_preview_image_3_small"
+          android:visibility="gone"
+          android:layout_width="120dp"
+          android:layout_height="65dp"
+          android:layout_below="@id/content_preview_image_2_small"
+          android:layout_toRightOf="@id/content_preview_image_1_large"
+          android:layout_marginLeft="10dp"
+          android:layout_marginTop="10dp"
+          android:adjustViewBounds="true"
+          android:gravity="center"
+          android:scaleType="centerCrop"/>
+
+  </RelativeLayout>
+</LinearLayout>
+
diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml
new file mode 100644
index 0000000..7cfbb1b
--- /dev/null
+++ b/core/res/res/layout/chooser_grid_preview_text.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 2019, 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.
+*/
+-->
+<!-- Layout Option: Text preview, with optional title and thumbnail -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content_preview_text_area"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:paddingBottom="@dimen/chooser_view_spacing"
+    android:background="?attr/colorBackgroundFloating">
+
+  <LinearLayout
+      android:layout_width="@dimen/chooser_preview_width"
+      android:layout_height="wrap_content"
+      android:layout_gravity="center"
+      android:orientation="horizontal"
+      android:paddingLeft="@dimen/chooser_edge_margin_normal"
+      android:paddingRight="@dimen/chooser_edge_margin_normal"
+      android:layout_marginBottom="@dimen/chooser_view_spacing"
+      android:id="@+id/content_preview_text_layout">
+    <TextView
+        android:id="@+id/content_preview_text"
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:ellipsize="end"
+        android:gravity="start|top"
+        android:paddingRight="24dp"
+        android:maxLines="2"/>
+    <Button
+        android:id="@+id/copy_button"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:gravity="center"
+        android:layout_gravity="center_vertical"
+        android:background="@drawable/ic_content_copy_gm2"/>
+  </LinearLayout>
+
+  <!-- Required sub-layout so we can get the nice rounded corners-->
+  <!-- around this section -->
+  <LinearLayout
+      android:layout_width="@dimen/chooser_preview_width"
+      android:layout_height="wrap_content"
+      android:layout_gravity="center"
+      android:orientation="horizontal"
+      android:layout_marginLeft="@dimen/chooser_edge_margin_thin"
+      android:layout_marginRight="@dimen/chooser_edge_margin_thin"
+      android:minHeight="80dp"
+      android:background="@drawable/chooser_content_preview_rounded"
+      android:id="@+id/content_preview_title_layout">
+
+    <view class="com.android.internal.app.ChooserActivity$RoundedRectImageView"
+          android:id="@+id/content_preview_thumbnail"
+          android:layout_width="75dp"
+          android:layout_height="75dp"
+          android:layout_marginRight="16dp"
+          android:adjustViewBounds="true"
+          android:layout_gravity="center_vertical"
+          android:gravity="center"
+          android:scaleType="centerCrop"/>
+
+    <TextView
+        android:id="@+id/content_preview_title"
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:ellipsize="end"
+        android:maxLines="2"
+        android:textAppearance="?attr/textAppearanceMedium"/>
+  </LinearLayout>
+</LinearLayout>
+
diff --git a/core/res/res/layout/chooser_row_direct_share.xml b/core/res/res/layout/chooser_row_direct_share.xml
new file mode 100644
index 0000000..d7e36ee
--- /dev/null
+++ b/core/res/res/layout/chooser_row_direct_share.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:orientation="vertical"
+                android:layout_width="match_parent"
+                android:layout_height="200dp">
+
+</LinearLayout>
+
+
diff --git a/core/res/res/layout/resolve_list_item.xml b/core/res/res/layout/resolve_list_item.xml
index 5d52832..0bdb25a 100644
--- a/core/res/res/layout/resolve_list_item.xml
+++ b/core/res/res/layout/resolve_list_item.xml
@@ -29,8 +29,8 @@
     <!-- Activity icon when presenting dialog
          Size will be filled in by ResolverActivity -->
     <ImageView android:id="@+id/icon"
-               android:layout_width="24dp"
-               android:layout_height="24dp"
+               android:layout_width="@dimen/resolver_icon_size"
+               android:layout_height="@dimen/resolver_icon_size"
                android:layout_gravity="start|center_vertical"
                android:layout_marginStart="?attr/listPreferredItemPaddingStart"
                android:layout_marginTop="12dp"
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 8f2d6c3..f058985 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -175,13 +175,7 @@
     </array>
 
     <!-- Used in ResolverTargetActionsDialogFragment -->
-    <string-array name="resolver_target_actions_pin">
-        <item>@string/pin_target</item>
-        <item>@string/app_info</item>
-    </string-array>
-
-    <string-array name="resolver_target_actions_unpin">
-        <item>@string/unpin_target</item>
+    <string-array name="resolver_target_actions">
         <item>@string/app_info</item>
     </string-array>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bfb6d24..71e071c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3306,6 +3306,9 @@
          where the user can launch other applications from.  -->
     <bool name="config_noHomeScreen">false</bool>
 
+    <!-- True if the device supports system decorations on secondary displays. -->
+    <bool name="config_supportsSystemDecorsOnSecondaryDisplays">true</bool>
+
     <!-- True if the device requires AppWidgetService even if it does not have
          the PackageManager.FEATURE_APP_WIDGETS feature -->
     <bool name="config_enableAppWidgetService">false</bool>
@@ -3513,6 +3516,12 @@
     -->
     <string name="config_defaultAttentionService" translatable="false"></string>
 
+    <!-- The component name for the system-wide captions service.
+         This service must be trusted, as it controls part of the UI of the volume bar.
+         Example: "com.android.captions/.SystemCaptionsService"
+    -->
+    <string name="config_defaultSystemCaptionsService" translatable="false"></string>
+
     <!-- The package name for the incident report approver app.
         This app is usually PermissionController or an app that replaces it.  When
         a bugreport or incident report with EXPLICT-level sharing flags is going to be
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index fafd8fe..7134eed 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -723,4 +723,6 @@
     <dimen name="chooser_edge_margin_normal">24dp</dimen>
     <dimen name="chooser_preview_image_font_size">20sp</dimen>
     <dimen name="chooser_preview_width">-1px</dimen>
+    <dimen name="resolver_icon_size">42dp</dimen>
+    <dimen name="resolver_badge_size">18dp</dimen>
 </resources>
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index 5014a29..d2cf40a 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -102,4 +102,7 @@
     <!-- Progress Bar -->
     <dimen name="car_progress_bar_height">@dimen/car_seekbar_height</dimen>
 
+    <!-- TextView -->
+    <dimen name="car_textview_fading_edge_length">40dp</dimen>
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a69655a..2b13c4e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -525,8 +525,8 @@
     <!-- label for screenshot item in power menu -->
     <string name="global_action_screenshot">Screenshot</string>
 
-    <!-- Take bug report menu title [CHAR LIMIT=NONE] -->
-    <string name="bugreport_title">Take bug report</string>
+    <!-- Take bug report menu title [CHAR LIMIT=20] -->
+    <string name="bugreport_title">Bug report</string>
     <!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] -->
     <!-- TODO: remove if not used anymore -->
     <string name="bugreport_message">This will collect information about your
@@ -800,7 +800,9 @@
     <string name="permgroupdesc_visual">access your photos &amp; videos</string>
     <!-- Message shown to the user when the apps requests permission from this group. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
     <string name="permgrouprequest_visual">Allow
-        &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your photos and videos, including tagged locations?</string>
+        &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access your photos and videos?</string>
+    <!-- Subtitle of the message shown to the user when the apps requests permission to access photos and videos [CHAR LIMIT=150]-->
+    <string name="permgrouprequestdetail_visual">Locations and other people in your photos and videos can be identified by the app</string>
 
     <!-- Title for the capability of an accessibility service to retrieve window content. -->
     <string name="capability_title_canRetrieveWindowContent">Retrieve window content</string>
@@ -3372,9 +3374,9 @@
     <string name="wifi_available_action_all_networks">All networks</string>
 
     <!-- Notification title for a connection to a app suggested wireless network.-->
-    <string name="wifi_suggestion_title">A Wi\u2011Fi network proposed by <xliff:g id="name" example="App123">%s</xliff:g> is available</string>
+    <string name="wifi_suggestion_title">Connect to Wi\u2011Fi networks?</string>
     <!-- Notification content for a connection to a app suggested wireless network.-->
-    <string name="wifi_suggestion_content">Do you want to connect to networks proposed by <xliff:g id="name" example="App123">%s</xliff:g>?</string>
+    <string name="wifi_suggestion_content">Suggested by <xliff:g id="name" example="App123">%s</xliff:g></string>
     <!-- Notification action for allowing app specified in the notification body.-->
     <string name="wifi_suggestion_action_allow_app">Yes</string>
     <!-- Notification action for disallowing app specified in the notification body.-->
@@ -3600,6 +3602,11 @@
     <string name="adb_active_notification_message">Tap to turn off USB debugging</string>
     <string name="adb_active_notification_message" product="tv">Select to disable USB debugging.</string>
 
+    <!-- Title of notification shown when Test Harness Mode is enabled. [CHAR LIMIT=NONE] -->
+    <string name="test_harness_mode_notification_title">Test Harness Mode enabled</string>
+    <!-- Message of notification shown when Test Harness Mode is enabled. [CHAR LIMIT=NONE] -->
+    <string name="test_harness_mode_notification_message">Perform a factory reset to disable Test Harness Mode.</string>
+
     <!-- Title of notification shown when contaminant is detected on the USB port. [CHAR LIMIT=NONE] -->
     <string name="usb_contaminant_detected_title">Liquid or debris in USB port</string>
     <!-- Message of notification shown when contaminant is detected on the USB port. [CHAR LIMIT=NONE] -->
@@ -5046,12 +5053,6 @@
     <string name="usb_mtp_launch_notification_description">Tap to view files</string>
 
     <!-- Resolver target actions strings -->
-
-    <!-- Pin (as in to a bulletin board with a pushpin) a resolver
-         target to the front of the list. -->
-    <string name="pin_target">Pin</string>
-    <!-- Unpin a resolver target such that it sorts normally. -->
-    <string name="unpin_target">Unpin</string>
     <!-- View application info for a target. -->
     <string name="app_info">App info</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 69def5b..e5fc104 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -390,6 +390,7 @@
   <java-symbol type="bool" name="config_supportsSplitScreenMultiWindow" />
   <java-symbol type="bool" name="config_supportsMultiDisplay" />
   <java-symbol type="bool" name="config_noHomeScreen" />
+  <java-symbol type="bool" name="config_supportsSystemDecorsOnSecondaryDisplays" />
   <java-symbol type="bool" name="config_guestUserEphemeral" />
   <java-symbol type="bool" name="config_localDisplaysMirrorContent" />
   <java-symbol type="bool" name="config_localDisplaysPrivate" />
@@ -2060,6 +2061,8 @@
   <java-symbol type="string" name="accessibility_binding_label" />
   <java-symbol type="string" name="adb_active_notification_message" />
   <java-symbol type="string" name="adb_active_notification_title" />
+  <java-symbol type="string" name="test_harness_mode_notification_title" />
+  <java-symbol type="string" name="test_harness_mode_notification_message" />
   <java-symbol type="string" name="taking_remote_bugreport_notification_title" />
   <java-symbol type="string" name="share_remote_bugreport_notification_title" />
   <java-symbol type="string" name="sharing_remote_bugreport_notification_title" />
@@ -2762,6 +2765,9 @@
   <java-symbol type="dimen" name="chooser_preview_image_font_size"/>
   <java-symbol type="dimen" name="chooser_preview_width" />
   <java-symbol type="layout" name="chooser_grid" />
+  <java-symbol type="layout" name="chooser_grid_preview_text" />
+  <java-symbol type="layout" name="chooser_grid_preview_image" />
+  <java-symbol type="layout" name="chooser_grid_preview_file" />
   <java-symbol type="id" name="chooser_row_text_option" />
   <java-symbol type="dimen" name="chooser_row_text_option_translate" />
   <java-symbol type="layout" name="resolve_grid_item" />
@@ -2770,6 +2776,7 @@
   <java-symbol type="drawable" name="scroll_indicator_material" />
 
   <java-symbol type="layout" name="chooser_row" />
+  <java-symbol type="layout" name="chooser_row_direct_share" />
   <java-symbol type="id" name="target_badge" />
   <java-symbol type="bool" name="config_supportDoubleTapWake" />
   <java-symbol type="drawable" name="ic_perm_device_info" />
@@ -2989,8 +2996,7 @@
   <java-symbol type="color" name="notification_material_background_color" />
 
   <!-- Resolver target actions -->
-  <java-symbol type="array" name="resolver_target_actions_pin" />
-  <java-symbol type="array" name="resolver_target_actions_unpin" />
+  <java-symbol type="array" name="resolver_target_actions" />
 
   <java-symbol type="array" name="non_removable_euicc_slots" />
 
@@ -3382,6 +3388,7 @@
   <java-symbol type="string" name="config_defaultAppPredictionService" />
   <java-symbol type="string" name="config_defaultContentSuggestionsService" />
   <java-symbol type="string" name="config_defaultAttentionService" />
+  <java-symbol type="string" name="config_defaultSystemCaptionsService" />
 
   <java-symbol type="string" name="notification_channel_foreground_service" />
   <java-symbol type="string" name="foreground_service_app_in_background" />
@@ -3674,6 +3681,7 @@
   <java-symbol type="array" name="config_displayWhiteBalanceAmbientColorTemperatures" />
   <java-symbol type="array" name="config_displayWhiteBalanceDisplayColorTemperatures" />
   <java-symbol type="drawable" name="ic_action_open" />
+  <java-symbol type="drawable" name="ic_menu_copy_material" />
 
   <!-- MIME types -->
   <java-symbol type="string" name="mime_type_folder" />
@@ -3700,4 +3708,9 @@
 
   <!-- For Auto-Brightness -->
   <java-symbol type="string" name="config_displayLightSensorType" />
+
+  <java-symbol type="drawable" name="iconfactory_adaptive_icon_drawable_wrapper"/>
+  <java-symbol type="dimen" name="resolver_icon_size"/>
+  <java-symbol type="dimen" name="resolver_badge_size"/>
+
 </resources>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 3791305..9955c51 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -55,6 +55,7 @@
     <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
+    <uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS"/>
     <uses-permission android:name="android.permission.READ_CONTACTS" />
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.READ_DREAM_STATE" />
diff --git a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
index 9b360db..cc48239 100644
--- a/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
+++ b/core/tests/coretests/src/android/content/pm/AndroidHidlUpdaterTest.java
@@ -42,8 +42,17 @@
         PackageBuilder before = builder()
                 .targetSdkVersion(Build.VERSION_CODES.P);
 
+        // no change, not system
+        checkBackwardsCompatibility(before, before);
+    }
+
+    @Test
+    public void targeted_at_P_system() {
+        PackageBuilder before = builder().asSystemApp()
+                .targetSdkVersion(Build.VERSION_CODES.P);
+
         // Should add both HIDL libraries
-        PackageBuilder after = builder()
+        PackageBuilder after = builder().asSystemApp()
                 .targetSdkVersion(Build.VERSION_CODES.P)
                 .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
 
@@ -56,9 +65,19 @@
                 .targetSdkVersion(Build.VERSION_CODES.P)
                 .requiredLibraries(OTHER_LIBRARY);
 
+        // no change, not system
+        checkBackwardsCompatibility(before, before);
+    }
+
+    @Test
+    public void targeted_at_P_not_empty_usesLibraries_system() {
+        PackageBuilder before = builder().asSystemApp()
+                .targetSdkVersion(Build.VERSION_CODES.P)
+                .requiredLibraries(OTHER_LIBRARY);
+
         // The hidl jars should be added at the start of the list because it
         // is not on the bootclasspath and the package targets pre-P.
-        PackageBuilder after = builder()
+        PackageBuilder after = builder().asSystemApp()
                 .targetSdkVersion(Build.VERSION_CODES.P)
                 .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE, OTHER_LIBRARY);
 
@@ -71,8 +90,21 @@
                 .targetSdkVersion(Build.VERSION_CODES.P)
                 .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
 
-        // No change is required because although the HIDL libraries has been removed from
-        // the bootclasspath the package explicitly requests it.
+        PackageBuilder after = builder()
+                .targetSdkVersion(Build.VERSION_CODES.P);
+
+        // Libraries are removed because they are not available for non-system apps
+        checkBackwardsCompatibility(before, after);
+    }
+
+    @Test
+    public void targeted_at_P_in_usesLibraries_system() {
+        PackageBuilder before = builder().asSystemApp()
+                .targetSdkVersion(Build.VERSION_CODES.P)
+                .requiredLibraries(ANDROID_HIDL_MANAGER, ANDROID_HIDL_BASE);
+
+        // No change is required because the package explicitly requests the HIDL libraries
+        // and is targeted at the current version so does not need backwards compatibility.
         checkBackwardsCompatibility(before, before);
     }
 
@@ -83,8 +115,7 @@
         // Dependency is removed, it is not available.
         PackageBuilder after = builder();
 
-        // No change is required because the package explicitly requests the HIDL libraries
-        // and is targeted at the current version so does not need backwards compatibility.
+        // Libraries are removed because they are not available for apps targetting Q+
         checkBackwardsCompatibility(before, after);
     }
 
@@ -95,8 +126,7 @@
         // Dependency is removed, it is not available.
         PackageBuilder after = builder();
 
-        // No change is required because the package explicitly requests the HIDL libraries
-        // and is targeted at the current version so does not need backwards compatibility.
+        // Libraries are removed because they are not available for apps targetting Q+
         checkBackwardsCompatibility(before, after);
     }
 
diff --git a/core/tests/coretests/src/android/content/pm/PackageBuilder.java b/core/tests/coretests/src/android/content/pm/PackageBuilder.java
index c5db962..f7544af 100644
--- a/core/tests/coretests/src/android/content/pm/PackageBuilder.java
+++ b/core/tests/coretests/src/android/content/pm/PackageBuilder.java
@@ -31,6 +31,8 @@
 
     private int mTargetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
 
+    private int mFlags = 0;
+
     private ArrayList<String> mRequiredLibraries;
 
     private ArrayList<String> mOptionalLibraries;
@@ -42,6 +44,7 @@
     public PackageParser.Package build() {
         PackageParser.Package pkg = new PackageParser.Package("org.package.name");
         pkg.applicationInfo.targetSdkVersion = mTargetSdkVersion;
+        pkg.applicationInfo.flags = mFlags;
         pkg.usesLibraries = mRequiredLibraries;
         pkg.usesOptionalLibraries = mOptionalLibraries;
         return pkg;
@@ -52,6 +55,11 @@
         return this;
     }
 
+    PackageBuilder asSystemApp() {
+        this.mFlags |= ApplicationInfo.FLAG_SYSTEM;
+        return this;
+    }
+
     PackageBuilder requiredLibraries(String... names) {
         this.mRequiredLibraries = arrayListOrNull(names);
         return this;
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index 04fa524..7a4fa3a 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -61,6 +61,26 @@
     }
 
     @Test
+    public void getProperty_nullNamespace() {
+        try {
+            DeviceConfig.getProperty(null, sKey);
+            Assert.fail("Null namespace should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void getProperty_nullName() {
+        try {
+            DeviceConfig.getProperty(sNamespace, null);
+            Assert.fail("Null name should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
     public void getString_empty() {
         final String default_value = "default_value";
         final String result = DeviceConfig.getString(sNamespace, sKey, default_value);
@@ -68,6 +88,12 @@
     }
 
     @Test
+    public void getString_nullDefault() {
+        final String result = DeviceConfig.getString(sNamespace, sKey, null);
+        assertThat(result).isNull();
+    }
+
+    @Test
     public void getString_nonEmpty() {
         final String value = "new_value";
         final String default_value = "default";
@@ -78,6 +104,26 @@
     }
 
     @Test
+    public void getString_nullNamespace() {
+        try {
+            DeviceConfig.getString(null, sKey, "default_value");
+            Assert.fail("Null namespace should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void getString_nullName() {
+        try {
+            DeviceConfig.getString(sNamespace, null, "default_value");
+            Assert.fail("Null name should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
     public void getBoolean_empty() {
         final boolean default_value = true;
         final boolean result = DeviceConfig.getBoolean(sNamespace, sKey, default_value);
@@ -105,6 +151,26 @@
     }
 
     @Test
+    public void getBoolean_nullNamespace() {
+        try {
+            DeviceConfig.getBoolean(null, sKey, false);
+            Assert.fail("Null namespace should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void getBoolean_nullName() {
+        try {
+            DeviceConfig.getBoolean(sNamespace, null, false);
+            Assert.fail("Null name should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
     public void getInt_empty() {
         final int default_value = 999;
         final int result = DeviceConfig.getInt(sNamespace, sKey, default_value);
@@ -132,6 +198,26 @@
     }
 
     @Test
+    public void getInt_nullNamespace() {
+        try {
+            DeviceConfig.getInt(null, sKey, 0);
+            Assert.fail("Null namespace should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void getInt_nullName() {
+        try {
+            DeviceConfig.getInt(sNamespace, null, 0);
+            Assert.fail("Null name should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
     public void getLong_empty() {
         final long default_value = 123456;
         final long result = DeviceConfig.getLong(sNamespace, sKey, default_value);
@@ -159,6 +245,26 @@
     }
 
     @Test
+    public void getLong_nullNamespace() {
+        try {
+            DeviceConfig.getLong(null, sKey, 0);
+            Assert.fail("Null namespace should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void getLong_nullName() {
+        try {
+            DeviceConfig.getLong(sNamespace, null, 0);
+            Assert.fail("Null name should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
     public void getFloat_empty() {
         final float default_value = 123.456f;
         final float result = DeviceConfig.getFloat(sNamespace, sKey, default_value);
@@ -186,6 +292,46 @@
     }
 
     @Test
+    public void getFloat_nullNamespace() {
+        try {
+            DeviceConfig.getFloat(null, sKey, 0);
+            Assert.fail("Null namespace should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void getFloat_nullName() {
+        try {
+            DeviceConfig.getFloat(sNamespace, null, 0);
+            Assert.fail("Null name should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void setProperty_nullNamespace() {
+        try {
+            DeviceConfig.setProperty(null, sKey, sValue, false);
+            Assert.fail("Null namespace should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void setProperty_nullName() {
+        try {
+            DeviceConfig.setProperty(sNamespace, null, sValue, false);
+            Assert.fail("Null name should have resulted in an NPE.");
+        } catch (NullPointerException e) {
+            // expected
+        }
+    }
+
+    @Test
     public void setAndGetProperty_sameNamespace() {
         DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
         String result = DeviceConfig.getProperty(sNamespace, sKey);
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 43f8db1..7322a54 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -655,6 +655,7 @@
                  Settings.Secure.NIGHT_DISPLAY_ACTIVATED,
                  Settings.Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
                  Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED,
+                 Settings.Secure.ODI_CAPTIONS_ENABLED,
                  Settings.Secure.PACKAGE_VERIFIER_STATE,
                  Settings.Secure.PACKAGE_VERIFIER_USER_CONSENT,
                  Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE,
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
new file mode 100644
index 0000000..4680a64
--- /dev/null
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureContextTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.view.contentcapture;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ComponentName;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Unit test for {@link ContentCaptureEvent}.
+ *
+ * <p>To run it:
+ * {@code atest FrameworksCoreTests:android.view.contentcapture.ContentCaptureContextTest}
+ */
+@RunWith(JUnit4.class)
+public class ContentCaptureContextTest {
+
+    @Test
+    public void testConstructorAdditionalFlags() {
+        final ComponentName componentName = new ComponentName("component", "name");
+        final ContentCaptureContext ctx = new ContentCaptureContext(/* clientContext= */ null,
+                componentName, /* taskId= */ 666, /* displayId= */ 42, /* flags= */ 1);
+        final ContentCaptureContext newCtx = new ContentCaptureContext(ctx, /* extraFlags= */ 2);
+        assertThat(newCtx.getFlags()).isEqualTo(3);
+
+        assertThat(newCtx.getActivityComponent()).isEqualTo(componentName);
+        assertThat(newCtx.getTaskId()).isEqualTo(666);
+        assertThat(newCtx.getDisplayId()).isEqualTo(42);
+        assertThat(newCtx.getExtras()).isNull();
+        assertThat(newCtx.getLocusId()).isNull();
+        assertThat(newCtx.getParentSessionId()).isNull();
+    }
+}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
index de2edc3..2416de1 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
@@ -19,6 +19,7 @@
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_FINISHED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -230,6 +231,68 @@
         assertContextUpdatedEvent(clone);
     }
 
+    @Test
+    public void testMergeEvent_typeViewTextChanged() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_TEXT_CHANGED)
+                .setText("test");
+        final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_TEXT_CHANGED)
+                .setText("empty");
+
+        event.mergeEvent(event2);
+        assertThat(event.getText()).isEqualTo(event2.getText());
+    }
+
+    @Test
+    public void testMergeEvent_typeViewDisappeared() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+                .setAutofillId(new AutofillId(1));
+        final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_DISAPPEARED)
+                .setAutofillId(new AutofillId(2));
+        final ArrayList<AutofillId> autofillIds = new ArrayList<>();
+        autofillIds.add(new AutofillId(3));
+        autofillIds.add(new AutofillId(4));
+        final ContentCaptureEvent event3 = new ContentCaptureEvent("17", TYPE_VIEW_DISAPPEARED)
+                .setAutofillIds(autofillIds);
+
+        event.mergeEvent(event2);
+        assertThat(event.getIds()).containsExactly(new AutofillId(1), new AutofillId(2));
+
+        event2.mergeEvent(event3);
+        assertThat(event2.getIds()).containsExactly(new AutofillId(2), new AutofillId(3),
+                new AutofillId(4));
+    }
+
+    @Test
+    public void testMergeEvent_typeViewDisappeared_noIds() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+                .setAutofillId(new AutofillId(1));
+        final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_DISAPPEARED);
+
+        assertThrows(IllegalArgumentException.class, () -> event.mergeEvent(event2));
+    }
+
+    @Test
+    public void testMergeEvent_nullArgument() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        assertThrows(NullPointerException.class, () -> event.mergeEvent(null));
+    }
+
+    @Test
+    public void testMergeEvent_differentEventTypes() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+                .setText("test").setAutofillId(new AutofillId(1));
+        final ContentCaptureEvent event2 = new ContentCaptureEvent("17", TYPE_VIEW_TEXT_CHANGED)
+                .setText("empty").setAutofillId(new AutofillId(2));
+
+        event.mergeEvent(event2);
+        assertThat(event.getText()).isEqualTo("test");
+        assertThat(event.getId()).isEqualTo(new AutofillId(1));
+
+        event2.mergeEvent(event);
+        assertThat(event2.getText()).isEqualTo("empty");
+        assertThat(event2.getId()).isEqualTo(new AutofillId(2));
+    }
+
     private void assertContextUpdatedEvent(ContentCaptureEvent event) {
         assertThat(event.getType()).isEqualTo(TYPE_CONTEXT_UPDATED);
         assertThat(event.getEventTime()).isAtLeast(MY_EPOCH);
diff --git a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
index f440953..5c7287f 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
@@ -27,13 +27,17 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.graphics.drawable.Icon;
+import android.net.Uri;
 import android.os.Bundle;
+import android.view.textclassifier.intent.LabeledIntent;
+import android.view.textclassifier.intent.TemplateIntentFactory;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.google.android.textclassifier.ActionsSuggestionsModel;
+import com.google.android.textclassifier.RemoteActionTemplate;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -204,6 +208,77 @@
         assertThat(conversationActions.get(2).getAction()).isNull();
     }
 
+    public void createLabeledIntentResult_null() {
+        ActionsSuggestionsModel.ActionSuggestion nativeSuggestion =
+                new ActionsSuggestionsModel.ActionSuggestion(
+                        "text",
+                        ConversationAction.TYPE_OPEN_URL,
+                        1.0f,
+                        null,
+                        null
+                );
+
+        LabeledIntent.Result labeledIntentResult =
+                ActionsSuggestionsHelper.createLabeledIntentResult(
+                        InstrumentationRegistry.getTargetContext(),
+                        new TemplateIntentFactory(),
+                        nativeSuggestion);
+
+        assertThat(labeledIntentResult).isNull();
+    }
+
+    @Test
+    public void createLabeledIntentResult_emptyList() {
+        ActionsSuggestionsModel.ActionSuggestion nativeSuggestion =
+                new ActionsSuggestionsModel.ActionSuggestion(
+                        "text",
+                        ConversationAction.TYPE_OPEN_URL,
+                        1.0f,
+                        null,
+                        new RemoteActionTemplate[0]
+                );
+
+        LabeledIntent.Result labeledIntentResult =
+                ActionsSuggestionsHelper.createLabeledIntentResult(
+                        InstrumentationRegistry.getTargetContext(),
+                        new TemplateIntentFactory(),
+                        nativeSuggestion);
+
+        assertThat(labeledIntentResult).isNull();
+    }
+
+    @Test
+    public void createLabeledIntentResult() {
+        ActionsSuggestionsModel.ActionSuggestion nativeSuggestion =
+                new ActionsSuggestionsModel.ActionSuggestion(
+                        "text",
+                        ConversationAction.TYPE_OPEN_URL,
+                        1.0f,
+                        null,
+                        new RemoteActionTemplate[]{
+                                new RemoteActionTemplate(
+                                        "title",
+                                        null,
+                                        "description",
+                                        Intent.ACTION_VIEW,
+                                        Uri.parse("http://www.android.com").toString(),
+                                        null,
+                                        0,
+                                        null,
+                                        null,
+                                        null,
+                                        0)});
+
+        LabeledIntent.Result labeledIntentResult =
+                ActionsSuggestionsHelper.createLabeledIntentResult(
+                        InstrumentationRegistry.getTargetContext(),
+                        new TemplateIntentFactory(),
+                        nativeSuggestion);
+
+        assertThat(labeledIntentResult.remoteAction.getTitle()).isEqualTo("title");
+        assertThat(labeledIntentResult.resolvedIntent.getAction()).isEqualTo(Intent.ACTION_VIEW);
+    }
+
     private ZonedDateTime createZonedDateTimeFromMsUtc(long msUtc) {
         return ZonedDateTime.ofInstant(Instant.ofEpochMilli(msUtc), ZoneId.of("UTC"));
     }
@@ -215,7 +290,7 @@
             long referenceTimeInMsUtc) {
         assertThat(nativeMessage.getText()).isEqualTo(text.toString());
         assertThat(nativeMessage.getUserId()).isEqualTo(userId);
-        assertThat(nativeMessage.getLocales()).isEqualTo(LOCALE_TAG);
+        assertThat(nativeMessage.getDetectedTextLanguageTags()).isEqualTo(LOCALE_TAG);
         assertThat(nativeMessage.getReferenceTimeMsUtc()).isEqualTo(referenceTimeInMsUtc);
     }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
index fef6583..2674e37 100644
--- a/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
+++ b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
@@ -44,8 +44,7 @@
 /**
  * A builder used to build a fake context for testing.
  */
-// TODO: Consider making public.
-final class FakeContextBuilder {
+public final class FakeContextBuilder {
 
     /**
      * A component name that can be used for tests.
@@ -57,7 +56,7 @@
     private final Map<String, ComponentName> mComponents = new HashMap<>();
     private @Nullable ComponentName mAllIntentComponent;
 
-    FakeContextBuilder() {
+    public FakeContextBuilder() {
         mPackageManager = mock(PackageManager.class);
         when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(null);
         mContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()) {
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
index fe2a660..f6bb1bf 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
@@ -21,6 +21,7 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -48,7 +49,8 @@
                 + "entity_list_editable=date:datetime,"
                 + "in_app_conversation_action_types_default=text_reply,"
                 + "notification_conversation_action_types_default=send_email:call_phone,"
-                + "lang_id_threshold_override=0.3";
+                + "lang_id_threshold_override=0.3,"
+                + "lang_id_context_settings=10:1:0.5";
         final TextClassificationConstants constants =
                 TextClassificationConstants.loadFromString(s);
 
@@ -91,6 +93,8 @@
                 .containsExactly("send_email", "call_phone");
         assertWithMessage("lang_id_threshold_override")
                 .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(0.3f);
+        Assert.assertArrayEquals("lang_id_context_settings",
+                constants.getLangIdContextSettings(), new float[]{10, 1, 0.5f}, EPSILON);
     }
 
     @Test
@@ -111,7 +115,8 @@
                 + "entity_list_editable=flight,"
                 + "in_app_conversation_action_types_default=view_map:track_flight,"
                 + "notification_conversation_action_types_default=share_location,"
-                + "lang_id_threshold_override=2";
+                + "lang_id_threshold_override=2,"
+                + "lang_id_context_settings=30:0.5:0.3";
         final TextClassificationConstants constants =
                 TextClassificationConstants.loadFromString(s);
 
@@ -154,6 +159,8 @@
                 .containsExactly("share_location");
         assertWithMessage("lang_id_threshold_override")
                 .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(2f);
+        Assert.assertArrayEquals("lang_id_context_settings",
+                constants.getLangIdContextSettings(), new float[]{30, 0.5f, 0.3f}, EPSILON);
     }
 
     @Test
@@ -196,13 +203,15 @@
                 .that(constants.getInAppConversationActionTypes())
                 .containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
                         "send_email", "send_sms", "track_flight", "view_calendar", "view_map",
-                        "add_contact");
+                        "add_contact", "copy");
         assertWithMessage("notification_conversation_action_types_default")
                 .that(constants.getNotificationConversationActionTypes())
                 .containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
                         "send_email", "send_sms", "track_flight", "view_calendar", "view_map",
-                        "add_contact");
+                        "add_contact", "copy");
         assertWithMessage("lang_id_threshold_override")
                 .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(-1f);
+        Assert.assertArrayEquals("lang_id_context_settings",
+                constants.getLangIdContextSettings(), new float[]{20, 1, 0.4f}, EPSILON);
     }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index bcaf663..8de5f13 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -32,6 +32,7 @@
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import com.google.common.truth.Truth;
 
@@ -41,7 +42,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
 
 import java.util.Arrays;
 import java.util.Collections;
@@ -53,22 +53,10 @@
  * Tests are skipped if such a textclassifier does not exist.
  */
 @SmallTest
-@RunWith(Parameterized.class)
+@RunWith(AndroidJUnit4.class)
 public class TextClassifierTest {
-    private static final String LOCAL = "local";
-    private static final String SYSTEM = "system";
 
-    @Parameterized.Parameters(name = "{0}")
-    public static Iterable<Object> textClassifierTypes() {
-        return Arrays.asList(LOCAL);
-
-        // TODO: The following will fail on any device that specifies a no-op TextClassifierService.
-        // Enable when we can set a specified TextClassifierService for testing.
-        // return Arrays.asList(LOCAL, SYSTEM);
-    }
-
-    @Parameterized.Parameter
-    public String mTextClassifierType;
+    // TODO: Implement TextClassifierService testing.
 
     private static final TextClassificationConstants TC_CONSTANTS =
             TextClassificationConstants.loadFromString("");
@@ -83,8 +71,7 @@
     public void setup() {
         mContext = InstrumentationRegistry.getTargetContext();
         mTcm = mContext.getSystemService(TextClassificationManager.class);
-        mClassifier = mTcm.getTextClassifier(
-                mTextClassifierType.equals(LOCAL) ? TextClassifier.LOCAL : TextClassifier.SYSTEM);
+        mClassifier = mTcm.getTextClassifier(TextClassifier.LOCAL);
     }
 
     @Test
@@ -278,6 +265,8 @@
         assertEquals("ja", ExtrasUtils.getEntityType(foreignLanguageInfo));
         assertTrue(ExtrasUtils.getScore(foreignLanguageInfo) >= 0);
         assertTrue(ExtrasUtils.getScore(foreignLanguageInfo) <= 1);
+        assertTrue(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER));
+        assertEquals("ja", ExtrasUtils.getTopLanguage(intent).getLanguage());
 
         LocaleList.setDefault(originalLocales);
     }
@@ -468,6 +457,34 @@
         Truth.assertThat(actionIntent.getData()).isEqualTo(Uri.parse("https://www.android.com"));
     }
 
+    @Test
+    public void testSuggestConversationActions_copy() {
+        if (isTextClassifierDisabled()) return;
+        ConversationActions.Message message =
+                new ConversationActions.Message.Builder(
+                        ConversationActions.Message.PERSON_USER_OTHERS)
+                        .setText("Authentication code: 12345")
+                        .build();
+        TextClassifier.EntityConfig typeConfig =
+                new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
+                        .setIncludedTypes(
+                                Collections.singletonList(ConversationAction.TYPE_COPY))
+                        .build();
+        ConversationActions.Request request =
+                new ConversationActions.Request.Builder(Collections.singletonList(message))
+                        .setMaxSuggestions(1)
+                        .setTypeConfig(typeConfig)
+                        .build();
+
+        ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
+        Truth.assertThat(conversationActions.getConversationActions()).hasSize(1);
+        ConversationAction conversationAction = conversationActions.getConversationActions().get(0);
+        Truth.assertThat(conversationAction.getType()).isEqualTo(ConversationAction.TYPE_COPY);
+        Truth.assertThat(conversationAction.getTextReply()).isAnyOf(null, "");
+        Truth.assertThat(conversationAction.getAction()).isNull();
+        String code = ExtrasUtils.getCopyText(conversationAction.getExtras());
+        Truth.assertThat(code).isEqualTo("12345");
+    }
 
     private boolean isTextClassifierDisabled() {
         return mClassifier == null || mClassifier == TextClassifier.NO_OP;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierUtilsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierUtilsTest.java
new file mode 100644
index 0000000..011866d
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierUtilsTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TextClassifierUtilsTest {
+
+    @Test
+    public void testGetSubString() {
+        final String text = "Yakuza call themselves 任侠団体";
+        int start;
+        int end;
+        int minimumLength;
+
+        // End index at end of text.
+        start = text.indexOf("任侠団体");
+        end = text.length();
+        minimumLength = 20;
+        assertThat(TextClassifier.Utils.getSubString(text, start, end, minimumLength))
+                .isEqualTo("call themselves 任侠団体");
+
+        // Start index at beginning of text.
+        start = 0;
+        end = "Yakuza".length();
+        minimumLength = 15;
+        assertThat(TextClassifier.Utils.getSubString(text, start, end, minimumLength))
+                .isEqualTo("Yakuza call themselves");
+
+        // Text in the middle
+        start = text.indexOf("all");
+        end = start + 1;
+        minimumLength = 10;
+        assertThat(TextClassifier.Utils.getSubString(text, start, end, minimumLength))
+                .isEqualTo("Yakuza call themselves");
+
+        // Selection >= minimumLength.
+        start = text.indexOf("themselves");
+        end = start + "themselves".length();
+        minimumLength = end - start;
+        assertThat(TextClassifier.Utils.getSubString(text, start, end, minimumLength))
+                .isEqualTo("themselves");
+
+        // text.length < minimumLength.
+        minimumLength = text.length() + 1;
+        assertThat(TextClassifier.Utils.getSubString(text, start, end, minimumLength))
+                .isEqualTo(text);
+    }
+
+    @Test
+    public void testGetSubString_invalidParams() {
+        final String text = "The Yoruba regard Olodumare as the principal agent of creation";
+        final int length = text.length();
+        final int minimumLength = 10;
+
+        // Null text
+        assertThrows(() -> TextClassifier.Utils.getSubString(null, 0, 1, minimumLength));
+        // start > end
+        assertThrows(() -> TextClassifier.Utils.getSubString(text, 6, 5, minimumLength));
+        // start < 0
+        assertThrows(() -> TextClassifier.Utils.getSubString(text, -1, 5, minimumLength));
+        // end > text.length
+        assertThrows(() -> TextClassifier.Utils.getSubString(text, 6, length + 1, minimumLength));
+    }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/LabeledIntentTest.java
similarity index 79%
rename from core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
rename to core/tests/coretests/src/android/view/textclassifier/intent/LabeledIntentTest.java
index 6520c8f..857408f 100644
--- a/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/LabeledIntentTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -23,8 +23,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Bundle;
+import android.view.textclassifier.FakeContextBuilder;
+import android.view.textclassifier.TextClassifier;
 
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -41,11 +43,15 @@
     private static final Intent INTENT =
             new Intent(Intent.ACTION_VIEW).setDataAndNormalize(Uri.parse("http://www.android.com"));
     private static final int REQUEST_CODE = 42;
+    private static final Bundle TEXT_LANGUAGES_BUNDLE = Bundle.EMPTY;
+
     private Context mContext;
 
     @Before
     public void setup() {
-        mContext = InstrumentationRegistry.getTargetContext();
+        mContext = new FakeContextBuilder()
+                .setIntentComponent(Intent.ACTION_VIEW, FakeContextBuilder.DEFAULT_COMPONENT)
+                .build();
     }
 
     @Test
@@ -58,8 +64,8 @@
                 REQUEST_CODE
         );
 
-        LabeledIntent.Result result =
-                labeledIntent.resolve(mContext, /*titleChooser*/ null);
+        LabeledIntent.Result result = labeledIntent.resolve(
+                mContext, /*titleChooser*/ null, TEXT_LANGUAGES_BUNDLE);
 
         assertThat(result).isNotNull();
         assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITH_ENTITY);
@@ -67,6 +73,7 @@
         Intent intent = result.resolvedIntent;
         assertThat(intent.getAction()).isEqualTo(intent.getAction());
         assertThat(intent.getComponent()).isNotNull();
+        assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
     }
 
     @Test
@@ -79,8 +86,8 @@
                 REQUEST_CODE
         );
 
-        LabeledIntent.Result result =
-                labeledIntent.resolve(mContext, /*titleChooser*/ null);
+        LabeledIntent.Result result = labeledIntent.resolve(
+                mContext, /*titleChooser*/ null, TEXT_LANGUAGES_BUNDLE);
 
         assertThat(result).isNotNull();
         assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITHOUT_ENTITY);
@@ -100,8 +107,8 @@
                 REQUEST_CODE
         );
 
-        LabeledIntent.Result result =
-                labeledIntent.resolve(mContext, (labeledIntent1, resolveInfo) -> "chooser");
+        LabeledIntent.Result result = labeledIntent.resolve(
+                mContext, (labeledIntent1, resolveInfo) -> "chooser", TEXT_LANGUAGES_BUNDLE);
 
         assertThat(result).isNotNull();
         assertThat(result.remoteAction.getTitle()).isEqualTo("chooser");
@@ -121,8 +128,8 @@
                 REQUEST_CODE
         );
 
-        LabeledIntent.Result result =
-                labeledIntent.resolve(mContext, (labeledIntent1, resolveInfo) -> null);
+        LabeledIntent.Result result = labeledIntent.resolve(
+                mContext, (labeledIntent1, resolveInfo) -> null, TEXT_LANGUAGES_BUNDLE);
 
         assertThat(result).isNotNull();
         assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITHOUT_ENTITY);
@@ -148,15 +155,16 @@
 
     @Test
     public void resolve_noIntentHandler() {
-        Intent intent = new Intent("some.thing.does.not.exist");
+        // See setup(). mContext can only resolve Intent.ACTION_VIEW.
+        Intent unresolvableIntent = new Intent(Intent.ACTION_TRANSLATE);
         LabeledIntent labeledIntent = new LabeledIntent(
                 TITLE_WITHOUT_ENTITY,
                 null,
                 DESCRIPTION,
-                intent,
+                unresolvableIntent,
                 REQUEST_CODE);
 
-        LabeledIntent.Result result = labeledIntent.resolve(mContext, null);
+        LabeledIntent.Result result = labeledIntent.resolve(mContext, null, null);
 
         assertThat(result).isNull();
     }
diff --git a/core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
similarity index 83%
rename from core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java
rename to core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
index 743818c..19e5b0a 100644
--- a/core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Intent;
+import android.view.textclassifier.TextClassifier;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -34,15 +35,15 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class LegacyIntentFactoryTest {
+public class LegacyIntentClassificationFactoryTest {
 
     private static final String TEXT = "text";
 
-    private LegacyIntentFactory mLegacyIntentFactory;
+    private LegacyClassificationIntentFactory mLegacyIntentClassificationFactory;
 
     @Before
     public void setup() {
-        mLegacyIntentFactory = new LegacyIntentFactory();
+        mLegacyIntentClassificationFactory = new LegacyClassificationIntentFactory();
     }
 
     @Test
@@ -61,9 +62,10 @@
                         null,
                         null,
                         null,
+                        null,
                         null);
 
-        List<LabeledIntent> intents = mLegacyIntentFactory.create(
+        List<LabeledIntent> intents = mLegacyIntentClassificationFactory.create(
                 InstrumentationRegistry.getContext(),
                 TEXT,
                 /* foreignText */ false,
@@ -75,8 +77,6 @@
         Intent intent = labeledIntent.intent;
         assertThat(intent.getAction()).isEqualTo(Intent.ACTION_DEFINE);
         assertThat(intent.getStringExtra(Intent.EXTRA_TEXT)).isEqualTo(TEXT);
-        assertThat(
-                intent.getBooleanExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, false)).isTrue();
     }
 
     @Test
@@ -95,9 +95,10 @@
                         null,
                         null,
                         null,
+                        null,
                         null);
 
-        List<LabeledIntent> intents = mLegacyIntentFactory.create(
+        List<LabeledIntent> intents = mLegacyIntentClassificationFactory.create(
                 InstrumentationRegistry.getContext(),
                 TEXT,
                 /* foreignText */ true,
diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
similarity index 66%
rename from core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
rename to core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
index 9fd9e8e..eaef0a0 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
@@ -14,11 +14,19 @@
  * limitations under the License.
  */
 
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
 import android.content.Intent;
+import android.view.textclassifier.TextClassifier;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -45,7 +53,7 @@
     private static final String ACTION = Intent.ACTION_VIEW;
 
     @Mock
-    private IntentFactory mFallback;
+    private ClassificationIntentFactory mFallback;
     private TemplateClassificationIntentFactory mTemplateClassificationIntentFactory;
 
     @Before
@@ -72,6 +80,7 @@
                         null,
                         null,
                         null,
+                        null,
                         createRemoteActionTemplates());
 
         List<LabeledIntent> intents =
@@ -87,12 +96,10 @@
         assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
         Intent intent = labeledIntent.intent;
         assertThat(intent.getAction()).isEqualTo(ACTION);
-        assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
 
         labeledIntent = intents.get(1);
         intent = labeledIntent.intent;
         assertThat(intent.getAction()).isEqualTo(Intent.ACTION_TRANSLATE);
-        assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
     }
 
     @Test
@@ -111,6 +118,7 @@
                         null,
                         null,
                         null,
+                        null,
                         createRemoteActionTemplates());
 
         List<LabeledIntent> intents =
@@ -126,9 +134,73 @@
         assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
         Intent intent = labeledIntent.intent;
         assertThat(intent.getAction()).isEqualTo(ACTION);
-        assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
     }
 
+    @Test
+    public void create_nullTemplate() {
+        AnnotatorModel.ClassificationResult classificationResult =
+                new AnnotatorModel.ClassificationResult(
+                        TextClassifier.TYPE_ADDRESS,
+                        1.0f,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null);
+
+        mTemplateClassificationIntentFactory.create(
+                InstrumentationRegistry.getContext(),
+                TEXT,
+                /* foreignText */ false,
+                null,
+                classificationResult);
+
+
+        verify(mFallback).create(
+                same(InstrumentationRegistry.getContext()), eq(TEXT), eq(false), eq(null),
+                same(classificationResult));
+    }
+
+    @Test
+    public void create_emptyResult() {
+        AnnotatorModel.ClassificationResult classificationResult =
+                new AnnotatorModel.ClassificationResult(
+                        TextClassifier.TYPE_ADDRESS,
+                        1.0f,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        new RemoteActionTemplate[0]);
+
+        mTemplateClassificationIntentFactory.create(
+                InstrumentationRegistry.getContext(),
+                TEXT,
+                /* foreignText */ false,
+                null,
+                classificationResult);
+
+
+        verify(mFallback, never()).create(
+                any(Context.class), eq(TEXT), eq(false), eq(null),
+                any(AnnotatorModel.ClassificationResult.class));
+    }
+
+
     private static RemoteActionTemplate[] createRemoteActionTemplates() {
         return new RemoteActionTemplate[]{
                 new RemoteActionTemplate(
diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateIntentFactoryTest.java
similarity index 97%
rename from core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
rename to core/tests/coretests/src/android/view/textclassifier/intent/TemplateIntentFactoryTest.java
index 1860734..6e3de2d 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateIntentFactoryTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -101,7 +101,6 @@
         assertThat(intent.getPackage()).isNull();
         assertThat(intent.getStringExtra(KEY_ONE)).isEqualTo(VALUE_ONE);
         assertThat(intent.getIntExtra(KEY_TWO, 0)).isEqualTo(VALUE_TWO);
-        assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
     }
 
     @Test
@@ -160,7 +159,6 @@
         assertThat(intent.getFlags()).isEqualTo(0);
         assertThat(intent.getCategories()).isNull();
         assertThat(intent.getPackage()).isNull();
-        assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
     }
 
     @Test
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 3578bc0..185fa07 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -97,9 +97,12 @@
         when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
                 Mockito.anyBoolean(),
                 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
-        mActivityRule.launchActivity(Intent.createChooser(viewIntent, "chooser test"));
+        final ChooserWrapperActivity activity = mActivityRule.launchActivity(
+                Intent.createChooser(viewIntent, "chooser test"));
 
         waitForIdle();
+        assertThat(activity.getAdapter().getCount(), is(2));
+        assertThat(activity.getAdapter().getServiceTargetCount(), is(0));
         onView(withId(R.id.title)).check(matches(withText("chooser test")));
     }
 
@@ -596,7 +599,7 @@
 
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
+        verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
         // First invocation is from onCreate
         assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
                 is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
@@ -626,16 +629,12 @@
         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
+        verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
         // First invocation is from onCreate
         assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
                 is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
         assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
                 is(CONTENT_PREVIEW_IMAGE));
-        assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
-                is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
-        assertThat(logMakerCaptor.getAllValues().get(2).getSubtype(),
-                is(CONTENT_PREVIEW_IMAGE));
     }
 
     @Test
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index a8dd69a..5e71129 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -39,8 +39,8 @@
     static final OverrideData sOverrides = new OverrideData();
     private UsageStatsManager mUsm;
 
-    ResolveListAdapter getAdapter() {
-        return mAdapter;
+    ChooserListAdapter getAdapter() {
+        return (ChooserListAdapter) mAdapter;
     }
 
     boolean getIsSelected() { return mIsSuccessfullySelected; }
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 2e56e09..4bd344f 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -122,13 +122,22 @@
     }
 
     /**
-     * Private constructor that must received an already allocated native bitmap
+     * Private constructor that must receive an already allocated native bitmap
      * int (pointer).
      */
-    // called from JNI
-    @UnsupportedAppUsage
-    Bitmap(long nativeBitmap, int width, int height, int density, boolean requestPremultiplied,
-            byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) {
+    // JNI now calls the version below this one. This is preserved due to UnsupportedAppUsage.
+    @UnsupportedAppUsage(maxTargetSdk = 28)
+    Bitmap(long nativeBitmap, int width, int height, int density,
+            boolean requestPremultiplied, byte[] ninePatchChunk,
+            NinePatch.InsetStruct ninePatchInsets) {
+        this(nativeBitmap, width, height, density, requestPremultiplied, ninePatchChunk,
+                ninePatchInsets, true);
+    }
+
+    // called from JNI and Bitmap_Delegate.
+    Bitmap(long nativeBitmap, int width, int height, int density,
+            boolean requestPremultiplied, byte[] ninePatchChunk,
+            NinePatch.InsetStruct ninePatchInsets, boolean fromMalloc) {
         if (nativeBitmap == 0) {
             throw new RuntimeException("internal error: native bitmap is 0");
         }
@@ -144,13 +153,21 @@
         }
 
         mNativePtr = nativeBitmap;
-        long nativeSize = NATIVE_ALLOCATION_SIZE + getAllocationByteCount();
-        NativeAllocationRegistry registry = new NativeAllocationRegistry(
-            Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), nativeSize);
+
+        final int allocationByteCount = getAllocationByteCount();
+        NativeAllocationRegistry registry;
+        if (fromMalloc) {
+            registry = NativeAllocationRegistry.createMalloced(
+                    Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), allocationByteCount);
+        } else {
+            registry = NativeAllocationRegistry.createNonmalloced(
+                    Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), allocationByteCount);
+        }
         registry.registerNativeAllocation(this, nativeBitmap);
 
         if (ResourcesImpl.TRACE_FOR_DETAILED_PRELOAD) {
             sPreloadTracingNumInstantiatedBitmaps++;
+            long nativeSize = NATIVE_ALLOCATION_SIZE + allocationByteCount;
             sPreloadTracingTotalBitmapsSize += nativeSize;
         }
     }
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 8f46e1a..7b3f3da 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -76,14 +76,11 @@
     // (see SkCanvas.cpp, SkDraw.cpp)
     private static final int MAXMIMUM_BITMAP_SIZE = 32766;
 
-    // The approximate size of the native allocation associated with
-    // a Canvas object.
-    private static final long NATIVE_ALLOCATION_SIZE = 525;
-
     // Use a Holder to allow static initialization of Canvas in the boot image.
     private static class NoImagePreloadHolder {
-        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-                Canvas.class.getClassLoader(), nGetNativeFinalizer(), NATIVE_ALLOCATION_SIZE);
+        public static final NativeAllocationRegistry sRegistry =
+                NativeAllocationRegistry.createMalloced(
+                Canvas.class.getClassLoader(), nGetNativeFinalizer());
     }
 
     // This field is used to finalize the native Canvas properly
diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java
index b24b988..4c2ef84 100644
--- a/graphics/java/android/graphics/ColorFilter.java
+++ b/graphics/java/android/graphics/ColorFilter.java
@@ -26,8 +26,9 @@
 public class ColorFilter {
 
     private static class NoImagePreloadHolder {
-        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-                ColorFilter.class.getClassLoader(), nativeGetFinalizer(), 50);
+        public static final NativeAllocationRegistry sRegistry =
+                NativeAllocationRegistry.createMalloced(
+                ColorFilter.class.getClassLoader(), nativeGetFinalizer());
     }
 
     /**
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 5d8ba93..5af0da8 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -44,13 +44,15 @@
 
     private static String TAG = "FontFamily";
 
-    private static final NativeAllocationRegistry sBuilderRegistry = new NativeAllocationRegistry(
-            FontFamily.class.getClassLoader(), nGetBuilderReleaseFunc(), 64);
+    private static final NativeAllocationRegistry sBuilderRegistry =
+            NativeAllocationRegistry.createMalloced(
+            FontFamily.class.getClassLoader(), nGetBuilderReleaseFunc());
 
     private @Nullable Runnable mNativeBuilderCleaner;
 
-    private static final NativeAllocationRegistry sFamilyRegistry = new NativeAllocationRegistry(
-            FontFamily.class.getClassLoader(), nGetFamilyReleaseFunc(), 64);
+    private static final NativeAllocationRegistry sFamilyRegistry =
+            NativeAllocationRegistry.createMalloced(
+            FontFamily.class.getClassLoader(), nGetFamilyReleaseFunc());
 
     /**
      * @hide
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index f8cb366..22b6401 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -16,12 +16,13 @@
 
 package android.graphics;
 
+import android.annotation.UnsupportedAppUsage;
+
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 
 import libcore.util.NativeAllocationRegistry;
 
-import android.annotation.UnsupportedAppUsage;
 import java.io.PrintWriter;
 
 /**
@@ -222,12 +223,10 @@
         }
     };
 
-    // sizeof(SkMatrix) is 9 * sizeof(float) + uint32_t
-    private static final long NATIVE_ALLOCATION_SIZE = 40;
-
     private static class NoImagePreloadHolder {
-        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-                Matrix.class.getClassLoader(), nGetNativeFinalizer(), NATIVE_ALLOCATION_SIZE);
+        public static final NativeAllocationRegistry sRegistry =
+                NativeAllocationRegistry.createMalloced(
+                Matrix.class.getClassLoader(), nGetNativeFinalizer());
     }
 
     /**
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 452f7c9..346c7ab 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -58,13 +58,11 @@
     private long mNativeShader;
     private long mNativeColorFilter;
 
-    // The approximate size of a native paint object.
-    private static final long NATIVE_PAINT_SIZE = 98;
-
     // Use a Holder to allow static initialization of Paint in the boot image.
     private static class NoImagePreloadHolder {
-        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-                Paint.class.getClassLoader(), nGetNativeFinalizer(), NATIVE_PAINT_SIZE);
+        public static final NativeAllocationRegistry sRegistry =
+                NativeAllocationRegistry.createMalloced(
+                Paint.class.getClassLoader(), nGetNativeFinalizer());
     }
 
     @ColorLong private long mColor;
@@ -1048,7 +1046,8 @@
      * @param color The new color (including alpha) to set in the paint.
      */
     public void setColor(@ColorInt int color) {
-        setColor(Color.pack(color));
+        nSetColor(mNativePaint, color);
+        mColor = Color.pack(color);
     }
 
     /**
@@ -1065,12 +1064,8 @@
      */
     public void setColor(@ColorLong long color) {
         ColorSpace cs = Color.colorSpace(color);
-        float r = Color.red(color);
-        float g = Color.green(color);
-        float b = Color.blue(color);
-        float a = Color.alpha(color);
 
-        nSetColor(mNativePaint, cs.getNativeInstance(), r, g, b, a);
+        nSetColor(mNativePaint, cs.getNativeInstance(), color);
         mColor = color;
     }
 
@@ -1500,11 +1495,7 @@
      */
     public void setShadowLayer(float radius, float dx, float dy, @ColorLong long shadowColor) {
         ColorSpace cs = Color.colorSpace(shadowColor);
-        float r = Color.red(shadowColor);
-        float g = Color.green(shadowColor);
-        float b = Color.blue(shadowColor);
-        float a = Color.alpha(shadowColor);
-        nSetShadowLayer(mNativePaint, radius, dx, dy, cs.getNativeInstance(), r, g, b, a);
+        nSetShadowLayer(mNativePaint, radius, dx, dy, cs.getNativeInstance(), shadowColor);
 
         mShadowLayerRadius = radius;
         mShadowLayerDx = dx;
@@ -1532,6 +1523,7 @@
     /**
      * Returns the blur radius of the shadow layer.
      * @see #setShadowLayer(float,float,float,int)
+     * @see #setShadowLayer(float,float,float,long)
      */
     public float getShadowLayerRadius() {
         return mShadowLayerRadius;
@@ -1540,6 +1532,7 @@
     /**
      * Returns the x offset of the shadow layer.
      * @see #setShadowLayer(float,float,float,int)
+     * @see #setShadowLayer(float,float,float,long)
      */
     public float getShadowLayerDx() {
         return mShadowLayerDx;
@@ -1548,6 +1541,7 @@
     /**
      * Returns the y offset of the shadow layer.
      * @see #setShadowLayer(float,float,float,int)
+     * @see #setShadowLayer(float,float,float,long)
      */
     public float getShadowLayerDy() {
         return mShadowLayerDy;
@@ -3137,7 +3131,7 @@
     @CriticalNative
     private static native void nSetShadowLayer(long paintPtr,
             float radius, float dx, float dy, long colorSpaceHandle,
-            float r, float g, float b, float a);
+            @ColorLong long shadowColor);
     @CriticalNative
     private static native boolean nHasShadowLayer(long paintPtr);
     @CriticalNative
@@ -3190,7 +3184,9 @@
     private static native void nSetFilterBitmap(long paintPtr, boolean filter);
     @CriticalNative
     private static native void nSetColor(long paintPtr, long colorSpaceHandle,
-            float r, float g, float b, float a);
+            @ColorLong long color);
+    @CriticalNative
+    private static native void nSetColor(long paintPtr, @ColorInt int color);
     @CriticalNative
     private static native void nSetStrikeThruText(long paintPtr, boolean strikeThruText);
     @CriticalNative
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 405ab0b..7282d52 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -36,8 +36,9 @@
  */
 public class Path {
 
-    private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-                Path.class.getClassLoader(), nGetFinalizer(), 48 /* dummy size */);
+    private static final NativeAllocationRegistry sRegistry =
+            NativeAllocationRegistry.createMalloced(
+                Path.class.getClassLoader(), nGetFinalizer());
 
     /**
      * @hide
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 5e48ea1..9b4f2c1 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -70,8 +70,7 @@
  *         canvas.drawRect(...);
  *     } finally {
  *         renderNode.endRecording();
- *     }
- * </pre>
+ *     }</pre>
  *
  * <h3>Drawing a RenderNode in a View</h3>
  * <pre class="prettyprint">
@@ -84,8 +83,7 @@
  *             // Draw the RenderNode into this canvas.
  *             canvas.drawRenderNode(myRenderNode);
  *         }
- *     }
- * </pre>
+ *     }</pre>
  *
  * <h3>Releasing resources</h3>
  * <p>This step is not mandatory but recommended if you want to release resources
@@ -93,8 +91,7 @@
  * <pre class="prettyprint">
  *     // Discards the display list content allowing for any held resources to be released.
  *     // After calling this
- *     renderNode.discardDisplayList();
- * </pre>
+ *     renderNode.discardDisplayList();</pre>
  *
  *
  * <h3>Properties</h3>
@@ -132,8 +129,7 @@
  *          // will be invoked and will execute very quickly
  *          mRenderNode.offsetLeftAndRight(x);
  *          invalidate();
- *     }
- * </pre>
+ *     }</pre>
  *
  * <p>A few of the properties may at first appear redundant, such as {@link #setElevation(float)}
  * and {@link #setTranslationZ(float)}. The reason for these duplicates are to allow for a
@@ -146,24 +142,26 @@
  * overlap with {@link #setPosition(Rect)}.
  *
  * <p>The RenderNode's transform matrix is computed at render time as follows:
- * First a setTranslate(getTranslationX(), getTranslationY()) is applied to a {@link Matrix}.
- * Second a preRotate(getRotationZ(), getPivotX(), getPivotY()) is applied to the matrix. And
- * finally a preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY()) is applied. The current
- * canvas transform matrix, which is translated to the RenderNode's position,
- * is then multiplied by the RenderNode's transform matrix. Therefore there is no implicit
- * ordering in setting various RenderNode properties. That is to say that:
+ * <pre class="prettyprint">
+ *     Matrix transform = new Matrix();
+ *     transform.setTranslate(renderNode.getTranslationX(), renderNode.getTranslationY());
+ *     transform.preRotate(renderNode.getRotationZ(),
+ *             renderNode.getPivotX(), renderNode.getPivotY());
+ *     transform.preScale(renderNode.getScaleX(), renderNode.getScaleY(),
+ *             renderNode.getPivotX(), renderNode.getPivotY());</pre>
+ * The current canvas transform matrix, which is translated to the RenderNode's position,
+ * is then multiplied by the RenderNode's transform matrix. Therefore the ordering of calling
+ * property setters does not affect the result. That is to say that:
  *
  * <pre class="prettyprint">
  *     renderNode.setTranslationX(100);
- *     renderNode.setScaleX(100);
- * </pre>
+ *     renderNode.setScaleX(100);</pre>
  *
- * is equivalent to
+ * is equivalent to:
  *
  * <pre class="prettyprint">
  *     renderNode.setScaleX(100);
- *     renderNode.setTranslationX(100);
- * </pre>
+ *     renderNode.setTranslationX(100);</pre>
  *
  * <h3>Threading</h3>
  * <p>RenderNode may be created and used on any thread but they are not thread-safe. Only
@@ -182,8 +180,7 @@
  *         if (needsUpdate) {
  *             myOwningView.invalidate();
  *         }
- *     }
- * </pre>
+ *     }</pre>
  * This is marginally faster than doing a more explicit up-front check if the value changed by
  * comparing the desired value against {@link #getTranslationX()} as it minimizes JNI transitions.
  * The actual mechanism of requesting a new frame to be rendered will depend on how this
@@ -198,8 +195,9 @@
 
     // Use a Holder to allow static initialization in the boot image.
     private static class NoImagePreloadHolder {
-        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-                RenderNode.class.getClassLoader(), nGetNativeFinalizer(), 1024);
+        public static final NativeAllocationRegistry sRegistry =
+                NativeAllocationRegistry.createMalloced(
+                RenderNode.class.getClassLoader(), nGetNativeFinalizer());
     }
 
     /**
@@ -808,14 +806,37 @@
      * for the matrix parameter.
      *
      * @param matrix The matrix, null indicates that the matrix should be cleared.
+     * @see #getAnimationMatrix()
+     *
      * @hide TODO Do we want this?
      */
-    public boolean setAnimationMatrix(Matrix matrix) {
+    public boolean setAnimationMatrix(@Nullable Matrix matrix) {
         return nSetAnimationMatrix(mNativeRenderNode,
                 (matrix != null) ? matrix.native_instance : 0);
     }
 
     /**
+     * Returns the previously set Animation matrix. This matrix exists if an Animation is
+     * currently playing on a View, and is set on the display list during at draw() time.
+     * Returns <code>null</code> when there is no transformation provided by
+     * {@link #setAnimationMatrix(Matrix)}.
+     *
+     * @return the current Animation matrix.
+     * @see #setAnimationMatrix(Matrix)
+     *
+     * @hide
+     */
+    @Nullable
+    public Matrix getAnimationMatrix() {
+        Matrix output = new Matrix();
+        if (nGetAnimationMatrix(mNativeRenderNode, output.native_instance)) {
+            return output;
+        } else {
+            return null;
+        }
+    }
+
+    /**
      * Sets the translucency level for the display list.
      *
      * @param alpha The translucency of the display list, must be a value between 0.0f and 1.0f
@@ -1660,6 +1681,9 @@
     private static native boolean nHasOverlappingRendering(long renderNode);
 
     @CriticalNative
+    private static native boolean nGetAnimationMatrix(long renderNode, long animationMatrix);
+
+    @CriticalNative
     private static native boolean nGetClipToOutline(long renderNode);
 
     @CriticalNative
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index d555128..3050d1d 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -33,8 +33,9 @@
 public class Shader {
 
     private static class NoImagePreloadHolder {
-        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-                Shader.class.getClassLoader(), nativeGetFinalizer(), 50);
+        public static final NativeAllocationRegistry sRegistry =
+                NativeAllocationRegistry.createMalloced(
+                Shader.class.getClassLoader(), nativeGetFinalizer());
     }
 
     /**
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 9518714..9995f1e 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -75,8 +75,9 @@
 
     private static String TAG = "Typeface";
 
-    private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-            Typeface.class.getClassLoader(), nativeGetReleaseFunc(), 64);
+    private static final NativeAllocationRegistry sRegistry =
+            NativeAllocationRegistry.createMalloced(
+            Typeface.class.getClassLoader(), nativeGetReleaseFunc());
 
     /** The default NORMAL typeface object */
     public static final Typeface DEFAULT;
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index bb6bf24..82f5870 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -313,7 +313,7 @@
                     extended, cropRect), inputStream, afd);
 
         final long nativeSize = nNativeByteSize(mState.mNativePtr);
-        NativeAllocationRegistry registry = new NativeAllocationRegistry(
+        NativeAllocationRegistry registry = NativeAllocationRegistry.createMalloced(
                 AnimatedImageDrawable.class.getClassLoader(), nGetNativeFinalizer(), nativeSize);
         registry.registerNativeAllocation(mState, mState.mNativePtr);
     }
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index d7aee77..d9dab98 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -1253,7 +1253,6 @@
         private boolean mInitialized = false;
         private boolean mIsReversible = false;
         private boolean mIsInfinite = false;
-        // TODO: Consider using NativeAllocationRegistery to track native allocation
         private final VirtualRefBasePtr mSetRefBasePtr;
         private WeakReference<RenderNode> mLastSeenTarget = null;
         private int mLastListenerId = 0;
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index f715f43..552088f 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -54,13 +54,13 @@
      * A builder class for creating new Font.
      */
     public static final class Builder {
-        private static final NativeAllocationRegistry sAssetByteBufferRegistroy =
-                new NativeAllocationRegistry(ByteBuffer.class.getClassLoader(),
-                    nGetReleaseNativeAssetFunc(), 64);
+        private static final NativeAllocationRegistry sAssetByteBufferRegistry =
+                NativeAllocationRegistry.createMalloced(ByteBuffer.class.getClassLoader(),
+                    nGetReleaseNativeAssetFunc());
 
-        private static final NativeAllocationRegistry sFontRegistory =
-                new NativeAllocationRegistry(Font.class.getClassLoader(),
-                    nGetReleaseNativeFont(), 64);
+        private static final NativeAllocationRegistry sFontRegistry =
+                NativeAllocationRegistry.createMalloced(Font.class.getClassLoader(),
+                    nGetReleaseNativeFont());
 
         private @Nullable ByteBuffer mBuffer;
         private @Nullable File mFile;
@@ -171,7 +171,7 @@
                 return;
             }
             final ByteBuffer b = nGetAssetBuffer(nativeAsset);
-            sAssetByteBufferRegistroy.registerNativeAllocation(b, nativeAsset);
+            sAssetByteBufferRegistry.registerNativeAllocation(b, nativeAsset);
             if (b == null) {
                 mException = new FileNotFoundException(path + " not found");
                 return;
@@ -206,7 +206,7 @@
                 return;
             }
             final ByteBuffer b = nGetAssetBuffer(nativeAsset);
-            sAssetByteBufferRegistroy.registerNativeAllocation(b, nativeAsset);
+            sAssetByteBufferRegistry.registerNativeAllocation(b, nativeAsset);
             if (b == null) {
                 mException = new FileNotFoundException(str + " not found");
                 return;
@@ -356,7 +356,7 @@
          * Creates the font based on the configured values.
          * @return the Font object
          */
-        public @Nullable Font build() throws IOException {
+        public @NonNull Font build() throws IOException {
             if (mException != null) {
                 throw new IOException("Failed to read font contents", mException);
             }
@@ -391,7 +391,7 @@
                     mTtcIndex);
             final Font font = new Font(ptr, readonlyBuffer, mFile,
                     new FontStyle(mWeight, slant), mTtcIndex, mAxes, mLocaleList);
-            sFontRegistory.registerNativeAllocation(font, ptr);
+            sFontRegistry.registerNativeAllocation(font, ptr);
             return font;
         }
 
diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java
index 4772c1c..75ea120 100644
--- a/graphics/java/android/graphics/fonts/FontFamily.java
+++ b/graphics/java/android/graphics/fonts/FontFamily.java
@@ -63,8 +63,8 @@
      */
     public static final class Builder {
         private static final NativeAllocationRegistry sFamilyRegistory =
-                new NativeAllocationRegistry(FontFamily.class.getClassLoader(),
-                    nGetReleaseNativeFamily(), 64);
+                NativeAllocationRegistry.createMalloced(FontFamily.class.getClassLoader(),
+                    nGetReleaseNativeFamily());
 
         private final ArrayList<Font> mFonts = new ArrayList<>();
         private final HashSet<Integer> mStyleHashSet = new HashSet<>();
diff --git a/graphics/java/android/graphics/text/LineBreaker.java b/graphics/java/android/graphics/text/LineBreaker.java
index 9cabf1c..54622c5 100644
--- a/graphics/java/android/graphics/text/LineBreaker.java
+++ b/graphics/java/android/graphics/text/LineBreaker.java
@@ -69,7 +69,7 @@
  * }
  *
  * // Draw text to the canvas
- * Bitmap bmp = new Bitmap.createBitmap(240, totalHeight, Bitmap.Config.ARGB_8888);
+ * Bitmap bmp = Bitmap.createBitmap(240, totalHeight, Bitmap.Config.ARGB_8888);
  * Canvas c = new Canvas(bmp);
  * float yOffset = 0f;
  * int prevOffset = 0;
@@ -248,8 +248,8 @@
         private @FloatRange(from = 0.0f) float mWidth = 0;
         private @FloatRange(from = 0.0f) float mFirstWidth = 0;
         private @IntRange(from = 0) int mFirstWidthLineCount = 0;
-        private @Nullable int[] mVariableTabStops = null;
-        private @IntRange(from = 0) int mDefaultTabStop = 0;
+        private @Nullable float[] mVariableTabStops = null;
+        private @FloatRange(from = 0) float mDefaultTabStop = 0;
 
         public ParagraphConstraints() {}
 
@@ -284,8 +284,8 @@
          * @see #getTabStops()
          * @see #getDefaultTabStop()
          */
-        public void setTabStops(@Nullable int[] tabStops,
-                @Px @IntRange(from = 0) int defaultTabStop) {
+        public void setTabStops(@Nullable float[] tabStops,
+                @Px @FloatRange(from = 0) float defaultTabStop) {
             mVariableTabStops = tabStops;
             mDefaultTabStop = defaultTabStop;
         }
@@ -320,18 +320,18 @@
         /**
          * Returns the array of tab stops in pixels.
          *
-         * @see #setTabStops(int[], int)
+         * @see #setTabStops(float[], int)
          */
-        public @Nullable int[] getTabStops() {
+        public @Nullable float[] getTabStops() {
             return mVariableTabStops;
         }
 
         /**
          * Returns the default tab stops in pixels.
          *
-         * @see #setTabStop(int[], int)
+         * @see #setTabStop(float[], int)
          */
-        public @Px @IntRange(from = 0) int getDefaultTabStop() {
+        public @Px @FloatRange(from = 0) float getDefaultTabStop() {
             return mDefaultTabStop;
         }
     }
@@ -349,8 +349,9 @@
         private static final int END_HYPHEN_MASK = 0x7;  // 0b00111
         private static final int START_HYPHEN_BITS_SHIFT = 3;
 
-        private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-                Result.class.getClassLoader(), nGetReleaseResultFunc(), 32);
+        private static final NativeAllocationRegistry sRegistry =
+                NativeAllocationRegistry.createMalloced(
+                Result.class.getClassLoader(), nGetReleaseResultFunc());
         private final long mPtr;
 
         private Result(long ptr) {
@@ -444,8 +445,9 @@
         }
     }
 
-    private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-            LineBreaker.class.getClassLoader(), nGetReleaseFunc(), 64);
+    private static final NativeAllocationRegistry sRegistry =
+            NativeAllocationRegistry.createMalloced(
+            LineBreaker.class.getClassLoader(), nGetReleaseFunc());
 
     private final long mNativePtr;
 
@@ -513,8 +515,8 @@
             @FloatRange(from = 0.0f) float firstWidth,
             @IntRange(from = 0) int firstWidthLineCount,
             @FloatRange(from = 0.0f) float restWidth,
-            @Nullable int[] variableTabStops,
-            int defaultTabStop,
+            @Nullable float[] variableTabStops,
+            float defaultTabStop,
             @IntRange(from = 0) int indentsOffset);
 
     // Result accessors
diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java
index 480aff2..66bcd865 100644
--- a/graphics/java/android/graphics/text/MeasuredText.java
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -169,8 +169,9 @@
      * Note: The appendStyle and appendReplacementRun should be called to cover the text length.
      */
     public static final class Builder {
-        private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-                MeasuredText.class.getClassLoader(), nGetReleaseFunc(), 1024);
+        private static final NativeAllocationRegistry sRegistry =
+                NativeAllocationRegistry.createMalloced(
+                MeasuredText.class.getClassLoader(), nGetReleaseFunc());
 
         private long mNativePtr;
 
diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp
index b04c774..3a8e559 100644
--- a/libs/hwui/FrameInfoVisualizer.cpp
+++ b/libs/hwui/FrameInfoVisualizer.cpp
@@ -17,6 +17,7 @@
 
 #include "IProfileRenderer.h"
 #include "utils/Color.h"
+#include "utils/TimeUtils.h"
 
 #include <cutils/compiler.h>
 #include <array>
@@ -26,22 +27,24 @@
 #define RETURN_IF_DISABLED() \
     if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
 
-#define PROFILE_DRAW_WIDTH 3
-#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
-#define PROFILE_DRAW_DP_PER_MS 7
-
 namespace android {
 namespace uirenderer {
 
-// Must be NUM_ELEMENTS in size
-static const SkColor THRESHOLD_COLOR = Color::Green_500;
-static const SkColor BAR_FAST_MASK = 0x8FFFFFFF;
-static const SkColor BAR_JANKY_MASK = 0xDFFFFFFF;
+static constexpr auto PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
+static constexpr auto PROFILE_DRAW_DP_PER_MS = 7;
 
-// We could get this from TimeLord and use the actual frame interval, but
-// this is good enough
-#define FRAME_THRESHOLD 16
-#define FRAME_THRESHOLD_NS 16000000
+struct Threshold {
+    SkColor color;
+    float percentFrametime;
+};
+
+static constexpr std::array<Threshold, 3> THRESHOLDS{
+        Threshold{.color = Color::Green_500, .percentFrametime = 0.8f},
+        Threshold{.color = Color::Lime_500, .percentFrametime = 1.0f},
+        Threshold{.color = Color::Red_500, .percentFrametime = 1.5f},
+};
+static constexpr SkColor BAR_FAST_MASK = 0x8FFFFFFF;
+static constexpr SkColor BAR_JANKY_MASK = 0xDFFFFFFF;
 
 struct BarSegment {
     FrameInfoIndex start;
@@ -64,7 +67,8 @@
     return (int)(dp * density + 0.5f);
 }
 
-FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source) : mFrameSource(source) {
+FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source, nsecs_t frameInterval)
+        : mFrameSource(source), mFrameInterval(frameInterval) {
     setDensity(1);
     consumeProperties();
 }
@@ -76,7 +80,10 @@
 void FrameInfoVisualizer::setDensity(float density) {
     if (CC_UNLIKELY(mDensity != density)) {
         mDensity = density;
-        mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
+        // We want the vertical units to scale height relative to a baseline 16ms.
+        // This keeps the threshold lines consistent across varying refresh rates
+        mVerticalUnit = static_cast<int>(dpToPx(PROFILE_DRAW_DP_PER_MS, density) * (float)16_ms /
+                                         (float)mFrameInterval);
         mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
     }
 }
@@ -148,7 +155,7 @@
         float* rect;
         int ri;
         // Rects are LTRB
-        if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) {
+        if (mFrameSource[fi].totalDuration() <= mFrameInterval) {
             rect = mFastRects.get();
             ri = fast_i;
             fast_i += 4;
@@ -181,7 +188,7 @@
         float* rect;
         int ri;
         // Rects are LTRB
-        if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) {
+        if (mFrameSource[fi].totalDuration() <= mFrameInterval) {
             rect = mFastRects.get();
             ri = fast_i;
             fast_i -= 4;
@@ -211,10 +218,13 @@
 
 void FrameInfoVisualizer::drawThreshold(IProfileRenderer& renderer) {
     SkPaint paint;
-    paint.setColor(THRESHOLD_COLOR);
-    float yLocation = renderer.getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
-    renderer.drawRect(0.0f, yLocation - mThresholdStroke / 2, renderer.getViewportWidth(),
-                      yLocation + mThresholdStroke / 2, paint);
+    for (auto& t : THRESHOLDS) {
+        paint.setColor(t.color);
+        float yLocation = renderer.getViewportHeight() -
+                          (ns2ms(mFrameInterval) * t.percentFrametime * mVerticalUnit);
+        renderer.drawRect(0.0f, yLocation - mThresholdStroke / 2, renderer.getViewportWidth(),
+                          yLocation + mThresholdStroke / 2, paint);
+    }
 }
 
 bool FrameInfoVisualizer::consumeProperties() {
diff --git a/libs/hwui/FrameInfoVisualizer.h b/libs/hwui/FrameInfoVisualizer.h
index b98f501..3040a77 100644
--- a/libs/hwui/FrameInfoVisualizer.h
+++ b/libs/hwui/FrameInfoVisualizer.h
@@ -39,7 +39,7 @@
 
 class FrameInfoVisualizer {
 public:
-    explicit FrameInfoVisualizer(FrameInfoSource& source);
+    explicit FrameInfoVisualizer(FrameInfoSource& source, nsecs_t frameInterval);
     ~FrameInfoVisualizer();
 
     bool consumeProperties();
@@ -71,6 +71,7 @@
 
     FrameInfoSource& mFrameSource;
 
+    nsecs_t mFrameInterval;
     int mVerticalUnit = 0;
     int mThresholdStroke = 0;
 
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 3bbee18..219d040 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -287,6 +287,8 @@
     switch (mPixelStorageType) {
         case PixelStorageType::Heap:
             return mPixelStorage.heap.size;
+        case PixelStorageType::Ashmem:
+            return mPixelStorage.ashmem.size;
         default:
             return rowBytes() * height();
     }
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 01e4516..dd98b25 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -103,6 +103,8 @@
 
     bool isHardware() const { return mPixelStorageType == PixelStorageType::Hardware; }
 
+    PixelStorageType pixelStorageType() const { return mPixelStorageType; }
+
     GraphicBuffer* graphicBuffer();
 
     /**
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 091775dbe7..f5b4d93 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -103,7 +103,7 @@
         , mOpaque(!translucent)
         , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
         , mJankTracker(&thread.globalProfileData(), thread.mainDisplayInfo())
-        , mProfiler(mJankTracker.frames())
+        , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos())
         , mContentDrawBounds(0, 0, 0, 0)
         , mRenderPipeline(std::move(renderPipeline)) {
     rootRenderNode->makeRoot();
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 08edd20..c784d64 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -52,9 +52,6 @@
 // using just a few large reads.
 static const size_t EVENT_BUFFER_SIZE = 100;
 
-// Slight delay to give the UI time to push us a new frame before we replay
-static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4);
-
 static bool gHasRenderThreadInstance = false;
 
 static JVMAttachHook gOnStartHook = nullptr;
@@ -171,6 +168,7 @@
     mDisplayInfo = DeviceInfo::get()->displayInfo();
     nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
     mTimeLord.setFrameInterval(frameIntervalNanos);
+    mDispatchFrameDelay = static_cast<nsecs_t>(frameIntervalNanos * .25f);
     initializeDisplayEventReceiver();
     mEglManager = new EglManager();
     mRenderState = new RenderState(*this);
@@ -311,7 +309,7 @@
         if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) {
             ATRACE_NAME("queue mFrameCallbackTask");
             mFrameCallbackTaskPending = true;
-            nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY);
+            nsecs_t runAt = (vsyncEvent + mDispatchFrameDelay);
             queue().postAt(runAt, [this]() { dispatchFrameCallbacks(); });
         }
     }
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 329b4b9..9298be6 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -24,6 +24,7 @@
 #include "TimeLord.h"
 #include "thread/ThreadBase.h"
 #include "WebViewFunctorManager.h"
+#include "utils/TimeUtils.h"
 
 #include <GrContext.h>
 #include <SkBitmap.h>
@@ -164,6 +165,7 @@
     bool mFrameCallbackTaskPending;
 
     TimeLord mTimeLord;
+    nsecs_t mDispatchFrameDelay = 4_ms;
     RenderState* mRenderState;
     EglManager* mEglManager;
     WebViewFunctorManager& mFunctorManager;
diff --git a/libs/hwui/tests/scripts/prep_generic.sh b/libs/hwui/tests/scripts/prep_generic.sh
new file mode 100755
index 0000000..223bf37
--- /dev/null
+++ b/libs/hwui/tests/scripts/prep_generic.sh
@@ -0,0 +1,249 @@
+#
+# 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.
+#
+
+#################################################################
+###
+###  DO NOT MODIFY THIS FILE
+###  This is a copy of androidx's benchmark/lockClocks.sh
+###  Make changes there instead then copy here!
+###
+#################################################################
+
+# This script can be used to lock device clocks to stable levels for comparing
+# different versions of software.  Since the clock levels are not necessarily
+# indicative of real world behavior, this should **never** be used to compare
+# performance between different device models.
+
+# Fun notes for maintaining this file:
+#      `expr` can deal with ints > INT32_MAX, but if compares cannot. This is why we use MHz.
+#      `expr` can sometimes evaluate right-to-left. This is why we use parens.
+#      Everything below the initial host-check isn't bash - Android uses mksh
+#      mksh allows `\n` in an echo, bash doesn't
+#      can't use `awk`
+
+CPU_TARGET_FREQ_PERCENT=50
+GPU_TARGET_FREQ_PERCENT=50
+
+if [ "`command -v getprop`" == "" ]; then
+    if [ -n "`command -v adb`" ]; then
+        echo ""
+        echo "Pushing $0 and running it on device..."
+        dest=/data/local/tmp/`basename $0`
+        adb push $0 ${dest}
+        adb shell ${dest}
+        adb shell rm ${dest}
+        exit
+    else
+        echo "Could not find adb. Options are:"
+        echo "  1. Ensure adb is on your \$PATH"
+        echo "  2. Use './gradlew lockClocks'"
+        echo "  3. Manually adb push this script to your device, and run it there"
+        exit -1
+    fi
+fi
+
+# require root
+if [ "`id -u`" -ne "0" ]; then
+    echo "Not running as root, cannot lock clocks, aborting"
+    exit -1
+fi
+
+DEVICE=`getprop ro.product.device`
+MODEL=`getprop ro.product.model`
+
+# Find CPU max frequency, and lock big cores to an available frequency
+# that's >= $CPU_TARGET_FREQ_PERCENT% of max. Disable other cores.
+function_lock_cpu() {
+    CPU_BASE=/sys/devices/system/cpu
+    GOV=cpufreq/scaling_governor
+
+    # Find max CPU freq, and associated list of available freqs
+    cpuMaxFreq=0
+    cpuAvailFreqCmpr=0
+    cpuAvailFreq=0
+    enableIndices=''
+    disableIndices=''
+    cpu=0
+    while [ -f ${CPU_BASE}/cpu${cpu}/online ]; do
+        # enable core, so we can find its frequencies
+        echo 1 > ${CPU_BASE}/cpu${cpu}/online
+
+        maxFreq=`cat ${CPU_BASE}/cpu$cpu/cpufreq/cpuinfo_max_freq`
+        availFreq=`cat ${CPU_BASE}/cpu$cpu/cpufreq/scaling_available_frequencies`
+        availFreqCmpr=${availFreq// /-}
+
+        if [ ${maxFreq} -gt ${cpuMaxFreq} ]; then
+            # new highest max freq, look for cpus with same max freq and same avail freq list
+            cpuMaxFreq=${maxFreq}
+            cpuAvailFreq=${availFreq}
+            cpuAvailFreqCmpr=${availFreqCmpr}
+
+            if [ -z ${disableIndices} ]; then
+                disableIndices="$enableIndices"
+            else
+                disableIndices="$disableIndices $enableIndices"
+            fi
+            enableIndices=${cpu}
+        elif [ ${maxFreq} == ${cpuMaxFreq} ] && [ ${availFreqCmpr} == ${cpuAvailFreqCmpr} ]; then
+            enableIndices="$enableIndices $cpu"
+        else
+            disableIndices="$disableIndices $cpu"
+        fi
+        cpu=$(($cpu + 1))
+    done
+
+    # Chose a frequency to lock to that's >= $CPU_TARGET_FREQ_PERCENT% of max
+    # (below, 100M = 1K for KHz->MHz * 100 for %)
+    TARGET_FREQ_MHZ=`expr \( ${cpuMaxFreq} \* ${CPU_TARGET_FREQ_PERCENT} \) \/ 100000`
+    chosenFreq=0
+    for freq in ${cpuAvailFreq}; do
+        freqMhz=`expr ${freq} \/ 1000`
+        if [ ${freqMhz} -ge ${TARGET_FREQ_MHZ} ]; then
+            chosenFreq=${freq}
+            break
+        fi
+    done
+
+    # enable 'big' CPUs
+    for cpu in ${enableIndices}; do
+        freq=${CPU_BASE}/cpu$cpu/cpufreq
+
+        echo 1 > ${CPU_BASE}/cpu${cpu}/online
+        echo userspace > ${CPU_BASE}/cpu${cpu}/${GOV}
+        echo ${chosenFreq} > ${freq}/scaling_max_freq
+        echo ${chosenFreq} > ${freq}/scaling_min_freq
+        echo ${chosenFreq} > ${freq}/scaling_setspeed
+
+        # validate setting the freq worked
+        obsCur=`cat ${freq}/scaling_cur_freq`
+        obsMin=`cat ${freq}/scaling_min_freq`
+        obsMax=`cat ${freq}/scaling_max_freq`
+        if [ obsCur -ne ${chosenFreq} ] || [ obsMin -ne ${chosenFreq} ] || [ obsMax -ne ${chosenFreq} ]; then
+            echo "Failed to set CPU$cpu to $chosenFreq Hz! Aborting..."
+            echo "scaling_cur_freq = $obsCur"
+            echo "scaling_min_freq = $obsMin"
+            echo "scaling_max_freq = $obsMax"
+            exit -1
+        fi
+    done
+
+    # disable other CPUs (Note: important to enable big cores first!)
+    for cpu in ${disableIndices}; do
+      echo 0 > ${CPU_BASE}/cpu${cpu}/online
+    done
+
+    echo "\nLocked CPUs ${enableIndices// /,} to $chosenFreq / $maxFreq KHz"
+    echo "Disabled CPUs ${disableIndices// /,}"
+}
+
+# If we have a Qualcomm GPU, find its max frequency, and lock to
+# an available frequency that's >= GPU_TARGET_FREQ_PERCENT% of max.
+function_lock_gpu_kgsl() {
+    if [ ! -d /sys/class/kgsl/kgsl-3d0/ ]; then
+        # not kgsl, abort
+        echo "\nCurrently don't support locking GPU clocks of $MODEL ($DEVICE)"
+        return -1
+    fi
+    if [ ${DEVICE} == "walleye" ] || [ ${DEVICE} == "taimen" ]; then
+        # Workaround crash
+        echo "\nUnable to lock GPU clocks of $MODEL ($DEVICE)"
+        return -1
+    fi
+
+    GPU_BASE=/sys/class/kgsl/kgsl-3d0
+
+    gpuMaxFreq=0
+    gpuAvailFreq=`cat $GPU_BASE/devfreq/available_frequencies`
+    for freq in ${gpuAvailFreq}; do
+        if [ ${freq} -gt ${gpuMaxFreq} ]; then
+            gpuMaxFreq=${freq}
+        fi
+    done
+
+    # (below, 100M = 1M for MHz * 100 for %)
+    TARGET_FREQ_MHZ=`expr \( ${gpuMaxFreq} \* ${GPU_TARGET_FREQ_PERCENT} \) \/ 100000000`
+
+    chosenFreq=${gpuMaxFreq}
+    index=0
+    chosenIndex=0
+    for freq in ${gpuAvailFreq}; do
+        freqMhz=`expr ${freq} \/ 1000000`
+        if [ ${freqMhz} -ge ${TARGET_FREQ_MHZ} ] && [ ${chosenFreq} -ge ${freq} ]; then
+            # note avail freq are generally in reverse order, so we don't break out of this loop
+            chosenFreq=${freq}
+            chosenIndex=${index}
+        fi
+        index=$(($index + 1))
+    done
+    lastIndex=$(($index - 1))
+
+    firstFreq=`echo $gpuAvailFreq | cut -d" " -f1`
+
+    if [ ${gpuMaxFreq} != ${firstFreq} ]; then
+        # pwrlevel is index of desired freq among available frequencies, from highest to lowest.
+        # If gpuAvailFreq appears to be in-order, reverse the index
+        chosenIndex=$(($lastIndex - $chosenIndex))
+    fi
+
+    echo 0 > ${GPU_BASE}/bus_split
+    echo 1 > ${GPU_BASE}/force_clk_on
+    echo 10000 > ${GPU_BASE}/idle_timer
+
+    echo performance > ${GPU_BASE}/devfreq/governor
+
+    # NOTE: we store in min/max twice, because we don't know if we're increasing
+    # or decreasing, and it's invalid to try and set min > max, or max < min
+    echo ${chosenFreq} > ${GPU_BASE}/devfreq/min_freq
+    echo ${chosenFreq} > ${GPU_BASE}/devfreq/max_freq
+    echo ${chosenFreq} > ${GPU_BASE}/devfreq/min_freq
+    echo ${chosenFreq} > ${GPU_BASE}/devfreq/max_freq
+    echo ${chosenIndex} > ${GPU_BASE}/min_pwrlevel
+    echo ${chosenIndex} > ${GPU_BASE}/max_pwrlevel
+    echo ${chosenIndex} > ${GPU_BASE}/min_pwrlevel
+    echo ${chosenIndex} > ${GPU_BASE}/max_pwrlevel
+
+    obsCur=`cat ${GPU_BASE}/devfreq/cur_freq`
+    obsMin=`cat ${GPU_BASE}/devfreq/min_freq`
+    obsMax=`cat ${GPU_BASE}/devfreq/max_freq`
+    if [ obsCur -ne ${chosenFreq} ] || [ obsMin -ne ${chosenFreq} ] || [ obsMax -ne ${chosenFreq} ]; then
+        echo "Failed to set GPU to $chosenFreq Hz! Aborting..."
+        echo "cur_freq = $obsCur"
+        echo "min_freq = $obsMin"
+        echo "max_freq = $obsMax"
+        echo "index = $chosenIndex"
+        exit -1
+    fi
+    echo "\nLocked GPU to $chosenFreq / $gpuMaxFreq Hz"
+}
+
+# kill processes that manage thermals / scaling
+stop thermal-engine
+stop perfd
+stop vendor.thermal-engine
+stop vendor.perfd
+
+function_lock_cpu
+
+function_lock_gpu_kgsl
+
+# Memory bus - hardcoded per-device for now
+if [ ${DEVICE} == "marlin" ] || [ ${DEVICE} == "sailfish" ]; then
+    echo 13763 > /sys/class/devfreq/soc:qcom,gpubw/max_freq
+else
+    echo "\nUnable to lock memory bus of $MODEL ($DEVICE)."
+fi
+
+echo "\n$DEVICE clocks have been locked - to reset, reboot the device\n"
\ No newline at end of file
diff --git a/libs/hwui/tests/scripts/prep_ryu.sh b/libs/hwui/tests/scripts/prep_ryu.sh
old mode 100644
new mode 100755
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 446ea85..9013a96 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -49,8 +49,7 @@
     private int mMultipathIndicator;
     private double mSnrInDb;
     private double mAutomaticGainControlLevelInDb;
-    private int mCodeType;
-    private String mOtherCodeTypeName;
+    @NonNull private String mCodeType;
 
     // The following enumerations must be in sync with the values declared in gps.h
 
@@ -209,113 +208,6 @@
     public static final int ADR_STATE_HALF_CYCLE_REPORTED = (1<<4);
 
     /**
-     * GNSS measurement code type.
-     * @hide
-     */
-    @IntDef(prefix = { "CODE_TYPE_" }, value = {
-            CODE_TYPE_UNKNOWN, CODE_TYPE_A, CODE_TYPE_B, CODE_TYPE_C, CODE_TYPE_I, CODE_TYPE_L,
-            CODE_TYPE_M, CODE_TYPE_N, CODE_TYPE_P, CODE_TYPE_Q, CODE_TYPE_S, CODE_TYPE_W,
-            CODE_TYPE_X, CODE_TYPE_Y, CODE_TYPE_Z, CODE_TYPE_OTHER
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface CodeType {}
-
-    /** The GNSS Measurement's code type is unknown. */
-    public static final int CODE_TYPE_UNKNOWN = -1;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GALILEO E1A, GALILEO E6A, IRNSS
-     * L5A, IRNSS SA.
-     */
-    public static final int CODE_TYPE_A = 0;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GALILEO E1B, GALILEO E6B, IRNSS
-     * L5B, IRNSS SB.
-     */
-    public static final int CODE_TYPE_B = 1;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GPS L1 C/A,  GPS L2 C/A, GLONASS G1
-     * C/A, GLONASS G2 C/A, GALILEO E1C, GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C.
-     */
-    public static final int CODE_TYPE_C = 2;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GPS L5 I, GLONASS G3 I, GALILEO E5a
-     * I, GALILEO E5b I, GALILEO E5a+b I, SBAS L5 I, QZSS L5 I, BDS B1 I, BDS B2 I, BDS B3 I.
-     */
-    public static final int CODE_TYPE_I = 3;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GPS L1C (P), GPS L2C (L), QZSS L1C
-     * (P), QZSS L2C (L), LEX(6) L.
-     */
-    public static final int CODE_TYPE_L = 4;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GPS L1M, GPS L2M.
-     */
-    public static final int CODE_TYPE_M = 5;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GPS L1P, GPS L2P, GLONASS G1P,
-     * GLONASS G2P.
-     */
-    public static final int CODE_TYPE_P = 6;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GPS L5 Q, GLONASS G3 Q, GALILEO E5a
-     * Q, GALILEO E5b Q, GALILEO E5a+b Q, SBAS L5 Q, QZSS L5 Q, BDS B1 Q, BDS B2 Q, BDS B3 Q.
-     */
-    public static final int CODE_TYPE_Q = 7;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GPS L1C (D), GPS L2C (M), QZSS L1C
-     * (D), QZSS L2C (M), LEX(6) S.
-     */
-    public static final int CODE_TYPE_S = 8;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GPS L1 Z-tracking, GPS L2
-     * Z-tracking.
-     */
-    public static final int CODE_TYPE_W = 9;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GPS L1C (D+P), GPS L2C (M+L), GPS
-     * L5 (I+Q), GLONASS G3 (I+Q), GALILEO E1 (B+C), GALILEO E5a (I+Q), GALILEO E5b (I+Q), GALILEO
-     * E5a+b(I+Q), GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q),
-     * LEX(6) (S+L), BDS B1 (I+Q), BDS B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C).
-     */
-    public static final int CODE_TYPE_X = 10;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GPS L1Y, GPS L2Y.
-     */
-    public static final int CODE_TYPE_Y = 11;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GALILEO E1 (A+B+C), GALILEO E6
-     * (A+B+C), QZSS L1-SAIF.
-     */
-    public static final int CODE_TYPE_Z = 12;
-
-    /**
-     * The GNSS Measurement's code type is one of the following: GPS L1 codeless, GPS L2 codeless.
-     */
-    public static final int CODE_TYPE_N = 13;
-
-    /**
-     * Other code type that does not belong to any of the above code types.
-     *
-     * This code type is used in the case that the code type being tracked in this measurement, as
-     * classified by RINEX standards, does not fit into one of the existing enumerated values. When
-     * this code type is set, the field otherCodeTypeName must specify the new code type.
-     */
-    public static final int CODE_TYPE_OTHER = 255;
-
-    /**
      * All the 'Accumulated Delta Range' flags.
      * @hide
      */
@@ -363,7 +255,6 @@
         mSnrInDb = measurement.mSnrInDb;
         mAutomaticGainControlLevelInDb = measurement.mAutomaticGainControlLevelInDb;
         mCodeType = measurement.mCodeType;
-        mOtherCodeTypeName = measurement.mOtherCodeTypeName;
     }
 
     /**
@@ -1414,9 +1305,50 @@
      *
      * <p>Similar to the Attribute field described in RINEX 3.03, e.g., in Tables 4-10, and Table
      * A2 at the RINEX 3.03 Update 1 Document.
+     *
+     * <p>Returns "A" for GALILEO E1A, GALILEO E6A, IRNSS L5A, IRNSS SA.
+     *
+     * <p>Returns "B" for GALILEO E1B, GALILEO E6B, IRNSS L5B, IRNSS SB.
+     *
+     * <p>Returns "C" for GPS L1 C/A,  GPS L2 C/A, GLONASS G1 C/A, GLONASS G2 C/A, GALILEO E1C,
+     * GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C.
+     *
+     * <p>Returns "I" for GPS L5 I, GLONASS G3 I, GALILEO E5a I, GALILEO E5b I, GALILEO E5a+b I,
+     * SBAS L5 I, QZSS L5 I, BDS B1 I, BDS B2 I, BDS B3 I.
+     *
+     * <p>Returns "L" for GPS L1C (P), GPS L2C (L), QZSS L1C (P), QZSS L2C (L), LEX(6) L.
+     *
+     * <p>Returns "M" for GPS L1M, GPS L2M.
+     *
+     * <p>Returns "N" for GPS L1 codeless, GPS L2 codeless.
+     *
+     * <p>Returns "P" for GPS L1P, GPS L2P, GLONASS G1P, GLONASS G2P.
+     *
+     * <p>Returns "Q" for GPS L5 Q, GLONASS G3 Q, GALILEO E5a Q, GALILEO E5b Q, GALILEO E5a+b Q,
+     * SBAS L5 Q, QZSS L5 Q, BDS B1 Q, BDS B2 Q, BDS B3 Q.
+     *
+     * <p>Returns "S" for GPS L1C (D), GPS L2C (M), QZSS L1C (D), QZSS L2C (M), LEX(6) S.
+     *
+     * <p>Returns "W" for GPS L1 Z-tracking, GPS L2 Z-tracking.
+     *
+     * <p>Returns "X" for GPS L1C (D+P), GPS L2C (M+L), GPS L5 (I+Q), GLONASS G3 (I+Q), GALILEO
+     * E1 (B+C), GALILEO E5a (I+Q), GALILEO E5b (I+Q), GALILEO E5a+b(I+Q), GALILEO E6 (B+C), SBAS
+     * L5 (I+Q), QZSS L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q), LEX(6) (S+L), BDS B1 (I+Q), BDS
+     * B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C).
+     *
+     * <p>Returns "Y" for GPS L1Y, GPS L2Y.
+     *
+     * <p>Returns "Z" for GALILEO E1 (A+B+C), GALILEO E6 (A+B+C), QZSS L1-SAIF.
+     *
+     * <p>Returns "UNKNOWN" if the GNSS Measurement's code type is unknown.
+     *
+     * <p>This is used to specify the observation descriptor defined in GNSS Observation Data File
+     * Header Section Description in the RINEX standard (Version 3.XX), in cases where the code type
+     * does not align with the above listed values. For example, if a code type "G" is added, this
+     * string shall be set to "G".
      */
-    @CodeType
-    public int getCodeType() {
+    @NonNull
+    public String getCodeType() {
         return mCodeType;
     }
 
@@ -1426,7 +1358,7 @@
      * @hide
      */
     @TestApi
-    public void setCodeType(@CodeType int codeType) {
+    public void setCodeType(@NonNull String codeType) {
         setFlag(HAS_CODE_TYPE);
         mCodeType = codeType;
     }
@@ -1439,74 +1371,7 @@
     @TestApi
     public void resetCodeType() {
         resetFlag(HAS_CODE_TYPE);
-        mCodeType = CODE_TYPE_UNKNOWN;
-    }
-
-    /**
-     * Gets the GNSS measurement's code type name when the code type is {@link #CODE_TYPE_OTHER}.
-     *
-     * <p>This is used to specify the observation descriptor defined in GNSS Observation Data File
-     * Header Section Description in the RINEX standard (Version 3.XX), in cases where the code type
-     * does not align with an existing Android enumerated value. For example, if a code type "G" is
-     * added, this string shall be set to "G".
-     */
-    @NonNull
-    public String getOtherCodeTypeName() {
-        return mOtherCodeTypeName;
-    }
-
-    /**
-     * Sets the GNSS measurement's code type name when the code type is {@link #CODE_TYPE_OTHER}.
-     *
-     * @hide
-     */
-    @TestApi
-    public void setOtherCodeTypeName(@NonNull String otherCodeTypeName) {
-        mOtherCodeTypeName = otherCodeTypeName;
-    }
-
-    /**
-     * Gets a string representation of the 'code type'.
-     *
-     * <p>For internal and logging use only.
-     */
-    private String getCodeTypeString() {
-        switch (mCodeType) {
-            case CODE_TYPE_UNKNOWN:
-                return "CODE_TYPE_UNKNOWN";
-            case CODE_TYPE_A:
-                return "CODE_TYPE_A";
-            case CODE_TYPE_B:
-                return "CODE_TYPE_B";
-            case CODE_TYPE_C:
-                return "CODE_TYPE_C";
-            case CODE_TYPE_I:
-                return "CODE_TYPE_I";
-            case CODE_TYPE_L:
-                return "CODE_TYPE_L";
-            case CODE_TYPE_M:
-                return "CODE_TYPE_M";
-            case CODE_TYPE_N:
-                return "CODE_TYPE_N";
-            case CODE_TYPE_P:
-                return "CODE_TYPE_P";
-            case CODE_TYPE_Q:
-                return "CODE_TYPE_Q";
-            case CODE_TYPE_S:
-                return "CODE_TYPE_S";
-            case CODE_TYPE_W:
-                return "CODE_TYPE_W";
-            case CODE_TYPE_X:
-                return "CODE_TYPE_X";
-            case CODE_TYPE_Y:
-                return "CODE_TYPE_Y";
-            case CODE_TYPE_Z:
-                return "CODE_TYPE_Z";
-            case CODE_TYPE_OTHER:
-                return "CODE_TYPE_OTHER";
-            default:
-                return "<Invalid: " + mCodeType + ">";
-        }
+        mCodeType = "UNKNOWN";
     }
 
     public static final @android.annotation.NonNull Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() {
@@ -1534,8 +1399,7 @@
             gnssMeasurement.mMultipathIndicator = parcel.readInt();
             gnssMeasurement.mSnrInDb = parcel.readDouble();
             gnssMeasurement.mAutomaticGainControlLevelInDb = parcel.readDouble();
-            gnssMeasurement.mCodeType = parcel.readInt();
-            gnssMeasurement.mOtherCodeTypeName = parcel.readString();
+            gnssMeasurement.mCodeType = parcel.readString();
 
             return gnssMeasurement;
         }
@@ -1568,8 +1432,7 @@
         parcel.writeInt(mMultipathIndicator);
         parcel.writeDouble(mSnrInDb);
         parcel.writeDouble(mAutomaticGainControlLevelInDb);
-        parcel.writeInt(mCodeType);
-        parcel.writeString(mOtherCodeTypeName);
+        parcel.writeString(mCodeType);
     }
 
     @Override
@@ -1647,10 +1510,7 @@
         builder.append(String.format(
                 format,
                 "CodeType",
-                hasCodeType() ? getCodeTypeString() : null));
-        builder.append(String.format(
-                format,
-                "OtherCodeTypeName", mOtherCodeTypeName));
+                hasCodeType() ? mCodeType : null));
 
         return builder.toString();
     }
@@ -1676,7 +1536,6 @@
         resetSnrInDb();
         resetAutomaticGainControlLevel();
         resetCodeType();
-        setOtherCodeTypeName("");
     }
 
     private void setFlag(int flag) {
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 4e37654..609a15e 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -30,7 +30,6 @@
  * <p>This class is used in conjunction with the {@link Listener} interface.
  *
  * @deprecated use {@link GnssStatus} and {@link GnssStatus.Callback}.
- * @removed
  */
 @Deprecated
 public final class GpsStatus {
@@ -113,7 +112,6 @@
     /**
      * Used for receiving notifications when GPS status has changed.
      * @deprecated use {@link GnssStatus.Callback} instead.
-     * @removed
      */
     @Deprecated
     public interface Listener {
@@ -144,7 +142,6 @@
      * You can implement this interface and call {@link LocationManager#addNmeaListener}
      * to receive NMEA data from the GPS engine.
      * @deprecated use {@link OnNmeaMessageListener} instead.
-     * @removed
      */
     @Deprecated
     public interface NmeaListener {
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index ed74333..673b411 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -150,7 +150,7 @@
     private Bundle mExtras = null;
 
     // A bitmask of fields present in this object (see HAS_* constants defined above).
-    private byte mFieldsMask = 0;
+    private int mFieldsMask = 0;
 
     /**
      * Construct a new Location with a named provider.
@@ -1137,7 +1137,7 @@
             l.mTime = in.readLong();
             l.mElapsedRealtimeNanos = in.readLong();
             l.mElapsedRealtimeUncertaintyNanos = in.readLong();
-            l.mFieldsMask = in.readByte();
+            l.mFieldsMask = in.readInt();
             l.mLatitude = in.readDouble();
             l.mLongitude = in.readDouble();
             l.mAltitude = in.readDouble();
@@ -1168,7 +1168,7 @@
         parcel.writeLong(mTime);
         parcel.writeLong(mElapsedRealtimeNanos);
         parcel.writeLong(mElapsedRealtimeUncertaintyNanos);
-        parcel.writeByte(mFieldsMask);
+        parcel.writeInt(mFieldsMask);
         parcel.writeDouble(mLatitude);
         parcel.writeDouble(mLongitude);
         parcel.writeDouble(mAltitude);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index db6a4d0..dd179f3 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1360,10 +1360,10 @@
             @NonNull String provider, boolean enabled, @NonNull UserHandle userHandle) {
         checkProvider(provider);
 
-        return Settings.Secure.setLocationProviderEnabledForUser(
+        return Settings.Secure.putStringForUser(
                 mContext.getContentResolver(),
-                provider,
-                enabled,
+                Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
+                (enabled ? "+" : "-") + provider,
                 userHandle.getIdentifier());
     }
 
@@ -1749,7 +1749,6 @@
      *
      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
      * @deprecated use {@link #registerGnssStatusCallback(GnssStatus.Callback)} instead.
-     * @removed
      */
     @Deprecated
     @RequiresPermission(ACCESS_FINE_LOCATION)
@@ -1762,7 +1761,6 @@
      *
      * @param listener GPS status listener object to remove
      * @deprecated use {@link #unregisterGnssStatusCallback(GnssStatus.Callback)} instead.
-     * @removed
      */
     @Deprecated
     public void removeGpsStatusListener(GpsStatus.Listener listener) {}
@@ -2088,7 +2086,6 @@
      *
      * @param status object containing GPS status details, or null.
      * @return status object containing updated GPS status.
-     * @removed
      */
     @Deprecated
     @RequiresPermission(ACCESS_FINE_LOCATION)
diff --git a/media/apex/java/android/media/MediaSession2.java b/media/apex/java/android/media/MediaSession2.java
index 09ac9ca..d63de09 100644
--- a/media/apex/java/android/media/MediaSession2.java
+++ b/media/apex/java/android/media/MediaSession2.java
@@ -511,7 +511,8 @@
         }
 
         /**
-         * Set extras for the session token.
+         * Set extras for the session token. If null or not set, {@link Session2Token#getExtras()}
+         * will return {@link Bundle#EMPTY}.
          *
          * @return The Builder to allow chaining
          * @see Session2Token#getExtras()
diff --git a/media/apex/java/android/media/Session2Token.java b/media/apex/java/android/media/Session2Token.java
index dc970ae..d7cb978 100644
--- a/media/apex/java/android/media/Session2Token.java
+++ b/media/apex/java/android/media/Session2Token.java
@@ -216,10 +216,11 @@
 
     /**
      * @return extras of the token
+     * @see MediaSession2.Builder#setExtras(Bundle)
      */
-    @Nullable
+    @NonNull
     public Bundle getExtras() {
-        return mExtras;
+        return mExtras == null ? Bundle.EMPTY : mExtras;
     }
 
     Session2Link getSessionLink() {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c11f446..6a595d2 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4166,6 +4166,10 @@
      /**
      * Indicate A2DP source or sink active device change and eventually suppress
      * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
+     * This operation is asynchronous but its execution will still be sequentially scheduled
+     * relative to calls to {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice,
+     * int, boolean, int)} and
+     * {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}.
      * @param device Bluetooth device connected/disconnected
      * @param state  new connection state (BluetoothProfile.STATE_xxx)
      * @param profile profile for the A2DP device
@@ -4179,18 +4183,16 @@
      * BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED intent.
      * {@hide}
      */
-    public int handleBluetoothA2dpActiveDeviceChange(
+    public void handleBluetoothA2dpActiveDeviceChange(
                 BluetoothDevice device, int state, int profile,
                 boolean suppressNoisyIntent, int a2dpVolume) {
         final IAudioService service = getService();
-        int delay = 0;
         try {
-            delay = service.handleBluetoothA2dpActiveDeviceChange(device,
+            service.handleBluetoothA2dpActiveDeviceChange(device,
                 state, profile, suppressNoisyIntent, a2dpVolume);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-        return delay;
     }
 
     /** {@hide} */
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 95d89bb..c29f355 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -171,7 +171,7 @@
 
     void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device);
 
-    int handleBluetoothA2dpActiveDeviceChange(in BluetoothDevice device,
+    void handleBluetoothA2dpActiveDeviceChange(in BluetoothDevice device,
             int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
 
     @UnsupportedAppUsage
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 9258b85..579ee8d 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -16,6 +16,7 @@
 
 package android.media;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -24,6 +25,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
@@ -36,8 +38,13 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+import java.util.function.Function;
 
 
 /**
@@ -131,21 +138,6 @@
 
     private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES;
 
-    private EventHandler mEventHandler;
-    private EventHandler mKeyStatusChangeHandler;
-    private EventHandler mExpirationUpdateHandler;
-    private EventHandler mSessionLostStateHandler;
-
-    private OnEventListener mOnEventListener;
-    private OnKeyStatusChangeListener mOnKeyStatusChangeListener;
-    private OnExpirationUpdateListener mOnExpirationUpdateListener;
-    private OnSessionLostStateListener mOnSessionLostStateListener;
-
-    private final Object mEventLock = new Object();
-    private final Object mKeyStatusChangeLock = new Object();
-    private final Object mExpirationUpdateLock = new Object();
-    private final Object mSessionLostStateLock = new Object();
-
     private long mNativeContext;
 
     /**
@@ -227,35 +219,19 @@
     private static final native boolean isCryptoSchemeSupportedNative(
             @NonNull byte[] uuid, @Nullable String mimeType, @SecurityLevel int securityLevel);
 
-    private EventHandler createHandler() {
+    private Handler createHandler() {
         Looper looper;
-        EventHandler handler;
+        Handler handler;
         if ((looper = Looper.myLooper()) != null) {
-            handler = new EventHandler(this, looper);
+            handler = new Handler(looper);
         } else if ((looper = Looper.getMainLooper()) != null) {
-            handler = new EventHandler(this, looper);
+            handler = new Handler(looper);
         } else {
             handler = null;
         }
         return handler;
     }
 
-    private EventHandler updateHandler(Handler handler) {
-        Looper looper;
-        EventHandler newHandler = null;
-        if (handler != null) {
-            looper = handler.getLooper();
-        } else {
-            looper = Looper.myLooper();
-        }
-        if (looper != null) {
-            if (handler == null || handler.getLooper() != looper) {
-                newHandler = new EventHandler(this, looper);
-            }
-        }
-        return newHandler;
-    }
-
     /**
      * Instantiate a MediaDrm object
      *
@@ -265,11 +241,6 @@
      * specified scheme UUID
      */
     public MediaDrm(@NonNull UUID uuid) throws UnsupportedSchemeException {
-        mEventHandler = createHandler();
-        mKeyStatusChangeHandler = createHandler();
-        mExpirationUpdateHandler = createHandler();
-        mSessionLostStateHandler = createHandler();
-
         /* Native setup requires a weak reference to our object.
          * It's easier to create it here than in C++.
          */
@@ -368,12 +339,30 @@
      */
     public void setOnExpirationUpdateListener(
             @Nullable OnExpirationUpdateListener listener, @Nullable Handler handler) {
-        synchronized(mExpirationUpdateLock) {
-            if (listener != null) {
-                mExpirationUpdateHandler = updateHandler(handler);
-            }
-            mOnExpirationUpdateListener = listener;
-        }
+        setListenerWithHandler(EXPIRATION_UPDATE, handler, listener,
+                this::createOnExpirationUpdateListener);
+    }
+    /**
+     * Register a callback to be invoked when a session expiration update
+     * occurs.
+     *
+     * @see #setOnExpirationUpdateListener(OnExpirationUpdateListener, Handler)
+     *
+     * @param executor the executor through which the listener should be invoked
+     * @param listener the callback that will be run.
+     */
+    public void setOnExpirationUpdateListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnExpirationUpdateListener listener) {
+        setListenerWithExecutor(EXPIRATION_UPDATE, executor, listener,
+                this::createOnExpirationUpdateListener);
+    }
+
+    /**
+     * Clear the {@link OnExpirationUpdateListener}.
+     */
+    public void clearOnExpirationUpdateListener() {
+        clearGenericListener(EXPIRATION_UPDATE);
     }
 
     /**
@@ -407,12 +396,31 @@
      */
     public void setOnKeyStatusChangeListener(
             @Nullable OnKeyStatusChangeListener listener, @Nullable Handler handler) {
-        synchronized(mKeyStatusChangeLock) {
-            if (listener != null) {
-                mKeyStatusChangeHandler = updateHandler(handler);
-            }
-            mOnKeyStatusChangeListener = listener;
-        }
+        setListenerWithHandler(KEY_STATUS_CHANGE, handler, listener,
+                this::createOnKeyStatusChangeListener);
+    }
+
+    /**
+     * Register a callback to be invoked when the state of keys in a session
+     * change.
+     *
+     * @see #setOnKeyStatusChangeListener(OnKeyStatusChangeListener, Handler)
+     *
+     * @param listener the callback that will be run when key status changes.
+     * @param executor the executor on which the listener should be invoked.
+     */
+    public void setOnKeyStatusChangeListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnKeyStatusChangeListener listener) {
+        setListenerWithExecutor(KEY_STATUS_CHANGE, executor, listener,
+                this::createOnKeyStatusChangeListener);
+    }
+
+    /**
+     * Clear the {@link OnKeyStatusChangeListener}.
+     */
+    public void clearOnKeyStatusChangeListener() {
+        clearGenericListener(KEY_STATUS_CHANGE);
     }
 
     /**
@@ -453,12 +461,31 @@
      */
     public void setOnSessionLostStateListener(
             @Nullable OnSessionLostStateListener listener, @Nullable Handler handler) {
-        synchronized(mSessionLostStateLock) {
-            if (listener != null) {
-                mSessionLostStateHandler = updateHandler(handler);
-            }
-            mOnSessionLostStateListener = listener;
-        }
+        setListenerWithHandler(SESSION_LOST_STATE, handler, listener,
+                this::createOnSessionLostStateListener);
+    }
+
+    /**
+     * Register a callback to be invoked when session state has been
+     * lost.
+     *
+     * @see #setOnSessionLostStateListener(OnSessionLostStateListener, Handler)
+     *
+     * @param listener the callback that will be run.
+     * @param executor the executor on which the listener should be invoked.
+     */
+    public void setOnSessionLostStateListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @Nullable OnSessionLostStateListener listener) {
+        setListenerWithExecutor(SESSION_LOST_STATE, executor, listener,
+                this::createOnSessionLostStateListener);
+    }
+
+    /**
+     * Clear the {@link OnSessionLostStateListener}.
+     */
+    public void clearOnSessionLostStateListener() {
+        clearGenericListener(SESSION_LOST_STATE);
     }
 
     /**
@@ -552,14 +579,48 @@
     /**
      * Register a callback to be invoked when an event occurs
      *
+     * @see #setOnEventListener(OnEventListener, Handler)
+     *
      * @param listener the callback that will be run.  Use {@code null} to
      *        stop receiving event callbacks.
      */
     public void setOnEventListener(@Nullable OnEventListener listener)
     {
-        synchronized(mEventLock) {
-            mOnEventListener = listener;
-        }
+        setOnEventListener(listener, null);
+    }
+
+    /**
+     * Register a callback to be invoked when an event occurs
+     *
+     * @param listener the callback that will be run.  Use {@code null} to
+     *        stop receiving event callbacks.
+     * @param handler the handler on which the listener should be invoked, or
+     *        null if the listener should be invoked on the calling thread's looper.
+     */
+
+    public void setOnEventListener(@Nullable OnEventListener listener, @Nullable Handler handler)
+    {
+        setListenerWithHandler(DRM_EVENT, handler, listener, this::createOnEventListener);
+    }
+
+    /**
+     * Register a callback to be invoked when an event occurs
+     *
+     * @see #setOnEventListener(OnEventListener)
+     *
+     * @param executor the executor through which the listener should be invoked
+     * @param listener the callback that will be run.
+     */
+    public void setOnEventListener(@NonNull @CallbackExecutor Executor executor,
+            @NonNull OnEventListener listener) {
+        setListenerWithExecutor(DRM_EVENT, executor, listener, this::createOnEventListener);
+    }
+
+    /**
+     * Clear the {@link OnEventListener}.
+     */
+    public void clearOnEventListener() {
+        clearGenericListener(DRM_EVENT);
     }
 
     /**
@@ -637,99 +698,112 @@
     private static final int KEY_STATUS_CHANGE = 202;
     private static final int SESSION_LOST_STATE = 203;
 
-    private class EventHandler extends Handler
-    {
-        private MediaDrm mMediaDrm;
+    // Use ConcurrentMap to support concurrent read/write to listener settings.
+    // ListenerWithExecutor is immutable so we shouldn't need further locks.
+    private final Map<Integer, ListenerWithExecutor> mListenerMap = new ConcurrentHashMap<>();
 
-        public EventHandler(@NonNull MediaDrm md, @NonNull Looper looper) {
-            super(looper);
-            mMediaDrm = md;
+    // called by old-style set*Listener APIs using Handlers; listener & handler are Nullable
+    private <T> void setListenerWithHandler(int what, Handler handler, T listener,
+            Function<T, Consumer<ListenerArgs>> converter) {
+        if (listener == null) {
+            clearGenericListener(what);
+        } else {
+            handler = handler == null ? createHandler() : handler;
+            final HandlerExecutor executor = new HandlerExecutor(handler);
+            setGenericListener(what, executor, listener, converter);
         }
+    }
 
-        @Override
-        public void handleMessage(@NonNull Message msg) {
-            if (mMediaDrm.mNativeContext == 0) {
-                Log.w(TAG, "MediaDrm went away with unhandled events");
-                return;
+    // called by new-style set*Listener APIs using Executors; listener & executor must be NonNull
+    private <T> void setListenerWithExecutor(int what, Executor executor, T listener,
+            Function<T, Consumer<ListenerArgs>> converter) {
+        if (executor == null || listener == null) {
+            final String errMsg = String.format("executor %s listener %s", executor, listener);
+            throw new IllegalArgumentException(errMsg);
+        }
+        setGenericListener(what, executor, listener, converter);
+    }
+
+    private <T> void setGenericListener(int what, Executor executor, T listener,
+            Function<T, Consumer<ListenerArgs>> converter) {
+        mListenerMap.put(what, new ListenerWithExecutor(executor, converter.apply(listener)));
+    }
+
+    private void clearGenericListener(int what) {
+        mListenerMap.remove(what);
+    }
+
+    private Consumer<ListenerArgs> createOnEventListener(OnEventListener listener) {
+        return args -> {
+            byte[] sessionId = args.parcel.createByteArray();
+            if (sessionId.length == 0) {
+                sessionId = null;
             }
-            switch(msg.what) {
-
-            case DRM_EVENT:
-                synchronized(mEventLock) {
-                    if (mOnEventListener != null) {
-                        if (msg.obj != null && msg.obj instanceof Parcel) {
-                            Parcel parcel = (Parcel)msg.obj;
-                            byte[] sessionId = parcel.createByteArray();
-                            if (sessionId.length == 0) {
-                                sessionId = null;
-                            }
-                            byte[] data = parcel.createByteArray();
-                            if (data.length == 0) {
-                                data = null;
-                            }
-
-                            Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
-                            mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
-                        }
-                    }
-                }
-                return;
-
-            case KEY_STATUS_CHANGE:
-                synchronized(mKeyStatusChangeLock) {
-                    if (mOnKeyStatusChangeListener != null) {
-                        if (msg.obj != null && msg.obj instanceof Parcel) {
-                            Parcel parcel = (Parcel)msg.obj;
-                            byte[] sessionId = parcel.createByteArray();
-                            if (sessionId.length > 0) {
-                                List<KeyStatus> keyStatusList = keyStatusListFromParcel(parcel);
-                                boolean hasNewUsableKey = (parcel.readInt() != 0);
-
-                                Log.i(TAG, "Drm key status changed");
-                                mOnKeyStatusChangeListener.onKeyStatusChange(mMediaDrm, sessionId,
-                                        keyStatusList, hasNewUsableKey);
-                            }
-                        }
-                    }
-                }
-                return;
-
-            case EXPIRATION_UPDATE:
-                synchronized(mExpirationUpdateLock) {
-                    if (mOnExpirationUpdateListener != null) {
-                        if (msg.obj != null && msg.obj instanceof Parcel) {
-                            Parcel parcel = (Parcel)msg.obj;
-                            byte[] sessionId = parcel.createByteArray();
-                            if (sessionId.length > 0) {
-                                long expirationTime = parcel.readLong();
-
-                                Log.i(TAG, "Drm key expiration update: " + expirationTime);
-                                mOnExpirationUpdateListener.onExpirationUpdate(mMediaDrm, sessionId,
-                                        expirationTime);
-                            }
-                        }
-                    }
-                }
-                return;
-
-            case SESSION_LOST_STATE:
-                synchronized(mSessionLostStateLock) {
-                    if (mOnSessionLostStateListener != null) {
-                        if (msg.obj != null && msg.obj instanceof Parcel) {
-                            Parcel parcel = (Parcel)msg.obj;
-                            byte[] sessionId = parcel.createByteArray();
-                            Log.i(TAG, "Drm session lost state event: ");
-                            mOnSessionLostStateListener.onSessionLostState(mMediaDrm,
-                                    sessionId);
-                        }
-                    }
-                }
-                return;
-
-            default:
-                Log.e(TAG, "Unknown message type " + msg.what);
-                return;
+            byte[] data = args.parcel.createByteArray();
+            if (data.length == 0) {
+                data = null;
             }
+
+            Log.i(TAG, "Drm event (" + args.arg1 + "," + args.arg2 + ")");
+            listener.onEvent(this, sessionId, args.arg1, args.arg2, data);
+        };
+    }
+
+    private Consumer<ListenerArgs> createOnKeyStatusChangeListener(
+            OnKeyStatusChangeListener listener) {
+        return args -> {
+            byte[] sessionId = args.parcel.createByteArray();
+            if (sessionId.length > 0) {
+                List<KeyStatus> keyStatusList = keyStatusListFromParcel(args.parcel);
+                boolean hasNewUsableKey = (args.parcel.readInt() != 0);
+
+                Log.i(TAG, "Drm key status changed");
+                listener.onKeyStatusChange(this, sessionId, keyStatusList, hasNewUsableKey);
+            }
+        };
+    }
+
+    private Consumer<ListenerArgs> createOnExpirationUpdateListener(
+            OnExpirationUpdateListener listener) {
+        return args -> {
+            byte[] sessionId = args.parcel.createByteArray();
+            if (sessionId.length > 0) {
+                long expirationTime = args.parcel.readLong();
+
+                Log.i(TAG, "Drm key expiration update: " + expirationTime);
+                listener.onExpirationUpdate(this, sessionId, expirationTime);
+            }
+        };
+    }
+
+    private Consumer<ListenerArgs> createOnSessionLostStateListener(
+            OnSessionLostStateListener listener) {
+        return args -> {
+            byte[] sessionId = args.parcel.createByteArray();
+            Log.i(TAG, "Drm session lost state event: ");
+            listener.onSessionLostState(this, sessionId);
+        };
+    }
+
+    private static class ListenerArgs {
+        private final Parcel parcel;
+        private final int arg1;
+        private final int arg2;
+
+        public ListenerArgs(Parcel parcel, int arg1, int arg2) {
+            this.parcel = parcel;
+            this.arg1 = arg1;
+            this.arg2 = arg2;
+        }
+    }
+
+    private static class ListenerWithExecutor {
+        private final Consumer<ListenerArgs> mConsumer;
+        private final Executor mExecutor;
+
+        public ListenerWithExecutor(Executor executor, Consumer<ListenerArgs> consumer) {
+            this.mExecutor = executor;
+            this.mConsumer = consumer;
         }
     }
 
@@ -764,35 +838,22 @@
         }
         switch (what) {
             case DRM_EVENT:
-                synchronized(md.mEventLock) {
-                    if (md.mEventHandler != null) {
-                        Message m = md.mEventHandler.obtainMessage(what, eventType, extra, obj);
-                        md.mEventHandler.sendMessage(m);
-                    }
-                }
-                break;
             case EXPIRATION_UPDATE:
-                synchronized(md.mExpirationUpdateLock) {
-                    if (md.mExpirationUpdateHandler != null) {
-                        Message m = md.mExpirationUpdateHandler.obtainMessage(what, obj);
-                        md.mExpirationUpdateHandler.sendMessage(m);
-                    }
-                }
-                break;
             case KEY_STATUS_CHANGE:
-                synchronized(md.mKeyStatusChangeLock) {
-                    if (md.mKeyStatusChangeHandler != null) {
-                        Message m = md.mKeyStatusChangeHandler.obtainMessage(what, obj);
-                        md.mKeyStatusChangeHandler.sendMessage(m);
-                    }
-                }
-                break;
             case SESSION_LOST_STATE:
-                synchronized(md.mSessionLostStateLock) {
-                    if (md.mSessionLostStateHandler != null) {
-                        Message m = md.mSessionLostStateHandler.obtainMessage(what, obj);
-                        md.mSessionLostStateHandler.sendMessage(m);
-                    }
+                ListenerWithExecutor listener  = md.mListenerMap.get(what);
+                if (listener != null) {
+                    final Runnable command = () -> {
+                        if (md.mNativeContext == 0) {
+                            Log.w(TAG, "MediaDrm went away with unhandled events");
+                            return;
+                        }
+                        if (obj != null && obj instanceof Parcel) {
+                            Parcel p = (Parcel)obj;
+                            listener.mConsumer.accept(new ListenerArgs(p, eventType, extra));
+                        }
+                    };
+                    listener.mExecutor.execute(command);
                 }
                 break;
             default:
@@ -1302,6 +1363,18 @@
         removeAllSecureStops();;
     }
 
+    /**
+     * @deprecated Not of any use for application development;
+     * please note that the related integer constants remain supported:
+     * {@link #HDCP_LEVEL_UNKNOWN},
+     * {@link #HDCP_NONE},
+     * {@link #HDCP_V1},
+     * {@link #HDCP_V2},
+     * {@link #HDCP_V2_1},
+     * {@link #HDCP_V2_2},
+     * {@link #HDCP_V2_3}
+     */
+    @Deprecated
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({HDCP_LEVEL_UNKNOWN, HDCP_NONE, HDCP_V1, HDCP_V2,
                         HDCP_V2_1, HDCP_V2_2, HDCP_V2_3, HDCP_NO_DIGITAL_OUTPUT})
@@ -1394,7 +1467,17 @@
     /**
      * Security level indicates the robustness of the device's DRM
      * implementation.
+     *
+     * @deprecated Not of any use for application development;
+     * please note that the related integer constants remain supported:
+     * {@link #SECURITY_LEVEL_UNKNOWN},
+     * {@link #SECURITY_LEVEL_SW_SECURE_CRYPTO},
+     * {@link #SECURITY_LEVEL_SW_SECURE_DECODE},
+     * {@link #SECURITY_LEVEL_HW_SECURE_CRYPTO},
+     * {@link #SECURITY_LEVEL_HW_SECURE_DECODE},
+     * {@link #SECURITY_LEVEL_HW_SECURE_ALL}
      */
+    @Deprecated
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SECURITY_LEVEL_UNKNOWN, SECURITY_LEVEL_SW_SECURE_CRYPTO,
             SECURITY_LEVEL_SW_SECURE_DECODE, SECURITY_LEVEL_HW_SECURE_CRYPTO,
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index abbfa88..040152a 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2645,7 +2645,7 @@
      */
     private synchronized void setSubtitleAnchor() {
         if ((mSubtitleController == null) && (ActivityThread.currentApplication() != null)) {
-            getMediaTimeProvider();
+            final TimeProvider timeProvider = (TimeProvider) getMediaTimeProvider();
             final HandlerThread thread = new HandlerThread("SetSubtitleAnchorThread");
             thread.start();
             Handler handler = new Handler(thread.getLooper());
@@ -2653,7 +2653,8 @@
                 @Override
                 public void run() {
                     Context context = ActivityThread.currentApplication();
-                    mSubtitleController = new SubtitleController(context, mTimeProvider, MediaPlayer.this);
+                    mSubtitleController =
+                            new SubtitleController(context, timeProvider, MediaPlayer.this);
                     mSubtitleController.setAnchor(new Anchor() {
                         @Override
                         public void setSubtitleWidget(RenderingWidget subtitleWidget) {
@@ -2661,7 +2662,7 @@
 
                         @Override
                         public Looper getSubtitleLooper() {
-                            return mTimeProvider.mEventHandler.getLooper();
+                            return timeProvider.mEventHandler.getLooper();
                         }
                     });
                     thread.getLooper().quitSafely();
diff --git a/media/java/android/media/SRTRenderer.java b/media/java/android/media/SRTRenderer.java
index a3e2abd..505f996 100644
--- a/media/java/android/media/SRTRenderer.java
+++ b/media/java/android/media/SRTRenderer.java
@@ -125,6 +125,7 @@
                 String[] startEnd = header.split("-->");
                 cue.mStartTimeMs = parseMs(startEnd[0]);
                 cue.mEndTimeMs = parseMs(startEnd[1]);
+                cue.mRunID = runID;
 
                 String s;
                 List<String> paragraph = new ArrayList<String>();
diff --git a/media/java/android/media/SubtitleData.java b/media/java/android/media/SubtitleData.java
index 31622a9..2c6c61f 100644
--- a/media/java/android/media/SubtitleData.java
+++ b/media/java/android/media/SubtitleData.java
@@ -91,7 +91,7 @@
     }
 
     /**
-     * Returns the index of the MediaPlayer track which contains this subtitle data.
+     * Returns the index of the media player track which contains this subtitle data.
      * @return an index in the array returned by {@link MediaPlayer#getTrackInfo()}.
      */
     public int getTrackIndex() {
@@ -198,7 +198,7 @@
         /**
          * Sets the info of subtitle data.
          *
-         * @param trackIndex the ParcelFileDescriptor for the file to play
+         * @param trackIndex the index of the media player track which contains this subtitle data.
          * @param startTimeUs the start time in microsecond for the subtile data
          * @param durationUs the duration in microsecond for the subtile data
          * @param data the data array for the subtile data. It should not be null.
diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java
index 5596c32..0705d97 100644
--- a/media/java/android/media/SubtitleTrack.java
+++ b/media/java/android/media/SubtitleTrack.java
@@ -263,7 +263,9 @@
         }
         updateView(mActiveCues);
         mNextScheduledTimeMs = -1;
-        mTimeProvider.notifyAt(MediaTimeProvider.NO_TIME, this);
+        if (mTimeProvider != null) {
+            mTimeProvider.notifyAt(MediaTimeProvider.NO_TIME, this);
+        }
     }
 
     /** @hide */
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index e85461f..cfcc294 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -55,8 +55,8 @@
     void addSession2TokensListener(in ISession2TokensListener listener, int userId);
     void removeSession2TokensListener(in ISession2TokensListener listener);
 
-    // This is for the system volume UI only
-    void setRemoteVolumeController(in IRemoteVolumeController rvc);
+    void registerRemoteVolumeController(in IRemoteVolumeController rvc);
+    void unregisterRemoteVolumeController(in IRemoteVolumeController rvc);
 
     // For PhoneWindowManager to precheck media keys
     boolean isGlobalPriorityActive();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 5ee52ce..7334044 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -954,7 +953,6 @@
         /**
          * @hide
          */
-        @SystemApi
         public PlaybackInfo(int type, int control, int max, int current, AudioAttributes attrs) {
             mVolumeType = type;
             mVolumeControl = control;
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index fde4f88..f530442 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -424,17 +424,33 @@
     }
 
     /**
-     * Set the remote volume controller to receive volume updates on. Only for
-     * use by system UI.
+     * Set the remote volume controller to receive volume updates on.
+     * Only for use by System UI and Settings application.
      *
      * @param rvc The volume controller to receive updates on.
      * @hide
      */
-    public void setRemoteVolumeController(IRemoteVolumeController rvc) {
+    public void registerRemoteVolumeController(IRemoteVolumeController rvc) {
         try {
-            mService.setRemoteVolumeController(rvc);
+            mService.registerRemoteVolumeController(rvc);
         } catch (RemoteException e) {
-            Log.e(TAG, "Error in setRemoteVolumeController.", e);
+            Log.e(TAG, "Error in registerRemoteVolumeController.", e);
+        }
+    }
+
+    /**
+     * Unregisters the remote volume controller which was previously registered with
+     * {@link #registerRemoteVolumeController(IRemoteVolumeController)}.
+     * Only for use by System UI and Settings application.
+     *
+     * @param rvc The volume controller which was registered.
+     * @hide
+     */
+    public void unregisterRemoteVolumeController(IRemoteVolumeController rvc) {
+        try {
+            mService.unregisterRemoteVolumeController(rvc);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in unregisterRemoteVolumeController.", e);
         }
     }
 
diff --git a/media/mca/Android.mk b/media/mca/Android.mk
deleted file mode 100644
index b1ce91e..0000000
--- a/media/mca/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright (C) 2011 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.
-#
-
-#
-# Build all native libraries
-#
-include $(call all-subdir-makefiles)
-
-
diff --git a/media/mca/samples/Android.mk b/media/mca/samples/Android.mk
deleted file mode 100644
index b1ce91e..0000000
--- a/media/mca/samples/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright (C) 2011 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.
-#
-
-#
-# Build all native libraries
-#
-include $(call all-subdir-makefiles)
-
-
diff --git a/media/mca/samples/CameraEffectsRecordingSample/Android.bp b/media/mca/samples/CameraEffectsRecordingSample/Android.bp
new file mode 100644
index 0000000..96e81ab
--- /dev/null
+++ b/media/mca/samples/CameraEffectsRecordingSample/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2011 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.
+//
+
+// Build activity
+
+android_test {
+    name: "CameraEffectsRecordingSample",
+    srcs: ["**/*.java"],
+    platform_apis: true,
+    optimize: {
+        enabled: false,
+    },
+}
+
diff --git a/media/mca/samples/CameraEffectsRecordingSample/Android.mk b/media/mca/samples/CameraEffectsRecordingSample/Android.mk
deleted file mode 100644
index c81f2fc..0000000
--- a/media/mca/samples/CameraEffectsRecordingSample/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2011 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.
-#
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := CameraEffectsRecordingSample
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
-
-# ============================================================
-
-# Also build all of the sub-targets under this one: the shared library.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/mca/tests/Android.bp b/media/mca/tests/Android.bp
new file mode 100644
index 0000000..6b11dd9
--- /dev/null
+++ b/media/mca/tests/Android.bp
@@ -0,0 +1,12 @@
+android_test {
+    name: "CameraEffectsTests",
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    static_libs: ["junit"],
+    // Include all test java files.
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    instrumentation_for: "CameraEffectsRecordingSample",
+}
diff --git a/media/mca/tests/Android.mk b/media/mca/tests/Android.mk
deleted file mode 100644
index 648af4e..0000000
--- a/media/mca/tests/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CameraEffectsTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_INSTRUMENTATION_FOR := CameraEffectsRecordingSample
-
-include $(BUILD_PACKAGE)
-
-
diff --git a/media/native/midi/include/Doxyfile b/media/native/midi/include/Doxyfile
index 2828f48..e40bbdc 100644
--- a/media/native/midi/include/Doxyfile
+++ b/media/native/midi/include/Doxyfile
@@ -790,7 +790,7 @@
 # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = "midi.h"
+INPUT                  = "amidi/AMidi.h"
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/media/native/midi/include/amidi/AMidi.h b/media/native/midi/include/amidi/AMidi.h
index 0d60b0d..cbe410f 100644
--- a/media/native/midi/include/amidi/AMidi.h
+++ b/media/native/midi/include/amidi/AMidi.h
@@ -13,6 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+/**
+ * @addtogroup Midi
+ * @{
+ */
+
+/**
+ * @file AMidi.h
+ */
 
 #ifndef ANDROID_MEDIA_AMIDI_H_
 #define ANDROID_MEDIA_AMIDI_H_
@@ -244,3 +252,6 @@
 #endif
 
 #endif /* ANDROID_MEDIA_AMIDI_H_ */
+/**
+@}
+*/
diff --git a/media/packages/BluetoothMidiService/Android.bp b/media/packages/BluetoothMidiService/Android.bp
new file mode 100644
index 0000000..f45114a
--- /dev/null
+++ b/media/packages/BluetoothMidiService/Android.bp
@@ -0,0 +1,6 @@
+android_app {
+    name: "BluetoothMidiService",
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+}
diff --git a/media/packages/BluetoothMidiService/Android.mk b/media/packages/BluetoothMidiService/Android.mk
deleted file mode 100644
index 6f262bf..0000000
--- a/media/packages/BluetoothMidiService/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES += \
-      $(call all-java-files-under,src)
-
-LOCAL_PACKAGE_NAME := BluetoothMidiService
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/media/tests/CameraBrowser/Android.bp b/media/tests/CameraBrowser/Android.bp
new file mode 100644
index 0000000..8e3ca19
--- /dev/null
+++ b/media/tests/CameraBrowser/Android.bp
@@ -0,0 +1,5 @@
+android_test {
+    name: "CameraBrowser",
+    srcs: ["**/*.java"],
+    sdk_version: "current",
+}
diff --git a/media/tests/CameraBrowser/Android.mk b/media/tests/CameraBrowser/Android.mk
deleted file mode 100644
index 46596a7..0000000
--- a/media/tests/CameraBrowser/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := CameraBrowser
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/media/tests/EffectsTest/Android.bp b/media/tests/EffectsTest/Android.bp
new file mode 100644
index 0000000..214e8c0
--- /dev/null
+++ b/media/tests/EffectsTest/Android.bp
@@ -0,0 +1,5 @@
+android_test {
+    name: "EffectsTest",
+    srcs: ["**/*.java"],
+    platform_apis: true,
+}
diff --git a/media/tests/EffectsTest/Android.mk b/media/tests/EffectsTest/Android.mk
deleted file mode 100644
index a066950..0000000
--- a/media/tests/EffectsTest/Android.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := EffectsTest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
diff --git a/media/tests/MediaDump/Android.bp b/media/tests/MediaDump/Android.bp
new file mode 100644
index 0000000..0eba8b2
--- /dev/null
+++ b/media/tests/MediaDump/Android.bp
@@ -0,0 +1,6 @@
+android_app {
+    name: "MediaDump",
+    // Only compile source java files in this apk.
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+}
diff --git a/media/tests/MediaDump/Android.mk b/media/tests/MediaDump/Android.mk
deleted file mode 100644
index 74afdd0..0000000
--- a/media/tests/MediaDump/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := MediaDump
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/tests/ScoAudioTest/Android.bp b/media/tests/ScoAudioTest/Android.bp
new file mode 100644
index 0000000..ad2b9171
--- /dev/null
+++ b/media/tests/ScoAudioTest/Android.bp
@@ -0,0 +1,5 @@
+android_test {
+    name: "scoaudiotest",
+    platform_apis: true,
+    srcs: ["**/*.java"],
+}
diff --git a/media/tests/ScoAudioTest/Android.mk b/media/tests/ScoAudioTest/Android.mk
deleted file mode 100644
index 2ad91a4..0000000
--- a/media/tests/ScoAudioTest/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-#LOCAL_SDK_VERSION := current
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := scoaudiotest
-
-include $(BUILD_PACKAGE)
diff --git a/media/tests/SoundPoolTest/Android.bp b/media/tests/SoundPoolTest/Android.bp
new file mode 100644
index 0000000..473f531
--- /dev/null
+++ b/media/tests/SoundPoolTest/Android.bp
@@ -0,0 +1,5 @@
+android_test {
+    name: "SoundPoolTest",
+    srcs: ["**/*.java"],
+    platform_apis: true,
+}
diff --git a/media/tests/SoundPoolTest/Android.mk b/media/tests/SoundPoolTest/Android.mk
deleted file mode 100644
index 9ca33c8..0000000
--- a/media/tests/SoundPoolTest/Android.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := SoundPoolTest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
diff --git a/media/tests/players/Android.bp b/media/tests/players/Android.bp
new file mode 100644
index 0000000..23c5f04
--- /dev/null
+++ b/media/tests/players/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2009 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.
+
+cc_test_library {
+    name: "invoke_mock_media_player",
+    srcs: ["invoke_mock_media_player.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libmedia",
+        "libutils",
+        "liblog",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+    gtest: false,
+}
diff --git a/media/tests/players/Android.mk b/media/tests/players/Android.mk
deleted file mode 100644
index ee9d850..0000000
--- a/media/tests/players/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2009 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_SRC_FILES:= invoke_mock_media_player.cpp
-
-LOCAL_SHARED_LIBRARIES:= \
-    libbinder \
-    libmedia \
-    libutils \
-    liblog
-
-LOCAL_MODULE:= invoke_mock_media_player
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
index 0c35204..3b278b4 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
@@ -20,9 +20,11 @@
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.car.CarNotificationEntryManager;
 import com.android.systemui.car.CarNotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.car.CarFacetButtonController;
 import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.volume.CarVolumeDialogComponent;
@@ -54,7 +56,7 @@
     }
 
     public StatusBarKeyguardViewManager createStatusBarKeyguardViewManager(Context context,
-        ViewMediatorCallback viewMediatorCallback, LockPatternUtils lockPatternUtils) {
+            ViewMediatorCallback viewMediatorCallback, LockPatternUtils lockPatternUtils) {
         return new CarStatusBarKeyguardViewManager(context, viewMediatorCallback, lockPatternUtils);
     }
 
@@ -92,4 +94,12 @@
     public interface CarDependencyComponent {
         CarFacetButtonController getCarFacetButtonController();
     }
+
+    /**
+     * Use {@link CarNotificationEntryManager}, which does nothing when adding a notification.
+     */
+    @Singleton
+    public NotificationEntryManager provideNotificationEntryManager(Context context) {
+        return new CarNotificationEntryManager(context);
+    }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
new file mode 100644
index 0000000..6d9c7ba
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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.car;
+
+import android.content.Context;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+
+/**
+ * Car specific notification entry manager that does nothing when adding a notification.
+ *
+ * <p> This is because system UI notifications are disabled and we have a different implementation.
+ * Please see {@link com.android.car.notification}.
+ */
+public class CarNotificationEntryManager extends NotificationEntryManager {
+    public CarNotificationEntryManager(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void addNotification(
+            StatusBarNotification notification, NotificationListenerService.RankingMap ranking) {
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index bd0e0b8..45459fc 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -161,6 +161,11 @@
         }
 
         buildNavBarContent();
+        // If the UI was rebuilt (day/night change) while the keyguard was up we need to
+        // correctly respect that state.
+        if (mIsKeyguard) {
+            updateNavBarForKeyguardContent();
+        }
     }
 
     private void addTemperatureViewToController(View v) {
@@ -211,6 +216,13 @@
     @Override
     public void showKeyguard() {
         super.showKeyguard();
+        updateNavBarForKeyguardContent();
+    }
+
+    /**
+     * Switch to the keyguard applicable content contained in the nav bars
+     */
+    private void updateNavBarForKeyguardContent() {
         getComponent(NotificationsUI.class).closeCarNotifications(0);
         if (mNavigationBarView != null) {
             mNavigationBarView.showKeyguardButtons();
@@ -606,4 +618,8 @@
         getComponent(NotificationsUI.class).toggleShowingCarNotifications();
     }
 
+    @Override
+    public void maybeEscalateHeadsUp() {
+        // Never send full screen intent in car.
+    }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
index 8c6b9b0..5921868 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarKeyguardViewManager.java
@@ -64,4 +64,12 @@
         CarStatusBar statusBar = (CarStatusBar) mStatusBar;
         statusBar.showUserSwitcher();
     }
+
+    /**
+     * Do nothing on this change.
+     * The base class hides the keyguard which for automotive we want to avoid b/c this would happen
+     * on a configuration change due to day/night (headlight state).
+     */
+    @Override
+    public void onDensityOrFontScaleChanged() {  }
 }
diff --git a/packages/CtsShim/build/shim/AndroidManifest.xml b/packages/CtsShim/build/shim/AndroidManifest.xml
index 9b813ace..3e546f1e 100644
--- a/packages/CtsShim/build/shim/AndroidManifest.xml
+++ b/packages/CtsShim/build/shim/AndroidManifest.xml
@@ -20,7 +20,7 @@
     package="com.android.cts.ctsshim" >
 
     <uses-sdk android:minSdkVersion="24"
-        android:targetSdkVersion="24" />
+        android:targetSdkVersion="28" />
 
     <restrict-update
         android:hash="__CAN_NOT_BE_UPDATED__" />
diff --git a/packages/CtsShim/build/shim_priv/AndroidManifest.xml b/packages/CtsShim/build/shim_priv/AndroidManifest.xml
index 9bf454c..9ab12c9 100644
--- a/packages/CtsShim/build/shim_priv/AndroidManifest.xml
+++ b/packages/CtsShim/build/shim_priv/AndroidManifest.xml
@@ -20,7 +20,7 @@
     package="com.android.cts.priv.ctsshim" >
 
     <uses-sdk android:minSdkVersion="24"
-        android:targetSdkVersion="24" />
+        android:targetSdkVersion="28" />
 
     <restrict-update
         android:hash="__HASH__" />
diff --git a/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml b/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml
index 023e93e..2354061 100644
--- a/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml
+++ b/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml
@@ -20,7 +20,7 @@
     package="com.android.cts.priv.ctsshim" >
 
     <uses-sdk android:minSdkVersion="24"
-        android:targetSdkVersion="24" />
+        android:targetSdkVersion="28" />
 
     <application
         android:hasCode="false"
diff --git a/packages/DynamicAndroidInstallationService/res/values/strings.xml b/packages/DynamicAndroidInstallationService/res/values/strings.xml
index 221e1d7..03c7c28 100644
--- a/packages/DynamicAndroidInstallationService/res/values/strings.xml
+++ b/packages/DynamicAndroidInstallationService/res/values/strings.xml
@@ -13,7 +13,7 @@
     <string name="keyguard_description">Please enter your password and continue to AndroidOnTap installation</string>
 
     <!-- Displayed on notification: DynAndroid installation is completed [CHAR LIMIT=128] -->
-    <string name="notification_install_completed">Installation is completed, you can reboot into the new installed system now.</string>
+    <string name="notification_install_completed">New system is ready, you can reboot into it or discard it.</string>
     <!-- Displayed on notification: DynAndroid installation is in progress [CHAR LIMIT=128] -->
     <string name="notification_install_inprogress">Installation is in progress.</string>
     <!-- Displayed on notification: DynAndroid installation is in progress [CHAR LIMIT=128] -->
@@ -30,4 +30,9 @@
     <!-- Action on notification: Reboot to AndroidOnTap [CHAR LIMIT=16] -->
     <string name="notification_action_reboot_to_dynandroid">Reboot</string>
 
+    <!-- Toast when installed DynamicAndroid is discarded [CHAR LIMIT=64] -->
+    <string name="toast_dynandroid_discarded">Installed AndroidOnTap is discarded.</string>
+    <!-- Toast when we fail to launch into DynamicAndroid [CHAR LIMIT=64] -->
+    <string name="toast_failed_to_reboot_to_dynandroid">Failed to reboot into AndroidOnTap.</string>
+
 </resources>
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
index 719417e..d942bab 100644
--- a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
+++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
@@ -54,6 +54,7 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.util.Log;
+import android.widget.Toast;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -73,6 +74,8 @@
      */
     private static final String ACTION_CANCEL_INSTALL =
             "com.android.dynandroid.ACTION_CANCEL_INSTALL";
+    private static final String ACTION_DISCARD_INSTALL =
+            "com.android.dynandroid.ACTION_DISCARD_INSTALL";
     private static final String ACTION_REBOOT_TO_DYN_ANDROID =
             "com.android.dynandroid.ACTION_REBOOT_TO_DYN_ANDROID";
     private static final String ACTION_REBOOT_TO_NORMAL =
@@ -118,10 +121,6 @@
     private long mInstalledSize;
     private boolean mJustCancelledByUser;
 
-    private PendingIntent mPiCancel;
-    private PendingIntent mPiRebootToDynamicAndroid;
-    private PendingIntent mPiUninstallAndReboot;
-
     private InstallationAsyncTask mInstallTask;
 
 
@@ -155,6 +154,8 @@
             executeInstallCommand(intent);
         } else if (ACTION_CANCEL_INSTALL.equals(action)) {
             executeCancelCommand();
+        } else if (ACTION_DISCARD_INSTALL.equals(action)) {
+            executeDiscardCommand();
         } else if (ACTION_REBOOT_TO_DYN_ANDROID.equals(action)) {
             executeRebootToDynAndroidCommand();
         } else if (ACTION_REBOOT_TO_NORMAL.equals(action)) {
@@ -210,7 +211,7 @@
         }
 
         if (mInstallTask != null) {
-            Log.e(TAG, "There is already an install task running");
+            Log.e(TAG, "There is already an installation task running");
             return;
         }
 
@@ -234,10 +235,8 @@
     }
 
     private void executeCancelCommand() {
-        if (mInstallTask == null || mInstallTask.getStatus() == PENDING) {
+        if (mInstallTask == null || mInstallTask.getStatus() != RUNNING) {
             Log.e(TAG, "Cancel command triggered, but there is no task running");
-            mNM.cancel(NOTIFICATION_ID);
-
             return;
         }
 
@@ -247,25 +246,47 @@
             // Will cleanup and post status in onCancelled()
             Log.d(TAG, "Cancel request filed successfully");
         } else {
-            Log.d(TAG, "Requested cancel, completed task will be discarded");
+            Log.e(TAG, "Trying to cancel installation while it's already completed.");
+        }
+    }
 
-            resetTaskAndStop();
-            postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED);
+    private void executeDiscardCommand() {
+        if (isInDynamicAndroid()) {
+            Log.e(TAG, "We are now running in AOT, please reboot to normal system first");
+            return;
         }
 
+        if (getStatus() != STATUS_READY) {
+            Log.e(TAG, "Trying to discard AOT while there is no complete installation");
+            return;
+        }
+
+        Toast.makeText(this,
+                getString(R.string.toast_dynandroid_discarded),
+                Toast.LENGTH_LONG).show();
+
+        resetTaskAndStop();
+        postStatus(STATUS_NOT_STARTED, CAUSE_INSTALL_CANCELLED);
+
+        mDynAndroid.remove();
     }
 
     private void executeRebootToDynAndroidCommand() {
         if (mInstallTask == null || mInstallTask.getStatus() != FINISHED) {
-            Log.e(TAG, "Trying to reboot to DynamicAndroid, but there is no complete installation");
+            Log.e(TAG, "Trying to reboot to AOT while there is no complete installation");
             return;
         }
 
         if (!mInstallTask.commit()) {
-            // TODO: b/123673280 better UI response
             Log.e(TAG, "Failed to commit installation because of native runtime error.");
             mNM.cancel(NOTIFICATION_ID);
 
+            Toast.makeText(this,
+                    getString(R.string.toast_failed_to_reboot_to_dynandroid),
+                    Toast.LENGTH_LONG).show();
+
+            mDynAndroid.remove();
+
             return;
         }
 
@@ -277,8 +298,13 @@
     }
 
     private void executeRebootToNormalCommand() {
-        mDynAndroid.remove();
+        if (!isInDynamicAndroid()) {
+            Log.e(TAG, "It's already running in normal system.");
+            return;
+        }
 
+        // Per current design, we don't have disable() API. AOT is disabled on next reboot.
+        // TODO: Use better status query when b/125079548 is done.
         PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
 
         if (powerManager != null) {
@@ -287,9 +313,14 @@
     }
 
     private void executeNotifyIfInUseCommand() {
-        if (isInDynamicAndroid()) {
+        int status = getStatus();
+
+        if (status == STATUS_IN_USE) {
             startForeground(NOTIFICATION_ID,
                     buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED));
+        } else if (status == STATUS_READY) {
+            startForeground(NOTIFICATION_ID,
+                    buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED));
         }
     }
 
@@ -312,18 +343,12 @@
         if (mNM != null) {
             mNM.createNotificationChannel(chan);
         }
+    }
 
-        Intent intentCancel = new Intent(this, DynamicAndroidInstallationService.class);
-        intentCancel.setAction(ACTION_CANCEL_INSTALL);
-        mPiCancel = PendingIntent.getService(this, 0, intentCancel, 0);
-
-        Intent intentRebootToDyn = new Intent(this, DynamicAndroidInstallationService.class);
-        intentRebootToDyn.setAction(ACTION_REBOOT_TO_DYN_ANDROID);
-        mPiRebootToDynamicAndroid = PendingIntent.getService(this, 0, intentRebootToDyn, 0);
-
-        Intent intentUninstallAndReboot = new Intent(this, DynamicAndroidInstallationService.class);
-        intentUninstallAndReboot.setAction(ACTION_REBOOT_TO_NORMAL);
-        mPiUninstallAndReboot = PendingIntent.getService(this, 0, intentUninstallAndReboot, 0);
+    private PendingIntent createPendingIntent(String action) {
+        Intent intent = new Intent(this, DynamicAndroidInstallationService.class);
+        intent.setAction(action);
+        return PendingIntent.getService(this, 0, intent, 0);
     }
 
     private Notification buildNotification(int status, int cause) {
@@ -342,7 +367,7 @@
 
                 builder.addAction(new Notification.Action.Builder(
                         null, getString(R.string.notification_action_cancel),
-                        mPiCancel).build());
+                        createPendingIntent(ACTION_CANCEL_INSTALL)).build());
 
                 break;
 
@@ -351,11 +376,11 @@
 
                 builder.addAction(new Notification.Action.Builder(
                         null, getString(R.string.notification_action_reboot_to_dynandroid),
-                        mPiRebootToDynamicAndroid).build());
+                        createPendingIntent(ACTION_REBOOT_TO_DYN_ANDROID)).build());
 
                 builder.addAction(new Notification.Action.Builder(
-                        null, getString(R.string.notification_action_cancel),
-                        mPiCancel).build());
+                        null, getString(R.string.notification_action_discard),
+                        createPendingIntent(ACTION_DISCARD_INSTALL)).build());
 
                 break;
 
@@ -364,7 +389,7 @@
 
                 builder.addAction(new Notification.Action.Builder(
                         null, getString(R.string.notification_action_uninstall),
-                        mPiUninstallAndReboot).build());
+                        createPendingIntent(ACTION_REBOOT_TO_NORMAL)).build());
 
                 break;
 
@@ -427,10 +452,10 @@
     private int getStatus() {
         if (isInDynamicAndroid()) {
             return STATUS_IN_USE;
-
+        } else if (isDynamicAndroidInstalled()) {
+            return STATUS_READY;
         } else if (mInstallTask == null) {
             return STATUS_NOT_STARTED;
-
         }
 
         switch (mInstallTask.getStatus()) {
@@ -458,6 +483,10 @@
         return mDynAndroid.isInUse();
     }
 
+    private boolean isDynamicAndroidInstalled() {
+        return mDynAndroid.isInstalled();
+    }
+
     void handleMessage(Message msg) {
         switch (msg.what) {
             case DynamicAndroidClient.MSG_REGISTER_LISTENER:
diff --git a/packages/ExtServices/Android.mk b/packages/ExtServices/Android.mk
index 1133499..a06dd86 100644
--- a/packages/ExtServices/Android.mk
+++ b/packages/ExtServices/Android.mk
@@ -25,10 +25,6 @@
 
 LOCAL_CERTIFICATE := platform
 
-LOCAL_AAPT_FLAGS := --shared-lib
-
-LOCAL_EXPORT_PACKAGE_RESOURCES := true
-
 LOCAL_PROGUARD_FLAG_FILES := proguard.proguard
 
 LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index e47d53c..76e2fe7 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -78,6 +78,10 @@
             </intent-filter>
         </service>
 
+        <activity android:name=".notification.CopyCodeActivity"
+                  android:exported="false"
+                  android:theme="@android:style/Theme.NoDisplay"/>
+
         <library android:name="android.ext.services"/>
     </application>
 
diff --git a/packages/ExtServices/res/values/strings.xml b/packages/ExtServices/res/values/strings.xml
index a9a5450..de35441 100644
--- a/packages/ExtServices/res/values/strings.xml
+++ b/packages/ExtServices/res/values/strings.xml
@@ -24,4 +24,10 @@
         <item>EDIT_DISTANCE</item>
         <item>EXACT_MATCH</item>
     </string-array>
+
+    <!-- Action chip to copy a one time code to the user's clipboard [CHAR LIMIT=NONE]-->
+    <string name="copy_code_desc">Copy \u201c<xliff:g id="code" example="12345">%1$s</xliff:g>\u201c</string>
+    <!-- Toast to display when text is copied to the device clipboard [CHAR LIMIT=64]-->
+    <string name="code_copied_to_clipboard">Code copied</string>
+
 </resources>
diff --git a/packages/ExtServices/src/android/ext/services/notification/CopyCodeActivity.java b/packages/ExtServices/src/android/ext/services/notification/CopyCodeActivity.java
new file mode 100644
index 0000000..6708d4d
--- /dev/null
+++ b/packages/ExtServices/src/android/ext/services/notification/CopyCodeActivity.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 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.ext.services.notification;
+
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Intent;
+import android.ext.services.R;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Toast;
+
+/**
+ * An activity that copies text in the Bundle.
+ */
+public class CopyCodeActivity extends Activity {
+    private static final String TAG = "CopyCodeActivity";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        handleIntent();
+        finish();
+    }
+
+    private void handleIntent() {
+        String code = getIntent().getStringExtra(Intent.EXTRA_TEXT);
+        if (TextUtils.isEmpty(code)) {
+            Log.w(TAG, "handleIntent: empty code");
+            return;
+        }
+        ClipboardManager clipboardManager = getSystemService(ClipboardManager.class);
+        ClipData clipData = ClipData.newPlainText(null, code);
+        clipboardManager.setPrimaryClip(clipData);
+        Toast.makeText(getApplicationContext(), R.string.code_copied_to_clipboard,
+                Toast.LENGTH_SHORT).show();
+    }
+}
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index 24fa87a..bf8a3fa 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -15,11 +15,15 @@
  */
 package android.ext.services.notification;
 
+import android.annotation.Nullable;
 import android.app.Notification;
+import android.app.PendingIntent;
 import android.app.Person;
 import android.app.RemoteAction;
 import android.app.RemoteInput;
 import android.content.Context;
+import android.content.Intent;
+import android.ext.services.R;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.os.Parcelable;
@@ -48,11 +52,12 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.stream.Collectors;
 
 public class SmartActionsHelper {
-    private static final String KEY_ACTION_TYPE = "action_type";
-    private static final String KEY_ACTION_SCORE = "action_score";
+    static final String ENTITIES_EXTRAS = "entities-extras";
+    static final String KEY_ACTION_TYPE = "action_type";
+    static final String KEY_ACTION_SCORE = "action_score";
+    static final String KEY_TEXT = "text";
     // If a notification has any of these flags set, it's inelgibile for actions being added.
     private static final int FLAG_MASK_INELGIBILE_FOR_ACTIONS =
             Notification.FLAG_ONGOING_EVENT
@@ -109,11 +114,25 @@
             repliesScore.put(textReply, conversationAction.getConfidenceScore());
         }
 
-        ArrayList<Notification.Action> actions = conversationActions.stream()
-                .filter(conversationAction -> conversationAction.getAction() != null)
-                .map(action -> createNotificationAction(
-                        action.getAction(), action.getType(), action.getConfidenceScore()))
-                .collect(Collectors.toCollection(ArrayList::new));
+        ArrayList<Notification.Action> actions = new ArrayList<>();
+        for (ConversationAction conversationAction : conversationActions) {
+            if (!TextUtils.isEmpty(conversationAction.getTextReply())) {
+                continue;
+            }
+            Notification.Action notificationAction;
+            if (conversationAction.getAction() == null) {
+                notificationAction =
+                        createNotificationActionWithoutRemoteAction(conversationAction);
+            } else {
+                notificationAction = createNotificationActionFromRemoteAction(
+                        conversationAction.getAction(),
+                        conversationAction.getType(),
+                        conversationAction.getConfidenceScore());
+            }
+            if (notificationAction != null) {
+                actions.add(notificationAction);
+            }
+        }
 
         // Start a new session for logging if necessary.
         if (!TextUtils.isEmpty(resultId)
@@ -127,6 +146,55 @@
     }
 
     /**
+     * Creates notification action from ConversationAction that does not come up a RemoteAction.
+     * It could happen because we don't have common intents for some actions, like copying text.
+     */
+    @Nullable
+    private Notification.Action createNotificationActionWithoutRemoteAction(
+            ConversationAction conversationAction) {
+        if (ConversationAction.TYPE_COPY.equals(conversationAction.getType())) {
+            return createCopyCodeAction(conversationAction);
+        }
+        return null;
+    }
+
+    @Nullable
+    private Notification.Action createCopyCodeAction(ConversationAction conversationAction) {
+        Bundle extras = conversationAction.getExtras();
+        if (extras == null) {
+            return null;
+        }
+        Bundle entitiesExtas = extras.getParcelable(ENTITIES_EXTRAS);
+        if (entitiesExtas == null) {
+            return null;
+        }
+        String code = entitiesExtas.getString(KEY_TEXT);
+        if (TextUtils.isEmpty(code)) {
+            return null;
+        }
+        String contentDescription = mContext.getString(R.string.copy_code_desc, code);
+        Intent intent = new Intent(mContext, CopyCodeActivity.class);
+        intent.putExtra(Intent.EXTRA_TEXT, code);
+
+        RemoteAction remoteAction = new RemoteAction(Icon.createWithResource(
+                mContext.getResources(),
+                com.android.internal.R.drawable.ic_menu_copy_material),
+                code,
+                contentDescription,
+                PendingIntent.getActivity(
+                        mContext,
+                        code.hashCode(),
+                        intent,
+                        PendingIntent.FLAG_UPDATE_CURRENT
+                ));
+
+        return createNotificationActionFromRemoteAction(
+                remoteAction,
+                ConversationAction.TYPE_COPY,
+                conversationAction.getConfidenceScore());
+    }
+
+    /**
      * Returns whether the suggestion might be used in the notifications in SysUI.
      * <p>
      * Currently, NAS has no idea if suggestions will actually be used in the notification, and thus
@@ -292,7 +360,7 @@
         mTextClassifier.onTextClassifierEvent(textClassifierEvent);
     }
 
-    private Notification.Action createNotificationAction(
+    private Notification.Action createNotificationActionFromRemoteAction(
             RemoteAction remoteAction, String actionType, float score) {
         Icon icon = remoteAction.shouldShowIcon()
                 ? remoteAction.getIcon()
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
index a1fbc7b..3a7d799 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
@@ -36,6 +36,7 @@
 import android.content.Intent;
 import android.content.pm.IPackageManager;
 import android.graphics.drawable.Icon;
+import android.os.Bundle;
 import android.os.Process;
 import android.service.notification.NotificationAssistantService;
 import android.service.notification.StatusBarNotification;
@@ -419,6 +420,31 @@
         assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_ACTIONS_SHOWN);
     }
 
+    @Test
+    public void testCopyAction() {
+        Bundle extras = new Bundle();
+        Bundle entitiesExtras = new Bundle();
+        entitiesExtras.putString(SmartActionsHelper.KEY_TEXT, "12345");
+        extras.putParcelable(SmartActionsHelper.ENTITIES_EXTRAS, entitiesExtras);
+        ConversationAction conversationAction =
+                new ConversationAction.Builder(ConversationAction.TYPE_COPY)
+                        .setExtras(extras)
+                        .build();
+        when(mTextClassifier.suggestConversationActions(any(ConversationActions.Request.class)))
+                .thenReturn(
+                        new ConversationActions(
+                                Collections.singletonList(conversationAction), null));
+
+        Notification notification = createMessageNotification();
+        when(mStatusBarNotification.getNotification()).thenReturn(notification);
+        SmartActionsHelper.SmartSuggestions suggestions =
+                mSmartActionsHelper.suggest(createNotificationEntry());
+
+        assertThat(suggestions.actions).hasSize(1);
+        Notification.Action action = suggestions.actions.get(0);
+        assertThat(action.title).isEqualTo("12345");
+    }
+
     private ZonedDateTime createZonedDateTimeFromMsUtc(long msUtc) {
         return ZonedDateTime.ofInstant(Instant.ofEpochMilli(msUtc), ZoneOffset.systemDefault());
     }
diff --git a/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java b/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java
index d1ca109..e23f10f 100644
--- a/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java
+++ b/packages/NetworkStack/src/android/net/metrics/DataStallStatsUtils.java
@@ -48,6 +48,8 @@
             return DataStallEventProto.VALID;
         } else if (result.isPortal()) {
             return DataStallEventProto.PORTAL;
+        } else if (result.isPartialConnectivity()) {
+            return DataStallEventProto.PARTIAL;
         } else {
             return DataStallEventProto.INVALID;
         }
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index fc56da7..bcfc412 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -1617,7 +1617,7 @@
             // See if the data sub is registered for PS services on cell.
             final NetworkRegistrationState nrs = dataSs.getNetworkRegistrationState(
                     NetworkRegistrationState.DOMAIN_PS,
-                    AccessNetworkConstants.TransportType.WWAN);
+                    AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
             latencyBroadcast.putExtra(
                     NetworkMonitorUtils.EXTRA_CELL_ID,
                     nrs == null ? null : nrs.getCellIdentity());
diff --git a/packages/SettingsLib/ActionBarShadow/AndroidManifest.xml b/packages/SettingsLib/ActionBarShadow/AndroidManifest.xml
index 4b9f1ab..98c4cb4 100644
--- a/packages/SettingsLib/ActionBarShadow/AndroidManifest.xml
+++ b/packages/SettingsLib/ActionBarShadow/AndroidManifest.xml
@@ -18,6 +18,4 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.settingslib.widget">
 
-    <uses-sdk android:minSdkVersion="21" />
-
 </manifest>
diff --git a/packages/SettingsLib/AndroidManifest.xml b/packages/SettingsLib/AndroidManifest.xml
index 3873593..a347345 100644
--- a/packages/SettingsLib/AndroidManifest.xml
+++ b/packages/SettingsLib/AndroidManifest.xml
@@ -18,7 +18,4 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.settingslib">
 
-    <uses-sdk
-        android:minSdkVersion="21" />
-
 </manifest>
diff --git a/packages/SettingsLib/AppPreference/AndroidManifest.xml b/packages/SettingsLib/AppPreference/AndroidManifest.xml
index 7e71308..4b9f1ab 100644
--- a/packages/SettingsLib/AppPreference/AndroidManifest.xml
+++ b/packages/SettingsLib/AppPreference/AndroidManifest.xml
@@ -16,7 +16,7 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.settingslib.widget.apppreference">
+          package="com.android.settingslib.widget">
 
     <uses-sdk android:minSdkVersion="21" />
 
diff --git a/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/apppreference/AppPreference.java b/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/apppreference/AppPreference.java
index 593b6f5..ab51a34 100644
--- a/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/apppreference/AppPreference.java
+++ b/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/apppreference/AppPreference.java
@@ -25,6 +25,8 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceViewHolder;
 
+import com.android.settingslib.widget.R;
+
 public class AppPreference extends Preference {
 
     private int mProgress;
diff --git a/packages/SettingsLib/HelpUtils/AndroidManifest.xml b/packages/SettingsLib/HelpUtils/AndroidManifest.xml
index 35b3933..5240ce4 100644
--- a/packages/SettingsLib/HelpUtils/AndroidManifest.xml
+++ b/packages/SettingsLib/HelpUtils/AndroidManifest.xml
@@ -18,6 +18,4 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.settingslib.helputils">
 
-    <uses-sdk android:minSdkVersion="21" />
-
 </manifest>
diff --git a/packages/SettingsLib/RestrictedLockUtils/AndroidManifest.xml b/packages/SettingsLib/RestrictedLockUtils/AndroidManifest.xml
index d7b323a..d19a022 100644
--- a/packages/SettingsLib/RestrictedLockUtils/AndroidManifest.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/AndroidManifest.xml
@@ -18,6 +18,4 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.settingslib.restrictedlockutils">
 
-    <uses-sdk android:minSdkVersion="21" />
-
 </manifest>
\ No newline at end of file
diff --git a/packages/SettingsLib/SearchWidget/AndroidManifest.xml b/packages/SettingsLib/SearchWidget/AndroidManifest.xml
index b86544e..5798801 100644
--- a/packages/SettingsLib/SearchWidget/AndroidManifest.xml
+++ b/packages/SettingsLib/SearchWidget/AndroidManifest.xml
@@ -18,6 +18,4 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.settingslib.search">
 
-    <uses-sdk android:minSdkVersion="21" />
-
 </manifest>
diff --git a/packages/SettingsLib/SettingsSpinner/AndroidManifest.xml b/packages/SettingsLib/SettingsSpinner/AndroidManifest.xml
index 5db9335..4b9f1ab 100644
--- a/packages/SettingsLib/SettingsSpinner/AndroidManifest.xml
+++ b/packages/SettingsLib/SettingsSpinner/AndroidManifest.xml
@@ -16,7 +16,7 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.settingslib.widget.settingsspinner">
+          package="com.android.settingslib.widget">
 
     <uses-sdk android:minSdkVersion="21" />
 
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
index 130cef2..5ef8f7a 100644
--- a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java
+++ b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinner.java
@@ -20,6 +20,8 @@
 import android.util.AttributeSet;
 import android.widget.Spinner;
 
+import com.android.settingslib.widget.R;
+
 /**
  * A {@link Spinner} with settings style.
  *
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
index 8bf8fce..f9aedd9 100644
--- a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java
+++ b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java
@@ -17,10 +17,10 @@
 package com.android.settingslib.widget.settingsspinner;
 
 import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
 
+import com.android.settingslib.widget.R;
+
 /**
  * An ArrayAdapter which was used by {@link SettingsSpinner} with settings style.
  */
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index c8c05a0..b34f445 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -103,7 +103,7 @@
             setBatterySaverConfirmationAcknowledged(context);
         }
 
-        if (context.getSystemService(PowerManager.class).setPowerSaveMode(enable)) {
+        if (context.getSystemService(PowerManager.class).setPowerSaveModeEnabled(enable)) {
             if (enable) {
                 final int count =
                         Secure.getInt(cr, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, 0) + 1;
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
index 09107ce..ea39317 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
@@ -18,11 +18,11 @@
 
 import android.app.AppOpsManager;
 import android.content.Context;
+import android.content.PermissionChecker;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.drawable.Drawable;
-import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.text.format.DateUtils;
@@ -82,6 +82,7 @@
      */
     public List<Access> getAppList() {
         // Retrieve a location usage list from AppOps
+        PackageManager pm = mContext.getPackageManager();
         AppOpsManager aoManager =
                 (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         List<AppOpsManager.PackageOps> appOps = aoManager.getPackagesForOps(LOCATION_OPS);
@@ -96,19 +97,40 @@
 
         for (int i = 0; i < appOpsCount; ++i) {
             AppOpsManager.PackageOps ops = appOps.get(i);
-            // Don't show the Android System in the list - it's not actionable for the user.
-            // Also don't show apps belonging to background users except managed users.
             String packageName = ops.getPackageName();
             int uid = ops.getUid();
-            int userId = UserHandle.getUserId(uid);
-            boolean isAndroidOs =
-                    (uid == Process.SYSTEM_UID) && ANDROID_SYSTEM_PACKAGE_NAME.equals(packageName);
-            if (isAndroidOs || !profiles.contains(new UserHandle(userId))) {
+            UserHandle user = UserHandle.getUserHandleForUid(uid);
+
+            // Don't show apps belonging to background users except managed users.
+            if (!profiles.contains(user)) {
                 continue;
             }
-            Access access = getAccessFromOps(now, ops);
-            if (access != null) {
-                accesses.add(access);
+
+            // Don't show apps that do not have user sensitive location permissions
+            boolean showApp = true;
+            for (int op : LOCATION_OPS) {
+                final String permission = AppOpsManager.opToPermission(op);
+                final int permissionFlags = pm.getPermissionFlags(permission, packageName, user);
+                if (PermissionChecker.checkPermission(mContext, permission, -1, uid, packageName)
+                        == PermissionChecker.PERMISSION_GRANTED) {
+                    if ((permissionFlags
+                            & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) == 0) {
+                        showApp = false;
+                        break;
+                    }
+                } else {
+                    if ((permissionFlags
+                            & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED) == 0) {
+                        showApp = false;
+                        break;
+                    }
+                }
+            }
+            if (showApp) {
+                Access access = getAccessFromOps(now, ops);
+                if (access != null) {
+                    accesses.add(access);
+                }
             }
         }
         return accesses;
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
index 4ed1154..f6cd971 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
@@ -95,7 +95,7 @@
         mMgr.addOnActiveSessionsChangedListener(mSessionsListener, null, mHandler);
         mInit = true;
         postUpdateSessions();
-        mMgr.setRemoteVolumeController(mRvc);
+        mMgr.registerRemoteVolumeController(mRvc);
     }
 
     protected void postUpdateSessions() {
@@ -110,6 +110,7 @@
         if (D.BUG) Log.d(TAG, "destroy");
         mInit = false;
         mMgr.removeOnActiveSessionsChangedListener(mSessionsListener);
+        mMgr.unregisterRemoteVolumeController(mRvc);
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 59fbb72..800c401 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -307,6 +307,7 @@
     public AccessPoint(Context context, WifiConfiguration config) {
         mContext = context;
         loadConfig(config);
+        updateKey();
     }
 
     /**
@@ -317,6 +318,7 @@
         mContext = context;
         mFqdn = config.getHomeSp().getFqdn();
         mProviderFriendlyName = config.getHomeSp().getFriendlyName();
+        updateKey();
     }
 
     /**
@@ -355,7 +357,6 @@
         security = getSecurity(config);
         networkId = config.networkId;
         mConfig = config;
-        updateKey();
     }
 
     /** Updates {@link #mKey} and should only called upon object creation/initialization. */
@@ -363,6 +364,8 @@
         // TODO(sghuman): Consolidate Key logic on ScanResultMatchInfo
         if (isPasspoint()) {
             mKey = getKey(mConfig);
+        } else if (isPasspointConfig()) {
+            mKey = getKey(mFqdn);
         } else if (isOsuProvider()) {
             mKey = getKey(mOsuProvider);
         } else { // Non-Passpoint AP
@@ -618,15 +621,22 @@
      */
     public static String getKey(WifiConfiguration config) {
         if (config.isPasspoint()) {
-            return new StringBuilder()
-                    .append(KEY_PREFIX_FQDN)
-                    .append(config.FQDN).toString();
+            return getKey(config.FQDN);
         } else {
             return getKey(removeDoubleQuotes(config.SSID), config.BSSID, getSecurity(config));
         }
     }
 
     /**
+     * Returns the AccessPoint key corresponding to a Passpoint network by its FQDN.
+     */
+    public static String getKey(String fqdn) {
+        return new StringBuilder()
+                .append(KEY_PREFIX_FQDN)
+                .append(fqdn).toString();
+    }
+
+    /**
      * Returns the AccessPoint key corresponding to the OsuProvider.
      */
     public static String getKey(OsuProvider provider) {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 7c367c7..9c8e3f4 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -1250,6 +1250,14 @@
         AccessPoint passpointAp = new AccessPoint(mContext, spyConfig, mScanResults, null);
         assertThat(passpointAp.getKey()).isEqualTo(AccessPoint.getKey(spyConfig));
 
+        PasspointConfiguration passpointConfig = new PasspointConfiguration();
+        HomeSp homeSp = new HomeSp();
+        homeSp.setFqdn("fqdn");
+        homeSp.setFriendlyName("Test Provider");
+        passpointConfig.setHomeSp(homeSp);
+        AccessPoint passpointConfigAp = new AccessPoint(mContext, passpointConfig);
+        assertThat(passpointConfigAp.getKey()).isEqualTo(AccessPoint.getKey("fqdn"));
+
         OsuProvider provider = createOsuProvider();
         AccessPoint osuAp = new AccessPoint(mContext, provider, mScanResults);
         assertThat(osuAp.getKey()).isEqualTo(AccessPoint.getKey(provider));
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java
index 2988905..2bb3c2a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java
@@ -60,7 +60,7 @@
 
         when(mMockContext.getContentResolver()).thenReturn(mMockResolver);
         when(mMockContext.getSystemService(eq(PowerManager.class))).thenReturn(mMockPowerManager);
-        when(mMockPowerManager.setPowerSaveMode(anyBoolean())).thenReturn(true);
+        when(mMockPowerManager.setPowerSaveModeEnabled(anyBoolean())).thenReturn(true);
     }
 
     @Test
@@ -71,7 +71,7 @@
         assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isFalse();
 
         verify(mMockContext, times(1)).sendBroadcast(any(Intent.class));
-        verify(mMockPowerManager, times(0)).setPowerSaveMode(anyBoolean());
+        verify(mMockPowerManager, times(0)).setPowerSaveModeEnabled(anyBoolean());
 
         // They shouldn't have changed.
         assertEquals(-1,
@@ -88,7 +88,7 @@
         assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isTrue();
 
         verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
-        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(true));
+        verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(true));
 
         assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
         assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
@@ -102,7 +102,7 @@
         assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, true)).isTrue();
 
         verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
-        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(true));
+        verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(true));
 
         assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
         assertEquals(2, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
@@ -116,7 +116,7 @@
         assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, true, false)).isTrue();
 
         verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
-        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(true));
+        verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(true));
 
         assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
         assertEquals(1, Secure.getInt(mMockResolver, Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT, -2));
@@ -131,7 +131,7 @@
         assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, false, false)).isTrue();
 
         verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
-        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(false));
+        verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(false));
 
         assertEquals(-1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
         assertEquals(-2,
@@ -147,7 +147,7 @@
         assertThat(BatterySaverUtils.setPowerSaveMode(mMockContext, false, true)).isTrue();
 
         verify(mMockContext, times(0)).sendBroadcast(any(Intent.class));
-        verify(mMockPowerManager, times(1)).setPowerSaveMode(eq(false));
+        verify(mMockPowerManager, times(1)).setPowerSaveModeEnabled(eq(false));
 
         assertEquals(-1, Secure.getInt(mMockResolver, Secure.LOW_POWER_WARNING_ACKNOWLEDGED, -1));
         assertEquals(-2,
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java
index da97cc8..042616a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java
@@ -23,6 +23,8 @@
 
 import androidx.preference.PreferenceViewHolder;
 
+import com.android.settingslib.widget.R;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 274acad..36bb8ef 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -16,10 +16,6 @@
 
 package com.android.providers.settings;
 
-import android.os.Process;
-import com.android.internal.app.LocalePicker;
-import com.android.internal.annotations.VisibleForTesting;
-
 import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.IActivityManager;
@@ -30,7 +26,6 @@
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.icu.util.ULocale;
-import android.location.LocationManager;
 import android.media.AudioManager;
 import android.media.RingtoneManager;
 import android.net.Uri;
@@ -38,13 +33,14 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.ArraySet;
 
-import java.lang.IllegalArgumentException;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.LocalePicker;
+
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Locale;
@@ -145,9 +141,6 @@
             if (Settings.System.SOUND_EFFECTS_ENABLED.equals(name)) {
                 setSoundEffects(Integer.parseInt(value) == 1);
                 // fall through to the ordinary write to settings
-            } else if (Settings.Secure.LOCATION_PROVIDERS_ALLOWED.equals(name)) {
-                setGpsLocation(value);
-                return;
             } else if (Settings.Secure.BACKUP_AUTO_RESTORE.equals(name)) {
                 setAutoRestore(Integer.parseInt(value) == 1);
             } else if (isAlreadyConfiguredCriticalAccessibilitySetting(name)) {
@@ -297,21 +290,6 @@
         } catch (RemoteException e) {}
     }
 
-    private void setGpsLocation(String value) {
-        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        if (um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION)) {
-            return;
-        }
-        final String GPS = LocationManager.GPS_PROVIDER;
-        boolean enabled =
-            GPS.equals(value) ||
-                value.startsWith(GPS + ",") ||
-                value.endsWith("," + GPS) ||
-                value.contains("," + GPS + ",");
-        LocationManager lm = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
-        lm.setProviderEnabledForUser(GPS, enabled, Process.myUserHandle());
-    }
-
     private void setSoundEffects(boolean enable) {
         if (enable) {
             mAudioManager.loadSoundEffects();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 2c2987c..ff25ad9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1103,9 +1103,7 @@
 
     private boolean mutateConfigSetting(String name, String value, String prefix,
             boolean makeDefault, int operation, int mode) {
-
-        // TODO(b/117663715): Ensure the caller can access the setting.
-        // enforceReadPermission(WRITE_DEVICE_CONFIG);
+        enforceWritePermission(Manifest.permission.WRITE_DEVICE_CONFIG);
 
         // Perform the mutation.
         synchronized (mLock) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index fc6ef2b..d639e5e 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -175,6 +175,9 @@
 
     <uses-permission android:name="android.permission.MANAGE_APPOPS" />
 
+    <!-- Permission needed to run network tests in CTS -->
+    <uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" />
+
     <application android:label="@string/app_label"
                  android:defaultToDeviceProtectedStorage="true"
                  android:directBootAware="true">
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 9425941..c2495b5 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -58,7 +58,6 @@
         "androidx.arch.core_core-runtime",
         "androidx.lifecycle_lifecycle-extensions",
         "androidx.dynamicanimation_dynamicanimation",
-        "iconloader_base",
         "SystemUI-tags",
         "SystemUI-proto",
         "dagger2-2.19",
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java
index 7c72688..6be7707 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActionsPanelPlugin.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.plugins;
 
+import android.app.PendingIntent;
 import android.view.View;
 
 import com.android.systemui.plugins.annotations.DependsOn;
@@ -62,6 +63,15 @@
 
         /** Dismisses the Global Actions menu. */
         void dismissGlobalActionsMenu();
+
+        /** Starts a PendingIntent, dismissing the keyguard if necessary. */
+        default void startPendingIntentDismissingKeyguard(PendingIntent pendingIntent) {
+            try {
+                pendingIntent.send();
+            } catch (PendingIntent.CanceledException e) {
+                // no-op
+            }
+        }
     }
 
     /**
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
index 5f4cf03..2b10ccb 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
@@ -58,6 +58,10 @@
     void userActivity();
     void getState();
 
+    boolean areCaptionsEnabled();
+    void setCaptionsEnabled(boolean isEnabled);
+    void getCaptionsComponentState();
+
     @ProvidesInterface(version = StreamState.VERSION)
     public static final class StreamState {
         public static final int VERSION = 1;
@@ -186,5 +190,6 @@
         void onScreenOff();
         void onShowSafetyWarning(int flags);
         void onAccessibilityModeChanged(Boolean showA11yStream);
+        void onCaptionComponentStateChanged(Boolean isComponentEnabled);
     }
 }
diff --git a/packages/SystemUI/res/drawable/global_action_panel_scrim.xml b/packages/SystemUI/res/drawable/global_action_panel_scrim.xml
index 177b8d2..8b8258f 100644
--- a/packages/SystemUI/res/drawable/global_action_panel_scrim.xml
+++ b/packages/SystemUI/res/drawable/global_action_panel_scrim.xml
@@ -19,8 +19,8 @@
        android:shape="rectangle">
     <gradient
         android:centerY="0.45"
-        android:startColor="#be3c4043"
-        android:centerColor="#be3c4043"
+        android:startColor="#dc3c4043"
+        android:centerColor="#dc3c4043"
         android:endColor="#4d3c4043"
         android:angle="270" />
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml b/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml
new file mode 100644
index 0000000..9b90729
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml
@@ -0,0 +1,24 @@
+<!--
+     Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M20,4C21.1,4 22,4.9 22,6L22,18C22,19.1 21.1,20 20,20L4,20C2.9,20 2,19.1 2,18L2,6C2,4.9 2.9,4 4,4L20,4ZM20,18L20,6L4,6L4,18L20,18ZM6,10L8,10L8,12L6,12L6,10ZM6,14L14,14L14,16L6,16L6,14ZM16,14L18,14L18,16L16,16L16,14ZM10,10L18,10L18,12L10,12L10,10Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml b/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml
new file mode 100644
index 0000000..f3d8d3b9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml
@@ -0,0 +1,24 @@
+<!--
+     Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:fillColor="#FF000000"
+      android:pathData="M16.9675,14L18,14L18,15.0275L16.9675,14ZM20,17.0176L20,6L8.9281,6L6.9182,4L20,4C21.1,4 22,4.9 22,6L22,18C22,18.2949 21.9353,18.5755 21.8194,18.8281L20,17.0176ZM12.9478,10L18,10L18,12L14.9576,12L12.9478,10ZM1.2823,0.8824L22.8489,22.4489L21.6337,23.6641L17.9696,20L4,20C2.9,20 2,19.1 2,18L2,6C2,5.4577 2.2188,4.964 2.5724,4.6028L0.0672,2.0975L1.2823,0.8824ZM13.9696,16L6,16L6,14L11.9696,14L8,10.0304L8,12L6,12L6,10L7.9696,10L4,6.0304L4,18L15.9696,18L13.9696,16Z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid.xml b/packages/SystemUI/res/layout-land/global_actions_grid.xml
index 235d0fc..c51e71b 100644
--- a/packages/SystemUI/res/layout-land/global_actions_grid.xml
+++ b/packages/SystemUI/res/layout-land/global_actions_grid.xml
@@ -7,7 +7,8 @@
     android:orientation="horizontal"
     android:clipToPadding="false"
     android:theme="@style/qs_theme"
-    android:gravity="top|right"
+    android:paddingLeft="@dimen/global_actions_top_padding"
+    android:gravity="top|left"
     android:clipChildren="false"
 >
     <LinearLayout
diff --git a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
index e028214..de853c7 100644
--- a/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
+++ b/packages/SystemUI/res/layout-land/global_actions_grid_seascape.xml
@@ -7,7 +7,8 @@
     android:orientation="horizontal"
     android:clipToPadding="false"
     android:theme="@style/qs_theme"
-    android:gravity="top|left"
+    android:gravity="top|right"
+    android:paddingRight="@dimen/global_actions_top_padding"
     android:clipChildren="false"
 >
     <LinearLayout
diff --git a/packages/SystemUI/res/layout/global_actions_grid.xml b/packages/SystemUI/res/layout/global_actions_grid.xml
index a620a8e..d90d5e9 100644
--- a/packages/SystemUI/res/layout/global_actions_grid.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid.xml
@@ -6,8 +6,9 @@
     android:layout_height="match_parent"
     android:orientation="horizontal"
     android:clipToPadding="false"
+    android:paddingTop="@dimen/global_actions_top_padding"
     android:theme="@style/qs_theme"
-    android:gravity="bottom|center"
+    android:gravity="top|center"
     android:clipChildren="false"
 >
     <LinearLayout
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 725ace4..0d44931 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -255,6 +255,7 @@
                             android:layout_width="40dp"
                             android:layout_height="40dp"
                             android:clickable="false"
+                            android:contentDescription="@string/inline_block_button"
                             android:tint="@color/GM2_grey_400"
                             style="@style/TextAppearance.NotificationInfo.Button"/>
                     </FrameLayout>
@@ -289,6 +290,7 @@
                             android:layout_width="40dp"
                             android:layout_height="40dp"
                             android:clickable="false"
+                            android:contentDescription="@string/inline_silent_button_silent"
                             android:tint="@color/GM2_grey_400"
                             style="@style/TextAppearance.NotificationInfo.Button"/>
                     </FrameLayout>
@@ -322,6 +324,7 @@
                             android:layout_gravity="center"
                             android:layout_width="40dp"
                             android:layout_height="40dp"
+                            android:contentDescription="@string/inline_silent_button_alert"
                             android:clickable="false"
                             android:tint="@color/GM2_grey_400"
                             style="@style/TextAppearance.NotificationInfo.Button"/>
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index f64a64e6..b16e062 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -28,7 +28,7 @@
     android:orientation="horizontal"
     android:focusable="true">
 
-        <LinearLayout
+        <FrameLayout
             android:id="@+id/background"
             android:layout_height="@dimen/ongoing_appops_chip_height"
             android:layout_width="wrap_content"
@@ -37,25 +37,8 @@
                     android:id="@+id/icons_container"
                     android:layout_height="match_parent"
                     android:layout_width="wrap_content"
-                    android:layout_marginStart="@dimen/ongoing_appops_chip_items_margin"
-                    android:layout_gravity="center_vertical"
+                    android:layout_gravity="center"
                     android:gravity="center_vertical"
                     />
-
-                <TextView
-                    android:id="@+id/text_container"
-                    android:layout_height="match_parent"
-                    android:layout_width="wrap_content"
-                    android:layout_gravity="center_vertical|end"
-                    android:paddingStart="@dimen/ongoing_appops_chip_text_padding"
-                    android:paddingEnd="@dimen/ongoing_appops_chip_text_padding"
-                    android:gravity="center_vertical"
-                    android:singleLine="true"
-                    android:ellipsize="end"
-                    android:lines="1"
-                    android:textAppearance="@style/TextAppearance.StatusBar.Clock"
-                    android:textSize="@dimen/ongoing_appops_chip_text_size"
-                    android:textColor="@color/status_bar_clock_color"
-                />
-          </LinearLayout>
+          </FrameLayout>
 </com.android.systemui.privacy.OngoingPrivacyChip>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
index 056f16a..174a3b8 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml
@@ -33,6 +33,7 @@
             android:layout_height="wrap_content"
             android:layout_gravity="start"
             android:focusable="true"
+            android:contentDescription="@string/accessibility_manage_notification"
             android:text="@string/manage_notifications_text"
             android:textColor="?attr/wallpaperTextColor"
             android:textAllCaps="false"/>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index ca34c23..130be89 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -98,5 +98,27 @@
             </FrameLayout>
         </LinearLayout>
 
+        <FrameLayout
+            android:id="@+id/odi_captions"
+            android:layout_width="@dimen/volume_dialog_caption_size"
+            android:layout_height="@dimen/volume_dialog_caption_size"
+            android:layout_marginTop="@dimen/volume_dialog_spacer"
+            android:translationZ="@dimen/volume_dialog_elevation"
+            android:layout_gravity="right"
+            android:clipToPadding="false"
+            android:visibility="gone"
+            android:background="@drawable/rounded_bg_full">
+            <com.android.keyguard.AlphaOptimizedImageButton
+                android:id="@+id/odi_captions_icon"
+                android:src="@drawable/ic_volume_odi_captions_disabled"
+                style="@style/VolumeButtons"
+                android:background="@drawable/rounded_ripple"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:tint="@color/accent_tint_color_selector"
+                android:layout_gravity="center"
+                android:soundEffectsEnabled="false" />
+        </FrameLayout>
+
     </LinearLayout>
 </FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 8b4f66d..f8295eb 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -330,7 +330,7 @@
     <!-- Nav bar button default ordering/layout -->
     <string name="config_navBarLayout" translatable="false">left[.5W],back[1WC];home;recent[1WC],right[.5W]</string>
     <string name="config_navBarLayoutQuickstep" translatable="false">back[1.7WC];home;contextual[1.7WC]</string>
-    <string name="config_navBarLayoutHandle" translatable="false">";home_handle;assistant_handle[.18WC]"</string>
+    <string name="config_navBarLayoutHandle" translatable="false">";home_handle;"</string>
 
     <bool name="quick_settings_show_full_alarm">false</bool>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c83cb59..30cbaaa 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -34,11 +34,10 @@
     <dimen name="navigation_bar_deadzone_size_max">32dp</dimen>
 
     <!-- dimensions for the navigation bar handle -->
-    <dimen name="navigation_handle_radius">2dp</dimen>
-    <dimen name="navigation_handle_bottom">8dp</dimen>
+    <dimen name="navigation_handle_radius">1dp</dimen>
+    <dimen name="navigation_handle_bottom">6dp</dimen>
     <dimen name="navigation_handle_horizontal_margin">30dp</dimen>
-    <dimen name="navigation_home_handle_width">180dp</dimen>
-    <dimen name="navigation_assistant_handle_width">36dp</dimen>
+    <dimen name="navigation_home_handle_width">280dp</dimen>
 
     <!-- Height of notification icons in the status bar -->
     <dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
@@ -336,6 +335,8 @@
 
     <dimen name="volume_dialog_ringer_size">64dp</dimen>
 
+    <dimen name="volume_dialog_caption_size">64dp</dimen>
+
     <dimen name="volume_dialog_tap_target_size">48dp</dimen>
 
     <dimen name="volume_dialog_spacer">4dp</dimen>
@@ -865,10 +866,12 @@
 
     <!-- Global actions power menu -->
     <dimen name="global_actions_panel_width">120dp</dimen>
-    <dimen name="global_actions_top_padding">120dp</dimen>
     <dimen name="global_actions_padding">12dp</dimen>
     <dimen name="global_actions_translate">9dp</dimen>
 
+    <!-- Distance from the top of screen in pixels, to position the power menu near the button. -->
+    <dimen name="global_actions_top_padding">330px</dimen>
+
     <!-- Global actions grid layout -->
     <dimen name="global_actions_grid_side_margin">4dp</dimen>
 
@@ -999,10 +1002,8 @@
     <dimen name="ongoing_appops_chip_margin">0dp</dimen>
     <!-- Height of the Ongoing App Ops chip -->
     <dimen name="ongoing_appops_chip_height">32dp</dimen>
-    <!-- Start and End padding for Ongoing App Ops chip -->
-    <dimen name="ongoing_appops_chip_text_padding">8dp</dimen>
     <!-- Padding between background of Ongoing App Ops chip and content -->
-    <dimen name="ongoing_appops_chip_bg_padding">0dp</dimen>
+    <dimen name="ongoing_appops_chip_bg_padding">8dp</dimen>
     <!-- Side padding between background of Ongoing App Ops chip and content -->
     <dimen name="ongoing_appops_chip_side_padding">8dp</dimen>
     <!-- Margin between icons of Ongoing App Ops chip when QQS-->
@@ -1013,10 +1014,7 @@
     <dimen name="ongoing_appops_chip_icon_size">@*android:dimen/status_bar_icon_size</dimen>
     <!-- Radius of Ongoing App Ops chip corners -->
     <dimen name="ongoing_appops_chip_bg_corner_radius">16dp</dimen>
-    <!-- Size of text of Ongoing App Ops chip -->
-    <dimen name="ongoing_appops_chip_text_size">12sp</dimen>
-    <!-- Margin between items in Ongoing App Ops chip -->
-    <dimen name="ongoing_appops_chip_items_margin">8dp</dimen>
+
 
     <!-- How much a bubble is elevated -->
     <dimen name="bubble_elevation">8dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 16222f7..da43391 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -266,6 +266,8 @@
     <string name="accessibility_scanning_face">Scanning face</string>
     <!-- Click action label for accessibility for the smart reply buttons (not shown on-screen).". [CHAR LIMIT=NONE] -->
     <string name="accessibility_send_smart_reply">Send</string>
+    <!-- Content description of the manage notification button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_manage_notification">Manage notifications</string>
     <!-- Click action label for accessibility for the unlock button. [CHAR LIMIT=NONE] -->
     <string name="unlock_label">unlock</string>
     <!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] -->
@@ -2318,26 +2320,12 @@
          app for debugging. Will not be seen by users. [CHAR LIMIT=20] -->
     <string name="heap_dump_tile_name">Dump SysUI Heap</string>
 
-    <!-- Text on chip for multiple apps using a single app op [CHAR LIMIT=12] -->
-    <plurals name="ongoing_privacy_chip_multiple_apps">
-        <item quantity="one"><xliff:g id="num_apps" example="1">%d</xliff:g> app</item>
-        <item quantity="few"><xliff:g id="num_apps" example="3">%d</xliff:g> apps</item>
-        <item quantity="other"><xliff:g id="num_apps" example="3">%d</xliff:g> apps</item>
-    </plurals>
-
     <!-- Content description for ongoing privacy chip. Use with a single app [CHAR LIMIT=NONE]-->
     <string name="ongoing_privacy_chip_content_single_app"><xliff:g id="app" example="Example App">%1$s</xliff:g> is using your <xliff:g id="types_list" example="camera, location">%2$s</xliff:g>.</string>
 
     <!-- Content description for ongoing privacy chip. Use with multiple apps [CHAR LIMIT=NONE]-->
     <string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string>
 
-    <!-- Content description for ongoing privacy chip. Use with multiple apps using same app op[CHAR LIMIT=NONE]-->
-    <plurals name="ongoing_privacy_chip_content_multiple_apps_single_op">
-        <item quantity="one"><xliff:g id="num_apps" example="1">%1$d</xliff:g> application is using your <xliff:g id="type" example="camera">%2$s</xliff:g>.</item>
-        <item quantity="few"><xliff:g id="num_apps" example="3">%1$d</xliff:g> applications are using your <xliff:g id="type" example="camera">%2$s</xliff:g>.</item>
-        <item quantity="other"><xliff:g id="num_apps" example="3">%1$d</xliff:g> applications are using your <xliff:g id="type" example="camera">%2$s</xliff:g>.</item>
-    </plurals>
-
     <!-- Action for accepting the Ongoing privacy dialog [CHAR LIMIT=10]-->
     <string name="ongoing_privacy_dialog_ok">Got it</string>
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
index ea6fb48..7b39ba3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
@@ -78,4 +78,12 @@
                     }
                 });
     }
+
+    /**
+     * Sets the flag to freeze the recents task list reordering as a part of launching the activity.
+     */
+    public static ActivityOptions setFreezeRecentTasksList(ActivityOptions opts) {
+        opts.setFreezeRecentTasksReordering();
+        return opts;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 97160b6..63f8cd6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -105,11 +105,6 @@
  * Watches for updates that may be interesting to the keyguard, and provides
  * the up to date information as well as a registration for callbacks that care
  * to be updated.
- *
- * Note: under time crunch, this has been extended to include some stuff that
- * doesn't really belong here.  see {@link #handleBatteryUpdate} where it shutdowns
- * the device, and {@link #getFailedUnlockAttempts()}, {@link #reportFailedAttempt()}
- * and {@link #clearFailedUnlockAttempts()}.  Maybe we should rename this 'KeyguardContext'...
  */
 public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
 
@@ -1568,6 +1563,15 @@
         updateFaceListeningState();
     }
 
+    /**
+     * Requests face authentication if we're on a state where it's allowed.
+     * This will re-trigger auth in case it fails.
+     */
+    public void requestFaceAuth() {
+        if (DEBUG) Log.d(TAG, "requestFaceAuth()");
+        updateFaceListeningState();
+    }
+
     private void updateFaceListeningState() {
         // If this message exists, we should not authenticate again until this message is
         // consumed by the handler
@@ -1629,7 +1633,7 @@
             return;
         }
         if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
-        int userId = ActivityManager.getCurrentUser();
+        int userId = getCurrentUser();
         if (isUnlockWithFingerprintPossible(userId)) {
             if (mFingerprintCancelSignal != null) {
                 mFingerprintCancelSignal.cancel();
@@ -1647,7 +1651,7 @@
             return;
         }
         if (DEBUG) Log.v(TAG, "startListeningForFace()");
-        int userId = ActivityManager.getCurrentUser();
+        int userId = getCurrentUser();
         if (isUnlockWithFacePossible(userId)) {
             if (mFaceCancelSignal != null) {
                 mFaceCancelSignal.cancel();
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
index 2275380..95f1004 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
@@ -59,7 +59,7 @@
      */
     public void onTimeChanged() {
         mTime.setTimeInMillis(System.currentTimeMillis());
-        final float hourAngle = mTime.get(Calendar.HOUR) * 30f;
+        final float hourAngle = mTime.get(Calendar.HOUR) * 30f + mTime.get(Calendar.MINUTE) * 0.5f;
         mHourHand.setRotation(hourAngle);
         final float minuteAngle = mTime.get(Calendar.MINUTE) * 6f;
         mMinuteHand.setRotation(minuteAngle);
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
index 34c855b..8cdd632 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
@@ -103,7 +103,8 @@
         final float centerY = getHeight() / 2f;
 
         final float minutesRotation = mTime.get(Calendar.MINUTE) * 6f;
-        final float hoursRotation = (mTime.get(Calendar.HOUR) * 30);
+        final float hoursRotation = mTime.get(Calendar.HOUR) * 30
+                + mTime.get(Calendar.MINUTE) * 0.5f;
 
         // Compute length of clock hands. Hour hand is 60% the length from center to edge
         // and minute hand is twice the length to make sure it extends past screen edge.
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index 5086c99..72ab02c 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -215,7 +215,7 @@
         } else {
             rotateLeft();
         }
-        if (mSeparated) {
+        if (mAdapter.hasSeparatedItems()) {
             if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
                 // Separated view has top margin, so seascape separated view need special rotation,
                 // not a full left or right rotation.
@@ -257,10 +257,10 @@
 
     @Override
     public void onUpdateList() {
-        removeAllItems();
+        super.onUpdateList();
         ArrayList<GlobalActionsDialog.Action> separatedActions =
-                mAdapter.getSeparatedItems(mSeparated);
-        ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems(mSeparated);
+                mAdapter.getSeparatedItems();
+        ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems();
 
         for (int i = 0; i < mAdapter.getCount(); i++) {
             Object action = mAdapter.getItem(i);
@@ -461,8 +461,9 @@
         if (mList == null) return;
         // If got separated button, setRotatedBackground to false,
         // all items won't get white background.
-        mListBackground.setRotatedBackground(mSeparated);
-        mSeparatedViewBackground.setRotatedBackground(mSeparated);
+        boolean separated = mAdapter.hasSeparatedItems();
+        mListBackground.setRotatedBackground(separated);
+        mSeparatedViewBackground.setRotatedBackground(separated);
         if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
             int index = mRotatedBackground ? 0 : 1;
             mDivision.getLocationOnScreen(mTmp2);
@@ -508,26 +509,27 @@
         int screenHeight;
         int totalHeight;
         int targetGravity;
+        boolean separated = mAdapter.hasSeparatedItems();
         MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
         switch (RotationUtils.getRotation(getContext())) {
             case RotationUtils.ROTATION_LANDSCAPE:
                 defaultTopPadding = getPaddingLeft();
                 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
-                separatedViewTopMargin = mSeparated ? params.leftMargin : 0;
+                separatedViewTopMargin = separated ? params.leftMargin : 0;
                 screenHeight = getMeasuredWidth();
                 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
                 break;
             case RotationUtils.ROTATION_SEASCAPE:
                 defaultTopPadding = getPaddingRight();
                 viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
-                separatedViewTopMargin = mSeparated ? params.leftMargin : 0;
+                separatedViewTopMargin = separated ? params.leftMargin : 0;
                 screenHeight = getMeasuredWidth();
                 targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
                 break;
             default: // Portrait
                 defaultTopPadding = getPaddingTop();
                 viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
-                separatedViewTopMargin = mSeparated ? params.topMargin : 0;
+                separatedViewTopMargin = separated ? params.topMargin : 0;
                 screenHeight = getMeasuredHeight();
                 targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
index 2bc4720..d063a0f 100644
--- a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
@@ -33,8 +33,8 @@
  */
 public abstract class MultiListLayout extends LinearLayout {
     protected boolean mHasOutsideTouch;
-    protected boolean mSeparated;
     protected MultiListAdapter mAdapter;
+    protected boolean mSnapToEdge;
 
     protected int mRotation;
     protected RotationListener mRotationListener;
@@ -70,12 +70,10 @@
     }
 
     /**
-     * Sets whether the separated view should be shown, and handles updating visibility on
-     * that view.
+     * Sets whether the GlobalActions view should snap to the edge of the screen.
      */
-    public void setSeparated(boolean separated) {
-        mSeparated = separated;
-        setSeparatedViewVisibility(separated);
+    public void setSnapToEdge(boolean snap) {
+        mSnapToEdge = snap;
     }
 
     /**
@@ -123,7 +121,9 @@
         onUpdateList();
     }
 
-    protected abstract void onUpdateList();
+    protected void onUpdateList() {
+        setSeparatedViewVisibility(mAdapter.hasSeparatedItems());
+    }
 
     public void setRotationListener(RotationListener listener) {
         mRotationListener = listener;
@@ -156,13 +156,13 @@
          * Creates an ArrayList of items which should be rendered in the separated view.
          * @param useSeparatedView is true if the separated view will be used, false otherwise.
          */
-        public abstract ArrayList getSeparatedItems(boolean useSeparatedView);
+        public abstract ArrayList getSeparatedItems();
 
         /**
          * Creates an ArrayList of items which should be rendered in the list view.
          * @param useSeparatedView True if the separated view will be used, false otherwise.
          */
-        public abstract ArrayList getListItems(boolean useSeparatedView);
+        public abstract ArrayList getListItems();
 
         /**
          * Callback to run when an individual item is clicked or pressed.
@@ -176,5 +176,13 @@
          * @return True if the long-click was handled, false otherwise.
          */
         public abstract boolean onLongClickItem(int position);
+
+        /**
+         * Determines whether the mAdapter contains any separated items, used to determine whether
+         * or not to hide the separated list from view.
+         */
+        public boolean hasSeparatedItems() {
+            return getSeparatedItems().size() > 0;
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index ff68d2b..97a277b 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -14,6 +14,7 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Bundle;
@@ -173,6 +174,26 @@
         startAssistInternal(args, assistComponent, isService);
     }
 
+    /**
+     * Returns a {@code Rect} containing system UI presented on behalf of the assistant that
+     * consumes touches.
+     */
+    @Nullable
+    public Rect getTouchableRegion() {
+        // intentional no-op, vendor's AssistManager implementation should override if needed.
+        return null;
+    }
+
+    /** Registers a listener for changes to system UI presented on behalf of the assistant. */
+    public void setAssistSysUiChangeListener(AssistSysUiChangeListener listener) {
+        // intentional no-op, vendor's AssistManager implementation should override if needed.
+    }
+
+    /** Returns {@code true} if the system UI is showing UI for the assistant. */
+    public boolean hasAssistUi() {
+        return false;
+    }
+
     public void hideAssist() {
         mAssistUtils.hideCurrentSession();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistSysUiChangeListener.java b/packages/SystemUI/src/com/android/systemui/assist/AssistSysUiChangeListener.java
new file mode 100644
index 0000000..d03afb6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistSysUiChangeListener.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 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.assist;
+
+/**
+ * Used to notify when system UI is showing UI for the assistant.
+ */
+public interface AssistSysUiChangeListener {
+
+    /** Called when the visibility of system UI for the assistant has changed. */
+    void onChange(boolean isVisible);
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index eb85589..e0ed111 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -118,6 +118,7 @@
     private final BubbleTaskStackListener mTaskStackListener;
     private BubbleStateChangeListener mStateChangeListener;
     private BubbleExpandListener mExpandListener;
+    @Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer;
 
     private BubbleData mBubbleData;
     private BubbleStackView mStackView;
@@ -178,7 +179,12 @@
 
     @Inject
     public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
-            BubbleData data) {
+                            BubbleData data) {
+        this(context, statusBarWindowController, data, null /* synchronizer */);
+    }
+
+    public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
+            BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer) {
         mContext = context;
 
         mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
@@ -206,6 +212,7 @@
         }
 
         mBubbleData = data;
+        mSurfaceSynchronizer = synchronizer;
     }
 
     /**
@@ -297,7 +304,7 @@
             mStackView.updateBubble(notif, updatePosition);
         } else {
             if (mStackView == null) {
-                mStackView = new BubbleStackView(mContext, mBubbleData);
+                mStackView = new BubbleStackView(mContext, mBubbleData, mSurfaceSynchronizer);
                 ViewGroup sbv = mStatusBarWindowController.getStatusBarView();
                 // XXX: Bug when you expand the shade on top of expanded bubble, there is no scrim
                 // between bubble and the shade
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 888e3fe..1cc6b87 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -19,6 +19,7 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
+import android.annotation.NonNull;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -32,6 +33,7 @@
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
 import android.util.StatsLog;
+import android.view.Choreographer;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -67,6 +69,43 @@
     private static final String TAG = "BubbleStackView";
     private static final boolean DEBUG = false;
 
+    /**
+     * Interface to synchronize {@link View} state and the screen.
+     *
+     * {@hide}
+     */
+    interface SurfaceSynchronizer {
+        /**
+         * Wait until requested change on a {@link View} is reflected on the screen.
+         *
+         * @param callback callback to run after the change is reflected on the screen.
+         */
+        void syncSurfaceAndRun(Runnable callback);
+    }
+
+    private static final SurfaceSynchronizer DEFAULT_SURFACE_SYNCHRONIZER =
+            new SurfaceSynchronizer() {
+        @Override
+        public void syncSurfaceAndRun(Runnable callback) {
+            Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
+                // Just wait 2 frames. There is no guarantee, but this is usually enough time that
+                // the requested change is reflected on the screen.
+                // TODO: Once SurfaceFlinger provide APIs to sync the state of {@code View} and
+                // surfaces, rewrite this logic with them.
+                private int mFrameWait = 2;
+
+                @Override
+                public void doFrame(long frameTimeNanos) {
+                    if (--mFrameWait > 0) {
+                        Choreographer.getInstance().postFrameCallback(this);
+                    } else {
+                        callback.run();
+                    }
+                }
+            });
+        }
+    };
+
     private Point mDisplaySize;
 
     private final SpringAnimation mExpandedViewXAnim;
@@ -79,7 +118,6 @@
 
     private FrameLayout mExpandedViewContainer;
 
-
     private int mBubbleSize;
     private int mBubblePadding;
     private int mExpandedAnimateXDistance;
@@ -129,7 +167,11 @@
         }
     };
 
-    public BubbleStackView(Context context, BubbleData data) {
+    @NonNull private final SurfaceSynchronizer mSurfaceSynchronizer;
+
+
+    public BubbleStackView(Context context, BubbleData data,
+                           @Nullable SurfaceSynchronizer synchronizer) {
         super(context);
 
         mBubbleData = data;
@@ -160,6 +202,7 @@
 
         mStackAnimationController = new StackAnimationController();
         mExpandedAnimationController = new ExpandedAnimationController(mDisplaySize);
+        mSurfaceSynchronizer = synchronizer != null ? synchronizer : DEFAULT_SURFACE_SYNCHRONIZER;
 
         mBubbleContainer = new PhysicsAnimationLayout(context);
         mBubbleContainer.setMaxRenderedChildren(
@@ -314,17 +357,28 @@
             // If we weren't previously expanded we should animate open.
             animateExpansion(true /* expand */);
             logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
+            mExpandedBubble.entry.setShowInShadeWhenBubble(false);
+            notifyExpansionChanged(mExpandedBubble.entry, true /* expanded */);
         } else {
-            // Otherwise just update the views
-            // TODO: probably animate / page to expanded one
-            updateExpandedBubble();
-            updatePointerPosition();
-            requestUpdate();
-            logBubbleEvent(prevBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
-            logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
+            // Make the container of the expanded view transparent before removing the expanded view
+            // from it. Otherwise a punch hole created by {@link android.view.SurfaceView} in the
+            // expanded view becomes visible on the screen. See b/126856255
+            mExpandedViewContainer.setAlpha(0.0f);
+
+            mSurfaceSynchronizer.syncSurfaceAndRun(new Runnable() {
+                @Override
+                public void run() {
+                    updateExpandedBubble();
+                    updatePointerPosition();
+                    requestUpdate();
+                    logBubbleEvent(prevBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
+                    logBubbleEvent(mExpandedBubble,
+                            StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
+                    mExpandedBubble.entry.setShowInShadeWhenBubble(false);
+                    notifyExpansionChanged(mExpandedBubble.entry, true /* expanded */);
+                }
+            });
         }
-        mExpandedBubble.entry.setShowInShadeWhenBubble(false);
-        notifyExpansionChanged(mExpandedBubble.entry, true /* expanded */);
     }
 
     /**
@@ -426,7 +480,9 @@
 
         if (reason == BubbleController.DISMISS_USER_GESTURE) {
             Notification.BubbleMetadata bubbleMetadata = bubble.entry.getBubbleMetadata();
-            PendingIntent deleteIntent = bubbleMetadata.getDeleteIntent();
+            PendingIntent deleteIntent = bubbleMetadata != null
+                    ? bubbleMetadata.getDeleteIntent()
+                    : null;
             if (deleteIntent != null) {
                 try {
                     deleteIntent.send();
@@ -767,6 +823,7 @@
             mExpandedViewContainer.addView(mExpandedBubble.expandedView);
             mExpandedBubble.expandedView.populateExpandedView();
             mExpandedViewContainer.setVisibility(mIsExpanded ? VISIBLE : GONE);
+            mExpandedViewContainer.setAlpha(1.0f);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index 06dbdbf..a4592d5 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -121,11 +121,17 @@
                     if (dozeState == State.DOZE
                             && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
                         mMachine.requestState(State.DOZE_AOD);
-                        break;
                     }
-                    // continue below
+                    else {
+                        requestPulseOutNow(dozeState);
+                    }
+                    break;
                 case DockManager.STATE_DOCKED_HIDE:
-                    requestPulseOutNow(dozeState);
+                    if (dozeState == State.DOZE_AOD) {
+                        mMachine.requestState(State.DOZE);
+                    } else {
+                        requestPulseOutNow(dozeState);
+                    }
                     break;
                 default:
                     // no-op
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index b2f707f..bc3f48d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -28,6 +28,7 @@
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.hardware.display.AmbientDisplayConfiguration;
+import android.metrics.LogMaker;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -35,7 +36,10 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.Preconditions;
+import com.android.systemui.Dependency;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.Assert;
@@ -79,6 +83,7 @@
     private long mNotificationPulseTime;
     private boolean mPulsePending;
 
+    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
     public DozeTriggers(Context context, DozeMachine machine, DozeHost dozeHost,
             AlarmManager alarmManager, AmbientDisplayConfiguration config,
@@ -159,8 +164,15 @@
                     if (screenX != -1 && screenY != -1) {
                         mDozeHost.onSlpiTap(screenX, screenY);
                     }
+                    // Logs screen wake up reason of either single or double tap.
+                    mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
+                            .setType(MetricsEvent.TYPE_UPDATE).setSubtype(pulseReason));
                     mMachine.wakeUp();
                 } else if (isPickup) {
+                    // Logs screen wake up reason of lift.
+                    mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
+                            .setType(MetricsEvent.TYPE_UPDATE)
+                            .setSubtype(DozeLog.REASON_SENSOR_PICKUP));
                     mMachine.wakeUp();
                 } else {
                     mDozeHost.extendPulse();
@@ -298,6 +310,10 @@
                 continuePulseRequest(reason);
             }
         }, !mDozeParameters.getProxCheckBeforePulse() || performedProxCheck, reason);
+
+        // Logs request pulse reason on AOD screen.
+        mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
+                .setType(MetricsEvent.TYPE_UPDATE).setSubtype(reason));
     }
 
     private boolean canPulse() {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index b07f909..b98ce2698 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -24,6 +24,7 @@
 import android.app.ActivityManager;
 import android.app.Dialog;
 import android.app.KeyguardManager;
+import android.app.PendingIntent;
 import android.app.WallpaperManager;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
@@ -38,7 +39,6 @@
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.net.ConnectivityManager;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.os.RemoteException;
@@ -87,6 +87,7 @@
 import com.android.systemui.MultiListLayout;
 import com.android.systemui.MultiListLayout.MultiListAdapter;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
 import com.android.systemui.plugins.GlobalActionsPanelPlugin;
 import com.android.systemui.statusbar.phone.ScrimController;
@@ -156,13 +157,13 @@
     private boolean mHasVibrator;
     private boolean mHasLogoutButton;
     private boolean mHasLockdownButton;
-    private boolean mUseSeparatedList;
     private final boolean mShowSilentToggle;
     private final EmergencyAffordanceManager mEmergencyAffordanceManager;
     private final ScreenshotHelper mScreenshotHelper;
     private final ScreenRecordHelper mScreenRecordHelper;
 
     private final Extension<GlobalActionsPanelPlugin> mPanelExtension;
+    private ActivityStarter mActivityStarter;
 
     /**
      * @param context everything needs a context :(
@@ -212,6 +213,7 @@
             .newExtension(GlobalActionsPanelPlugin.class)
             .withPlugin(GlobalActionsPanelPlugin.class)
             .build();
+        mActivityStarter = Dependency.get(ActivityStarter.class);
     }
 
     /**
@@ -334,7 +336,6 @@
         ArraySet<String> addedKeys = new ArraySet<String>();
         mHasLogoutButton = false;
         mHasLockdownButton = false;
-        mUseSeparatedList = true;
         for (int i = 0; i < defaultActions.length; i++) {
             String actionKey = defaultActions[i];
             if (addedKeys.contains(actionKey)) {
@@ -382,7 +383,7 @@
                     mHasLogoutButton = true;
                 }
             } else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) {
-                if (mUseSeparatedList
+                if (shouldUseSeparatedView()
                         && !mEmergencyAffordanceManager.needsEmergencyAffordance()) {
                     mItems.add(new EmergencyDialerAction());
                 }
@@ -401,14 +402,24 @@
 
         GlobalActionsPanelPlugin.PanelViewController panelViewController =
                 mPanelExtension.get() != null
-                        ? mPanelExtension.get().onPanelShown(() -> {
-                            if (mDialog != null) {
-                                mDialog.dismiss();
-                            }
-                        })
+                        ? mPanelExtension.get().onPanelShown(
+                                new GlobalActionsPanelPlugin.Callbacks() {
+                                    @Override
+                                    public void dismissGlobalActionsMenu() {
+                                        if (mDialog != null) {
+                                            mDialog.dismiss();
+                                        }
+                                    }
+
+                                    @Override
+                                    public void startPendingIntentDismissingKeyguard(
+                                            PendingIntent intent) {
+                                        mActivityStarter
+                                                .startPendingIntentDismissingKeyguard(intent);
+                                    }
+                                })
                         : null;
-        ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, mUseSeparatedList,
-                panelViewController);
+        ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, panelViewController);
         dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
         dialog.setKeyguardShowing(mKeyguardShowing);
 
@@ -636,14 +647,6 @@
         public boolean showBeforeProvisioning() {
             return false;
         }
-
-        @Override
-        public String getStatus() {
-            return mContext.getString(
-                    R.string.bugreport_status,
-                    Build.VERSION.RELEASE,
-                    Build.ID);
-        }
     }
 
     private final class LogoutAction extends SinglePressAction {
@@ -702,7 +705,7 @@
 
     private Action getEmergencyAction() {
         Drawable emergencyIcon = mContext.getDrawable(R.drawable.emergency_icon);
-        if (!mUseSeparatedList) {
+        if (!shouldUseSeparatedView()) {
             // use un-colored legacy treatment
             emergencyIcon.setTintList(null);
         }
@@ -931,9 +934,9 @@
         }
 
         @Override
-        public ArrayList<Action> getSeparatedItems(boolean shouldUseSeparatedView) {
+        public ArrayList<Action> getSeparatedItems() {
             ArrayList<Action> separatedActions = new ArrayList<Action>();
-            if (!shouldUseSeparatedView) {
+            if (!shouldUseSeparatedView()) {
                 return separatedActions;
             }
             for (int i = 0; i < mItems.size(); i++) {
@@ -946,8 +949,8 @@
         }
 
         @Override
-        public ArrayList<Action> getListItems(boolean shouldUseSeparatedView) {
-            if (!shouldUseSeparatedView) {
+        public ArrayList<Action> getListItems() {
+            if (!shouldUseSeparatedView()) {
                 return new ArrayList<Action>(mItems);
             }
             ArrayList<Action> listActions = new ArrayList<Action>();
@@ -1495,17 +1498,15 @@
         private final ColorExtractor mColorExtractor;
         private final GlobalActionsPanelPlugin.PanelViewController mPanelController;
         private boolean mKeyguardShowing;
-        private boolean mUseSeparatedList;
         private boolean mShowing;
         private final float mScrimAlpha;
 
-        ActionsDialog(Context context, MyAdapter adapter, boolean separated,
+        ActionsDialog(Context context, MyAdapter adapter,
                 GlobalActionsPanelPlugin.PanelViewController plugin) {
             super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
             mContext = context;
             mAdapter = adapter;
             mColorExtractor = Dependency.get(SysuiColorExtractor.class);
-            mUseSeparatedList = separated;
 
             // Window initialization
             Window window = getWindow();
@@ -1569,7 +1570,6 @@
             mGlobalActionsLayout = (MultiListLayout)
                     findViewById(com.android.systemui.R.id.global_actions_view);
             mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
-            mGlobalActionsLayout.setSeparated(mUseSeparatedList);
             mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
                 @Override
                 public boolean dispatchPopulateAccessibilityEvent(
@@ -1581,11 +1581,8 @@
             });
             mGlobalActionsLayout.setRotationListener(this::onRotate);
             mGlobalActionsLayout.setAdapter(mAdapter);
-        }
-
-        private boolean isPanelEnabled(Context context) {
-            return FeatureFlagUtils.isEnabled(
-                    context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED);
+            mGlobalActionsLayout.setSnapToEdge(isPanelEnabled(mContext)
+                    && mPanelController != null);
         }
 
         private int getGlobalActionsLayoutId(Context context) {
@@ -1691,6 +1688,9 @@
         void dismissImmediately() {
             super.dismiss();
             mShowing = false;
+            if (mPanelController != null) {
+                mPanelController.onDismissed();
+            }
         }
 
         private float getAnimTranslation() {
@@ -1726,9 +1726,24 @@
     }
 
     /**
-     * Determines whether or not the Global Actions Dialog should use the newer grid-style layout.
+     * Determines whether or not the Global Actions menu should use the newer grid-style layout.
      */
-    public static boolean isGridEnabled(Context context) {
+    private static boolean isGridEnabled(Context context) {
         return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.GLOBAL_ACTIONS_GRID_ENABLED);
     }
+
+    /**
+     * Determines whether or not the Global Actions Panel should appear when the power button
+     * is held.
+     */
+    private static boolean isPanelEnabled(Context context) {
+        return FeatureFlagUtils.isEnabled(
+                context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED);    }
+
+    /**
+     * Determines whether the Global Actions menu should use a separated view for emergency actions.
+     */
+    private static boolean shouldUseSeparatedView() {
+        return true;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
index cda7669..058ea60 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -71,10 +72,10 @@
 
     @Override
     public void onUpdateList() {
-        removeAllItems();
+        super.onUpdateList();
         ArrayList<GlobalActionsDialog.Action> separatedActions =
-                mAdapter.getSeparatedItems(mSeparated);
-        ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems(mSeparated);
+                mAdapter.getSeparatedItems();
+        ArrayList<GlobalActionsDialog.Action> listActions = mAdapter.getListItems();
         setExpectedListItemCount(listActions.size());
         int rotation = RotationUtils.getRotation(mContext);
 
@@ -108,6 +109,7 @@
                 parent.addView(v);
             }
         }
+        updateSnapPosition();
     }
 
     @Override
@@ -115,6 +117,19 @@
         return findViewById(com.android.systemui.R.id.separated_button);
     }
 
+    private void updateSnapPosition() {
+        if (mSnapToEdge) {
+            setPadding(0, 0, 0, 0);
+            if (mRotation == RotationUtils.ROTATION_LANDSCAPE) {
+                setGravity(Gravity.RIGHT);
+            } else if (mRotation == RotationUtils.ROTATION_SEASCAPE) {
+                setGravity(Gravity.LEFT);
+            } else {
+                setGravity(Gravity.BOTTOM);
+            }
+        }
+    }
+
     @Override
     protected ListGridLayout getListView() {
         return findViewById(android.R.id.list);
@@ -148,7 +163,7 @@
     }
 
     /**
-     * Not used in this implementation of the Global Actions Menu, but necessary for some others.
+     * Not ued in this implementation of the Global Actions Menu, but necessary for some others.
      */
     @Override
     public void setDivisionView(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
index 6c106df..048f801 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
@@ -114,7 +114,7 @@
         if (mExpectedCount == 3) {
             return 1;
         }
-        return (int) Math.ceil(Math.sqrt(mExpectedCount));
+        return (int) Math.round(Math.sqrt(mExpectedCount));
     }
 
     private int getColumnCount() {
@@ -122,6 +122,6 @@
         if (mExpectedCount == 3) {
             return 3;
         }
-        return (int) Math.round(Math.sqrt(mExpectedCount));
+        return (int) Math.ceil(Math.sqrt(mExpectedCount));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index 15dc43f..23742c0 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -17,9 +17,9 @@
 import android.content.Context
 import android.util.AttributeSet
 import android.view.ViewGroup
+import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
-import android.widget.TextView
 import com.android.systemui.Dependency
 import com.android.systemui.R
 import com.android.systemui.statusbar.policy.KeyguardMonitor
@@ -42,9 +42,8 @@
     private val sidePadding =
             context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding)
     private val backgroundDrawable = context.getDrawable(R.drawable.privacy_chip_bg)
-    private lateinit var text: TextView
     private lateinit var iconsContainer: LinearLayout
-    private lateinit var back: LinearLayout
+    private lateinit var back: FrameLayout
     var expanded = false
         set(value) {
             if (value != field) {
@@ -66,14 +65,14 @@
         super.onFinishInflate()
 
         back = findViewById(R.id.background)
-        text = findViewById(R.id.text_container)
         iconsContainer = findViewById(R.id.icons_container)
     }
 
     // Should only be called if the builder icons or app changed
     private fun updateView() {
         back.background = if (expanded) backgroundDrawable else null
-        back.setPaddingRelative(0, 0, if (expanded) sidePadding else 0, 0)
+        val padding = if (expanded) sidePadding else 0
+        back.setPaddingRelative(padding, 0, padding, 0)
         fun setIcons(dialogBuilder: PrivacyDialogBuilder, iconsContainer: ViewGroup) {
             iconsContainer.removeAllViews()
             dialogBuilder.generateIcons().forEachIndexed { i, it ->
@@ -95,44 +94,17 @@
         if (!privacyList.isEmpty()) {
             generateContentDescription()
             setIcons(builder, iconsContainer)
-            setApplicationText()
         } else {
-            text.visibility = GONE
             iconsContainer.removeAllViews()
         }
         requestLayout()
     }
 
-    private fun setApplicationText() {
-        text.visibility = if (builder.types.size == 1 && expanded) VISIBLE else GONE
-        if (builder.types.size == 1 && expanded) {
-            if (builder.app != null && !amISecure()) {
-                text.setText(builder.app?.applicationName)
-            } else {
-                text.text = context.resources.getQuantityString(
-                        R.plurals.ongoing_privacy_chip_multiple_apps,
-                        builder.appsAndTypes.size, builder.appsAndTypes.size)
-            }
-        }
-    }
-
     private fun amISecure() = keyguardMonitor.isShowing && keyguardMonitor.isSecure
 
     private fun generateContentDescription() {
         val typesText = builder.joinTypes()
-        if (builder.types.size > 1) {
-            contentDescription = context.getString(
-                    R.string.ongoing_privacy_chip_content_multiple_apps, typesText)
-        } else {
-            if (builder.app != null && !amISecure()) {
-                contentDescription =
-                        context.getString(R.string.ongoing_privacy_chip_content_single_app,
-                                builder.app?.applicationName, typesText)
-            } else {
-                contentDescription = context.resources.getQuantityString(
-                        R.plurals.ongoing_privacy_chip_content_multiple_apps_single_op,
-                        builder.appsAndTypes.size, builder.appsAndTypes.size, typesText)
-            }
-        }
+        contentDescription = context.getString(
+                R.string.ongoing_privacy_chip_content_multiple_apps, typesText)
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
index bbea6b2..59b3c34 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt
@@ -22,7 +22,6 @@
 
     val appsAndTypes: List<Pair<PrivacyApplication, List<PrivacyType>>>
     val types: List<PrivacyType>
-    val app: PrivacyApplication?
     private val separator = context.getString(R.string.ongoing_privacy_dialog_separator)
     private val lastSeparator = context.getString(R.string.ongoing_privacy_dialog_last_separator)
 
@@ -32,8 +31,6 @@
                 .sortedWith(compareBy({ -it.second.size }, // Sort by number of AppOps
                         { it.second.min() })) // Sort by "smallest" AppOpp (Location is largest)
         types = itemsList.map { it.privacyType }.distinct().sorted()
-        val singleApp = appsAndTypes.size == 1
-        app = if (singleApp) appsAndTypes[0].first else null
     }
 
     fun generateIconsForApp(types: List<PrivacyType>): List<Drawable> {
@@ -58,11 +55,7 @@
     }
 
     fun getDialogTitle(): String {
-        if (app != null) {
-            return context.getString(R.string.ongoing_privacy_dialog_single_app_title, joinTypes())
-        } else {
-            return context.getString(R.string.ongoing_privacy_dialog_multiple_apps_title,
+        return context.getString(R.string.ongoing_privacy_dialog_multiple_apps_title,
                     joinTypes())
-        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index aa972e3..8e77851 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -127,12 +127,12 @@
     @Override
     public void onTuningChanged(String key, String newValue) {
         if (ALLOW_FANCY_ANIMATION.equals(key)) {
-            mAllowFancy = newValue == null || Integer.parseInt(newValue) != 0;
+            mAllowFancy = TunerService.parseIntegerSwitch(newValue, true);
             if (!mAllowFancy) {
                 clearAnimationState();
             }
         } else if (MOVE_FULL_ROWS.equals(key)) {
-            mFullRows = newValue == null || Integer.parseInt(newValue) != 0;
+            mFullRows = TunerService.parseIntegerSwitch(newValue, true);
         } else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) {
             mNumQuickTiles = mQuickQsPanel.getNumQuickTiles(mQs.getContext());
             clearAnimationState();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 3c3dfb1..b93f8d04 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -183,7 +183,7 @@
     }
 
     private void updateViewVisibilityForTuningValue(View view, @Nullable String newValue) {
-        view.setVisibility(newValue == null || Integer.parseInt(newValue) != 0 ? VISIBLE : GONE);
+        view.setVisibility(TunerService.parseIntegerSwitch(newValue, true) ? VISIBLE : GONE);
     }
 
     public void openDetails(String subPanel) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 305fbf2..b135f7b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -159,8 +159,8 @@
             mBindTryCount++;
             try {
                 mIsBound = mContext.bindServiceAsUser(mIntent, this,
-                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
-                        mUser);
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+                        | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, mUser);
             } catch (SecurityException e) {
                 Log.e(TAG, "Failed to bind to service", e);
                 mIsBound = false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 4da8ca2..9219594 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -107,6 +107,7 @@
     private IOverviewProxy mOverviewProxy;
     private int mConnectionBackoffAttempts;
     private @InteractionType int mInteractionFlags;
+    private boolean mBound;
     private boolean mIsEnabled;
     private int mCurrentBoundedUserId = -1;
     private float mBackButtonAlpha;
@@ -510,16 +511,15 @@
         mHandler.removeCallbacks(mConnectionRunnable);
         Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
                 .setPackage(mRecentsComponentName.getPackageName());
-        boolean bound = false;
         try {
-            bound = mContext.bindServiceAsUser(launcherServiceIntent,
+            mBound = mContext.bindServiceAsUser(launcherServiceIntent,
                     mOverviewServiceConnection,
                     Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
                     UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
         } catch (SecurityException e) {
             Log.e(TAG_OPS, "Unable to bind because of security error", e);
         }
-        if (bound) {
+        if (mBound) {
             // Ensure that connection has been established even if it thinks it is bound
             mHandler.postDelayed(mDeferredConnectionCallback, DEFERRED_CALLBACK_MILLIS);
         } else {
@@ -573,9 +573,14 @@
     }
 
     private void disconnectFromLauncherService() {
+        if (mBound) {
+            // Always unbind the service (ie. if called through onNullBinding or onBindingDied)
+            mContext.unbindService(mOverviewServiceConnection);
+            mBound = false;
+        }
+
         if (mOverviewProxy != null) {
             mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
-            mContext.unbindService(mOverviewServiceConnection);
             mOverviewProxy = null;
             notifyBackButtonAlphaChanged(1f, false /* animate */);
             notifyConnectionChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index dfbb32e..8faeb15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -664,6 +664,9 @@
         public void onBiometricRunningStateChanged(boolean running,
                 BiometricSourceType biometricSourceType) {
             if (running) {
+                // Let's hide any previous messages when authentication starts, otherwise
+                // multiple auth attempts would overlap.
+                hideTransientIndication();
                 mMessageToShowOnScreenOn = null;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 311bf7a..c2da517 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -79,6 +79,8 @@
         mDismissButton.setContentDescription(
                 mContext.getString(R.string.accessibility_clear_all));
         mManageButton.setText(R.string.manage_notifications_text);
+        mManageButton.setContentDescription(
+                mContext.getString(R.string.accessibility_manage_notification));
     }
 
     public boolean isButtonVisible() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index fea01ef..54bdaa2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -122,11 +122,22 @@
     }
 
     /**
-     * Sends an intent to open the app settings for a particular package and optional
+     * Sends an intent to open the notification settings for a particular package and optional
      * channel.
      */
     private void startAppNotificationSettingsActivity(String packageName, final int appUid,
             final NotificationChannel channel, ExpandableNotificationRow row) {
+        final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
+        intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
+        intent.putExtra(Settings.EXTRA_APP_UID, appUid);
+        if (channel != null) {
+            intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, channel.getId());
+        }
+        mNotificationActivityStarter.startNotificationGutsIntent(intent, appUid, row);
+    }
+
+    private void startAppDetailsSettingsActivity(String packageName, final int appUid,
+            final NotificationChannel channel, ExpandableNotificationRow row) {
         final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
         intent.setData(Uri.fromParts("package", packageName, null));
         intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
@@ -141,7 +152,7 @@
             ExpandableNotificationRow row) {
         if (ops.contains(OP_SYSTEM_ALERT_WINDOW)) {
             if (ops.contains(OP_CAMERA) || ops.contains(OP_RECORD_AUDIO)) {
-                startAppNotificationSettingsActivity(pkg, uid, null, row);
+                startAppDetailsSettingsActivity(pkg, uid, null, row);
             } else {
                 Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
                 intent.setData(Uri.fromParts("package", pkg, null));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index de0e194..9844d8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -37,7 +37,6 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.ScreenDecorations;
-import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.StatusBarState;
@@ -57,14 +56,14 @@
  * A implementation of HeadsUpManager for phone and car.
  */
 public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
-        ViewTreeObserver.OnComputeInternalInsetsListener, VisualStabilityManager.Callback,
-        OnHeadsUpChangedListener, ConfigurationController.ConfigurationListener, StateListener {
+        VisualStabilityManager.Callback, OnHeadsUpChangedListener,
+        ConfigurationController.ConfigurationListener, StateListener {
     private static final String TAG = "HeadsUpManagerPhone";
 
     private final View mStatusBarWindowView;
     private final NotificationGroupManager mGroupManager;
-    private final StatusBar mBar;
     private final VisualStabilityManager mVisualStabilityManager;
+    private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
     private boolean mReleaseOnExpandFinish;
 
     private int mStatusBarHeight;
@@ -78,13 +77,9 @@
     private boolean mIsExpanded;
     private int[] mTmpTwoArray = new int[2];
     private boolean mHeadsUpGoingAway;
-    private boolean mWaitingOnCollapseWhenGoingAway;
-    private boolean mBubbleGoingAway;
-    private boolean mIsObserving;
     private int mStatusBarState;
 
     private AnimationStateHandler mAnimationStateHandler;
-    private BubbleController mBubbleController = Dependency.get(BubbleController.class);
 
     private final Pools.Pool<HeadsUpEntryPhone> mEntryPool = new Pools.Pool<HeadsUpEntryPhone>() {
         private Stack<HeadsUpEntryPhone> mPoolObjects = new Stack<>();
@@ -107,14 +102,17 @@
     ///////////////////////////////////////////////////////////////////////////////////////////////
     //  Constructor:
 
-    public HeadsUpManagerPhone(@NonNull final Context context, @NonNull View statusBarWindowView,
-            @NonNull NotificationGroupManager groupManager, @NonNull StatusBar bar,
-            @NonNull VisualStabilityManager visualStabilityManager) {
+    public HeadsUpManagerPhone(@NonNull final Context context,
+                               @NonNull View statusBarWindowView,
+                               @NonNull NotificationGroupManager groupManager,
+                               @NonNull StatusBar bar,
+                               @NonNull VisualStabilityManager visualStabilityManager) {
         super(context);
 
         mStatusBarWindowView = statusBarWindowView;
+        mStatusBarTouchableRegionManager = new StatusBarTouchableRegionManager(context, this, bar,
+                statusBarWindowView);
         mGroupManager = groupManager;
-        mBar = bar;
         mVisualStabilityManager = visualStabilityManager;
 
         initResources();
@@ -125,16 +123,10 @@
                 if (Log.isLoggable(TAG, Log.WARN)) {
                     Log.w(TAG, "onHeadsUpPinnedModeChanged");
                 }
-                updateTouchableRegionListener();
+                mStatusBarTouchableRegionManager.updateTouchableRegion();
             }
         });
         Dependency.get(StatusBarStateController.class).addCallback(this);
-        mBubbleController.setBubbleStateChangeListener((hasBubbles) -> {
-            if (!hasBubbles) {
-                mBubbleGoingAway = true;
-            }
-            updateTouchableRegionListener();
-        });
     }
 
     public void setAnimationStateHandler(AnimationStateHandler handler) {
@@ -209,14 +201,10 @@
         if (isExpanded != mIsExpanded) {
             mIsExpanded = isExpanded;
             if (isExpanded) {
-                // make sure our state is sane
-                mWaitingOnCollapseWhenGoingAway = false;
                 mHeadsUpGoingAway = false;
-                updateTouchableRegionListener();
             }
-            if (mBubbleController.hasBubbles() || !mIsExpanded) {
-                updateTouchableRegionListener();
-            }
+            mStatusBarTouchableRegionManager.setIsStatusBarExpanded(isExpanded);
+            mStatusBarTouchableRegionManager.updateTouchableRegion();
         }
     }
 
@@ -233,15 +221,21 @@
         if (headsUpGoingAway != mHeadsUpGoingAway) {
             mHeadsUpGoingAway = headsUpGoingAway;
             if (!headsUpGoingAway) {
-                waitForStatusBarLayout();
+                mStatusBarTouchableRegionManager.updateTouchableRegionAfterLayout();
+            } else {
+                mStatusBarTouchableRegionManager.updateTouchableRegion();
             }
-            updateTouchableRegionListener();
         }
     }
 
+    public boolean isHeadsUpGoingAway() {
+        return mHeadsUpGoingAway;
+    }
+
     /**
      * Notifies that a remote input textbox in notification gets active or inactive.
-     * @param entry The entry of the target notification.
+     *
+     * @param entry             The entry of the target notification.
      * @param remoteInputActive True to notify active, False to notify inactive.
      */
     public void setRemoteInputActive(
@@ -295,23 +289,23 @@
         dumpInternal(fd, pw, args);
     }
 
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    //  ViewTreeObserver.OnComputeInternalInsetsListener overrides:
-
     /**
-     * Overridden from TreeObserver.
+     * Update touch insets to include any area needed for touching a heads up notification.
+     *
+     * @param info Insets that will include heads up notification touch area after execution.
      */
-    @Override
-    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
-        if (mIsExpanded || mBar.isBouncerShowing()) {
-            // The touchable region is always the full area when expanded
-            return;
-        }
-        if (hasPinnedHeadsUp()) {
+    @Nullable
+    public void updateTouchableRegion(ViewTreeObserver.InternalInsetsInfo info) {
+        info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+
+        if (!hasPinnedHeadsUp()) {
+            info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
+            updateRegionForNotch(info.touchableRegion);
+        } else {
             NotificationEntry topEntry = getTopEntry();
             if (topEntry.isChildInGroup()) {
-                final NotificationEntry groupSummary
-                        = mGroupManager.getGroupSummary(topEntry.notification);
+                final NotificationEntry groupSummary =
+                        mGroupManager.getGroupSummary(topEntry.notification);
                 if (groupSummary != null) {
                     topEntry = groupSummary;
                 }
@@ -321,23 +315,8 @@
             int minX = mTmpTwoArray[0];
             int maxX = mTmpTwoArray[0] + topRow.getWidth();
             int height = topRow.getIntrinsicHeight();
-
-            info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
             info.touchableRegion.set(minX, 0, maxX, mHeadsUpInset + height);
-        } else {
-            setCollapsedTouchableInsets(info);
         }
-        Rect r = mBubbleController.getTouchableRegion();
-        if (r != null) {
-            info.touchableRegion.union(r);
-        }
-        mBubbleGoingAway = false;
-    }
-
-    private void setCollapsedTouchableInsets(ViewTreeObserver.InternalInsetsInfo info) {
-        info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
-        info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
-        updateRegionForNotch(info.touchableRegion);
     }
 
     private void updateRegionForNotch(Region region) {
@@ -364,9 +343,7 @@
 
     @Override
     public void onConfigChanged(Configuration newConfig) {
-        Resources resources = mContext.getResources();
-        mStatusBarHeight = resources.getDimensionPixelSize(
-                com.android.internal.R.dimen.status_bar_height);
+        initResources();
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -401,14 +378,15 @@
 
     @Override
     protected boolean shouldHeadsUpBecomePinned(NotificationEntry entry) {
-          return mStatusBarState != StatusBarState.KEYGUARD && !mIsExpanded
-                  || super.shouldHeadsUpBecomePinned(entry);
+        return mStatusBarState != StatusBarState.KEYGUARD && !mIsExpanded
+                || super.shouldHeadsUpBecomePinned(entry);
     }
 
     @Override
     protected void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
         super.dumpInternal(fd, pw, args);
-        pw.print("  mBarState="); pw.println(mStatusBarState);
+        pw.print("  mBarState=");
+        pw.println(mStatusBarState);
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -438,45 +416,6 @@
         return headsUpEntry == null || headsUpEntry != topEntry || super.canRemoveImmediately(key);
     }
 
-    /**
-     * We need to wait on the whole panel to collapse, before we can remove the touchable region
-     * listener.
-     */
-    private void waitForStatusBarLayout() {
-        mWaitingOnCollapseWhenGoingAway = true;
-        mStatusBarWindowView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
-            @Override
-            public void onLayoutChange(View v, int left, int top, int right, int bottom,
-                    int oldLeft,
-                    int oldTop, int oldRight, int oldBottom) {
-                if (mStatusBarWindowView.getHeight() <= mStatusBarHeight) {
-                    mStatusBarWindowView.removeOnLayoutChangeListener(this);
-                    mWaitingOnCollapseWhenGoingAway = false;
-                    updateTouchableRegionListener();
-                }
-            }
-        });
-    }
-
-    // TODO: some kind of TouchableRegionManager to deal with this, HeadsUpManager is not really
-    // the right place
-    private void updateTouchableRegionListener() {
-        boolean shouldObserve = hasPinnedHeadsUp() || mHeadsUpGoingAway
-                || mBubbleController.hasBubbles() || mBubbleGoingAway
-                || mWaitingOnCollapseWhenGoingAway
-                || mStatusBarWindowView.getRootWindowInsets().getDisplayCutout() != null;
-        if (shouldObserve == mIsObserving) {
-            return;
-        }
-        if (shouldObserve) {
-            mStatusBarWindowView.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
-            mStatusBarWindowView.requestLayout();
-        } else {
-            mStatusBarWindowView.getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
-        }
-        mIsObserving = shouldObserve;
-    }
-
     ///////////////////////////////////////////////////////////////////////////////////////////////
     //  HeadsUpEntryPhone:
 
@@ -490,7 +429,7 @@
         }
 
         public void setEntry(@NonNull final NotificationEntry entry) {
-           Runnable removeHeadsUpRunnable = () -> {
+            Runnable removeHeadsUpRunnable = () -> {
                 if (!mVisualStabilityManager.isReorderingAllowed()) {
                     mEntriesToRemoveWhenReorderingAllowed.add(entry);
                     mVisualStabilityManager.addReorderingAllowedCallback(
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 e953ad5..c8ce392 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -483,7 +483,9 @@
                 R.color.light_mode_icon_color_single_tone);
         float intensity = textColor == Color.WHITE ? 0 : 1;
         mCarrierLabel.setTextColor(iconColor);
-        mIconManager.setTint(iconColor);
+        if (mIconManager != null) {
+            mIconManager.setTint(iconColor);
+        }
 
         applyDarkness(R.id.battery, mEmptyRect, intensity * (1f - mDarkAmount), iconColor);
         applyDarkness(R.id.clock, mEmptyRect, intensity, iconColor);
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 b7d1fc6..27394d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -21,6 +21,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.PorterDuff;
+import android.graphics.drawable.Animatable2;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
@@ -134,6 +135,16 @@
 
             if (animation != null && isAnim) {
                 animation.forceAnimationOnUI();
+                animation.clearAnimationCallbacks();
+                animation.registerAnimationCallback(new Animatable2.AnimationCallback() {
+                    @Override
+                    public void onAnimationEnd(Drawable drawable) {
+                        if (getDrawable() == animation && state == getState()
+                                && doesAnimationLoop(iconAnimRes)) {
+                            animation.start();
+                        }
+                    }
+                });
                 animation.start();
             }
 
@@ -215,6 +226,10 @@
         return mContext.getDrawable(iconRes);
     }
 
+    private boolean doesAnimationLoop(int resourceId) {
+        return resourceId == com.android.internal.R.anim.lock_scanning;
+    }
+
     private static int getAnimationResForTransition(int oldState, int newState,
             boolean wasPulsing, boolean pulsing,
             boolean wasDozing, boolean dozing) {
@@ -236,7 +251,7 @@
             return com.android.internal.R.anim.lock_lock;
         } else if (newState == STATE_SCANNING_FACE) {
             return com.android.internal.R.anim.lock_scanning;
-        } else if (!wasPulsing && pulsing) {
+        } else if (!wasPulsing && pulsing && newState != STATE_LOCK_OPEN) {
             return com.android.internal.R.anim.lock_in;
         }
         return -1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
index 409d60f..2d54970 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
@@ -16,203 +16,159 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
 import android.provider.Settings;
-import android.util.DisplayMetrics;
-import android.view.SurfaceControl;
+import android.view.CompositionSamplingListener;
 import android.view.View;
 
-import com.android.systemui.R;
+import java.io.PrintWriter;
 
-public class NavBarTintController {
+/**
+ * Updates the nav bar tint based on the color of the content behind the nav bar.
+ */
+public class NavBarTintController implements View.OnAttachStateChangeListener,
+        View.OnLayoutChangeListener {
+
     public static final int MIN_COLOR_ADAPT_TRANSITION_TIME = 400;
     public static final int DEFAULT_COLOR_ADAPT_TRANSITION_TIME = 1700;
 
-    private final HandlerThread mColorAdaptHandlerThread = new HandlerThread("ColorExtractThread");
-    private Handler mColorAdaptionHandler;
-
-    // Poll time for each iteration to color sample
-    private static final int COLOR_ADAPTION_TIMEOUT = 300;
-
     // Passing the threshold of this luminance value will make the button black otherwise white
     private static final float LUMINANCE_THRESHOLD = 0.3f;
 
-    // The margin from the bounds of the view to color sample around
-    private static final int COLOR_SAMPLE_MARGIN = 10;
-
-    private boolean mRunning;
-
+    private final Handler mHandler = new Handler();
     private final NavigationBarView mNavigationBarView;
     private final LightBarTransitionsController mLightBarController;
-    private final Handler mMainHandler = new Handler(Looper.getMainLooper());
-    private final int mBarRadius;
-    private final int mBarBottom;
+
+    private final CompositionSamplingListener mSamplingListener;
+    private final Runnable mUpdateSamplingListener = this::updateSamplingListener;
+    private final Rect mSamplingBounds = new Rect();
+    private boolean mSamplingEnabled = false;
+    private boolean mSamplingListenerRegistered = false;
+
+    private float mLastMediaLuma;
+    private boolean mUpdateOnNextDraw;
 
     public NavBarTintController(NavigationBarView navigationBarView,
             LightBarTransitionsController lightBarController) {
+        mSamplingListener = new CompositionSamplingListener(
+                navigationBarView.getContext().getMainExecutor()) {
+            @Override
+            public void onSampleCollected(float medianLuma) {
+                updateTint(medianLuma);
+            }
+        };
         mNavigationBarView = navigationBarView;
+        mNavigationBarView.addOnAttachStateChangeListener(this);
+        mNavigationBarView.addOnLayoutChangeListener(this);
         mLightBarController = lightBarController;
-
-        final Resources res = navigationBarView.getResources();
-        mBarRadius = res.getDimensionPixelSize(R.dimen.navigation_handle_radius);
-        mBarBottom = res.getDimensionPixelSize(R.dimen.navigation_handle_bottom);
     }
 
-    public void start() {
+    void onDraw() {
+        if (mUpdateOnNextDraw) {
+            mUpdateOnNextDraw = false;
+            requestUpdateSamplingListener();
+        }
+    }
+
+    void start() {
         if (!isEnabled(mNavigationBarView.getContext())) {
             return;
         }
-        if (mColorAdaptionHandler == null) {
-            mColorAdaptHandlerThread.start();
-            mColorAdaptionHandler = new Handler(mColorAdaptHandlerThread.getLooper());
-        }
-        mColorAdaptionHandler.removeCallbacksAndMessages(null);
-        mColorAdaptionHandler.post(this::updateTint);
-        mRunning = true;
+        mSamplingEnabled = true;
+        // Defer calling updateSamplingListener since we may have just reinflated prior to this
+        requestUpdateSamplingListener();
     }
 
-    public void end() {
-        if (mColorAdaptionHandler != null) {
-            mColorAdaptionHandler.removeCallbacksAndMessages(null);
-        }
-        mRunning = false;
+    void stop() {
+        mSamplingEnabled = false;
+        requestUpdateSamplingListener();
     }
 
-    public void stop() {
-        end();
-        if (mColorAdaptionHandler != null) {
-            mColorAdaptHandlerThread.quitSafely();
-        }
+    @Override
+    public void onViewAttachedToWindow(View view) {
+        requestUpdateSamplingListener();
     }
 
-    private void updateTint() {
-        int[] navPos = new int[2];
-        int[] butPos = new int[2];
+    @Override
+    public void onViewDetachedFromWindow(View view) {
+        // Defer calling updateSamplingListener the attach info has not yet been reset
+        requestUpdateSamplingListener();
+    }
+
+    @Override
+    public void onLayoutChange(View v, int left, int top, int right, int bottom,
+            int oldLeft, int oldTop, int oldRight, int oldBottom) {
+        mSamplingBounds.setEmpty();
+        // TODO: Extend this to 2/3 button layout as well
         View view = mNavigationBarView.getHomeHandle().getCurrentView();
-        if (view == null) {
-            return;
+        if (view != null) {
+            int[] pos = new int[2];
+            view.getLocationOnScreen(pos);
+            final Rect samplingBounds = new Rect(pos[0], pos[1],
+                    pos[0] + view.getWidth(), pos[1] + view.getHeight());
+            if (!samplingBounds.equals(mSamplingBounds)) {
+                mSamplingBounds.set(samplingBounds);
+                requestUpdateSamplingListener();
+            }
         }
-
-        // Determine the area of the icon within its view bounds
-        view.getLocationInSurface(butPos);
-        final int navWidth = view.getWidth();
-        final int navHeight = view.getHeight();
-        int viewBottom = butPos[1] + navHeight - mBarBottom;
-        final Rect viewIconRect = new Rect(butPos[0], viewBottom - mBarRadius * 2,
-                butPos[0] + navWidth, viewBottom);
-
-        if (mNavigationBarView.getCurrentView() == null || viewIconRect.isEmpty()) {
-            scheduleColorAdaption();
-            return;
-        }
-        mNavigationBarView.getCurrentView().getLocationOnScreen(navPos);
-        viewIconRect.offset(navPos[0], navPos[1]);
-
-        // Apply a margin area around the button region to sample the colors, crop from screenshot
-        final Rect cropRect = new Rect(viewIconRect);
-        cropRect.inset(-COLOR_SAMPLE_MARGIN, -COLOR_SAMPLE_MARGIN);
-        if (cropRect.isEmpty()) {
-            scheduleColorAdaption();
-            return;
-        }
-
-        // Determine the size of the home area
-        Rect homeArea = new Rect(COLOR_SAMPLE_MARGIN, COLOR_SAMPLE_MARGIN,
-                viewIconRect.width() + COLOR_SAMPLE_MARGIN,
-                viewIconRect.height() + COLOR_SAMPLE_MARGIN);
-
-        // Get the screenshot around the home button icon to determine the color
-        DisplayMetrics mDisplayMetrics = new DisplayMetrics();
-        mNavigationBarView.getContext().getDisplay().getRealMetrics(mDisplayMetrics);
-        final Bitmap hardBitmap = SurfaceControl
-                .screenshot(new Rect(), mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
-                        mNavigationBarView.getContext().getDisplay().getRotation());
-        if (hardBitmap != null && cropRect.bottom <= hardBitmap.getHeight()
-                && cropRect.left + cropRect.width() <= hardBitmap.getWidth()) {
-            final Bitmap cropBitmap = Bitmap.createBitmap(hardBitmap, cropRect.left, cropRect.top,
-                    cropRect.width(), cropRect.height());
-            final Bitmap softBitmap = cropBitmap.copy(Config.ARGB_8888, false);
-
-            // Get the luminance value to determine if the home button should be black or white
-            final int[] pixels = new int[softBitmap.getByteCount() / 4];
-            softBitmap.getPixels(pixels, 0, softBitmap.getWidth(), 0, 0, softBitmap.getWidth(),
-                    softBitmap.getHeight());
-            float r = 0, g = 0, blue = 0;
-
-            int width = cropRect.width();
-            int total = 0;
-            for (int i = 0; i < pixels.length; i += 4) {
-                int x = i % width;
-                int y = i / width;
-                if (!homeArea.contains(x, y)) {
-                    r += Color.red(pixels[i]);
-                    g += Color.green(pixels[i]);
-                    blue += Color.blue(pixels[i]);
-                    total++;
-                }
-            }
-
-            r /= total;
-            g /= total;
-            blue /= total;
-
-            r = Math.max(Math.min(r / 255f, 1), 0);
-            g = Math.max(Math.min(g / 255f, 1), 0);
-            blue = Math.max(Math.min(blue / 255f, 1), 0);
-
-            if (r <= 0.03928) {
-                r /= 12.92;
-            } else {
-                r = (float) Math.pow((r + 0.055) / 1.055, 2.4);
-            }
-            if (g <= 0.03928) {
-                g /= 12.92;
-            } else {
-                g = (float) Math.pow((g + 0.055) / 1.055, 2.4);
-            }
-            if (blue <= 0.03928) {
-                blue /= 12.92;
-            } else {
-                blue = (float) Math.pow((blue + 0.055) / 1.055, 2.4);
-            }
-
-            if (r * 0.2126 + g * 0.7152 + blue * 0.0722 > LUMINANCE_THRESHOLD) {
-                // Black
-                mMainHandler.post(
-                        () -> mLightBarController
-                                .setIconsDark(true /* dark */, true /* animate */));
-            } else {
-                // White
-                mMainHandler.post(
-                        () -> mLightBarController
-                                .setIconsDark(false /* dark */, true /* animate */));
-            }
-            cropBitmap.recycle();
-            hardBitmap.recycle();
-        }
-        scheduleColorAdaption();
     }
 
-    private void scheduleColorAdaption() {
-        mColorAdaptionHandler.removeCallbacksAndMessages(null);
-        if (!mRunning || !isEnabled(mNavigationBarView.getContext())) {
-            return;
+    private void requestUpdateSamplingListener() {
+        mHandler.removeCallbacks(mUpdateSamplingListener);
+        mHandler.post(mUpdateSamplingListener);
+    }
+
+    private void updateSamplingListener() {
+        if (mSamplingListenerRegistered) {
+            mSamplingListenerRegistered = false;
+            CompositionSamplingListener.unregister(mSamplingListener);
         }
-        mColorAdaptionHandler.postDelayed(this::updateTint, COLOR_ADAPTION_TIMEOUT);
+        if (mSamplingEnabled && !mSamplingBounds.isEmpty()
+                && mNavigationBarView.isAttachedToWindow()) {
+            if (!mNavigationBarView.getViewRootImpl().getSurfaceControl().isValid()) {
+                // The view may still be attached, but the surface backing the window can be
+                // destroyed, so wait until the next draw to update the listener again
+                mUpdateOnNextDraw = true;
+                return;
+            }
+            mSamplingListenerRegistered = true;
+            CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
+                    mNavigationBarView.getViewRootImpl().getSurfaceControl().getHandle(),
+                    mSamplingBounds);
+        }
+    }
+
+    private void updateTint(float medianLuma) {
+        mLastMediaLuma = medianLuma;
+        if (medianLuma > LUMINANCE_THRESHOLD) {
+            // Black
+            mLightBarController.setIconsDark(true /* dark */, true /* animate */);
+        } else {
+            // White
+            mLightBarController.setIconsDark(false /* dark */, true /* animate */);
+        }
+    }
+
+    void dump(PrintWriter pw) {
+        pw.println("NavBarTintController:");
+        pw.println("  navBar isAttached: " + mNavigationBarView.isAttachedToWindow());
+        pw.println("  navBar isScValid: " + (mNavigationBarView.isAttachedToWindow()
+                ? mNavigationBarView.getViewRootImpl().getSurfaceControl().isValid()
+                : "false"));
+        pw.println("  mSamplingListenerRegistered: " + mSamplingListenerRegistered);
+        pw.println("  mSamplingBounds: " + mSamplingBounds);
+        pw.println("  mLastMediaLuma: " + mLastMediaLuma);
     }
 
     public static boolean isEnabled(Context context) {
-        return Settings.Global.getInt(context.getContentResolver(),
-                NavigationPrototypeController.NAV_COLOR_ADAPT_ENABLE_SETTING, 0) == 1
-            && Settings.Global.getInt(context.getContentResolver(),
-                NavigationPrototypeController.SHOW_HOME_HANDLE_SETTING, 0) == 1;
+        return context.getDisplayId() == DEFAULT_DISPLAY
+                && Settings.Global.getInt(context.getContentResolver(),
+                        NavigationPrototypeController.NAV_COLOR_ADAPT_ENABLE_SETTING, 0) == 1
+                && Settings.Global.getInt(context.getContentResolver(),
+                        NavigationPrototypeController.SHOW_HOME_HANDLE_SETTING, 0) == 1;
     }
 }
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 b68c7c6..0978901 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -991,7 +991,7 @@
                     }
                 } else {
                     // Screen off disable it
-                    mNavigationBarView.getColorAdaptionController().end();
+                    mNavigationBarView.getColorAdaptionController().stop();
                 }
             }
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 2a38f77..faa2ab1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -63,7 +63,6 @@
     public static final String NAVSPACE = "space";
     public static final String CLIPBOARD = "clipboard";
     public static final String HOME_HANDLE = "home_handle";
-    public static final String ASSISTANT_HANDLE = "assistant_handle";
     public static final String KEY = "key";
     public static final String LEFT = "left";
     public static final String RIGHT = "right";
@@ -399,8 +398,6 @@
             v = inflater.inflate(R.layout.contextual, parent, false);
         } else if (HOME_HANDLE.equals(button)) {
             v = inflater.inflate(R.layout.home_handle, parent, false);
-        } else if (ASSISTANT_HANDLE.equals(button)) {
-            v = inflater.inflate(R.layout.assistant_handle, parent, false);
         } else if (button.startsWith(KEY)) {
             String uri = extractImage(button);
             int code = extractKeycode(button);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index b540fb4..18612c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -333,7 +333,7 @@
             if (enabled) {
                 mColorAdaptionController.start();
             } else {
-                mColorAdaptionController.end();
+                mColorAdaptionController.stop();
             }
         }
 
@@ -434,7 +434,6 @@
         mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
         mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
         mButtonDispatchers.put(R.id.home_handle, new ButtonDispatcher(R.id.home_handle));
-        mButtonDispatchers.put(R.id.assistant_handle, new ButtonDispatcher(R.id.assistant_handle));
         mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
         mButtonDispatchers.put(R.id.menu, menuButton);
         mButtonDispatchers.put(R.id.ime_switcher, imeSwitcherButton);
@@ -486,6 +485,12 @@
         }
     }
 
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        super.dispatchDraw(canvas);
+        mColorAdaptionController.onDraw();
+    }
+
     private void updateNavigationGestures() {
         if (mGestureHelper instanceof QuickStepController) {
             final int[] assignedMap = mPrototypeController.getGestureActionMap();
@@ -632,10 +637,6 @@
         return mButtonDispatchers.get(R.id.home_handle);
     }
 
-    public ButtonDispatcher getAssistantHandle() {
-        return mButtonDispatchers.get(R.id.assistant_handle);
-    }
-
     public SparseArray<ButtonDispatcher> getButtonDispatchers() {
         return mButtonDispatchers;
     }
@@ -990,7 +991,7 @@
         if (visible) {
             mColorAdaptionController.start();
         } else {
-            mColorAdaptionController.end();
+            mColorAdaptionController.stop();
         }
     }
 
@@ -1002,7 +1003,6 @@
     // TODO(b/112934365): move this back to NavigationBarFragment when prototype is removed
     private void updateAssistantAvailability() {
         boolean available = mAssistantAvailable && mPrototypeController.isAssistantGestureEnabled();
-        getAssistantHandle().setVisibility(available ? View.VISIBLE : View.GONE);
         if (mOverviewProxyService.getProxy() != null) {
             try {
                 mOverviewProxyService.getProxy().onAssistantAvailable(available);
@@ -1244,7 +1244,7 @@
         if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
             mColorAdaptionController.start();
         } else {
-            mColorAdaptionController.end();
+            mColorAdaptionController.stop();
         }
     }
 
@@ -1330,7 +1330,6 @@
         Dependency.get(PluginManager.class).addPluginListener(this,
                 NavGesture.class, false /* Only one */);
         setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
-        mColorAdaptionController.start();
 
         if (mPrototypeController.isEnabled()) {
             WindowManager wm = (WindowManager) getContext()
@@ -1363,7 +1362,6 @@
             mGestureHelper.destroy();
         }
         mPrototypeController.unregister();
-        mColorAdaptionController.stop();
         setUpSwipeUpOnboarding(false);
         for (int i = 0; i < mButtonDispatchers.size(); ++i) {
             mButtonDispatchers.valueAt(i).onDestroy();
@@ -1454,6 +1452,7 @@
             mGestureHelper.dump(pw);
         }
         mRecentsOnboarding.dump(pw);
+        mColorAdaptionController.dump(pw);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 142f398..babee53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -326,6 +326,14 @@
             Dependency.get(ShadeController.class);
     private int mDisplayId;
 
+    /**
+     * Cache the resource id of the theme to avoid unnecessary work in onThemeChanged.
+     *
+     * onThemeChanged is forced when the theme might not have changed. So, to avoid unncessary
+     * work, check the current id with the cached id.
+     */
+    private int mThemeResId;
+
     @Inject
     public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
             NotificationWakeUpCoordinator coordinator,
@@ -342,6 +350,7 @@
         mCommandQueue = getComponent(context, CommandQueue.class);
         mDisplayId = context.getDisplayId();
         mPulseExpansionHandler = pulseExpansionHandler;
+        mThemeResId = context.getThemeResId();
     }
 
     /**
@@ -390,6 +399,9 @@
         Dependency.get(StatusBarStateController.class).addCallback(this);
         Dependency.get(ZenModeController.class).addCallback(this);
         Dependency.get(ConfigurationController.class).addCallback(this);
+        // Theme might have changed between inflating this view and attaching it to the window, so
+        // force a call to onThemeChanged
+        onThemeChanged();
     }
 
     @Override
@@ -452,6 +464,12 @@
 
     @Override
     public void onThemeChanged() {
+        final int themeResId = getContext().getThemeResId();
+        if (mThemeResId == themeResId) {
+            return;
+        }
+        mThemeResId = themeResId;
+
         updateShowEmptyShadeView();
 
         // Re-inflate the status view group.
@@ -1217,6 +1235,12 @@
         setQsExpansion(height);
         requestPanelHeightUpdate();
         mNotificationStackScroller.checkSnoozeLeavebehind();
+
+        // When expanding QS, let's authenticate the user if possible,
+        // this will speed up notification actions.
+        if (height == 0) {
+            mStatusBar.requestFaceAuth();
+        }
     }
 
     private void setQsExpanded(boolean expanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
index a7b8eff..e887f5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java
@@ -83,6 +83,10 @@
     private final Stub mRotationWatcher = new Stub() {
         @Override
         public void onRotationChanged(final int rotation) throws RemoteException {
+            if (getCurrentView() == null) {
+                return;
+            }
+
             // We need this to be scheduled as early as possible to beat the redrawing of
             // window in response to the orientation change.
             Handler h = getCurrentView().getHandler();
@@ -235,7 +239,9 @@
 
         // If window rotation matches suggested rotation, remove any current suggestions
         if (rotation == windowRotation) {
-            getCurrentView().removeCallbacks(mRemoveRotationProposal);
+            if (getCurrentView() != null) {
+                getCurrentView().removeCallbacks(mRemoveRotationProposal);
+            }
             setRotateSuggestionButtonState(false /* visible */);
             return;
         }
@@ -259,9 +265,11 @@
             // If the navbar isn't shown, flag the rotate icon to be shown should the navbar become
             // visible given some time limit.
             mPendingRotationSuggestion = true;
-            getCurrentView().removeCallbacks(mCancelPendingRotationProposal);
-            getCurrentView().postDelayed(mCancelPendingRotationProposal,
-                    NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS);
+            if (getCurrentView() != null) {
+                getCurrentView().removeCallbacks(mCancelPendingRotationProposal);
+                getCurrentView().postDelayed(mCancelPendingRotationProposal,
+                        NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS);
+            }
         }
     }
 
@@ -328,7 +336,9 @@
     private void onRotationSuggestionsDisabled() {
         // Immediately hide the rotate button and clear any planned removal
         setRotateSuggestionButtonState(false /* visible */, true /* force */);
-        getCurrentView().removeCallbacks(mRemoveRotationProposal);
+        if (getCurrentView() != null) {
+            getCurrentView().removeCallbacks(mRemoveRotationProposal);
+        }
     }
 
     private void showAndLogRotationSuggestion() {
@@ -361,6 +371,10 @@
     }
 
     private void rescheduleRotationTimeout(final boolean reasonHover) {
+        if (getCurrentView() == null) {
+            return;
+        }
+
         // May be called due to a new rotation proposal or a change in hover state
         if (reasonHover) {
             // Don't reschedule if a hide animator is running
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 60b1659..8db0822 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -538,7 +538,7 @@
     private BatteryController mBatteryController;
     protected boolean mPanelExpanded;
     private UiModeManager mUiModeManager;
-    private boolean mIsKeyguard;
+    protected boolean mIsKeyguard;
     private LogMaker mStatusBarStateLog;
     protected NotificationIconAreaController mNotificationIconAreaController;
     @Nullable private View mAmbientIndicationContainer;
@@ -1315,6 +1315,15 @@
         mEntryManager.updateNotifications();
     }
 
+    /**
+     * Asks {@link KeyguardUpdateMonitor} to run face auth.
+     */
+    public void requestFaceAuth() {
+        if (!mUnlockMethodCache.canSkipBouncer()) {
+            mKeyguardUpdateMonitor.requestFaceAuth();
+        }
+    }
+
     public void updateAreThereNotifications() {
         if (SPEW) {
             final boolean clearable = hasActiveNotifications() &&
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index b0e006d..74c0018 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -248,7 +248,6 @@
             ActivityManager.getService().resumeAppSwitches();
         } catch (RemoteException e) {
         }
-        int launchResult;
         // If we are launching a work activity and require to launch
         // separate work challenge, we defer the activity action and cancel
         // notification until work challenge is unlocked.
@@ -277,24 +276,7 @@
             fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
                     remoteInputText.toString());
         }
-        RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(
-                row, wasOccluded);
-        try {
-            if (adapter != null) {
-                ActivityTaskManager.getService()
-                        .registerRemoteAnimationForNextActivityStart(
-                                intent.getCreatorPackage(), adapter);
-            }
-            launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
-                    null, null, getActivityOptions(adapter));
-            mActivityLaunchAnimator.setLaunchResult(launchResult, isActivityIntent);
-        } catch (RemoteException | PendingIntent.CanceledException e) {
-            // the stack trace isn't very helpful here.
-            // Just log the exception message.
-            Log.w(TAG, "Sending contentIntent failed: " + e);
-
-            // TODO: Dismiss Keyguard.
-        }
+        startNotificationIntent(intent, fillInIntent, row, wasOccluded, isActivityIntent);
         if (isActivityIntent) {
             mAssistManager.hideAssist();
         }
@@ -327,6 +309,27 @@
         mIsCollapsingToShowActivityOverLockscreen = false;
     }
 
+    private void startNotificationIntent(PendingIntent intent, Intent fillInIntent,
+            ExpandableNotificationRow row, boolean wasOccluded, boolean isActivityIntent) {
+        RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(row,
+                wasOccluded);
+        try {
+            if (adapter != null) {
+                ActivityTaskManager.getService()
+                        .registerRemoteAnimationForNextActivityStart(
+                                intent.getCreatorPackage(), adapter);
+            }
+            int launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
+                    null, null, getActivityOptions(adapter));
+            mActivityLaunchAnimator.setLaunchResult(launchResult, isActivityIntent);
+        } catch (RemoteException | PendingIntent.CanceledException e) {
+            // the stack trace isn't very helpful here.
+            // Just log the exception message.
+            Log.w(TAG, "Sending contentIntent failed: " + e);
+            // TODO: Dismiss Keyguard.
+        }
+    }
+
     @Override
     public void startNotificationGutsIntent(final Intent intent, final int appUid,
             ExpandableNotificationRow row) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
new file mode 100644
index 0000000..603c969
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+
+/**
+ * Manages what parts of the status bar are touchable. Clients are primarily UI that displays in the
+ * status bar even though the UI doesn't look like part of the status bar.
+ */
+public final class StatusBarTouchableRegionManager implements
+        OnComputeInternalInsetsListener, ConfigurationListener {
+
+    private final AssistManager mAssistManager = Dependency.get(AssistManager.class);
+    private final BubbleController mBubbleController = Dependency.get(BubbleController.class);
+    private final Context mContext;
+    private final HeadsUpManagerPhone mHeadsUpManager;
+    private boolean mIsStatusBarExpanded = false;
+    private boolean mShouldAdjustInsets = false;
+    private final StatusBar mStatusBar;
+    private int mStatusBarHeight;
+    private final View mStatusBarWindowView;
+    private boolean mForceCollapsedUntilLayout = false;
+
+    public StatusBarTouchableRegionManager(@NonNull Context context,
+                                           HeadsUpManagerPhone headsUpManager,
+                                           @NonNull StatusBar statusBar,
+                                           @NonNull View statusBarWindowView) {
+        mContext = context;
+        mHeadsUpManager = headsUpManager;
+        mStatusBar = statusBar;
+        mStatusBarWindowView = statusBarWindowView;
+
+        initResources();
+
+        mAssistManager.setAssistSysUiChangeListener((isVisible) -> {
+            updateTouchableRegion();
+        });
+        mBubbleController.setBubbleStateChangeListener((hasBubbles) -> {
+            updateTouchableRegion();
+        });
+        Dependency.get(ConfigurationController.class).addCallback(this);
+    }
+
+    /**
+     * Set the touchable portion of the status bar based on what elements are visible.
+     */
+    public void updateTouchableRegion() {
+        boolean hasCutoutInset = (mStatusBarWindowView != null)
+                && (mStatusBarWindowView.getRootWindowInsets() != null)
+                && (mStatusBarWindowView.getRootWindowInsets().getDisplayCutout() != null);
+        boolean shouldObserve =
+                mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpManager.isHeadsUpGoingAway()
+                        || mBubbleController.hasBubbles()
+                        || mAssistManager.hasAssistUi()
+                        || mForceCollapsedUntilLayout
+                        || hasCutoutInset;
+        if (shouldObserve == mShouldAdjustInsets) {
+            return;
+        }
+
+        if (shouldObserve) {
+            mStatusBarWindowView.getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+            mStatusBarWindowView.requestLayout();
+        } else {
+            mStatusBarWindowView.getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
+        }
+        mShouldAdjustInsets = shouldObserve;
+    }
+
+    /**
+     * Calls {@code updateTouchableRegion()} after a layout pass completes.
+     */
+    public void updateTouchableRegionAfterLayout() {
+        mForceCollapsedUntilLayout = true;
+        mStatusBarWindowView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+            @Override
+            public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                                       int oldLeft,
+                                       int oldTop, int oldRight, int oldBottom) {
+                if (mStatusBarWindowView.getHeight() <= mStatusBarHeight) {
+                    mStatusBarWindowView.removeOnLayoutChangeListener(this);
+                    mForceCollapsedUntilLayout = false;
+                    updateTouchableRegion();
+                }
+            }
+        });
+    }
+
+    /**
+     * Notify that the status bar panel gets expanded or collapsed.
+     *
+     * @param isExpanded True to notify expanded, false to notify collapsed.
+     */
+    public void setIsStatusBarExpanded(boolean isExpanded) {
+        if (isExpanded != mIsStatusBarExpanded) {
+            mIsStatusBarExpanded = isExpanded;
+            if (isExpanded) {
+                // make sure our state is sane
+                mForceCollapsedUntilLayout = false;
+            }
+            updateTouchableRegion();
+        }
+    }
+
+    @Override
+    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
+        if (mIsStatusBarExpanded || mStatusBar.isBouncerShowing()) {
+            // The touchable region is always the full area when expanded
+            return;
+        }
+
+        mHeadsUpManager.updateTouchableRegion(info);
+
+        Rect bubbleRect = mBubbleController.getTouchableRegion();
+        if (bubbleRect != null) {
+            info.touchableRegion.union(bubbleRect);
+        }
+
+        Rect assistRect = mAssistManager.getTouchableRegion();
+        if (assistRect != null) {
+            info.touchableRegion.union(assistRect);
+        }
+    }
+
+    @Override
+    public void onConfigChanged(Configuration newConfig) {
+        initResources();
+    }
+
+    @Override
+    public void onDensityOrFontScaleChanged() {
+        initResources();
+    }
+
+    @Override
+    public void onOverlayChanged() {
+        initResources();
+    }
+
+    private void initResources() {
+        Resources resources = mContext.getResources();
+        mStatusBarHeight = resources.getDimensionPixelSize(
+                com.android.internal.R.dimen.status_bar_height);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 4299af7..c2c3f81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -288,7 +288,7 @@
     @Override
     public void onTuningChanged(String key, String newValue) {
         if (CLOCK_SECONDS.equals(key)) {
-            mShowSeconds = newValue != null && Integer.parseInt(newValue) != 0;
+            mShowSeconds = TunerService.parseIntegerSwitch(newValue, false);
             updateShowSeconds();
         } else {
             setClockVisibleByUser(!StatusBarIconController.getIconBlacklist(newValue)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 0461057..d1a2253 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -26,8 +26,10 @@
 import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.view.accessibility.AccessibilityManager;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -55,9 +57,11 @@
     protected int mUser;
 
     private final ArrayMap<String, Long> mSnoozedPackages;
+    private final AccessibilityManagerWrapper mAccessibilityMgr;
 
     public HeadsUpManager(@NonNull final Context context) {
         mContext = context;
+        mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class);
         Resources resources = context.getResources();
         mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time);
         mAutoDismissNotificationDecay = resources.getInteger(R.integer.heads_up_notification_decay);
@@ -409,5 +413,22 @@
             // The actual post time will be just after the heads-up really slided in
             return super.calculatePostTime() + mTouchAcceptanceDelay;
         }
+
+        @Override
+        protected long calculateFinishTime() {
+            return mPostTime + getRecommendedTimeoutMillis();
+        }
+
+        /**
+         * Get user-preferred or default timeout duration. The larger one will be returned.
+         * @return milliseconds before auto-dismiss
+         */
+        private int getRecommendedTimeoutMillis() {
+            return mAccessibilityMgr.getRecommendedTimeoutMillis(
+                    mAutoDismissNotificationDecay,
+                    AccessibilityManager.FLAG_CONTENT_CONTROLS
+                            | AccessibilityManager.FLAG_CONTENT_ICONS
+                            | AccessibilityManager.FLAG_CONTENT_TEXT);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 3bccdab..338e178 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -107,4 +107,12 @@
         });
         dialog.show();
     }
+
+    public static boolean parseIntegerSwitch(String value, boolean defaultValue) {
+        try {
+            return value != null ? Integer.parseInt(value) != 0 : defaultValue;
+        } catch (NumberFormatException e) {
+            return defaultValue;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
index 2df9000..52b58d4 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
@@ -39,7 +39,7 @@
 
     @Override
     public void onTuningChanged(String key, String newValue) {
-        setChecked(newValue != null ? Integer.parseInt(newValue) != 0 : mDefault);
+        setChecked(TunerService.parseIntegerSwitch(newValue, mDefault));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 1596ddb..6e740b8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -55,6 +55,7 @@
     public static final int EVENT_RINGER_TOGGLE = 18; // (ringer_mode)
     public static final int EVENT_SHOW_USB_OVERHEAT_ALARM = 19; // (reason|int) (keyguard|bool)
     public static final int EVENT_DISMISS_USB_OVERHEAT_ALARM = 20; // (reason|int) (keyguard|bool)
+    public static final int EVENT_ODI_CAPTIONS_CLICK = 21;
 
     private static final String[] EVENT_TAGS = {
             "show_dialog",
@@ -77,7 +78,8 @@
             "zen_mode_config_changed",
             "ringer_toggle",
             "show_usb_overheat_alarm",
-            "dismiss_usb_overheat_alarm"
+            "dismiss_usb_overheat_alarm",
+            "odi_captions_click"
     };
 
     public static final int DISMISS_REASON_UNKNOWN = 0;
@@ -90,6 +92,7 @@
     public static final int DISMISS_STREAM_GONE = 7;
     public static final int DISMISS_REASON_OUTPUT_CHOOSER = 8;
     public static final int DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED = 9;
+    public static final int DISMISS_REASON_ODI_CAPTIONS_CLICKED = 10;
     public static final String[] DISMISS_REASONS = {
             "unknown",
             "touch_outside",
@@ -100,7 +103,8 @@
             "done_clicked",
             "a11y_stream_changed",
             "output_chooser",
-            "usb_temperature_below_threshold"
+            "usb_temperature_below_threshold",
+            "odi_captions_clicked"
     };
 
     public static final int SHOW_REASON_UNKNOWN = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 0805677..d2f185a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -101,28 +101,23 @@
 
     @Override
     public void onTuningChanged(String key, String newValue) {
+        boolean volumeDownToEnterSilent = mVolumePolicy.volumeDownToEnterSilent;
+        boolean volumeUpToExitSilent = mVolumePolicy.volumeUpToExitSilent;
+        boolean doNotDisturbWhenSilent = mVolumePolicy.doNotDisturbWhenSilent;
+
         if (VOLUME_DOWN_SILENT.equals(key)) {
-            final boolean volumeDownToEnterSilent = newValue != null
-                    ? Integer.parseInt(newValue) != 0
-                    : DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT;
-            setVolumePolicy(volumeDownToEnterSilent,
-                    mVolumePolicy.volumeUpToExitSilent, mVolumePolicy.doNotDisturbWhenSilent,
-                    mVolumePolicy.vibrateToSilentDebounce);
+            volumeDownToEnterSilent =
+                TunerService.parseIntegerSwitch(newValue, DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT);
         } else if (VOLUME_UP_SILENT.equals(key)) {
-            final boolean volumeUpToExitSilent = newValue != null
-                    ? Integer.parseInt(newValue) != 0
-                    : DEFAULT_VOLUME_UP_TO_EXIT_SILENT;
-            setVolumePolicy(mVolumePolicy.volumeDownToEnterSilent,
-                    volumeUpToExitSilent, mVolumePolicy.doNotDisturbWhenSilent,
-                    mVolumePolicy.vibrateToSilentDebounce);
+            volumeUpToExitSilent =
+                TunerService.parseIntegerSwitch(newValue, DEFAULT_VOLUME_UP_TO_EXIT_SILENT);
         } else if (VOLUME_SILENT_DO_NOT_DISTURB.equals(key)) {
-            final boolean doNotDisturbWhenSilent = newValue != null
-                    ? Integer.parseInt(newValue) != 0
-                    : DEFAULT_DO_NOT_DISTURB_WHEN_SILENT;
-            setVolumePolicy(mVolumePolicy.volumeDownToEnterSilent,
-                    mVolumePolicy.volumeUpToExitSilent, doNotDisturbWhenSilent,
-                    mVolumePolicy.vibrateToSilentDebounce);
+            doNotDisturbWhenSilent =
+                TunerService.parseIntegerSwitch(newValue, DEFAULT_DO_NOT_DISTURB_WHEN_SILENT);
         }
+
+        setVolumePolicy(volumeDownToEnterSilent, volumeUpToExitSilent, doNotDisturbWhenSilent,
+                mVolumePolicy.vibrateToSilentDebounce);
     }
 
     private void setVolumePolicy(boolean volumeDownToEnterSilent, boolean volumeUpToExitSilent,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 4c16297..9192a25 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -48,6 +48,7 @@
 import android.provider.Settings;
 import android.service.notification.Condition;
 import android.service.notification.ZenModeConfig;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.accessibility.AccessibilityManager;
@@ -270,6 +271,22 @@
         mWorker.sendEmptyMessage(W.GET_STATE);
     }
 
+    public boolean areCaptionsEnabled() {
+        int currentValue = Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.ODI_CAPTIONS_ENABLED, 0);
+        return currentValue == 1;
+    }
+
+    public void setCaptionsEnabled(boolean isEnabled) {
+        Settings.Secure.putInt(mContext.getContentResolver(),
+                Settings.Secure.ODI_CAPTIONS_ENABLED, isEnabled ? 1 : 0);
+    }
+
+    public void getCaptionsComponentState() {
+        if (mDestroyed) return;
+        mWorker.sendEmptyMessage(W.GET_CAPTIONS_COMPONENT_STATE);
+    }
+
     public void notifyVisible(boolean visible) {
         if (mDestroyed) return;
         mWorker.obtainMessage(W.NOTIFY_VISIBLE, visible ? 1 : 0, 0).sendToTarget();
@@ -365,6 +382,38 @@
         }
     }
 
+    private void onGetCaptionsComponentStateW() {
+        try {
+            String componentNameString = mContext.getString(
+                    com.android.internal.R.string.config_defaultSystemCaptionsService);
+            if (TextUtils.isEmpty(componentNameString)) {
+                // component doesn't exist
+                mCallbacks.onCaptionComponentStateChanged(false);
+                return;
+            }
+
+            if (D.BUG) {
+                Log.i(TAG, String.format(
+                        "isCaptionsServiceEnabled componentNameString=%s", componentNameString));
+            }
+
+            ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
+            if (componentName == null) {
+                mCallbacks.onCaptionComponentStateChanged(false);
+                return;
+            }
+
+            PackageManager packageManager = mContext.getPackageManager();
+            mCallbacks.onCaptionComponentStateChanged(
+                    packageManager.getComponentEnabledSetting(componentName)
+                    == PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+        } catch (Exception ex) {
+            Log.e(TAG,
+                    "isCaptionsServiceEnabled failed to check for captions component", ex);
+            mCallbacks.onCaptionComponentStateChanged(false);
+        }
+    }
+
     private void onAccessibilityModeChanged(Boolean showA11yStream) {
         mCallbacks.onAccessibilityModeChanged(showA11yStream);
     }
@@ -718,6 +767,7 @@
         private static final int USER_ACTIVITY = 13;
         private static final int SHOW_SAFETY_WARNING = 14;
         private static final int ACCESSIBILITY_MODE_CHANGED = 15;
+        private static final int GET_CAPTIONS_COMPONENT_STATE = 16;
 
         W(Looper looper) {
             super(looper);
@@ -740,8 +790,8 @@
                 case NOTIFY_VISIBLE: onNotifyVisibleW(msg.arg1 != 0); break;
                 case USER_ACTIVITY: onUserActivityW(); break;
                 case SHOW_SAFETY_WARNING: onShowSafetyWarningW(msg.arg1); break;
+                case GET_CAPTIONS_COMPONENT_STATE: onGetCaptionsComponentStateW(); break;
                 case ACCESSIBILITY_MODE_CHANGED: onAccessibilityModeChanged((Boolean) msg.obj);
-
             }
         }
     }
@@ -881,6 +931,15 @@
                 });
             }
         }
+
+        @Override
+        public void onCaptionComponentStateChanged(Boolean isComponentEnabled) {
+            boolean componentEnabled = isComponentEnabled == null ? false : isComponentEnabled;
+            for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
+                entry.getValue().post(
+                        () -> entry.getKey().onCaptionComponentStateChanged(componentEnabled));
+            }
+        }
     }
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index ffd8206..398b309 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -29,6 +29,7 @@
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
 
+import static com.android.systemui.volume.Events.DISMISS_REASON_ODI_CAPTIONS_CLICKED;
 import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
 
 import android.animation.ObjectAnimator;
@@ -125,6 +126,8 @@
     private ViewGroup mDialogRowsView;
     private ViewGroup mRinger;
     private ImageButton mRingerIcon;
+    private ViewGroup mODICaptionsView;
+    private ImageButton mODICaptionsIcon;
     private View mSettingsView;
     private ImageButton mSettingsIcon;
     private FrameLayout mZenIcon;
@@ -240,6 +243,10 @@
             mRingerIcon = mRinger.findViewById(R.id.ringer_icon);
             mZenIcon = mRinger.findViewById(R.id.dnd_icon);
         }
+        mODICaptionsView = mDialog.findViewById(R.id.odi_captions);
+        if (mODICaptionsView != null) {
+            mODICaptionsIcon = mODICaptionsView.findViewById(R.id.odi_captions_icon);
+        }
         mSettingsView = mDialog.findViewById(R.id.settings_container);
         mSettingsIcon = mDialog.findViewById(R.id.settings);
 
@@ -270,6 +277,7 @@
         updateRowsH(getActiveRow());
         initRingerH();
         initSettingsH();
+        initODICaptionsH();
     }
 
     protected ViewGroup getDialogView() {
@@ -478,6 +486,42 @@
         updateRingerH();
     }
 
+    private void initODICaptionsH() {
+        if (mODICaptionsIcon != null) {
+            mODICaptionsIcon.setOnClickListener(v -> {
+                onCaptionIconClicked();
+                Events.writeEvent(mContext, Events.EVENT_ODI_CAPTIONS_CLICK);
+                dismissH(DISMISS_REASON_ODI_CAPTIONS_CLICKED);
+            });
+        }
+
+        mController.getCaptionsComponentState();
+    }
+
+    private void updateODICaptionsH(boolean isServiceComponentEnabled) {
+        if (mODICaptionsView != null) {
+            mODICaptionsView.setVisibility(isServiceComponentEnabled ? VISIBLE : GONE);
+        }
+
+        if (!isServiceComponentEnabled) return;
+
+        updateCaptionsIcon();
+    }
+
+    private void updateCaptionsIcon() {
+        mHandler.post(
+                mODICaptionsIcon.setImageResourceAsync(
+                        mController.areCaptionsEnabled()
+                                ? R.drawable.ic_volume_odi_captions
+                                : R.drawable.ic_volume_odi_captions_disabled));
+    }
+
+    private void onCaptionIconClicked() {
+        boolean isEnabled = mController.areCaptionsEnabled();
+        mController.setCaptionsEnabled(!isEnabled);
+        updateCaptionsIcon();
+    }
+
     private void incrementManualToggleCount() {
         ContentResolver cr = mContext.getContentResolver();
         int ringerCount = Settings.Secure.getInt(cr, Settings.Secure.MANUAL_RINGER_TOGGLE_COUNT, 0);
@@ -558,6 +602,7 @@
         mDialog.show();
         Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
         mController.notifyVisible(true);
+        mController.getCaptionsComponentState();
     }
 
     protected void rescheduleTimeoutH() {
@@ -1151,6 +1196,11 @@
             }
 
         }
+
+        @Override
+        public void onCaptionComponentStateChanged(Boolean isComponentEnabled) {
+            updateODICaptionsH(isComponentEnabled);
+        }
     };
 
     private final class H extends Handler {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 42c221a..4e9d892 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -329,10 +329,10 @@
     }
 
     static class TestableBubbleController extends BubbleController {
-
+        // Let's assume surfaces can be synchronized immediately.
         TestableBubbleController(Context context,
                 StatusBarWindowController statusBarWindowController, BubbleData data) {
-            super(context, statusBarWindowController, data);
+            super(context, statusBarWindowController, data, Runnable::run);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
index 4ba2858..df014a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
@@ -202,4 +202,16 @@
 
         verify(mMachine).requestState(eq(State.DOZE));
     }
+
+    @Test
+    public void testTransitionToPulsing_whenDockedHide_requestPulseOut() {
+        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
+        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_PULSING);
+        when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_DOCKING);
+        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
+
+        mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, State.DOZE_PULSING);
+
+        verify(mHost).stopPulsing();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 7797cb3..7bd4158 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -19,8 +19,10 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.when;
 
+import android.content.Context;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.View;
@@ -31,6 +33,7 @@
 import com.android.systemui.statusbar.AlertingNotificationManagerTest;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -53,15 +56,29 @@
     @Mock private VisualStabilityManager mVSManager;
     @Mock private StatusBar mBar;
 
+    private final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
+        TestableHeadsUpManagerPhone(Context context, View statusBarWindowView,
+                NotificationGroupManager groupManager, StatusBar bar,
+                VisualStabilityManager vsManager) {
+            super(context, statusBarWindowView, groupManager, bar, vsManager);
+            mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
+            mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
+        }
+    }
+
     protected AlertingNotificationManager createAlertingNotificationManager() {
         return mHeadsUpManager;
     }
 
     @Before
     public void setUp() {
+        AccessibilityManagerWrapper mAccessibilityMgr =
+                mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
+        when(mAccessibilityMgr.getRecommendedTimeoutMillis(anyInt(), anyInt()))
+                .thenReturn(TEST_AUTO_DISMISS_TIME);
         when(mVSManager.isReorderingAllowed()).thenReturn(true);
-        mHeadsUpManager = new HeadsUpManagerPhone(mContext, mStatusBarWindowView, mGroupManager,
-                mBar, mVSManager);
+        mHeadsUpManager = new TestableHeadsUpManagerPhone(mContext, mStatusBarWindowView,
+                mGroupManager, mBar, mVSManager);
         super.setUp();
         mHeadsUpManager.mHandler = mTestHandler;
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
new file mode 100644
index 0000000..6b83fed
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.statusbar.AlertingNotificationManager;
+import com.android.systemui.statusbar.AlertingNotificationManagerTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
+    private static final int TEST_A11Y_AUTO_DISMISS_TIME = 600;
+    private static final int TEST_A11Y_TIMEOUT_TIME = 5_000;
+
+    private AccessibilityManagerWrapper mAccessibilityMgr;
+    private HeadsUpManager mHeadsUpManager;
+    private boolean mLivesPastNormalTime;
+
+    private final class TestableHeadsUpManager extends HeadsUpManager {
+        TestableHeadsUpManager(Context context) {
+            super(context);
+            mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
+            mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
+        }
+    }
+
+    protected AlertingNotificationManager createAlertingNotificationManager() {
+        return mHeadsUpManager;
+    }
+
+    @Before
+    public void setUp() {
+        mAccessibilityMgr = mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
+
+        mHeadsUpManager = new TestableHeadsUpManager(mContext);
+        super.setUp();
+        mHeadsUpManager.mHandler = mTestHandler;
+    }
+
+    @Test
+    public void testShowNotification_autoDismissesWithAccessibilityTimeout() {
+        doReturn(TEST_A11Y_AUTO_DISMISS_TIME).when(mAccessibilityMgr)
+                .getRecommendedTimeoutMillis(anyInt(), anyInt());
+        mHeadsUpManager.showNotification(mEntry);
+        Runnable pastNormalTimeRunnable =
+                () -> mLivesPastNormalTime = mHeadsUpManager.isAlerting(mEntry.key);
+        mTestHandler.postDelayed(pastNormalTimeRunnable,
+                        (TEST_A11Y_AUTO_DISMISS_TIME + TEST_AUTO_DISMISS_TIME) / 2);
+        mTestHandler.postDelayed(TEST_TIMEOUT_RUNNABLE, TEST_A11Y_TIMEOUT_TIME);
+
+        TestableLooper.get(this).processMessages(2);
+
+        assertFalse("Test timed out", mTimedOut);
+        assertTrue("Heads up should live long enough", mLivesPastNormalTime);
+        assertFalse(mHeadsUpManager.isAlerting(mEntry.key));
+    }
+}
+
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 16d8e95..ffbf1ae 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -226,6 +226,10 @@
     // Inform that user that the USB port is free of contaminants.
     NOTE_USB_CONTAMINANT_NOT_DETECTED = 53;
 
+    // Inform the user that Test Harness Mode is active.
+    // Package: android
+    NOTE_TEST_HARNESS_MODE_ENABLED = 54;
+
     // ADD_NEW_IDS_ABOVE_THIS_LINE
     // Legacy IDs with arbitrary values appear below
     // Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index a19a847..3bd6220 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -91,7 +91,8 @@
         if (userState == null) return;
         final long identity = Binder.clearCallingIdentity();
         try {
-            int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE;
+            int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+                    | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS;
             if (userState.getBindInstantServiceAllowed()) {
                 flags |= Context.BIND_ALLOW_INSTANT;
             }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 0e852f8..6597312 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -38,6 +38,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.graphics.Rect;
 import android.os.Binder;
@@ -189,6 +190,16 @@
         final IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         context.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler());
+
+        if (mSupportedSmartSuggestionModes != AutofillManager.FLAG_SMART_SUGGESTION_OFF) {
+            // Must eager load the services so they bind to the augmented autofill service
+            final UserManager um = getContext().getSystemService(UserManager.class);
+            final List<UserInfo> users = um.getUsers();
+            for (int i = 0; i < users.size(); i++) {
+                final int userId = users.get(i).id;
+                getServiceForUserLocked(userId);
+            }
+        }
     }
 
     @Override // from AbstractMasterSystemService
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index f5f26a3..9612346 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -194,7 +194,7 @@
         mAugmentedAutofillResolver = new FrameworkResourcesServiceNameResolver(master.getContext(),
                 com.android.internal.R.string.config_defaultAugmentedAutofillService);
         mAugmentedAutofillResolver.setOnTemporaryServiceNameChangedCallback(
-                (u, s) -> updateRemoteAugmentedAutofillService(s));
+                (u, s) -> updateRemoteAugmentedAutofillService());
 
         updateLocked(disabled);
     }
@@ -223,6 +223,7 @@
             }
             sendStateToClients(false);
         }
+        updateRemoteAugmentedAutofillService();
         return enabledChanged;
     }
 
@@ -298,7 +299,8 @@
             final IAutoFillManagerClient client = IAutoFillManagerClient.Stub
                     .asInterface(appCallbackToken);
             try {
-                client.setSessionFinished(AutofillManager.STATE_DISABLED_BY_SERVICE);
+                client.setSessionFinished(AutofillManager.STATE_DISABLED_BY_SERVICE,
+                        /* autofillableIds= */ null);
             } catch (RemoteException e) {
                 Slog.w(TAG, "Could not notify " + shortComponentName + " that it's disabled: " + e);
             }
@@ -1093,7 +1095,7 @@
     /**
      * Called when the {@link #mAugmentedAutofillResolver} changed (among other places).
      */
-    private void updateRemoteAugmentedAutofillService(@Nullable String serviceName) {
+    void updateRemoteAugmentedAutofillService() {
         synchronized (mLock) {
             if (mRemoteAugmentedAutofillService != null) {
                 if (sVerbose) {
@@ -1105,7 +1107,9 @@
                 mRemoteAugmentedAutofillServiceInfo = null;
             }
 
-            mRemoteAugmentedAutofillService = getRemoteAugmentedAutofillServiceLocked();
+            if (isEnabledLocked()) {
+                mRemoteAugmentedAutofillService = getRemoteAugmentedAutofillServiceLocked();
+            }
         }
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 3c0da7d..3d392c7 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -20,12 +20,14 @@
 import android.annotation.Nullable;
 import android.app.assist.AssistStructure;
 import android.app.assist.AssistStructure.ViewNode;
+import android.app.assist.AssistStructure.WindowNode;
 import android.content.ComponentName;
 import android.metrics.LogMaker;
 import android.service.autofill.Dataset;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
+import android.view.View;
 import android.view.WindowManager;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
@@ -205,6 +207,32 @@
         }
     }
 
+    /**
+     * Gets the {@link AutofillId} of the autofillable nodes in the {@code structure}.
+     */
+    @NonNull
+    static ArraySet<AutofillId> getAutofillableIds(@NonNull AssistStructure structure) {
+        final ArraySet<AutofillId> ids = new ArraySet<>();
+        final int size = structure.getWindowNodeCount();
+        for (int i = 0; i < size; i++) {
+            final WindowNode node = structure.getWindowNodeAt(i);
+            addAutofillableIds(node.getRootViewNode(), ids);
+        }
+        return ids;
+    }
+
+    private static void addAutofillableIds(@NonNull ViewNode node,
+            @NonNull ArraySet<AutofillId> ids) {
+        if (node.getAutofillType() != View.AUTOFILL_TYPE_NONE) {
+            ids.add(node.getAutofillId());
+        }
+        final int size = node.getChildCount();
+        for (int i = 0; i < size; i++) {
+            final ViewNode child = node.getChildAt(i);
+            addAutofillableIds(child, ids);
+        }
+    }
+
     private interface ViewNodeFilter {
         boolean matches(ViewNode node);
     }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 7fbfc42..ea47033 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -26,6 +26,7 @@
 import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
 import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
 import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
+import static android.view.autofill.Helper.toList;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 import static com.android.server.autofill.Helper.getNumericValue;
@@ -266,6 +267,15 @@
     @GuardedBy("mLock")
     private ArrayList<LogMaker> mAugmentedRequestsLogs;
 
+
+    /**
+     * List of autofill ids of autofillable fields present in the AssistStructure that can be used
+     * to trigger new augmented autofill requests (because the "standard" service was not interested
+     * on autofilling the app.
+     */
+    @GuardedBy("mLock")
+    private ArraySet<AutofillId> mAugmentedAutofillableIds;
+
     /**
      * Receiver of assist data from the app's {@link Activity}.
      */
@@ -699,14 +709,14 @@
                 if (requestLog != null) {
                     requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1);
                 }
-                processNullResponseLocked(requestFlags);
+                processNullResponseLocked(requestId, requestFlags);
                 return;
             }
 
             fieldClassificationIds = response.getFieldClassificationIds();
             if (fieldClassificationIds != null && !mService.isFieldClassificationEnabledLocked()) {
                 Slog.w(TAG, "Ignoring " + response + " because field detection is disabled");
-                processNullResponseLocked(requestFlags);
+                processNullResponseLocked(requestId, requestFlags);
                 return;
             }
         }
@@ -739,7 +749,7 @@
                         && response.getAuthentication() == null)
                 || disableDuration > 0) {
             // Response is "empty" from an UI point of view, need to notify client.
-            notifyUnavailableToClient(sessionFinishedState);
+            notifyUnavailableToClient(sessionFinishedState, /* autofillableIds= */ null);
         }
 
         if (requestLog != null) {
@@ -802,7 +812,8 @@
                 }
             }
         }
-        notifyUnavailableToClient(AutofillManager.STATE_UNKNOWN_FAILED);
+        notifyUnavailableToClient(AutofillManager.STATE_UNKNOWN_FAILED,
+                /* autofillableIds= */ null);
         if (showMessage) {
             getUiForShowing().showError(message, this);
         }
@@ -1131,7 +1142,7 @@
             }
             logAuthenticationStatusLocked(requestId,
                     MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION);
-            processNullResponseLocked(0);
+            processNullResponseLocked(requestId, 0);
         }
     }
 
@@ -2326,12 +2337,28 @@
                     return;
                 }
 
+                if (mAugmentedAutofillableIds != null && mAugmentedAutofillableIds.contains(id)) {
+                    // View was already reported when server could not handle a response, but it
+                    // triggered augmented autofill
+
+                    if (sDebug) Slog.d(TAG, "updateLocked(" + id + "): augmented-autofillable");
+
+                    // Update the view states first...
+                    mCurrentViewId = viewState.id;
+                    viewState.setCurrentValue(value);
+
+                    // ...then trigger the augmented autofill UI
+                    triggerAugmentedAutofillLocked();
+                    return;
+                }
+
                 requestNewFillResponseOnViewEnteredIfNecessaryLocked(id, viewState, flags);
 
                 // Remove the UI if the ViewState has changed.
                 if (!Objects.equals(mCurrentViewId, viewState.id)) {
                     mUi.hideFillUi(this);
                     mCurrentViewId = viewState.id;
+                    hideAugmentedAutofillLocked(viewState);
                 }
 
                 // If the ViewState is ready to be displayed, onReady() will be called.
@@ -2339,8 +2366,9 @@
                 break;
             case ACTION_VIEW_EXITED:
                 if (Objects.equals(mCurrentViewId, viewState.id)) {
-                    if (sVerbose) Slog.d(TAG, "Exiting view " + id);
+                    if (sVerbose) Slog.v(TAG, "Exiting view " + id);
                     mUi.hideFillUi(this);
+                    hideAugmentedAutofillLocked(viewState);
                     mCurrentViewId = null;
                 }
                 break;
@@ -2349,6 +2377,15 @@
         }
     }
 
+    @GuardedBy("mLock")
+    private void hideAugmentedAutofillLocked(@NonNull ViewState viewState) {
+        if ((viewState.getState()
+                & ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL) != 0) {
+            viewState.resetState(ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL);
+            cancelAugmentedAutofillLocked();
+        }
+    }
+
     /**
      * Checks whether a view should be ignored.
      */
@@ -2428,14 +2465,15 @@
         }
     }
 
-    private void notifyUnavailableToClient(int sessionFinishedState) {
+    private void notifyUnavailableToClient(int sessionFinishedState,
+            @Nullable ArraySet<AutofillId> autofillableIds) {
         synchronized (mLock) {
             if (mCurrentViewId == null) return;
             try {
                 if (mHasCallback) {
                     mClient.notifyNoFillUi(id, mCurrentViewId, sessionFinishedState);
                 } else if (sessionFinishedState != 0) {
-                    mClient.setSessionFinished(sessionFinishedState);
+                    mClient.setSessionFinished(sessionFinishedState, toList(autofillableIds));
                 }
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error notifying client no fill UI: id=" + mCurrentViewId, e);
@@ -2551,10 +2589,22 @@
     }
 
     @GuardedBy("mLock")
-    private void processNullResponseLocked(int flags) {
+    private void processNullResponseLocked(int requestId, int flags) {
         if ((flags & FLAG_MANUAL_REQUEST) != 0) {
             getUiForShowing().showError(R.string.autofill_error_cannot_autofill, this);
         }
+
+        final FillContext context = getFillContextByRequestIdLocked(requestId);
+
+        final ArraySet<AutofillId> autofillableIds;
+        if (context != null) {
+            final AssistStructure structure = context.getStructure();
+            autofillableIds = Helper.getAutofillableIds(structure);
+        } else {
+            Slog.w(TAG, "processNullResponseLocked(): no context for req " + requestId);
+            autofillableIds = null;
+        }
+
         mService.resetLastResponse();
 
         // The default autofill service cannot fullfill the request, let's check if the augmented
@@ -2563,19 +2613,18 @@
         if (mAugmentedAutofillDestroyer == null) {
             if (sVerbose) {
                 Slog.v(TAG, "canceling session " + id + " when server returned null and there is no"
-                        + " AugmentedAutofill for user");
+                        + " AugmentedAutofill for user. AutofillableIds: " + autofillableIds);
             }
             // Nothing to be done, but need to notify client.
-            notifyUnavailableToClient(AutofillManager.STATE_FINISHED);
+            notifyUnavailableToClient(AutofillManager.STATE_FINISHED, autofillableIds);
             removeSelf();
         } else {
-            // TODO(b/123099468, b/119638958): must set internal state so when user focus other
-            // fields it does not generate a new call to the standard autofill service (right now
-            // it does). Must also add CTS tests to exercise this scenario.
             if (sVerbose) {
                 Slog.v(TAG, "keeping session " + id + " when server returned null but "
-                        + "there is an AugmentedAutofill for user");
+                        + "there is an AugmentedAutofill for user. AutofillableIds: "
+                        + autofillableIds);
             }
+            mAugmentedAutofillableIds = autofillableIds;
         }
     }
 
@@ -2643,7 +2692,9 @@
             return null;
         }
 
-        final AutofillValue currentValue = mViewStates.get(mCurrentViewId).getCurrentValue();
+        final ViewState viewState = mViewStates.get(mCurrentViewId);
+        viewState.setState(ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL);
+        final AutofillValue currentValue = viewState.getCurrentValue();
 
         // TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize
         // further AFM -> AFMS calls.
@@ -2665,6 +2716,18 @@
     }
 
     @GuardedBy("mLock")
+    private void cancelAugmentedAutofillLocked() {
+        final RemoteAugmentedAutofillService remoteService = mService
+                .getRemoteAugmentedAutofillServiceLocked();
+        if (remoteService == null) {
+            Slog.w(TAG, "cancelAugmentedAutofillLocked(): no service for user");
+            return;
+        }
+        if (sVerbose) Slog.v(TAG, "cancelAugmentedAutofillLocked() on " + mCurrentViewId);
+        remoteService.onDestroyAutofillWindowsRequest();
+    }
+
+    @GuardedBy("mLock")
     private void processResponseLocked(@NonNull FillResponse newResponse,
             @Nullable Bundle newClientState, int flags) {
         // Make sure we are hiding the UI which will be shown
@@ -2950,6 +3013,10 @@
             pw.println(mAugmentedRequestsLogs.size());
         }
 
+        if (mAugmentedAutofillableIds != null) {
+            pw.print(prefix); pw.print("mAugmentedAutofillableIds: ");
+            pw.println(mAugmentedAutofillableIds);
+        }
         mRemoteFillService.dump(prefix, pw);
     }
 
@@ -3134,7 +3201,7 @@
         mUi.destroyAll(mPendingSaveUi, this, false);
         if (!isPendingSaveUi) {
             try {
-                mClient.setSessionFinished(clientState);
+                mClient.setSessionFinished(clientState, /* autofillableIds= */ null);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error notifying client to finish session", e);
             }
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 2cc6d20..33a2e50 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -17,6 +17,7 @@
 package com.android.server.autofill;
 
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
+
 import static com.android.server.autofill.Helper.sDebug;
 
 import android.annotation.NonNull;
@@ -47,8 +48,6 @@
 
     private static final String TAG = "ViewState";
 
-    // NOTE: state constants must be public because of flagstoString().
-    public static final int STATE_UNKNOWN = 0x000;
     /** Initial state. */
     public static final int STATE_INITIAL = 0x001;
     /** View id is present in a dataset returned by the service. */
@@ -73,6 +72,8 @@
     public static final int STATE_AUTOFILL_FAILED = 0x400;
     /** View has been autofilled at least once. */
     public static final int STATE_AUTOFILLED_ONCE = 0x800;
+    /** View triggered the latest augmented autofill request. */
+    public static final int STATE_TRIGGERED_AUGMENTED_AUTOFILL = 0x1000;
 
     public final AutofillId id;
 
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index 836a5e8..56eacc0 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -41,6 +41,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.backup.BackupAgentTimeoutParameters;
@@ -120,6 +121,7 @@
 
     // Pipes for moving data
     private ParcelFileDescriptor[] mPipes = null;
+    private final Object mPipesLock = new Object();
 
     // Widget blob to be restored out-of-band
     private byte[] mWidgetData = null;
@@ -129,6 +131,8 @@
 
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
     final boolean mIsAdbRestore;
+    @GuardedBy("mPipesLock")
+    private boolean mPipesClosed;
 
     public FullRestoreEngine(UserBackupManagerService backupManagerService,
             BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer,
@@ -578,24 +582,26 @@
     }
 
     private void setUpPipes() throws IOException {
-        mPipes = ParcelFileDescriptor.createPipe();
+        synchronized (mPipesLock) {
+            mPipes = ParcelFileDescriptor.createPipe();
+            mPipesClosed = false;
+        }
     }
 
     private void tearDownPipes() {
         // Teardown might arise from the inline restore processing or from the asynchronous
         // timeout mechanism, and these might race.  Make sure we don't try to close and
         // null out the pipes twice.
-        synchronized (this) {
-            if (mPipes != null) {
+        synchronized (mPipesLock) {
+            if (!mPipesClosed && mPipes != null) {
                 try {
                     mPipes[0].close();
-                    mPipes[0] = null;
                     mPipes[1].close();
-                    mPipes[1] = null;
+
+                    mPipesClosed = true;
                 } catch (IOException e) {
                     Slog.w(TAG, "Couldn't close agent pipes", e);
                 }
-                mPipes = null;
             }
         }
     }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index c75b4c6..9995d8e 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -115,7 +115,7 @@
     public ContentCaptureManagerService(@NonNull Context context) {
         super(context, new FrameworkResourcesServiceNameResolver(context,
                 com.android.internal.R.string.config_defaultContentCaptureService),
-                UserManager.DISALLOW_CONTENT_CAPTURE);
+                UserManager.DISALLOW_CONTENT_CAPTURE, /* refreshServiceOnPackageUpdate=*/ false);
         DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
                 ActivityThread.currentApplication().getMainExecutor(),
                 (namespace, key, value) -> onDeviceConfigChange(key, value));
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index feb1ac1..c423f9c 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -100,6 +100,13 @@
     @GuardedBy("mLock")
     private final WhitelistHelper mWhitelistHelper = new WhitelistHelper();
 
+    /**
+     * When {@code true}, remote service died but service state is kept so it's restored after
+     * the system re-binds to it.
+     */
+    @GuardedBy("mLock")
+    private boolean mZombie;
+
     // TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's
 
     ContentCapturePerUserService(@NonNull ContentCaptureManagerService master,
@@ -179,6 +186,37 @@
     public void onServiceDied(@NonNull RemoteContentCaptureService service) {
         // Don't do anything; eventually the system will bind to it again...
         Slog.w(TAG, "remote service died: " + service);
+        synchronized (mLock) {
+            mZombie = true;
+        }
+    }
+
+    /**
+     * Called after the remote service connected, it's used to restore state from a 'zombie'
+     * service (i.e., after it died).
+     */
+    void onConnected() {
+        synchronized (mLock) {
+            if (mZombie) {
+                // Sanity check - shouldn't happen
+                if (mRemoteService == null) {
+                    Slog.w(TAG, "Cannot ressurect sessions because remote service is null");
+                    return;
+                }
+
+                mZombie = false;
+                final int numSessions = mSessions.size();
+                if (mMaster.debug) {
+                    Slog.d(TAG, "Ressurrecting remote service (" + mRemoteService + ") on "
+                            + numSessions + " sessions");
+                }
+
+                for (int i = 0; i < numSessions; i++) {
+                    final ContentCaptureServerSession session = mSessions.valueAt(i);
+                    session.resurrectLocked();
+                }
+            }
+        }
     }
 
     // TODO(b/119613670): log metrics
@@ -260,7 +298,7 @@
         }
 
         final ContentCaptureServerSession newSession = new ContentCaptureServerSession(
-                activityToken, this, mRemoteService, componentName, taskId,
+                activityToken, this, mRemoteService, componentName, clientReceiver, taskId,
                 displayId, sessionId, uid, flags);
         if (mMaster.verbose) {
             Slog.v(TAG, "startSession(): new session for "
@@ -389,6 +427,9 @@
     @GuardedBy("mLock")
     public void destroyLocked() {
         if (mMaster.debug) Slog.d(TAG, "destroyLocked()");
+        if (mRemoteService != null) {
+            mRemoteService.destroy();
+        }
         destroySessionsLocked();
     }
 
@@ -449,6 +490,8 @@
     protected void dumpLocked(String prefix, PrintWriter pw) {
         super.dumpLocked(prefix, pw);
 
+        pw.print(prefix); pw.print("Zombie: "); pw.println(mZombie);
+
         final String prefix2 = prefix + "  ";
         if (mRemoteService != null) {
             pw.print(prefix); pw.println("remote service:");
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index 4094843..da19836 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -23,6 +23,7 @@
 import android.util.LocalLog;
 import android.util.Slog;
 import android.view.contentcapture.ContentCaptureContext;
+import android.view.contentcapture.ContentCaptureSession;
 import android.view.contentcapture.ContentCaptureSessionId;
 
 import com.android.internal.annotations.GuardedBy;
@@ -44,6 +45,12 @@
     private final ContentCaptureContext mContentCaptureContext;
 
     /**
+     * Reference to the binder object help at the client-side process and used to set its state.
+     */
+    @NonNull
+    private final IResultReceiver mSessionStateReceiver;
+
+    /**
      * Canonical session id.
      */
     private final String mId;
@@ -56,7 +63,7 @@
     ContentCaptureServerSession(@NonNull IBinder activityToken,
             @NonNull ContentCapturePerUserService service,
             @NonNull RemoteContentCaptureService remoteService,
-            @NonNull ComponentName appComponentName,
+            @NonNull ComponentName appComponentName, @NonNull IResultReceiver sessionStateReceiver,
             int taskId, int displayId, @NonNull String sessionId, int uid, int flags) {
         mActivityToken = activityToken;
         mService = service;
@@ -65,6 +72,7 @@
         mRemoteService = remoteService;
         mContentCaptureContext = new ContentCaptureContext(/* clientContext= */ null,
                 appComponentName, taskId, displayId, flags);
+        mSessionStateReceiver = sessionStateReceiver;
     }
 
     /**
@@ -79,7 +87,8 @@
      */
     @GuardedBy("mLock")
     public void notifySessionStartedLocked(@NonNull IResultReceiver clientReceiver) {
-        mRemoteService.onSessionStarted(mContentCaptureContext, mId, mUid, clientReceiver);
+        mRemoteService.onSessionStarted(mContentCaptureContext, mId, mUid, clientReceiver,
+                ContentCaptureSession.STATE_ACTIVE);
     }
 
     /**
@@ -129,6 +138,17 @@
         }
     }
 
+    /**
+     * Called to restore the active state of a session that was paused while the service died.
+     */
+    @GuardedBy("mLock")
+    public void resurrectLocked() {
+        mRemoteService.onSessionStarted(new ContentCaptureContext(mContentCaptureContext,
+                ContentCaptureContext.FLAG_RECONNECTED), mId, mUid, mSessionStateReceiver,
+                ContentCaptureSession.STATE_ACTIVE
+                        | ContentCaptureSession.STATE_SERVICE_RESURRECTED);
+    }
+
     @GuardedBy("mLock")
     public void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
         pw.print(prefix); pw.print("id: ");  pw.print(mId); pw.println();
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index 1d2d625..2ce5059 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -40,14 +40,16 @@
 
     private final IBinder mServerCallback;
     private final int mIdleUnbindTimeoutMs;
+    private final ContentCapturePerUserService mPerUserService;
 
     RemoteContentCaptureService(Context context, String serviceInterface,
             ComponentName serviceComponentName, IContentCaptureServiceCallback callback, int userId,
-            ContentCaptureServiceCallbacks callbacks, boolean bindInstantServiceAllowed,
+            ContentCapturePerUserService perUserService, boolean bindInstantServiceAllowed,
             boolean verbose, int idleUnbindTimeoutMs) {
-        super(context, serviceInterface, serviceComponentName, userId, callbacks,
+        super(context, serviceInterface, serviceComponentName, userId, perUserService,
                 context.getMainThreadHandler(), bindInstantServiceAllowed, verbose,
                 /* initialCapacity= */ 2);
+        mPerUserService = perUserService;
         mServerCallback = callback.asBinder();
         mIdleUnbindTimeoutMs = idleUnbindTimeoutMs;
 
@@ -65,19 +67,25 @@
         return mIdleUnbindTimeoutMs;
     }
 
-    @Override // from RemoteService
-    protected void handleOnConnectedStateChanged(boolean state) {
-        if (state && getTimeoutIdleBindMillis() != PERMANENT_BOUND_TIMEOUT_MS) {
+    @Override // from AbstractRemoteService
+    protected void handleOnConnectedStateChanged(boolean connected) {
+        if (connected && getTimeoutIdleBindMillis() != PERMANENT_BOUND_TIMEOUT_MS) {
             scheduleUnbind();
         }
         try {
-            if (state) {
-                mService.onConnected(mServerCallback, sVerbose, sDebug);
+            if (connected) {
+                try {
+                    mService.onConnected(mServerCallback, sVerbose, sDebug);
+                } finally {
+                    // Update the system-service state, in case the service reconnected after
+                    // dying
+                    mPerUserService.onConnected();
+                }
             } else {
                 mService.onDisconnected();
             }
         } catch (Exception e) {
-            Slog.w(mTag, "Exception calling onConnectedStateChanged(" + state + "): " + e);
+            Slog.w(mTag, "Exception calling onConnectedStateChanged(" + connected + "): " + e);
         }
     }
 
@@ -86,8 +94,10 @@
      * {@link RemoteContentCaptureService} to indicate the session was created.
      */
     public void onSessionStarted(@Nullable ContentCaptureContext context,
-            @NonNull String sessionId, int uid, @NonNull IResultReceiver clientReceiver) {
-        scheduleAsyncRequest((s) -> s.onSessionStarted(context, sessionId, uid, clientReceiver));
+            @NonNull String sessionId, int uid, @NonNull IResultReceiver clientReceiver,
+            int initialState) {
+        scheduleAsyncRequest(
+                (s) -> s.onSessionStarted(context, sessionId, uid, clientReceiver, initialState));
     }
 
     /**
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
index 69b4672..55a0621 100644
--- a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
@@ -35,6 +35,7 @@
 import android.os.UserManager;
 import android.util.Slog;
 
+import com.android.internal.os.IResultReceiver;
 import com.android.server.LocalServices;
 import com.android.server.infra.AbstractMasterSystemService;
 import com.android.server.infra.FrameworkResourcesServiceNameResolver;
@@ -114,13 +115,14 @@
 
     private class ContentSuggestionsManagerStub extends IContentSuggestionsManager.Stub {
         @Override
-        public void provideContextImage(int taskId, @NonNull Bundle imageContextRequestExtras) {
+        public void provideContextImage(
+                int userId,
+                int taskId,
+                @NonNull Bundle imageContextRequestExtras) {
             if (imageContextRequestExtras == null) {
                 throw new IllegalArgumentException("Expected non-null imageContextRequestExtras");
             }
-
-            final int userId = UserHandle.getCallingUserId();
-            enforceCallerIsRecents(userId, "provideContextImage");
+            enforceCallerIsRecents(UserHandle.getCallingUserId(), "provideContextImage");
 
             synchronized (mLock) {
                 final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
@@ -136,10 +138,10 @@
 
         @Override
         public void suggestContentSelections(
+                int userId,
                 @NonNull SelectionsRequest selectionsRequest,
                 @NonNull ISelectionsCallback selectionsCallback) {
-            final int userId = UserHandle.getCallingUserId();
-            enforceCallerIsRecents(userId, "suggestContentSelections");
+            enforceCallerIsRecents(UserHandle.getCallingUserId(), "suggestContentSelections");
 
             synchronized (mLock) {
                 final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
@@ -155,10 +157,10 @@
 
         @Override
         public void classifyContentSelections(
+                int userId,
                 @NonNull ClassificationsRequest classificationsRequest,
                 @NonNull IClassificationsCallback callback) {
-            final int userId = UserHandle.getCallingUserId();
-            enforceCallerIsRecents(userId, "classifyContentSelections");
+            enforceCallerIsRecents(UserHandle.getCallingUserId(), "classifyContentSelections");
 
             synchronized (mLock) {
                 final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
@@ -173,9 +175,9 @@
         }
 
         @Override
-        public void notifyInteraction(@NonNull String requestId, @NonNull Bundle bundle) {
-            final int userId = UserHandle.getCallingUserId();
-            enforceCallerIsRecents(userId, "notifyInteraction");
+        public void notifyInteraction(
+                int userId, @NonNull String requestId, @NonNull Bundle bundle) {
+            enforceCallerIsRecents(UserHandle.getCallingUserId(), "notifyInteraction");
 
             synchronized (mLock) {
                 final ContentSuggestionsPerUserService service = getServiceForUserLocked(userId);
@@ -189,6 +191,18 @@
             }
         }
 
+        @Override
+        public void isEnabled(int userId, @NonNull IResultReceiver receiver)
+                throws RemoteException {
+            enforceCallerIsRecents(UserHandle.getCallingUserId(), "isEnabled");
+
+            boolean isDisabled;
+            synchronized (mLock) {
+                isDisabled = isDisabledLocked(userId);
+            }
+            receiver.send(isDisabled ? 0 : 1, null);
+        }
+
         public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,
                 @Nullable FileDescriptor err,
                 @NonNull String[] args, @Nullable ShellCallback callback,
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 72f7a68..343cee1 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -73,6 +73,7 @@
 import android.net.INetworkPolicyListener;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
+import android.net.ISocketKeepaliveCallback;
 import android.net.ITetheringEventCallback;
 import android.net.InetAddresses;
 import android.net.IpPrefix;
@@ -299,6 +300,15 @@
     private INetworkPolicyManager mPolicyManager;
     private NetworkPolicyManagerInternal mPolicyManagerInternal;
 
+    /**
+     * TestNetworkService (lazily) created upon first usage. Locked to prevent creation of multiple
+     * instances.
+     */
+    @GuardedBy("mTNSLock")
+    private TestNetworkService mTNS;
+
+    private final Object mTNSLock = new Object();
+
     private String mCurrentTcpBufferSizes;
 
     private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
@@ -6690,32 +6700,32 @@
     }
 
     @Override
-    public void startNattKeepalive(Network network, int intervalSeconds, Messenger messenger,
-            IBinder binder, String srcAddr, int srcPort, String dstAddr) {
+    public void startNattKeepalive(Network network, int intervalSeconds,
+            ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr) {
         enforceKeepalivePermission();
         mKeepaliveTracker.startNattKeepalive(
                 getNetworkAgentInfoForNetwork(network),
-                intervalSeconds, messenger, binder,
+                intervalSeconds, cb,
                 srcAddr, srcPort, dstAddr, NattSocketKeepalive.NATT_PORT);
     }
 
     @Override
     public void startNattKeepaliveWithFd(Network network, FileDescriptor fd, int resourceId,
-            int intervalSeconds, Messenger messenger, IBinder binder, String srcAddr,
+            int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr,
             String dstAddr) {
         enforceKeepalivePermission();
         mKeepaliveTracker.startNattKeepalive(
                 getNetworkAgentInfoForNetwork(network), fd, resourceId,
-                intervalSeconds, messenger, binder,
+                intervalSeconds, cb,
                 srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT);
     }
 
     @Override
     public void startTcpKeepalive(Network network, FileDescriptor fd, int intervalSeconds,
-            Messenger messenger, IBinder binder) {
+            ISocketKeepaliveCallback cb) {
         enforceKeepalivePermission();
         mKeepaliveTracker.startTcpKeepalive(
-                getNetworkAgentInfoForNetwork(network), fd, intervalSeconds, messenger, binder);
+                getNetworkAgentInfoForNetwork(network), fd, intervalSeconds, cb);
     }
 
     @Override
@@ -6958,4 +6968,22 @@
             return vpn != null && vpn.getLockdown();
         }
     }
+
+    /**
+     * Returns a IBinder to a TestNetworkService. Will be lazily created as needed.
+     *
+     * <p>The TestNetworkService must be run in the system server due to TUN creation.
+     */
+    @Override
+    public IBinder startOrGetTestNetworkService() {
+        synchronized (mTNSLock) {
+            TestNetworkService.enforceTestNetworkPermissions(mContext);
+
+            if (mTNS == null) {
+                mTNS = new TestNetworkService(mContext, mNMS);
+            }
+
+            return mTNS;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index e28d484..f416110 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2717,6 +2717,38 @@
     }
 
     /**
+     * Check whether the device supports filesystem checkpointing.
+     *
+     * @return true if the device supports filesystem checkpointing, false otherwise.
+     */
+    @Override
+    public boolean supportsCheckpoint() throws RemoteException {
+        // Only the system process is permitted to start checkpoints
+        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+            throw new SecurityException("no permission to check filesystem checkpoint support");
+        }
+
+        return mVold.supportsCheckpoint();
+    }
+
+    /**
+     * Signal that checkpointing partitions should start a checkpoint on the next boot.
+     *
+     * @param numTries Number of times to try booting in checkpoint mode, before we will boot
+     *                 non-checkpoint mode and commit all changes immediately. Callers are
+     *                 responsible for ensuring that boot is safe (eg, by rolling back updates).
+     */
+    @Override
+    public void startCheckpoint(int numTries) throws RemoteException {
+        // Only the system process is permitted to start checkpoints
+        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+            throw new SecurityException("no permission to start filesystem checkpoint");
+        }
+
+        mVold.startCheckpoint(numTries);
+    }
+
+    /**
      * Signal that checkpointing partitions should commit changes
      */
     @Override
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 710a0ba3..3a50aa8 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -30,13 +30,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.BatteryManager;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.PowerManager.ServiceType;
@@ -356,8 +354,8 @@
             try {
                 synchronized (mLock) {
                     if (mNightMode != mode) {
-                        // Only persist setting if not transient night mode or not in car mode
-                        if (!shouldTransientNightWhenInCarMode() || !mCarModeEnabled) {
+                        // Only persist setting if not in car mode
+                        if (!mCarModeEnabled) {
                             Settings.Secure.putIntForUser(getContext().getContentResolver(),
                                     Settings.Secure.UI_NIGHT_MODE, mode, user);
                         }
@@ -444,34 +442,12 @@
         }
     }
 
-    // Night mode settings in car mode are only persisted below Q.
-    // When targeting Q, changes are not saved and night mode will be re-read
-    // from settings when exiting car mode.
-    private boolean shouldTransientNightWhenInCarMode() {
-        int uid = Binder.getCallingUid();
-        PackageManager packageManager = getContext().getPackageManager();
-        String[] packagesForUid = packageManager.getPackagesForUid(uid);
-        if (packagesForUid == null || packagesForUid.length == 0) {
-            return false;
-        }
-
-        try {
-            ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser(
-                    packagesForUid[0], 0, uid);
-
-            return appInfo.targetSdkVersion >= Build.VERSION_CODES.Q;
-        } catch (PackageManager.NameNotFoundException ignored) {
-        }
-
-        return false;
-    }
-
     void setCarModeLocked(boolean enabled, int flags) {
         if (mCarModeEnabled != enabled) {
             mCarModeEnabled = enabled;
 
-            // When transient night mode and exiting car mode, restore night mode from settings
-            if (shouldTransientNightWhenInCarMode() && !mCarModeEnabled) {
+            // When exiting car mode, restore night mode from settings
+            if (!mCarModeEnabled) {
                 Context context = getContext();
                 updateNightModeFromSettings(context,
                         context.getResources(),
@@ -534,9 +510,8 @@
             uiMode |= mNightMode << 4;
         }
 
-        // Override night mode in power save mode if not transient night mode or not in car mode
-        boolean shouldOverrideNight = !mCarModeEnabled || !shouldTransientNightWhenInCarMode();
-        if (mPowerSave && shouldOverrideNight) {
+        // Override night mode in power save mode if not in car mode
+        if (mPowerSave && !mCarModeEnabled) {
             uiMode &= ~Configuration.UI_MODE_NIGHT_NO;
             uiMode |= Configuration.UI_MODE_NIGHT_YES;
         }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 85ec2dd..6270106 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -131,9 +131,6 @@
     // calling startForeground() before we ANR + stop it.
     static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000;
 
-    // For how long after a whitelisted service's start its process can start a background activity
-    private static final int SERVICE_BG_ACTIVITY_START_TIMEOUT_MS = 10*1000;
-
     final ActivityManagerService mAm;
 
     // Maximum number of services that we allow to start in the background
@@ -333,8 +330,8 @@
                             + " delayedStop=" + r.delayedStop);
                 } else {
                     try {
-                        startServiceInnerLocked(this, r.pendingStarts.get(0).intent, r, false, true,
-                                false);
+                        startServiceInnerLocked(this, r.pendingStarts.get(0).intent, r, false,
+                                true);
                     } catch (TransactionTooLargeException e) {
                         // Ignore, nobody upstack cares.
                     }
@@ -637,26 +634,26 @@
         }
 
         if (allowBackgroundActivityStarts) {
-            ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
-            if (proc != null) {
-                proc.addAllowBackgroundActivityStartsToken(r);
-                // schedule removal of the whitelisting token after the timeout
-                removeAllowBackgroundActivityStartsServiceToken(proc, r,
-                        SERVICE_BG_ACTIVITY_START_TIMEOUT_MS);
-            }
+            r.hasStartedWhitelistingBgActivityStarts = true;
+            scheduleCleanUpHasStartedWhitelistingBgActivityStartsLocked(r);
         }
-        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting,
-                allowBackgroundActivityStarts);
+
+        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
         return cmp;
     }
 
-    private void removeAllowBackgroundActivityStartsServiceToken(ProcessRecord proc,
-            ServiceRecord r, int delayMillis) {
-        mAm.mHandler.postDelayed(() -> {
-            if (proc != null) {
-                proc.removeAllowBackgroundActivityStartsToken(r);
-            }
-        }, delayMillis);
+    private void scheduleCleanUpHasStartedWhitelistingBgActivityStartsLocked(ServiceRecord r) {
+        // if there's a request pending from the past, drop it before scheduling a new one
+        if (r.startedWhitelistingBgActivityStartsCleanUp == null) {
+            r.startedWhitelistingBgActivityStartsCleanUp = () -> {
+                synchronized(mAm) {
+                    r.setHasStartedWhitelistingBgActivityStarts(false);
+                }
+            };
+        }
+        mAm.mHandler.removeCallbacks(r.startedWhitelistingBgActivityStartsCleanUp);
+        mAm.mHandler.postDelayed(r.startedWhitelistingBgActivityStartsCleanUp,
+                mAm.mConstants.SERVICE_BG_ACTIVITY_START_TIMEOUT);
     }
 
     private boolean requestStartTargetPermissionsReviewIfNeededLocked(ServiceRecord r,
@@ -705,8 +702,7 @@
     }
 
     ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
-            boolean callerFg, boolean addToStarting, boolean allowBackgroundActivityStarts)
-            throws TransactionTooLargeException {
+            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
         ServiceState stracker = r.getTracker();
         if (stracker != null) {
             stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
@@ -717,8 +713,7 @@
         synchronized (r.stats.getBatteryStats()) {
             r.stats.startRunningLocked();
         }
-        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false,
-                allowBackgroundActivityStarts);
+        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
         if (error != null) {
             return new ComponentName("!!", error);
         }
@@ -765,6 +760,12 @@
                     SystemClock.uptimeMillis());
         }
         service.callStart = false;
+
+        // the service will not necessarily be brought down, so only clear the whitelisting state
+        // for start-based bg activity starts now, and drop any existing future cleanup callback
+        service.setHasStartedWhitelistingBgActivityStarts(false);
+        mAm.mHandler.removeCallbacks(service.startedWhitelistingBgActivityStartsCleanUp);
+
         bringDownServiceIfNeededLocked(service, false, false);
     }
 
@@ -788,9 +789,6 @@
             if (r.record != null) {
                 final long origId = Binder.clearCallingIdentity();
                 try {
-                    // immediately remove bg activity whitelisting token if there was one
-                    removeAllowBackgroundActivityStartsServiceToken(callerApp, r.record,
-                            0 /* delayMillis */);
                     stopServiceLocked(r.record);
                 } finally {
                     Binder.restoreCallingIdentity(origId);
@@ -1614,6 +1612,12 @@
                             + ") set BIND_ALLOW_INSTANT when binding service " + service);
         }
 
+        if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
+            mAm.enforceCallingPermission(
+                    android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
+                    "BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS");
+        }
+
         final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
         final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
         final boolean allowInstant = (flags & Context.BIND_ALLOW_INSTANT) != 0;
@@ -1672,7 +1676,7 @@
                                 try {
                                     bringUpServiceLocked(serviceRecord,
                                             serviceIntent.getFlags(),
-                                            callerFg, false, false, false);
+                                            callerFg, false, false);
                                 } catch (RemoteException e) {
                                     /* ignore - local call */
                                 }
@@ -1762,6 +1766,9 @@
             if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
                 s.whitelistManager = true;
             }
+            if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
+                s.setHasBindingWhitelistingBgActivityStarts(true);
+            }
             if (s.app != null) {
                 updateServiceClientActivitiesLocked(s.app, c, true);
             }
@@ -1775,7 +1782,7 @@
             if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                 s.lastActivity = SystemClock.uptimeMillis();
                 if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
-                        permissionsReviewRequired, false) != null) {
+                        permissionsReviewRequired) != null) {
                     return 0;
                 }
             }
@@ -2445,8 +2452,7 @@
             return;
         }
         try {
-            bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false,
-                    false);
+            bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false);
         } catch (TransactionTooLargeException e) {
             // Ignore, it's been logged and nothing upstack cares.
         }
@@ -2491,11 +2497,8 @@
     }
 
     private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
-            boolean whileRestarting, boolean permissionsReviewRequired,
-            boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
-        //Slog.i(TAG, "Bring up service:");
-        //r.dump("  ");
-
+            boolean whileRestarting, boolean permissionsReviewRequired)
+            throws TransactionTooLargeException {
         if (r.app != null && r.app.thread != null) {
             sendServiceArgsLocked(r, execInFg, false);
             return null;
@@ -2603,13 +2606,6 @@
             }
         }
 
-        if (app != null && allowBackgroundActivityStarts) {
-            app.addAllowBackgroundActivityStartsToken(r);
-            // schedule removal of the whitelisting token after the timeout
-            removeAllowBackgroundActivityStartsServiceToken(app, r,
-                    SERVICE_BG_ACTIVITY_START_TIMEOUT_MS);
-        }
-
         if (r.fgRequired) {
             if (DEBUG_FOREGROUND_SERVICE) {
                 Slog.v(TAG, "Whitelisting " + UserHandle.formatUid(r.appInfo.uid)
@@ -2646,6 +2642,11 @@
         }
     }
 
+    /**
+     * Note the name of this method should not be confused with the started services concept.
+     * The "start" here means bring up the instance in the client, and this method is called
+     * from bindService() as well.
+     */
     private final void realStartServiceLocked(ServiceRecord r,
             ProcessRecord app, boolean execInFg) throws RemoteException {
         if (app.thread == null) {
@@ -3085,6 +3086,10 @@
                     updateWhitelistManagerLocked(s.app);
                 }
             }
+            // And do the same for bg activity starts whitelisting.
+            if ((c.flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
+                s.updateHasBindingWhitelistingBgActivityStarts();
+            }
             if (s.app != null) {
                 updateServiceClientActivitiesLocked(s.app, c, true);
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index f9fcef6..1751856 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -69,6 +69,7 @@
     static final String KEY_SERVICE_MIN_RESTART_TIME_BETWEEN = "service_min_restart_time_between";
     static final String KEY_MAX_SERVICE_INACTIVITY = "service_max_inactivity";
     static final String KEY_BG_START_TIMEOUT = "service_bg_start_timeout";
+    static final String KEY_SERVICE_BG_ACTIVITY_START_TIMEOUT = "service_bg_activity_start_timeout";
     static final String KEY_BOUND_SERVICE_CRASH_RESTART_DURATION = "service_crash_restart_duration";
     static final String KEY_BOUND_SERVICE_CRASH_MAX_RETRY = "service_crash_max_retry";
     static final String KEY_PROCESS_START_ASYNC = "process_start_async";
@@ -99,6 +100,7 @@
     private static final long DEFAULT_SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
     private static final long DEFAULT_MAX_SERVICE_INACTIVITY = 30*60*1000;
     private static final long DEFAULT_BG_START_TIMEOUT = 15*1000;
+    private static final long DEFAULT_SERVICE_BG_ACTIVITY_START_TIMEOUT = 10_000;
     private static final long DEFAULT_BOUND_SERVICE_CRASH_RESTART_DURATION = 30*60_000;
     private static final int DEFAULT_BOUND_SERVICE_CRASH_MAX_RETRY = 16;
     private static final boolean DEFAULT_PROCESS_START_ASYNC = true;
@@ -212,6 +214,9 @@
     // allowing the next pending start to run.
     public long BG_START_TIMEOUT = DEFAULT_BG_START_TIMEOUT;
 
+    // For how long after a whitelisted service's start its process can start a background activity
+    public long SERVICE_BG_ACTIVITY_START_TIMEOUT = DEFAULT_SERVICE_BG_ACTIVITY_START_TIMEOUT;
+
     // Initial backoff delay for retrying bound foreground services
     public long BOUND_SERVICE_CRASH_RESTART_DURATION = DEFAULT_BOUND_SERVICE_CRASH_RESTART_DURATION;
 
@@ -398,6 +403,9 @@
                     DEFAULT_MAX_SERVICE_INACTIVITY);
             BG_START_TIMEOUT = mParser.getLong(KEY_BG_START_TIMEOUT,
                     DEFAULT_BG_START_TIMEOUT);
+            SERVICE_BG_ACTIVITY_START_TIMEOUT = mParser.getLong(
+                    KEY_SERVICE_BG_ACTIVITY_START_TIMEOUT,
+                    DEFAULT_SERVICE_BG_ACTIVITY_START_TIMEOUT);
             BOUND_SERVICE_CRASH_RESTART_DURATION = mParser.getLong(
                 KEY_BOUND_SERVICE_CRASH_RESTART_DURATION,
                 DEFAULT_BOUND_SERVICE_CRASH_RESTART_DURATION);
@@ -518,6 +526,8 @@
         pw.println(MAX_SERVICE_INACTIVITY);
         pw.print("  "); pw.print(KEY_BG_START_TIMEOUT); pw.print("=");
         pw.println(BG_START_TIMEOUT);
+        pw.print("  "); pw.print(KEY_SERVICE_BG_ACTIVITY_START_TIMEOUT); pw.print("=");
+        pw.println(SERVICE_BG_ACTIVITY_START_TIMEOUT);
         pw.print("  "); pw.print(KEY_BOUND_SERVICE_CRASH_RESTART_DURATION); pw.print("=");
         pw.println(BOUND_SERVICE_CRASH_RESTART_DURATION);
         pw.print("  "); pw.print(KEY_BOUND_SERVICE_CRASH_MAX_RETRY); pw.print("=");
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0a80d45..7c6049c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -251,6 +251,7 @@
 import android.os.Message;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
 import android.os.PowerManager.ServiceType;
 import android.os.PowerManagerInternal;
 import android.os.Process;
@@ -268,6 +269,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.WorkSource;
+import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
 import android.sysprop.VoldProperties;
@@ -306,6 +308,7 @@
 import com.android.internal.app.ProcessMap;
 import com.android.internal.app.SystemUserHomeActivity;
 import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.content.PackageHelper;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.BackgroundThread;
@@ -2931,8 +2934,8 @@
                         taskRoot);
             }
         }
-        if (mContentCaptureService != null
-                && (event == Event.ACTIVITY_PAUSED || event == Event.ACTIVITY_RESUMED)) {
+        if (mContentCaptureService != null && (event == Event.ACTIVITY_PAUSED
+                || event == Event.ACTIVITY_RESUMED || event == Event.ACTIVITY_STOPPED)) {
             mContentCaptureService.notifyActivityEvent(userId, activity, event);
         }
     }
@@ -5020,6 +5023,16 @@
             }
         }, dumpheapFilter);
 
+        // Inform checkpointing systems of success
+        try {
+            IStorageManager storageManager = PackageHelper.getStorageManager();
+            storageManager.commitChanges();
+        } catch (Exception e) {
+            PowerManager pm = (PowerManager)
+                     mInjector.getContext().getSystemService(Context.POWER_SERVICE);
+            pm.reboot("Checkpoint commit failed");
+        }
+
         // Let system services know.
         mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED);
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 57ce98c..cc90182 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -65,6 +65,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.IProgressListener;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallback;
 import android.os.RemoteCallback.OnResultListener;
@@ -103,6 +104,7 @@
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import javax.microedition.khronos.egl.EGL10;
 import javax.microedition.khronos.egl.EGLConfig;
@@ -114,6 +116,8 @@
     public static final String NO_CLASS_ERROR_CODE = "Error type 3";
     private static final String SHELL_PACKAGE_NAME = "com.android.shell";
 
+    private static final int USER_OPERATION_TIMEOUT_MS = 2 * 60 * 1000; // 2 minutes
+
     // IPC interface to activity manager -- don't need to do additional security checks.
     final IActivityManager mInterface;
     final IActivityTaskManager mTaskInterface;
@@ -377,6 +381,30 @@
         });
     }
 
+    private class ProgressWaiter extends IProgressListener.Stub {
+        private final CountDownLatch mFinishedLatch = new CountDownLatch(1);
+
+        @Override
+        public void onStarted(int id, Bundle extras) {}
+
+        @Override
+        public void onProgress(int id, int progress, Bundle extras) {}
+
+        @Override
+        public void onFinished(int id, Bundle extras) {
+            mFinishedLatch.countDown();
+        }
+
+        public boolean waitForFinish(long timeoutMillis) {
+            try {
+                return mFinishedLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+            } catch (InterruptedException e) {
+                System.err.println("Thread interrupted unexpectedly.");
+                return false;
+            }
+        }
+    }
+
     int runStartActivity(PrintWriter pw) throws RemoteException {
         Intent intent;
         try {
@@ -1692,8 +1720,24 @@
     }
 
     int runStartUser(PrintWriter pw) throws RemoteException {
-        String user = getNextArgRequired();
-        boolean success = mInterface.startUserInBackground(Integer.parseInt(user));
+        boolean wait = false;
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            if ("-w".equals(opt)) {
+                wait = true;
+            } else {
+                getErrPrintWriter().println("Error: unknown option: " + opt);
+                return -1;
+            }
+        }
+        int userId = Integer.parseInt(getNextArgRequired());
+
+        final ProgressWaiter waiter = wait ? new ProgressWaiter() : null;
+        boolean success = mInterface.startUserInBackgroundWithListener(userId, waiter);
+        if (wait && success) {
+            success = waiter.waitForFinish(USER_OPERATION_TIMEOUT_MS);
+        }
+
         if (success) {
             pw.println("Success: user started");
         } else {
@@ -3023,9 +3067,10 @@
             pw.println("      execution of that user if it is currently stopped.");
             pw.println("  get-current-user");
             pw.println("      Returns id of the current foreground user.");
-            pw.println("  start-user <USER_ID>");
+            pw.println("  start-user [-w] <USER_ID>");
             pw.println("      Start USER_ID in background if it is currently stopped;");
-            pw.println("      use switch-user if you want to start the user in foreground");
+            pw.println("      use switch-user if you want to start the user in foreground.");
+            pw.println("      -w: wait for start-user to complete and the user to be unlocked.");
             pw.println("  unlock-user <USER_ID> [TOKEN_HEX]");
             pw.println("      Attempt to unlock the given user using the given authorization token.");
             pw.println("  stop-user [-w] [-f] <USER_ID>");
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index a584914..0d03580 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -57,15 +57,18 @@
     private static final String PROC_STATUS_FILE_FMT = "/proc/%d/status";
     /** Path to procfs cmdline file. Used with pid: /proc/pid/cmdline. */
     private static final String PROC_CMDLINE_FILE_FMT = "/proc/%d/cmdline";
+    /** Path to debugfs file for the system ion heap. */
+    private static final String DEBUG_SYSTEM_ION_HEAP_FILE = "/sys/kernel/debug/ion/heaps/system";
 
     private static final Pattern PGFAULT = Pattern.compile("total_pgfault (\\d+)");
     private static final Pattern PGMAJFAULT = Pattern.compile("total_pgmajfault (\\d+)");
     private static final Pattern RSS_IN_BYTES = Pattern.compile("total_rss (\\d+)");
     private static final Pattern CACHE_IN_BYTES = Pattern.compile("total_cache (\\d+)");
     private static final Pattern SWAP_IN_BYTES = Pattern.compile("total_swap (\\d+)");
-
     private static final Pattern RSS_HIGH_WATERMARK_IN_BYTES =
             Pattern.compile("VmHWM:\\s*(\\d+)\\s*kB");
+    private static final Pattern ION_HEAP_SIZE_IN_BYTES =
+            Pattern.compile("\n\\s*total\\s*(\\d+)\\s*\n");
 
     private static final int PGFAULT_INDEX = 9;
     private static final int PGMAJFAULT_INDEX = 11;
@@ -127,6 +130,16 @@
         return parseCmdlineFromProcfs(readFileContents(path));
     }
 
+    /**
+     * Reads size of the system ion heap from debugfs.
+     *
+     * Returns value of the total size in bytes of the system ion heap from
+     * /sys/kernel/debug/ion/heaps/system.
+     */
+    public static long readSystemIonHeapSizeFromDebugfs() {
+        return parseIonHeapSizeFromDebugfs(readFileContents(DEBUG_SYSTEM_ION_HEAP_FILE));
+    }
+
     private static String readFileContents(String path) {
         final File file = new File(path);
         if (!file.exists()) {
@@ -228,6 +241,19 @@
     }
 
     /**
+     * Parses the ion heap size from the contents of a file under /sys/kernel/debug/ion/heaps in
+     * debugfs. The returned value is in bytes.
+     */
+    @VisibleForTesting
+    static long parseIonHeapSizeFromDebugfs(String contents) {
+        if (contents == null || contents.isEmpty()) {
+            return 0;
+        }
+        Matcher m = ION_HEAP_SIZE_IN_BYTES.matcher(contents);
+        return m.find() ? Long.parseLong(m.group(1)) : 0;
+    }
+
+    /**
      * Returns whether per-app memcg is available on device.
      */
     static boolean hasMemcg() {
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index e483b26..877bef7 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -23,6 +23,9 @@
 svetoslavganov@google.com
 toddke@google.com
 
+# Battery Stats
+joeo@google.com
+
 # Londoners
 michaelwr@google.com
 narayan@google.com
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 0387774..eeaa7de 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -125,6 +125,14 @@
     int pendingConnectionGroup;        // To be filled in to ProcessRecord once it connects
     int pendingConnectionImportance;   // To be filled in to ProcessRecord once it connects
 
+    // any current binding to this service has BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS flag?
+    private boolean hasBindingWhitelistingBgActivityStarts;
+    // is this service currently whitelisted to start activities from background by providing
+    // allowBackgroundActivityStarts=true to startServiceLocked()?
+    boolean hasStartedWhitelistingBgActivityStarts;
+    // used to clean up the state of hasStartedWhitelistingBgActivityStarts after a timeout
+    Runnable startedWhitelistingBgActivityStartsCleanUp;
+
     String stringName;      // caching of toString
 
     private int lastStartId;    // identifier of most recent start request.
@@ -371,6 +379,14 @@
         if (whitelistManager) {
             pw.print(prefix); pw.print("whitelistManager="); pw.println(whitelistManager);
         }
+        if (hasBindingWhitelistingBgActivityStarts) {
+            pw.print(prefix); pw.print("hasBindingWhitelistingBgActivityStarts=");
+            pw.println(hasBindingWhitelistingBgActivityStarts);
+        }
+        if (hasStartedWhitelistingBgActivityStarts) {
+            pw.print(prefix); pw.print("hasStartedWhitelistingBgActivityStarts=");
+            pw.println(hasStartedWhitelistingBgActivityStarts);
+        }
         if (delayed) {
             pw.print(prefix); pw.print("delayed="); pw.println(delayed);
         }
@@ -518,6 +534,15 @@
     }
 
     public void setProcess(ProcessRecord _proc) {
+        if (_proc != null) {
+            if (hasStartedWhitelistingBgActivityStarts || hasBindingWhitelistingBgActivityStarts) {
+                _proc.addAllowBackgroundActivityStartsToken(this);
+            } else {
+                _proc.removeAllowBackgroundActivityStartsToken(this);
+            }
+        } else if (app != null) {
+            app.removeAllowBackgroundActivityStartsToken(this);
+        }
         app = _proc;
         if (pendingConnectionGroup > 0 && _proc != null) {
             _proc.connectionService = this;
@@ -540,6 +565,62 @@
         }
     }
 
+    void updateHasBindingWhitelistingBgActivityStarts() {
+        boolean hasWhitelistingBinding = false;
+        for (int conni = connections.size() - 1; conni >= 0; conni--) {
+            ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
+            for (int i = 0; i < cr.size(); i++) {
+                if ((cr.get(i).flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
+                    hasWhitelistingBinding = true;
+                    break;
+                }
+            }
+            if (hasWhitelistingBinding) {
+                break;
+            }
+        }
+        if (hasBindingWhitelistingBgActivityStarts != hasWhitelistingBinding) {
+            hasBindingWhitelistingBgActivityStarts = hasWhitelistingBinding;
+            updateParentProcessBgActivityStartsWhitelistingToken();
+        }
+    }
+
+    void setHasBindingWhitelistingBgActivityStarts(boolean newValue) {
+        if (hasBindingWhitelistingBgActivityStarts != newValue) {
+            hasBindingWhitelistingBgActivityStarts = newValue;
+            updateParentProcessBgActivityStartsWhitelistingToken();
+        }
+    }
+
+    void setHasStartedWhitelistingBgActivityStarts(boolean newValue) {
+        if (hasStartedWhitelistingBgActivityStarts != newValue) {
+            hasStartedWhitelistingBgActivityStarts = newValue;
+            updateParentProcessBgActivityStartsWhitelistingToken();
+        }
+    }
+
+    /**
+     * Whether the process this service runs in should be temporarily whitelisted to start
+     * activities from background depends on the current state of both
+     * {@code hasStartedWhitelistingBgActivityStarts} and
+     * {@code hasBindingWhitelistingBgActivityStarts}. If either is true, this ServiceRecord
+     * should be contributing as a token in parent ProcessRecord.
+     *
+     * @see com.android.server.am.ProcessRecord#mAllowBackgroundActivityStartsTokens
+     */
+    private void updateParentProcessBgActivityStartsWhitelistingToken() {
+        if (app == null) {
+            return;
+        }
+        if (hasStartedWhitelistingBgActivityStarts || hasBindingWhitelistingBgActivityStarts) {
+            // if the token is already there it's safe to "re-add it" - we're deadling with
+            // a set of Binder objects
+            app.addAllowBackgroundActivityStartsToken(this);
+        } else {
+            app.removeAllowBackgroundActivityStartsToken(this);
+        }
+    }
+
     public AppBindRecord retrieveAppBindingLocked(Intent intent,
             ProcessRecord app) {
         Intent.FilterComparison filter = new Intent.FilterComparison(intent);
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 194549f..99380c9 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -83,8 +83,8 @@
         DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
         DeviceConfig.NAMESPACE_MEDIA_NATIVE,
         DeviceConfig.NAMESPACE_NETD_NATIVE,
+        DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
         DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
-        DeviceConfig.RuntimeNative.NAMESPACE,
     };
 
     private final String[] mGlobalSettings;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 1e406c0..029c3fb 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -67,7 +67,6 @@
 import android.os.IUserManager;
 import android.os.Looper;
 import android.os.Message;
-import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -335,14 +334,6 @@
                 return;
             }
         }
-        // Inform checkpointing systems of success
-        try {
-            getStorageManager().commitChanges();
-        } catch (Exception e) {
-            PowerManager pm = (PowerManager)
-                     mInjector.getContext().getSystemService(Context.POWER_SERVICE);
-            pm.reboot("Checkpoint commit failed");
-        }
 
         // We always walk through all the user lifecycle states to send
         // consistent developer events. We step into RUNNING_LOCKED here,
@@ -938,6 +929,7 @@
      *
      * @param userId ID of the user to start
      * @param foreground true if user should be brought to the foreground
+     * @param unlockListener Listener to be informed when the user has started and unlocked.
      * @return true if the user has been successfully started
      */
     boolean startUser(
@@ -962,6 +954,15 @@
         try {
             final int oldUserId = getCurrentUserId();
             if (oldUserId == userId) {
+                final UserState state = getStartedUserState(userId);
+                if (state != null && state.state == STATE_RUNNING_UNLOCKED) {
+                    // We'll skip all later code, so we must tell listener it's already unlocked.
+                    try {
+                        unlockListener.onFinished(userId, null);
+                    } catch (RemoteException ignore) {
+                        // Ignore.
+                    }
+                }
                 return true;
             }
 
@@ -1547,8 +1548,8 @@
                     }
                     builder.append(" asks to run as user ");
                     builder.append(userId);
-                    builder.append(" but is calling from user ");
-                    builder.append(UserHandle.getUserId(callingUid));
+                    builder.append(" but is calling from uid ");
+                    UserHandle.formatUid(builder, callingUid);
                     builder.append("; this requires ");
                     builder.append(INTERACT_ACROSS_USERS_FULL);
                     if (allowMode != ALLOW_FULL_ONLY) {
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 5965d59..7da848c 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -16,9 +16,7 @@
 
 package com.android.server.attention;
 
-import static android.provider.DeviceConfig.AttentionManagerService.COMPONENT_NAME;
-import static android.provider.DeviceConfig.AttentionManagerService.NAMESPACE;
-import static android.provider.DeviceConfig.AttentionManagerService.SERVICE_ENABLED;
+import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
 
 import android.Manifest;
 import android.annotation.Nullable;
@@ -80,6 +78,12 @@
     /** If the check attention called within that period - cached value will be returned. */
     private static final long STALE_AFTER_MILLIS = 5_000;
 
+    /** DeviceConfig flag name, if {@code true}, enables AttentionManagerService features. */
+    private static final String SERVICE_ENABLED = "service_enabled";
+
+    /** DeviceConfig flag name, allows a CTS to inject a fake implementation. */
+    private static final String COMPONENT_NAME = "component_name";
+
     private final Context mContext;
     private final PowerManager mPowerManager;
     private final Object mLock;
@@ -122,12 +126,13 @@
     /**
      * Returns {@code true} if attention service is supported on this device.
      */
-    public boolean isAttentionServiceSupported() {
+    private boolean isAttentionServiceSupported() {
         return isServiceEnabled() && isServiceAvailable();
     }
 
     private boolean isServiceEnabled() {
-        return DeviceConfig.getBoolean(NAMESPACE, SERVICE_ENABLED, DEFAULT_SERVICE_ENABLED);
+        return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, SERVICE_ENABLED,
+                DEFAULT_SERVICE_ENABLED);
     }
 
     /**
@@ -135,7 +140,7 @@
      *
      * @return {@code true} if the framework was able to send the provided callback to the service
      */
-    public boolean checkAttention(int requestCode, long timeout,
+    private boolean checkAttention(int requestCode, long timeout,
             AttentionCallbackInternal callback) {
         Preconditions.checkNotNull(callback);
 
@@ -213,7 +218,7 @@
     }
 
     /** Cancels the specified attention check. */
-    public void cancelAttentionCheck(int requestCode) {
+    private void cancelAttentionCheck(int requestCode) {
         synchronized (mLock) {
             final UserState userState = peekCurrentUserStateLocked();
             if (userState == null) {
@@ -283,7 +288,8 @@
      * system.
      */
     private static ComponentName resolveAttentionService(Context context) {
-        final String flag = DeviceConfig.getProperty(NAMESPACE, COMPONENT_NAME);
+        final String flag = DeviceConfig.getProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+                COMPONENT_NAME);
 
         final String componentNameString = flag != null ? flag : context.getString(
                 R.string.config_defaultAttentionService);
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 451fd66..69a9e7e 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -230,17 +230,13 @@
         sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT, SENDMSG_QUEUE, info);
     }
 
-    /*package*/ int handleBluetoothA2dpActiveDeviceChange(
+    /*package*/ void postBluetoothA2dpDeviceConfigChangeExt(
             @NonNull BluetoothDevice device,
             @AudioService.BtProfileConnectionState int state, int profile,
             boolean suppressNoisyIntent, int a2dpVolume) {
-        // FIXME method was added by @a8439e2 but never used, and now conflicts with async behavior
-        //   of handleBluetoothA2dpDeviceConfigChange and
-        //   setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
-        synchronized (mDeviceStateLock) {
-            return mDeviceInventory.handleBluetoothA2dpActiveDeviceChange(device, state, profile,
-                    suppressNoisyIntent, a2dpVolume);
-        }
+        final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile,
+                suppressNoisyIntent, a2dpVolume);
+        sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE_EXT, SENDMSG_QUEUE, info);
     }
 
     private static final class HearingAidDeviceConnectionInfo {
@@ -542,7 +538,8 @@
         mBrokerHandler.removeMessages(MSG_IL_BTA2DP_DOCK_TIMEOUT);
     }
 
-    /*package*/ void postA2dpActiveDeviceChange(BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
+    /*package*/ void postA2dpActiveDeviceChange(
+                    @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
         sendLMsgNoDelay(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE, SENDMSG_QUEUE, btDeviceInfo);
     }
 
@@ -714,8 +711,9 @@
                     final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
                     synchronized (mDeviceStateLock) {
                         a2dpCodec = mBtHelper.getA2dpCodec(btDevice);
-                        mDeviceInventory.onBluetoothA2dpDeviceConfigChange(
-                                new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec));
+                        mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
+                                new BtHelper.BluetoothA2dpDeviceInfo(btDevice, -1, a2dpCodec),
+                                        BtHelper.EVENT_DEVICE_CONFIG_CHANGE);
                     }
                     break;
                 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
@@ -744,7 +742,8 @@
                 case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
                     synchronized (mDeviceStateLock) {
                         mDeviceInventory.onBluetoothA2dpActiveDeviceChange(
-                                (BtHelper.BluetoothA2dpDeviceInfo) msg.obj);
+                                (BtHelper.BluetoothA2dpDeviceInfo) msg.obj,
+                                 BtHelper.EVENT_ACTIVE_DEVICE_CHANGE);
                     }
                     break;
                 case MSG_DISCONNECT_A2DP:
@@ -816,6 +815,22 @@
                                 info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice);
                     }
                 } break;
+                case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE_EXT: {
+                    final BtDeviceConnectionInfo info = (BtDeviceConnectionInfo) msg.obj;
+                    AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+                            "handleBluetoothA2dpActiveDeviceChangeExt "
+                                    + " state=" + info.mState
+                                    // only querying address as this is the only readily available
+                                    // field on the device
+                                    + " addr=" + info.mDevice.getAddress()
+                                    + " prof=" + info.mProfile + " supprNoisy=" + info.mSupprNoisy
+                                    + " vol=" + info.mVolume)).printLog(TAG));
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.handleBluetoothA2dpActiveDeviceChangeExt(
+                                info.mDevice, info.mState, info.mProfile,
+                                info.mSupprNoisy, info.mVolume);
+                    }
+                } break;
                 default:
                     Log.wtf(TAG, "Invalid message " + msg.what);
             }
@@ -863,6 +878,8 @@
     private static final int MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT = 27;
     // process external command to (dis)connect a hearing aid device
     private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 28;
+    // process external command to (dis)connect or change active A2DP device
+    private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE_EXT = 29;
 
 
     private static boolean isMessageHandledUnderWakelock(int msgId) {
@@ -877,6 +894,7 @@
             case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE:
             case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT:
             case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT:
+            case MSG_L_A2DP_ACTIVE_DEVICE_CHANGE_EXT:
                 return true;
             default:
                 return false;
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 41a3c98..5ec8cfa 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -263,74 +263,25 @@
         }
     }
 
-    /*package*/ void onBluetoothA2dpDeviceConfigChange(
-            @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo) {
+    /*package*/ void onBluetoothA2dpActiveDeviceChange(
+            @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, int event) {
         final BluetoothDevice btDevice = btInfo.getBtDevice();
-        if (AudioService.DEBUG_DEVICES) {
-            Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
-        }
         if (btDevice == null) {
             return;
         }
-        String address = btDevice.getAddress();
-        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
-            address = "";
-        }
-        AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
-                "onBluetoothA2dpDeviceConfigChange addr=" + address));
-
-        final int a2dpCodec = btInfo.getCodec();
-
-        synchronized (mConnectedDevices) {
-            if (mDeviceBroker.hasScheduledA2dpSinkConnectionState(btDevice)) {
-                AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
-                        "A2dp config change ignored"));
-                return;
-            }
-            final String key =
-                    DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
-            final DeviceInfo di = mConnectedDevices.get(key);
-            if (di == null) {
-                Log.e(TAG, "invalid null DeviceInfo in onBluetoothA2dpDeviceConfigChange");
-                return;
-            }
-            // Device is connected
-            if (di.mDeviceCodecFormat != a2dpCodec) {
-                di.mDeviceCodecFormat = a2dpCodec;
-                mConnectedDevices.replace(key, di);
-            }
-            if (AudioService.DEBUG_DEVICES) {
-                Log.d(TAG, "onBluetoothA2dpDeviceConfigChange: codec="
-                        + di.mDeviceCodecFormat);
-            }
-            if (AudioSystem.handleDeviceConfigChange(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address,
-                    btDevice.getName(), di.mDeviceCodecFormat) != AudioSystem.AUDIO_STATUS_OK) {
-                // force A2DP device disconnection in case of error so that AudioService state
-                // is consistent with audio policy manager state
-                final int musicDevice = mDeviceBroker.getDeviceForStream(AudioSystem.STREAM_MUSIC);
-                setBluetoothA2dpDeviceConnectionState(
-                        btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
-                        false /* suppressNoisyIntent */, musicDevice,
-                        -1 /* a2dpVolume */);
-            }
-        }
-    }
-
-    /*package*/ void onBluetoothA2dpActiveDeviceChange(
-            @NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo) {
-        final BluetoothDevice btDevice = btInfo.getBtDevice();
-        int a2dpVolume = btInfo.getVolume();
-        final int a2dpCodec = btInfo.getCodec();
-
         if (AudioService.DEBUG_DEVICES) {
             Log.d(TAG, "onBluetoothA2dpActiveDeviceChange btDevice=" + btDevice);
         }
+        int a2dpVolume = btInfo.getVolume();
+        final int a2dpCodec = btInfo.getCodec();
+
         String address = btDevice.getAddress();
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             address = "";
         }
         AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
-                "onBluetoothA2dpActiveDeviceChange addr=" + address));
+                "onBluetoothA2dpActiveDeviceChange addr=" + address
+                    + " event=" + BtHelper.a2dpDeviceEventToString(event)));
 
         synchronized (mConnectedDevices) {
             //TODO original CL is not consistent between BluetoothDevice and BluetoothA2dpDeviceInfo
@@ -344,20 +295,28 @@
                     AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
             final DeviceInfo di = mConnectedDevices.get(key);
             if (di == null) {
+                Log.e(TAG, "invalid null DeviceInfo in onBluetoothA2dpActiveDeviceChange");
                 return;
             }
 
-            // Device is connected
-            if (a2dpVolume != -1) {
-                final AudioService.VolumeStreamState streamState =
-                        mDeviceBroker.getStreamState(AudioSystem.STREAM_MUSIC);
-                // Convert index to internal representation in VolumeStreamState
-                a2dpVolume = a2dpVolume * 10;
-                streamState.setIndex(a2dpVolume, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
-                        "onBluetoothA2dpActiveDeviceChange");
-                mDeviceBroker.setDeviceVolume(streamState, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+            if (event == BtHelper.EVENT_ACTIVE_DEVICE_CHANGE) {
+                // Device is connected
+                if (a2dpVolume != -1) {
+                    final AudioService.VolumeStreamState streamState =
+                            mDeviceBroker.getStreamState(AudioSystem.STREAM_MUSIC);
+                    // Convert index to internal representation in VolumeStreamState
+                    a2dpVolume = a2dpVolume * 10;
+                    streamState.setIndex(a2dpVolume, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                            "onBluetoothA2dpActiveDeviceChange");
+                    mDeviceBroker.setDeviceVolume(
+                            streamState, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+                }
+            } else if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
+                if (di.mDeviceCodecFormat != a2dpCodec) {
+                    di.mDeviceCodecFormat = a2dpCodec;
+                    mConnectedDevices.replace(key, di);
+                }
             }
-
             if (AudioSystem.handleDeviceConfigChange(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address,
                     btDevice.getName(), a2dpCodec) != AudioSystem.AUDIO_STATUS_OK) {
                 int musicDevice = mDeviceBroker.getDeviceForStream(AudioSystem.STREAM_MUSIC);
@@ -616,52 +575,48 @@
         }
     }
 
-    /*package*/ int handleBluetoothA2dpActiveDeviceChange(
+    /*package*/ void handleBluetoothA2dpActiveDeviceChangeExt(
             @NonNull BluetoothDevice device,
             @AudioService.BtProfileConnectionState int state, int profile,
             boolean suppressNoisyIntent, int a2dpVolume) {
-        // method was added by QC but never used, and now conflicts with async behavior of
-        // handleBluetoothA2dpDeviceConfigChange and
-        // setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
-        if (false) {
-            if (state == BluetoothProfile.STATE_DISCONNECTED) {
-                setBluetoothA2dpDeviceConnectionState(device, state, profile,
-                        suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume);
+        if (state == BluetoothProfile.STATE_DISCONNECTED) {
+            mDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+                           device, state, profile, suppressNoisyIntent, a2dpVolume);
+            return;
+        }
+        // state == BluetoothProfile.STATE_CONNECTED
+        synchronized (mConnectedDevices) {
+            final String address = device.getAddress();
+            final int a2dpCodec = mDeviceBroker.getA2dpCodec(device);
+            final String deviceKey = DeviceInfo.makeDeviceListKey(
+                        AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
+            DeviceInfo deviceInfo = mConnectedDevices.get(deviceKey);
+            if (deviceInfo != null) {
+                // Device config change for matching A2DP device
+                mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device);
+                return;
             }
-            // state == BluetoothProfile.STATE_CONNECTED
-            synchronized (mConnectedDevices) {
-                for (int i = 0; i < mConnectedDevices.size(); i++) {
-                    final DeviceInfo deviceInfo = mConnectedDevices.valueAt(i);
-                    if (deviceInfo.mDeviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
-                        continue;
-                    }
-                    // If A2DP device exists, this is either an active device change or
-                    // device config change
-                    final String existingDevicekey = mConnectedDevices.keyAt(i);
-                    final String deviceName = device.getName();
-                    final String address = device.getAddress();
-                    final String newDeviceKey = DeviceInfo.makeDeviceListKey(
-                            AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
-                    int a2dpCodec = mDeviceBroker.getA2dpCodec(device);
-                    // Device not equal to existing device, active device change
-                    if (!TextUtils.equals(existingDevicekey, newDeviceKey)) {
-                        mConnectedDevices.remove(existingDevicekey);
-                        mConnectedDevices.put(newDeviceKey, new DeviceInfo(
-                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, deviceName,
-                                address, a2dpCodec));
-                        mDeviceBroker.postA2dpActiveDeviceChange(
-                                new BtHelper.BluetoothA2dpDeviceInfo(
-                                        device, a2dpVolume, a2dpCodec));
-                        return 0;
-                    } else {
-                        // Device config change for existing device
-                        mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device);
-                        return 0;
-                    }
+            for (int i = 0; i < mConnectedDevices.size(); i++) {
+                deviceInfo = mConnectedDevices.valueAt(i);
+                if (deviceInfo.mDeviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+                    continue;
                 }
+                // A2DP device exists, handle active device change
+                final String existingDevicekey = mConnectedDevices.keyAt(i);
+                final String deviceName = device.getName();
+                mConnectedDevices.remove(existingDevicekey);
+                mConnectedDevices.put(deviceKey, new DeviceInfo(
+                        AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, deviceName,
+                        address, a2dpCodec));
+                mDeviceBroker.postA2dpActiveDeviceChange(
+                        new BtHelper.BluetoothA2dpDeviceInfo(
+                            device, a2dpVolume, a2dpCodec));
+                return;
             }
         }
-        return 0;
+        // New A2DP device connection
+        mDeviceBroker.postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
+                           device, state, profile, suppressNoisyIntent, a2dpVolume);
     }
 
     /*package*/ int setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state,
@@ -858,11 +813,20 @@
         if (musicDevice == AudioSystem.DEVICE_NONE) {
             musicDevice = mDeviceBroker.getDeviceForStream(AudioSystem.STREAM_MUSIC);
         }
-        // ignore condition on device being actually used for music when in communication
+
+        // always ignore condition on device being actually used for music when in communication
         // because music routing is altered in this case.
-        // also checks whether media routing if affected by a dynamic policy
+        // also checks whether media routing if affected by a dynamic policy or mirroring
         if (((device == musicDevice) || mDeviceBroker.isInCommunication())
-                && (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy()) {
+                && (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy()
+                        && ((musicDevice & AudioSystem.DEVICE_OUT_REMOTE_SUBMIX) == 0)) {
+            if (!AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/)) {
+                // no media playback, not a "becoming noisy" situation, otherwise it could cause
+                // the pausing of some apps that are playing remotely
+                AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+                        "dropping ACTION_AUDIO_BECOMING_NOISY, no media playback")).printLog(TAG));
+                return 0;
+            }
             mDeviceBroker.postBroadcastBecomingNoisy();
             delay = 1000;
         }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 100113c..68f76ab 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4094,12 +4094,9 @@
      * @see AudioManager#handleBluetoothA2dpActiveDeviceChange(BluetoothDevice, int, int,
      *                                                          boolean, int)
      */
-    public int handleBluetoothA2dpActiveDeviceChange(
+    public void handleBluetoothA2dpActiveDeviceChange(
             BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent,
             int a2dpVolume) {
-        // FIXME method was added by @a8439e2 but never used, and now conflicts with async behavior
-        //   of handleBluetoothA2dpDeviceConfigChange and
-        //   setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent
         if (device == null) {
             throw new IllegalArgumentException("Illegal null device");
         }
@@ -4110,7 +4107,7 @@
                 && state != BluetoothProfile.STATE_DISCONNECTED) {
             throw new IllegalArgumentException("Invalid state " + state);
         }
-        return mDeviceBroker.handleBluetoothA2dpActiveDeviceChange(device, state, profile,
+        mDeviceBroker.postBluetoothA2dpDeviceConfigChangeExt(device, state, profile,
                 suppressNoisyIntent, a2dpVolume);
     }
 
@@ -5956,6 +5953,14 @@
         pw.print("  mVolumePolicy="); pw.println(mVolumePolicy);
         pw.print("  mAvrcpAbsVolSupported=");
         pw.println(mDeviceBroker.isAvrcpAbsoluteVolumeSupported());
+        pw.print("  mIsSingleVolume="); pw.println(mIsSingleVolume);
+        pw.print("  mUseFixedVolume="); pw.println(mUseFixedVolume);
+        pw.print("  mFixedVolumeDevices=0x"); pw.println(Integer.toHexString(mFixedVolumeDevices));
+        pw.print("  mHdmiCecSink="); pw.println(mHdmiCecSink);
+        pw.print("  mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient);
+        pw.print("  mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient);
+        pw.print("  mHdmiTvClient="); pw.println(mHdmiTvClient);
+        pw.print("  mHdmiSystemAudioSupported="); pw.println(mHdmiSystemAudioSupported);
 
         dumpAudioPolicies(pw);
         mDynPolicyLogger.dump(pw);
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 04073cb..522a55d 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -139,6 +139,19 @@
         }
     }
 
+    // A2DP device events
+    /*package*/ static final int EVENT_DEVICE_CONFIG_CHANGE = 0;
+    /*package*/ static final int EVENT_ACTIVE_DEVICE_CHANGE = 1;
+
+    /*package*/ static String a2dpDeviceEventToString(int event) {
+        switch (event) {
+            case EVENT_DEVICE_CONFIG_CHANGE: return "DEVICE_CONFIG_CHANGE";
+            case EVENT_ACTIVE_DEVICE_CHANGE: return "ACTIVE_DEVICE_CHANGE";
+            default:
+                return new String("invalid event:" + event);
+        }
+    }
+
     //----------------------------------------------------------------------
     // Interface for AudioDeviceBroker
 
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index b4bbbc7..d028e88 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -543,16 +543,17 @@
     }
 
     /**
-     * Called synchronized on mAudioFocusLock
+     * Called synchronized on mAudioFocusLock.
+     * Can only be called with an external focus policy installed (mFocusPolicy != null)
      * @param afi
-     * @param requestResult
-     * @return true if the external audio focus policy (if any) is handling the focus request
+     * @param fd
+     * @param cb binder of the focus requester
+     * @return true if the external audio focus policy (if any) can handle the focus request,
+     *     and false if there was any error handling the request (e.g. error talking to policy,
+     *     focus requester is already dead)
      */
     boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi,
-            IAudioFocusDispatcher fd, IBinder cb) {
-        if (mFocusPolicy == null) {
-            return false;
-        }
+            IAudioFocusDispatcher fd, @NonNull IBinder cb) {
         if (DEBUG) {
             Log.v(TAG, "notifyExtFocusPolicyFocusRequest client="+afi.getClientId()
             + " dispatcher=" + fd);
@@ -561,19 +562,28 @@
             afi.setGen(mExtFocusChangeCounter++);
         }
         final FocusRequester existingFr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
+        boolean keepTrack = false;
         if (existingFr != null) {
             if (!existingFr.hasSameDispatcher(fd)) {
                 existingFr.release();
-                final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
-                mFocusOwnersForFocusPolicy.put(afi.getClientId(),
-                        new FocusRequester(afi, fd, cb, hdlr, this));
+                keepTrack = true;
             }
         } else {
-            // new focus (future) focus owner to keep track of
+            keepTrack = true;
+        }
+        if (keepTrack) {
             final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
+            try {
+                cb.linkToDeath(hdlr, 0);
+            } catch (RemoteException e) {
+                // client has already died!
+                return false;
+            }
+            // new focus (future) focus owner to keep track of
             mFocusOwnersForFocusPolicy.put(afi.getClientId(),
                     new FocusRequester(afi, fd, cb, hdlr, this));
         }
+
         try {
             //oneway
             mFocusPolicy.notifyAudioFocusRequest(afi, AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
@@ -600,7 +610,6 @@
     /**
      * Called synchronized on mAudioFocusLock
      * @param afi
-     * @param requestResult
      * @return true if the external audio focus policy (if any) is handling the focus request
      */
     boolean notifyExtFocusPolicyFocusAbandon_syncAf(AudioFocusInfo afi) {
@@ -767,10 +776,15 @@
             }
 
             // external focus policy?
-            if (notifyExtFocusPolicyFocusRequest_syncAf(
-                    afiForExtPolicy, fd, cb)) {
-                // stop handling focus request here as it is handled by external audio focus policy
-                return AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY;
+            if (mFocusPolicy != null) {
+                if (notifyExtFocusPolicyFocusRequest_syncAf(afiForExtPolicy, fd, cb)) {
+                    // stop handling focus request here as it is handled by external audio
+                    // focus policy (return code will be handled in AudioManager)
+                    return AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY;
+                } else {
+                    // an error occured, client already dead, bail early
+                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+                }
             }
 
             // handle the potential premature death of the new holder of the focus
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index d787758..ebb9e06 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -43,6 +43,7 @@
 import android.os.IHwBinder;
 import android.os.IRemoteCallback;
 import android.os.PowerManager;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -958,6 +959,10 @@
             int pid, int userId) {
         checkUseBiometricPermission();
 
+
+        if (Binder.getCallingUid() == Process.SYSTEM_UID) {
+            return true; // System process (BiometricService, etc) is always allowed
+        }
         if (isKeyguard(opPackageName)) {
             return true; // Keyguard is always allowed
         }
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index feeb16b..c385991 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -633,11 +633,19 @@
         }
 
         @Override
-        public void onRemoved(final long deviceId, final int faceId, final int userId,
-                final int remaining) {
+        public void onRemoved(final long deviceId, ArrayList<Integer> faceIds, final int userId) {
             mHandler.post(() -> {
-                final Face face = new Face("", faceId, deviceId);
-                FaceService.super.handleRemoved(face, remaining);
+                if (!faceIds.isEmpty()) {
+                    for (int i = 0; i < faceIds.size(); i++) {
+                        final Face face = new Face("", faceIds.get(i), deviceId);
+                        // Convert to old behavior
+                        FaceService.super.handleRemoved(face, faceIds.size() - i - 1);
+                    }
+                } else {
+                    final Face face = new Face("", 0 /* identifier */, deviceId);
+                    FaceService.super.handleRemoved(face, 0 /* remaining */);
+                }
+
             });
         }
 
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index cc4c173..35d6860 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -21,8 +21,8 @@
 import static android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER;
 import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE;
 import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE;
-import static android.net.NetworkAgent.EVENT_SOCKET_KEEPALIVE;
 import static android.net.SocketKeepalive.BINDER_DIED;
+import static android.net.SocketKeepalive.DATA_RECEIVED;
 import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL;
 import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
 import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
@@ -34,6 +34,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.net.ISocketKeepaliveCallback;
 import android.net.KeepalivePacketData;
 import android.net.NattKeepalivePacketData;
 import android.net.NetworkAgent;
@@ -47,7 +48,6 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
-import android.os.Messenger;
 import android.os.Process;
 import android.os.RemoteException;
 import android.system.ErrnoException;
@@ -99,8 +99,7 @@
      */
     class KeepaliveInfo implements IBinder.DeathRecipient {
         // Bookkeeping data.
-        private final Messenger mMessenger;
-        private final IBinder mBinder;
+        private final ISocketKeepaliveCallback mCallback;
         private final int mUid;
         private final int mPid;
         private final NetworkAgentInfo mNai;
@@ -124,15 +123,13 @@
         private static final int STARTED = 3;
         private int mStartedState = NOT_STARTED;
 
-        KeepaliveInfo(@NonNull Messenger messenger,
-                @NonNull IBinder binder,
+        KeepaliveInfo(@NonNull ISocketKeepaliveCallback callback,
                 @NonNull NetworkAgentInfo nai,
                 @NonNull KeepalivePacketData packet,
                 int interval,
                 int type,
                 @NonNull FileDescriptor fd) {
-            mMessenger = messenger;
-            mBinder = binder;
+            mCallback = callback;
             mPid = Binder.getCallingPid();
             mUid = Binder.getCallingUid();
 
@@ -143,7 +140,7 @@
             mFd = fd;
 
             try {
-                mBinder.linkToDeath(this, 0);
+                mCallback.asBinder().linkToDeath(this, 0);
             } catch (RemoteException e) {
                 binderDied();
             }
@@ -176,22 +173,14 @@
                     + " ]";
         }
 
-        /** Sends a message back to the application via its SocketKeepalive.Callback. */
-        void notifyMessenger(int slot, int err) {
-            if (DBG) {
-                Log.d(TAG, "notify keepalive " + mSlot + " on " + mNai.network + " for " + err);
-            }
-            KeepaliveTracker.this.notifyMessenger(mMessenger, slot, err);
-        }
-
         /** Called when the application process is killed. */
         public void binderDied() {
             stop(BINDER_DIED);
         }
 
         void unlinkDeathRecipient() {
-            if (mBinder != null) {
-                mBinder.unlinkToDeath(this, 0);
+            if (mCallback != null) {
+                mCallback.asBinder().unlinkToDeath(this, 0);
             }
         }
 
@@ -283,9 +272,23 @@
                     Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType);
                 }
             }
-            // TODO: at the moment we unconditionally return failure here. In cases where the
-            // NetworkAgent is alive, should we ask it to reply, so it can return failure?
-            notifyMessenger(mSlot, reason);
+
+            if (reason == SUCCESS) {
+                try {
+                    mCallback.onStopped();
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Discarded onStop callback: " + reason);
+                }
+            } else if (reason == DATA_RECEIVED) {
+                try {
+                    mCallback.onDataReceived();
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Discarded onDataReceived callback: " + reason);
+                }
+            } else {
+                notifyErrorCallback(mCallback, reason);
+            }
+
             unlinkDeathRecipient();
         }
 
@@ -294,16 +297,12 @@
         }
     }
 
-    void notifyMessenger(Messenger messenger, int slot, int err) {
-        Message message = Message.obtain();
-        message.what = EVENT_SOCKET_KEEPALIVE;
-        message.arg1 = slot;
-        message.arg2 = err;
-        message.obj = null;
+    void notifyErrorCallback(ISocketKeepaliveCallback cb, int error) {
+        if (DBG) Log.w(TAG, "Sending onError(" + error + ") callback");
         try {
-            messenger.send(message);
+            cb.onError(error);
         } catch (RemoteException e) {
-            // Process died?
+            Log.w(TAG, "Discarded onError(" + error + ") callback");
         }
     }
 
@@ -414,7 +413,11 @@
             // Keepalive successfully started.
             if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name());
             ki.mStartedState = KeepaliveInfo.STARTED;
-            ki.notifyMessenger(slot, reason);
+            try {
+                ki.mCallback.onStarted(slot);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Discarded onStarted(" + slot + ") callback");
+            }
         } else {
             // Keepalive successfully stopped, or error.
             ki.mStartedState = KeepaliveInfo.NOT_STARTED;
@@ -436,14 +439,13 @@
      **/
     public void startNattKeepalive(@Nullable NetworkAgentInfo nai,
             int intervalSeconds,
-            @NonNull Messenger messenger,
-            @NonNull IBinder binder,
+            @NonNull ISocketKeepaliveCallback cb,
             @NonNull String srcAddrString,
             int srcPort,
             @NonNull String dstAddrString,
             int dstPort) {
         if (nai == null) {
-            notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_NETWORK);
+            notifyErrorCallback(cb, ERROR_INVALID_NETWORK);
             return;
         }
 
@@ -452,7 +454,7 @@
             srcAddress = NetworkUtils.numericToInetAddress(srcAddrString);
             dstAddress = NetworkUtils.numericToInetAddress(dstAddrString);
         } catch (IllegalArgumentException e) {
-            notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_IP_ADDRESS);
+            notifyErrorCallback(cb, ERROR_INVALID_IP_ADDRESS);
             return;
         }
 
@@ -461,11 +463,12 @@
             packet = NattKeepalivePacketData.nattKeepalivePacket(
                     srcAddress, srcPort, dstAddress, NATT_PORT);
         } catch (InvalidPacketException e) {
-            notifyMessenger(messenger, NO_KEEPALIVE, e.error);
+            notifyErrorCallback(cb, e.error);
             return;
         }
-        KeepaliveInfo ki = new KeepaliveInfo(messenger, binder, nai, packet, intervalSeconds,
+        KeepaliveInfo ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
                 KeepaliveInfo.TYPE_NATT, null);
+        Log.d(TAG, "Created keepalive: " + ki.toString());
         mConnectivityServiceHandler.obtainMessage(
                 NetworkAgent.CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget();
     }
@@ -483,10 +486,9 @@
     public void startTcpKeepalive(@Nullable NetworkAgentInfo nai,
             @NonNull FileDescriptor fd,
             int intervalSeconds,
-            @NonNull Messenger messenger,
-            @NonNull IBinder binder) {
+            @NonNull ISocketKeepaliveCallback cb) {
         if (nai == null) {
-            notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_NETWORK);
+            notifyErrorCallback(cb, ERROR_INVALID_NETWORK);
             return;
         }
 
@@ -500,10 +502,10 @@
             } catch (ErrnoException e1) {
                 Log.e(TAG, "Couldn't move fd out of repair mode after failure to start keepalive");
             }
-            notifyMessenger(messenger, NO_KEEPALIVE, e.error);
+            notifyErrorCallback(cb, e.error);
             return;
         }
-        KeepaliveInfo ki = new KeepaliveInfo(messenger, binder, nai, packet, intervalSeconds,
+        KeepaliveInfo ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
                 KeepaliveInfo.TYPE_TCP, fd);
         Log.d(TAG, "Created keepalive: " + ki.toString());
         mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget();
@@ -520,14 +522,13 @@
             @Nullable FileDescriptor fd,
             int resourceId,
             int intervalSeconds,
-            @NonNull Messenger messenger,
-            @NonNull IBinder binder,
+            @NonNull ISocketKeepaliveCallback cb,
             @NonNull String srcAddrString,
             @NonNull String dstAddrString,
             int dstPort) {
         // Ensure that the socket is created by IpSecService.
         if (!isNattKeepaliveSocketValid(fd, resourceId)) {
-            notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_SOCKET);
+            notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
         }
 
         // Get src port to adopt old API.
@@ -536,11 +537,11 @@
             final SocketAddress srcSockAddr = Os.getsockname(fd);
             srcPort = ((InetSocketAddress) srcSockAddr).getPort();
         } catch (ErrnoException e) {
-            notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_SOCKET);
+            notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
         }
 
         // Forward request to old API.
-        startNattKeepalive(nai, intervalSeconds, messenger, binder, srcAddrString, srcPort,
+        startNattKeepalive(nai, intervalSeconds, cb, srcAddrString, srcPort,
                 dstAddrString, dstPort);
     }
 
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 053da0d..828a1e5 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -28,6 +28,7 @@
 import android.content.res.Resources;
 import android.net.wifi.WifiInfo;
 import android.os.UserHandle;
+import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -92,7 +93,7 @@
         return -1;
     }
 
-    private static String getTransportName(int transportType) {
+    private static String getTransportName(@TransportType int transportType) {
         Resources r = Resources.getSystem();
         String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
         try {
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index d84a4d2..123564e 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -46,13 +46,11 @@
 import android.util.Slog;
 import android.util.SparseIntArray;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.LocalServices;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -84,20 +82,14 @@
     // Keys are App IDs. Values are true for SYSTEM permission and false for NETWORK permission.
     private final Map<Integer, Boolean> mApps = new HashMap<>();
 
-    // Keys are App packageNames, Values are app uids. . We need to keep track of this information
-    // because PackageListObserver#onPackageRemoved does not pass the UID.
-    @GuardedBy("mPackageNameUidMap")
-    private final Map<String, Integer> mPackageNameUidMap = new HashMap<>();
-
     private class PackageListObserver implements PackageManagerInternal.PackageListObserver {
         @Override
-        public void onPackageAdded(String packageName) {
+        public void onPackageAdded(String packageName, int uid) {
             final PackageInfo app = getPackageInfo(packageName);
             if (app == null) {
                 Slog.wtf(TAG, "Failed to get information of installed package: " + packageName);
                 return;
             }
-            int uid = (app.applicationInfo != null) ? app.applicationInfo.uid : INVALID_UID;
             if (uid == INVALID_UID) {
                 Slog.wtf(TAG, "Failed to get the uid of installed package: " + packageName
                         + "uid: " + uid);
@@ -107,29 +99,21 @@
                 return;
             }
             sendPackagePermissionsForUid(uid,
-                    filterPermission(Arrays.asList(app.requestedPermissions)));
-            synchronized (mPackageNameUidMap) {
-                mPackageNameUidMap.put(packageName, uid);
-            }
+                    getNetdPermissionMask(app.requestedPermissions));
         }
 
         @Override
-        public void onPackageRemoved(String packageName) {
-            int uid;
-            synchronized (mPackageNameUidMap) {
-                if (!mPackageNameUidMap.containsKey(packageName)) {
-                    return;
-                }
-                uid = mPackageNameUidMap.get(packageName);
-                mPackageNameUidMap.remove(packageName);
-            }
+        public void onPackageRemoved(String packageName, int uid) {
             int permission = 0;
+            // If there are still packages remain under the same uid, check the permission of the
+            // remaining packages. We only remove the permission for a given uid when all packages
+            // for that uid no longer have that permission.
             String[] packages = mPackageManager.getPackagesForUid(uid);
             if (packages != null && packages.length > 0) {
                 for (String name : packages) {
                     final PackageInfo app = getPackageInfo(name);
                     if (app != null && app.requestedPermissions != null) {
-                        permission |= filterPermission(Arrays.asList(app.requestedPermissions));
+                        permission |= getNetdPermissionMask(app.requestedPermissions);
                     }
                 }
             }
@@ -184,12 +168,9 @@
 
             //TODO: unify the management of the permissions into one codepath.
             if (app.requestedPermissions != null) {
-                int otherNetdPerms = filterPermission(Arrays.asList(app.requestedPermissions));
+                int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions);
                 if (otherNetdPerms != 0) {
                     netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
-                    synchronized (mPackageNameUidMap) {
-                        mPackageNameUidMap.put(app.applicationInfo.packageName, uid);
-                    }
                 }
             }
         }
@@ -422,13 +403,15 @@
         }
     }
 
-    private static int filterPermission(List<String> requestedPermissions) {
+    private static int getNetdPermissionMask(String[] requestedPermissions) {
         int permissions = 0;
-        if (requestedPermissions.contains(INTERNET)) {
-            permissions |= INetd.PERMISSION_INTERNET;
-        }
-        if (requestedPermissions.contains(UPDATE_DEVICE_STATS)) {
-            permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
+        for (String permissionName : requestedPermissions) {
+            if (permissionName.equals(INTERNET)) {
+                permissions |= INetd.PERMISSION_INTERNET;
+            }
+            if (permissionName.equals(UPDATE_DEVICE_STATS)) {
+                permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
+            }
         }
         return permissions;
     }
@@ -439,8 +422,6 @@
                     | MATCH_ANY_USER);
             return app;
         } catch (NameNotFoundException e) {
-            // App not found.
-            loge("NameNotFoundException " + packageName);
             return null;
         }
     }
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index d2ccfcc..3c27bf2 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -126,8 +126,26 @@
     private final SparseArray<S> mServicesCache = new SparseArray<>();
 
     /**
+     * Whether the per-user service should be removed from the cache when its apk is updated.
+     */
+    private final boolean mRefreshServiceOnPackageUpdate;
+
+    /**
+     * Name of the service's package that was active but then was removed because its package
+     * update.
+     *
+     * <p>It's a temporary state set / used by the {@link PackageMonitor} implementation, but
+     * defined here so it can be dumped.
+     */
+    @GuardedBy("mLock")
+    private String mLastActivePackageName;
+
+    /**
      * Default constructor.
      *
+     * <p>When using this constructor, the {@link AbstractPerUserSystemService} is removed from
+     * the cache (and re-added) when the service package is updated.
+     *
      * @param context system context.
      * @param serviceNameResolver resolver for
      * {@link com.android.internal.infra.AbstractRemoteService} instances, or
@@ -139,8 +157,32 @@
     protected AbstractMasterSystemService(@NonNull Context context,
             @Nullable ServiceNameResolver serviceNameResolver,
             @Nullable String disallowProperty) {
+        this(context, serviceNameResolver, disallowProperty,
+                /* refreshServiceOnPackageUpdate=*/ true);
+    }
+
+    /**
+     * Full constructor.
+     *
+     * @param context system context.
+     * @param serviceNameResolver resolver for
+     * {@link com.android.internal.infra.AbstractRemoteService} instances, or
+     * {@code null} when the service doesn't bind to remote services.
+     * @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that
+     *        disables the service. <b>NOTE: </b> you'll also need to add it to
+     *        {@code UserRestrictionsUtils.USER_RESTRICTIONS}.
+     * @param refreshServiceOnPackageUpdate when {@code true}, the
+     *        {@link AbstractPerUserSystemService} is removed from the cache (and re-added) when the
+     *        service package is updated; when {@code false}, the service is untouched during the
+     *        update.
+     */
+    protected AbstractMasterSystemService(@NonNull Context context,
+            @Nullable ServiceNameResolver serviceNameResolver,
+            @Nullable String disallowProperty, boolean refreshServiceOnPackageUpdate) {
         super(context);
 
+        mRefreshServiceOnPackageUpdate = refreshServiceOnPackageUpdate;
+
         mServiceNameResolver = serviceNameResolver;
         if (mServiceNameResolver != null) {
             mServiceNameResolver
@@ -280,9 +322,6 @@
                 oldService.removeSelfFromCacheLocked();
             }
             mServiceNameResolver.setTemporaryService(userId, componentName, durationMs);
-
-            // Must update the service on cache so its initialization code is triggered
-            updateCachedServiceLocked(userId);
         }
     }
 
@@ -553,6 +592,8 @@
             final int size = mServicesCache.size();
             pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
             pw.print(" Verbose: "); pw.println(realVerbose);
+            pw.print(" Refresh on package update: "); pw.println(mRefreshServiceOnPackageUpdate);
+            pw.print(" Last active service on update: "); pw.println(mLastActivePackageName);
             if (mServiceNameResolver != null) {
                 pw.print(prefix); pw.print("Name resolver: ");
                 mServiceNameResolver.dumpShort(pw); pw.println();
@@ -590,21 +631,42 @@
     }
 
     private void startTrackingPackageChanges() {
-        PackageMonitor monitor = new PackageMonitor() {
+        final PackageMonitor monitor = new PackageMonitor() {
+
             @Override
-            public void onSomePackagesChanged() {
+            public void onPackageUpdateStarted(String packageName, int uid) {
                 synchronized (mLock) {
-                    updateCachedServiceLocked(getChangingUserId());
+                    final String activePackageName = getActiveServicePackageNameLocked();
+                    if (packageName.equals(activePackageName)) {
+                        final int userId = getChangingUserId();
+                        if (mRefreshServiceOnPackageUpdate) {
+                            if (debug) {
+                                Slog.d(mTag, "Removing service for user " + userId
+                                        + " because package " + activePackageName
+                                        + " is being updated");
+                            }
+                            mLastActivePackageName = activePackageName;
+                            removeCachedServiceLocked(userId);
+                        } else {
+                            if (debug) {
+                                Slog.d(mTag, "Holding service for user " + userId
+                                        + " while package " + activePackageName
+                                        + " is being updated");
+                            }
+                        }
+                    }
                 }
             }
 
             @Override
             public void onPackageUpdateFinished(String packageName, int uid) {
                 synchronized (mLock) {
-                    final String activePackageName = getActiveServicePackageName();
-                    if (packageName.equals(activePackageName)) {
-                        removeCachedServiceLocked(getChangingUserId());
-                    } else {
+                    String activePackageName = getActiveServicePackageNameLocked();
+                    if (activePackageName == null) {
+                        activePackageName = mLastActivePackageName;
+                        mLastActivePackageName = null;
+                    }
+                    if (!packageName.equals(activePackageName)) {
                         handlePackageUpdateLocked(packageName);
                     }
                 }
@@ -630,7 +692,7 @@
             public boolean onHandleForceStop(Intent intent, String[] packages,
                     int uid, boolean doit) {
                 synchronized (mLock) {
-                    final String activePackageName = getActiveServicePackageName();
+                    final String activePackageName = getActiveServicePackageNameLocked();
                     for (String pkg : packages) {
                         if (pkg.equals(activePackageName)) {
                             if (!doit) {
@@ -646,7 +708,9 @@
             }
 
             private void handleActiveServiceRemoved(@UserIdInt int userId) {
-                removeCachedServiceLocked(userId);
+                synchronized (mLock) {
+                    removeCachedServiceLocked(userId);
+                }
                 final String serviceSettingsProperty = getServiceSettingsProperty();
                 if (serviceSettingsProperty != null) {
                     Settings.Secure.putStringForUser(getContext().getContentResolver(),
@@ -654,7 +718,7 @@
                 }
             }
 
-            private String getActiveServicePackageName() {
+            private String getActiveServicePackageNameLocked() {
                 final int userId = getChangingUserId();
                 final S service = peekServiceForUserLocked(userId);
                 if (service == null) {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 98f1740..2ede384 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -29,7 +29,6 @@
 import android.os.Environment;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.os.storage.StorageManager;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
@@ -49,6 +48,7 @@
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
@@ -808,7 +808,7 @@
         }
 
         byte[] peekFile(String fileName) {
-            return (byte[]) peek(CacheKey.TYPE_FILE, fileName, -1 /* userId */);
+            return copyOf((byte[]) peek(CacheKey.TYPE_FILE, fileName, -1 /* userId */));
         }
 
         boolean hasFile(String fileName) {
@@ -816,11 +816,11 @@
         }
 
         void putFile(String key, byte[] value) {
-            put(CacheKey.TYPE_FILE, key, value, -1 /* userId */);
+            put(CacheKey.TYPE_FILE, key, copyOf(value), -1 /* userId */);
         }
 
         void putFileIfUnchanged(String key, byte[] value, int version) {
-            putIfUnchanged(CacheKey.TYPE_FILE, key, value, -1 /* userId */, version);
+            putIfUnchanged(CacheKey.TYPE_FILE, key, copyOf(value), -1 /* userId */, version);
         }
 
         void setFetched(int userId) {
@@ -868,6 +868,10 @@
             mVersion++;
         }
 
+        private byte[] copyOf(byte[] data) {
+            return data != null ? Arrays.copyOf(data, data.length) : null;
+        }
+
         synchronized void purgePath(String path) {
             for (int i = mCache.size() - 1; i >= 0; i--) {
                 CacheKey entry = mCache.keyAt(i);
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
index b86328b..94f289f 100644
--- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -64,6 +64,7 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -138,9 +139,9 @@
     private MediaSessionRecord mGlobalPrioritySession;
     private AudioPlayerStateMonitor mAudioPlayerStateMonitor;
 
-    // Used to notify system UI when remote volume was changed. TODO find a
-    // better way to handle this.
-    private IRemoteVolumeController mRvc;
+    // Used to notify System UI and Settings when remote volume was changed.
+    final RemoteCallbackList<IRemoteVolumeController> mRemoteVolumeControllers =
+            new RemoteCallbackList<>();
 
     public MediaSessionServiceImpl(Context context) {
         mContext = context;
@@ -281,20 +282,23 @@
     }
 
     /**
-     * Tells the system UI that volume has changed on an active remote session.
+     * Tells the System UI and Settings app that volume has changed on an active remote session.
      */
     public void notifyRemoteVolumeChanged(int flags, MediaSessionRecord session) {
-        synchronized (mLock) {
-            if (mRvc == null || !session.isActive()) {
-                return;
-            }
+        if (!session.isActive()) {
+            return;
+        }
+        int size = mRemoteVolumeControllers.beginBroadcast();
+        MediaSession.Token token = session.getSessionToken();
+        for (int i = size - 1; i >= 0; i--) {
             try {
-                mRvc.remoteVolumeChanged(session.getSessionToken(), flags);
+                IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i);
+                cb.remoteVolumeChanged(token, flags);
             } catch (Exception e) {
-                Log.w(TAG, "Error sending volume change to system UI.", e);
-                mRvc = null;
+                Log.w(TAG, "Error sending volume change.", e);
             }
         }
+        mRemoteVolumeControllers.finishBroadcast();
     }
 
     @Override
@@ -497,7 +501,7 @@
      */
     private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
             int resolvedUserId) {
-        if (isCurrentVolumeController(pid, uid)) return;
+        if (hasStatusBarServicePermission(pid, uid)) return;
         if (mContext
                 .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
                 != PackageManager.PERMISSION_GRANTED
@@ -507,14 +511,14 @@
         }
     }
 
-    private boolean isCurrentVolumeController(int pid, int uid) {
+    private boolean hasStatusBarServicePermission(int pid, int uid) {
         return mContext.checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
                 pid, uid) == PackageManager.PERMISSION_GRANTED;
     }
 
-    private void enforceSystemUiPermission(String action, int pid, int uid) {
-        if (!isCurrentVolumeController(pid, uid)) {
-            throw new SecurityException("Only system ui may " + action);
+    private void enforceStatusBarServicePermission(String action, int pid, int uid) {
+        if (!hasStatusBarServicePermission(pid, uid)) {
+            throw new SecurityException("Only System UI and Settings may " + action);
         }
     }
 
@@ -638,20 +642,25 @@
     }
 
     private void pushRemoteVolumeUpdateLocked(int userId) {
-        if (mRvc != null) {
+        FullUserRecord user = getFullUserRecordLocked(userId);
+        if (user == null) {
+            Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId);
+            return;
+        }
+
+        int size = mRemoteVolumeControllers.beginBroadcast();
+        MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
+        MediaSession.Token token = record == null ? null : record.getSessionToken();
+
+        for (int i = size - 1; i >= 0; i--) {
             try {
-                FullUserRecord user = getFullUserRecordLocked(userId);
-                if (user == null) {
-                    Log.w(TAG, "pushRemoteVolumeUpdateLocked failed. No user with id=" + userId);
-                    return;
-                }
-                MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
-                mRvc.updateRemoteController(record == null ? null : record.getSessionToken());
-            } catch (RemoteException e) {
-                Log.w(TAG, "Error sending default remote volume to sys ui.", e);
-                mRvc = null;
+                IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i);
+                cb.updateRemoteController(token);
+            } catch (Exception e) {
+                Log.w(TAG, "Error sending default remote volume.", e);
             }
         }
+        mRemoteVolumeControllers.finishBroadcast();
     }
 
     void pushSession2TokensChangedLocked(int userId) {
@@ -1661,15 +1670,26 @@
         }
 
         @Override
-        public void setRemoteVolumeController(IRemoteVolumeController rvc) {
+        public void registerRemoteVolumeController(IRemoteVolumeController rvc) {
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                enforceSystemUiPermission("listen for volume changes", pid, uid);
-                synchronized (mLock) {
-                    mRvc = rvc;
-                }
+                enforceStatusBarServicePermission("listen for volume changes", pid, uid);
+                mRemoteVolumeControllers.register(rvc);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void unregisterRemoteVolumeController(IRemoteVolumeController rvc) {
+            final int pid = Binder.getCallingPid();
+            final int uid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                enforceStatusBarServicePermission("listen for volume changes", pid, uid);
+                mRemoteVolumeControllers.unregister(rvc);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -1755,8 +1775,8 @@
 
         private boolean hasMediaControlPermission(int resolvedUserId, String packageName,
                 int pid, int uid) throws RemoteException {
-            // Allow API calls from the System UI
-            if (isCurrentVolumeController(pid, uid)) {
+            // Allow API calls from the System UI and Settings
+            if (hasStatusBarServicePermission(pid, uid)) {
                 return true;
             }
 
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 64f31cd..5c0874d 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -40,10 +40,6 @@
 
 import java.io.FileDescriptor;
 
-// TODO(b/111441001):
-// Intercept onFinished() & implement death recipient here and shutdown
-// bugreportd service.
-
 /**
  * Implementation of the service that provides a privileged API to capture and consume bugreports.
  *
@@ -171,9 +167,12 @@
             reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
             return;
         }
+
+        // Wrap the listener so we can intercept binder events directly.
+        IDumpstateListener myListener = new DumpstateListener(listener, ds);
         try {
             ds.startBugreport(callingUid, callingPackage,
-                    bugreportFd, screenshotFd, bugreportMode, listener);
+                    bugreportFd, screenshotFd, bugreportMode, myListener);
         } catch (RemoteException e) {
             reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
         }
@@ -240,4 +239,73 @@
         Slog.w(TAG, message);
         throw new IllegalArgumentException(message);
     }
+
+
+    private final class DumpstateListener extends IDumpstateListener.Stub
+            implements DeathRecipient {
+        private final IDumpstateListener mListener;
+        private final IDumpstate mDs;
+        private boolean mDone = false;
+
+        DumpstateListener(IDumpstateListener listener, IDumpstate ds) {
+            mListener = listener;
+            mDs = ds;
+            try {
+                mDs.asBinder().linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to register Death Recipient for IDumpstate", e);
+            }
+        }
+
+        @Override
+        public void onProgress(int progress) throws RemoteException {
+            mListener.onProgress(progress);
+        }
+
+        @Override
+        public void onError(int errorCode) throws RemoteException {
+            synchronized (mLock) {
+                mDone = true;
+            }
+            mListener.onError(errorCode);
+        }
+
+        @Override
+        public void onFinished() throws RemoteException {
+            synchronized (mLock) {
+                mDone = true;
+            }
+            mListener.onFinished();
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (mLock) {
+                if (!mDone) {
+                    // If we have not gotten a "done" callback this must be a crash.
+                    Slog.e(TAG, "IDumpstate likely crashed. Notifying listener");
+                    try {
+                        mListener.onError(IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
+                    } catch (RemoteException ignored) {
+                        // If listener is not around, there isn't anything to do here.
+                    }
+                }
+            }
+            mDs.asBinder().unlinkToDeath(this, 0);
+        }
+
+        // Old methods; unused in the API flow.
+        @Override
+        public void onProgressUpdated(int progress) throws RemoteException {
+        }
+
+        @Override
+        public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
+        }
+
+        @Override
+        public void onSectionComplete(String title, int status, int size, int durationMs)
+                throws RemoteException {
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index a4c04b2..5fdd872 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -41,6 +41,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Function;
@@ -135,6 +136,17 @@
     }
 
     /**
+     * Checks if {@code packageName} is an apex package.
+     *
+     * @param packageName package to check.
+     * @return {@code true} if {@code packageName} is an apex package.
+     */
+    boolean isApexPackage(String packageName) {
+        populateActivePackagesCacheIfNeeded();
+        return mActivePackagesCache.containsKey(packageName);
+    }
+
+    /**
      * Retrieves information about an apexd staged session i.e. the internal state used by apexd to
      * track the different states of a session.
      *
@@ -246,6 +258,23 @@
     }
 
     /**
+     * Uninstalls given {@code apexPackage}.
+     *
+     * <p>NOTE. Device must be rebooted in order for uninstall to take effect.
+     *
+     * @param apexPackagePath package to uninstall.
+     * @return {@code true} upon successful uninstall, {@code false} otherwise.
+     */
+    boolean uninstallApex(String apexPackagePath) {
+        try {
+            mApexService.unstagePackages(Collections.singletonList(apexPackagePath));
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    /**
      * Dumps various state information to the provided {@link PrintWriter} object.
      *
      * @param pw the {@link PrintWriter} object to send information to.
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 05af13a..7f057f0 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -432,7 +432,7 @@
                     }
                     ApplicationInfo appInfo = pmInt.getApplicationInfo(packageName, /*flags*/ 0,
                             callingUid, user.getIdentifier());
-                    if (shouldShowHiddenApp(user, appInfo)) {
+                    if (shouldShowSyntheticActivity(user, appInfo)) {
                         ResolveInfo info = getHiddenAppActivityInfo(packageName, callingUid, user);
                         if (info != null) {
                             result.add(info);
@@ -448,7 +448,7 @@
                         user.getIdentifier(), callingUid);
                 for (ApplicationInfo applicationInfo : installedPackages) {
                     if (!visiblePackages.contains(applicationInfo.packageName)) {
-                        if (!shouldShowHiddenApp(user, applicationInfo)) {
+                        if (!shouldShowSyntheticActivity(user, applicationInfo)) {
                             continue;
                         }
                         ResolveInfo info = getHiddenAppActivityInfo(applicationInfo.packageName,
@@ -464,7 +464,7 @@
             }
         }
 
-        private boolean shouldShowHiddenApp(UserHandle user, ApplicationInfo appInfo) {
+        private boolean shouldShowSyntheticActivity(UserHandle user, ApplicationInfo appInfo) {
             if (appInfo == null || appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) {
                 return false;
             }
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index 3c1ee3e..af9b12a 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -10,76 +10,48 @@
 toddke@google.com
 
 # apex support
-per-file ApexManager.java = dariofreni@google.com, narayan@google.com, toddke@android.com, toddke@google.com
-per-file StagingManager.java = dariofreni@google.com, narayan@google.com, toddke@android.com, toddke@google.com
+per-file ApexManager.java = dariofreni@google.com
+per-file StagingManager.java = dariofreni@google.com
 
 # dex
-per-file AbstractStatsBase.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file AbstractStatsBase.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file AbstractStatsBase.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file BackgroundDexOptService.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file BackgroundDexOptService.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file BackgroundDexOptService.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file CompilerStats.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file CompilerStats.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file CompilerStats.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file DynamicCodeLoggingService.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file DynamicCodeLoggingService.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file DynamicCodeLoggingService.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file InstructionSets.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file InstructionSets.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file InstructionSets.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file OtaDexoptService.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file OtaDexoptService.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file OtaDexoptService.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file OtaDexoptShellCommand.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file OtaDexoptShellCommand.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file OtaDexoptShellCommand.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageDexOptimizer.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageDexOptimizer.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageDexOptimizer.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageManagerServiceCompilerMapping.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageManagerServiceCompilerMapping.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageManagerServiceCompilerMapping.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageUsage.java = agampe@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageUsage.java = calin@google.com, toddke@google.com, svetoslavganov@google.com
-per-file PackageUsage.java = ngeoffray@google.com, toddke@google.com, svetoslavganov@google.com
+per-file AbstractStatsBase.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file BackgroundDexOptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file CompilerStats.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file DynamicCodeLoggingService.java = alanstokes@google.com, agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file InstructionSets.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file OtaDexoptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file OtaDexoptShellCommand.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file PackageDexOptimizer.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file PackageManagerServiceCompilerMapping.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file PackageUsage.java = agampe@google.com, calin@google.com, ngeoffray@google.com
 
 # multi user / cross profile
-per-file CrossProfileAppsServiceImpl.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file CrossProfileAppsServiceImpl.java = yamasani@google.com, omakoto@google.com, hackbod@google.com
-per-file CrossProfileAppsService.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file CrossProfileAppsService.java = yamasani@google.com, omakoto@google.com, hackbod@google.com
-per-file CrossProfileIntentFilter.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file CrossProfileIntentFilter.java = yamasani@google.com, omakoto@google.com, hackbod@google.com
-per-file CrossProfileIntentResolver.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file CrossProfileIntentResolver.java = yamasani@google.com, omakoto@google.com, hackbod@google.com
-per-file UserManagerService.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file UserManagerService.java = yamasani@google.com, omakoto@google.com, hackbod@google.com
-per-file UserRestrictionsUtils.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file UserRestrictionsUtils.java = yamasani@google.com, omakoto@google.com, hackbod@google.com
-per-file UserRestrictionsUtils.java = rubinxu@google.com, yamasani@google.com, hackbod@google.com
-per-file UserRestrictionsUtils.java = sandness@google.com, yamasani@google.com, hackbod@google.com
+per-file CrossProfileAppsServiceImpl.java = omakoto@google.com, yamasani@google.com
+per-file CrossProfileAppsService.java = omakoto@google.com, yamasani@google.com
+per-file CrossProfileIntentFilter.java = omakoto@google.com, yamasani@google.com
+per-file CrossProfileIntentResolver.java = omakoto@google.com, yamasani@google.com
+per-file UserManagerService.java = omakoto@google.com, yamasani@google.com
+per-file UserRestrictionsUtils.java = omakoto@google.com, rubinxu@google.com, sandness@google.com, yamasani@google.com
 
 # security
-per-file KeySetHandle.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com
-per-file KeySetManagerService.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com
-per-file PackageKeySetData.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com
-per-file PackageSignatures.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com
-per-file SELinuxMMAC.java = cbrubaker@google.com, svetoslavganov@google.com, hackbod@google.com
+per-file KeySetHandle.java = cbrubaker@google.com
+per-file KeySetManagerService.java = cbrubaker@google.com
+per-file PackageKeySetData.java = cbrubaker@google.com
+per-file PackageSignatures.java = cbrubaker@google.com
+per-file SELinuxMMAC.java = cbrubaker@google.com
 
 # shortcuts
-per-file LauncherAppsService.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShareTargetInfo.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutBitmapSaver.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutDumpFiles.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutLauncher.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutNonPersistentUser.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutPackage.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutPackageInfo.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutPackageItem.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutParser.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutRequestPinProcessor.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutService.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
-per-file ShortcutUser.java = omakoto@google.com, yamasani@google.com, hackbod@google.com
+per-file LauncherAppsService.java = omakoto@google.com, yamasani@google.com
+per-file ShareTargetInfo.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutBitmapSaver.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutDumpFiles.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutLauncher.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutNonPersistentUser.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutPackage.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutPackageInfo.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutPackageItem.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutParser.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutRequestPinProcessor.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutService.java = omakoto@google.com, yamasani@google.com
+per-file ShortcutUser.java = omakoto@google.com, yamasani@google.com
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 3a4bcca..181b7a2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -27,6 +27,7 @@
 import android.app.NotificationManager;
 import android.app.PackageDeleteObserver;
 import android.app.PackageInstallObserver;
+import android.app.admin.DevicePolicyEventLogger;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.Context;
 import android.content.Intent;
@@ -59,6 +60,7 @@
 import android.os.SELinux;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
+import android.stats.devicepolicy.DevicePolicyEnums;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.text.TextUtils;
@@ -205,7 +207,7 @@
 
         mApexManager = am;
 
-        mStagingManager = new StagingManager(pm, this, am, context);
+        mStagingManager = new StagingManager(this, am, context);
     }
 
     boolean okToSendBroadcasts()  {
@@ -589,7 +591,7 @@
         session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
                 mInstallThread.getLooper(), mStagingManager, sessionId, userId,
                 installerPackageName, callingUid, params, createdMillis, stageDir, stageCid, false,
-                false, null, SessionInfo.INVALID_ID, false, false, false,
+                false, false, null, SessionInfo.INVALID_ID, false, false, false,
                 SessionInfo.STAGED_SESSION_NO_ERROR, "");
 
         synchronized (mSessions) {
@@ -810,6 +812,10 @@
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
+            DevicePolicyEventLogger
+                    .createEvent(DevicePolicyEnums.UNINSTALL_PACKAGE)
+                    .setAdmin(callerPackageName)
+                    .write();
         } else {
             ApplicationInfo appInfo = mPm.getApplicationInfo(callerPackageName, 0, userId);
             if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 45b3b5b..6451b56 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -44,6 +44,7 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.admin.DevicePolicyEventLogger;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.Context;
 import android.content.IIntentReceiver;
@@ -82,6 +83,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
+import android.stats.devicepolicy.DevicePolicyEnums;
 import android.system.ErrnoException;
 import android.system.Int64Ref;
 import android.system.Os;
@@ -145,6 +147,7 @@
     private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
     private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
     private static final String ATTR_PREPARED = "prepared";
+    private static final String ATTR_COMMITTED = "committed";
     private static final String ATTR_SEALED = "sealed";
     private static final String ATTR_MULTI_PACKAGE = "multiPackage";
     private static final String ATTR_PARENT_SESSION_ID = "parentSessionId";
@@ -401,7 +404,7 @@
             PackageSessionProvider sessionProvider, Looper looper, StagingManager stagingManager,
             int sessionId, int userId,
             String installerPackageName, int installerUid, SessionParams params, long createdMillis,
-            File stageDir, String stageCid, boolean prepared, boolean sealed,
+            File stageDir, String stageCid, boolean prepared, boolean committed, boolean sealed,
             @Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
             boolean isFailed, boolean isApplied, int stagedSessionErrorCode,
             String stagedSessionErrorMessage) {
@@ -434,6 +437,7 @@
         }
 
         mPrepared = prepared;
+        mCommitted = committed;
         mStagedSessionReady = isReady;
         mStagedSessionFailed = isFailed;
         mStagedSessionApplied = isApplied;
@@ -510,6 +514,13 @@
         }
     }
 
+    /** {@hide} */
+    boolean isCommitted() {
+        synchronized (mLock) {
+            return mCommitted;
+        }
+    }
+
     @GuardedBy("mLock")
     private void assertPreparedAndNotSealedLocked(String cookie) {
         assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
@@ -984,6 +995,19 @@
 
         mSealed = true;
 
+        if (params.isStaged) {
+            final PackageInstallerSession activeSession = mStagingManager.getActiveSession();
+            final boolean anotherSessionAlreadyInProgress =
+                    activeSession != null && sessionId != activeSession.sessionId
+                            && mParentSessionId != activeSession.sessionId;
+            if (anotherSessionAlreadyInProgress) {
+                throw new PackageManagerException(
+                        PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
+                        "There is already in-progress committed staged session "
+                                + activeSession.sessionId, null);
+            }
+        }
+
         // Read transfers from the original owner stay open, but as the session's data
         // cannot be modified anymore, there is no leak of information. For staged sessions,
         // further validation is performed by the staging manager.
@@ -1063,6 +1087,12 @@
     }
 
     private void handleCommit() {
+        if (isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()) {
+            DevicePolicyEventLogger
+                    .createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
+                    .setAdmin(mInstallerPackageName)
+                    .write();
+        }
         if (params.isStaged) {
             mStagingManager.commitSession(this);
             destroyInternal();
@@ -2143,6 +2173,7 @@
 
         pw.printPair("mClientProgress", mClientProgress);
         pw.printPair("mProgress", mProgress);
+        pw.printPair("mCommitted", mCommitted);
         pw.printPair("mSealed", mSealed);
         pw.printPair("mPermissionsManuallyAccepted", mPermissionsManuallyAccepted);
         pw.printPair("mRelinquished", mRelinquished);
@@ -2201,6 +2232,7 @@
                 writeStringAttribute(out, ATTR_SESSION_STAGE_CID, stageCid);
             }
             writeBooleanAttribute(out, ATTR_PREPARED, isPrepared());
+            writeBooleanAttribute(out, ATTR_COMMITTED, isCommitted());
             writeBooleanAttribute(out, ATTR_SEALED, isSealed());
 
             writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage);
@@ -2298,6 +2330,7 @@
         final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
         final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
         final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
+        final boolean committed = readBooleanAttribute(in, ATTR_COMMITTED);
         final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
         final int parentSessionId = readIntAttribute(in, ATTR_PARENT_SESSION_ID,
                 SessionInfo.INVALID_ID);
@@ -2374,8 +2407,8 @@
 
         return new PackageInstallerSession(callback, context, pm, sessionProvider,
                 installerThread, stagingManager, sessionId, userId, installerPackageName,
-                installerUid, params, createdMillis, stageDir, stageCid, prepared, sealed,
-                childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied,
+                installerUid, params, createdMillis, stageDir, stageCid, prepared, committed,
+                sealed, childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied,
                 stagedSessionErrorCode, stagedSessionErrorMessage);
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4dcab5e..e5b6397 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -160,6 +160,7 @@
 import android.content.pm.InstantAppRequest;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
+import android.content.pm.PackageBackwardCompatibility;
 import android.content.pm.KeySet;
 import android.content.pm.ModuleInfo;
 import android.content.pm.PackageInfo;
@@ -1952,7 +1953,7 @@
             }
 
             if (allNewUsers && !update) {
-                notifyPackageAdded(packageName);
+                notifyPackageAdded(packageName, res.uid);
             }
 
             // Log current value of "unknown sources" setting
@@ -11058,6 +11059,8 @@
             pkg.mRealPackage = null;
             pkg.mAdoptPermissions = null;
         }
+
+        PackageBackwardCompatibility.modifySharedLibraries(pkg);
     }
 
     private static @NonNull <T> T assertNotNull(@Nullable T object, String message)
@@ -12317,7 +12320,7 @@
     }
 
     @Override
-    public void notifyPackageAdded(String packageName) {
+    public void notifyPackageAdded(String packageName, int uid) {
         final PackageListObserver[] observers;
         synchronized (mPackages) {
             if (mPackageListObservers.size() == 0) {
@@ -12328,7 +12331,7 @@
             observers = mPackageListObservers.toArray(observerArray);
         }
         for (int i = observers.length - 1; i >= 0; --i) {
-            observers[i].onPackageAdded(packageName);
+            observers[i].onPackageAdded(packageName, uid);
         }
     }
 
@@ -12339,7 +12342,7 @@
     };
 
     @Override
-    public void notifyPackageRemoved(String packageName) {
+    public void notifyPackageRemoved(String packageName, int uid) {
         final PackageListObserver[] observers;
         synchronized (mPackages) {
             if (mPackageListObservers.size() == 0) {
@@ -12350,7 +12353,7 @@
             observers = mPackageListObservers.toArray(observerArray);
         }
         for (int i = observers.length - 1; i >= 0; --i) {
-            observers[i].onPackageRemoved(packageName);
+            observers[i].onPackageRemoved(packageName, uid);
         }
     }
 
@@ -12937,6 +12940,8 @@
         final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
         final IntArray changedUids = new IntArray(packageNames.length);
         final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
+        final boolean[] canRestrict = (restrictionFlags != 0) ? canSuspendPackageForUserInternal(
+                packageNames, userId) : null;
 
         for (int i = 0; i < packageNames.length; i++) {
             final String packageName = packageNames[i];
@@ -12950,7 +12955,7 @@
                     continue;
                 }
             }
-            if (restrictionFlags != 0 && !canSuspendPackageForUserInternal(packageName, userId)) {
+            if (canRestrict != null && !canRestrict[i]) {
                 unactionedPackages.add(packageName);
                 continue;
             }
@@ -13007,6 +13012,8 @@
         final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
         final IntArray changedUids = new IntArray(packageNames.length);
         final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
+        final boolean[] canSuspend = suspended ? canSuspendPackageForUserInternal(packageNames,
+                userId) : null;
 
         for (int i = 0; i < packageNames.length; i++) {
             final String packageName = packageNames[i];
@@ -13026,7 +13033,7 @@
                     continue;
                 }
             }
-            if (suspended && !canSuspendPackageForUserInternal(packageName, userId)) {
+            if (canSuspend != null && !canSuspend[i]) {
                 unactionedPackages.add(packageName);
                 continue;
             }
@@ -13190,87 +13197,97 @@
                     + " cannot query getUnsuspendablePackagesForUser for user " + userId);
         }
         final ArraySet<String> unactionablePackages = new ArraySet<>();
-        for (String packageName : packageNames) {
-            if (!canSuspendPackageForUserInternal(packageName, userId)) {
-                unactionablePackages.add(packageName);
+        final boolean[] canSuspend = canSuspendPackageForUserInternal(packageNames, userId);
+        for (int i = 0; i < packageNames.length; i++) {
+            if (!canSuspend[i]) {
+                unactionablePackages.add(packageNames[i]);
             }
         }
         return unactionablePackages.toArray(new String[unactionablePackages.size()]);
     }
 
-    private boolean canSuspendPackageForUserInternal(String packageName, int userId) {
+    /**
+     * Returns an array of booleans, such that the ith boolean denotes whether the ith package can
+     * be suspended or not.
+     *
+     * @param packageNames  The package names to check suspendability for.
+     * @param userId The user to check in
+     * @return An array containing results of the checks
+     */
+    @NonNull
+    private boolean[] canSuspendPackageForUserInternal(@NonNull String[] packageNames, int userId) {
+        final boolean[] canSuspend = new boolean[packageNames.length];
         final long callingId = Binder.clearCallingIdentity();
         try {
-            if (isPackageDeviceAdmin(packageName, userId)) {
-                Slog.w(TAG, "Cannot suspend package \"" + packageName
-                        + "\": has an active device admin");
-                return false;
-            }
+            final String activeLauncherPackageName = getActiveLauncherPackageName(userId);
+            final String dialerPackageName = getDefaultDialerPackageName(userId);
+            for (int i = 0; i < packageNames.length; i++) {
+                canSuspend[i] = false;
+                final String packageName = packageNames[i];
 
-            String activeLauncherPackageName = getActiveLauncherPackageName(userId);
-            if (packageName.equals(activeLauncherPackageName)) {
-                Slog.w(TAG, "Cannot suspend package \"" + packageName
-                        + "\": contains the active launcher");
-                return false;
-            }
-
-            if (packageName.equals(mRequiredInstallerPackage)) {
-                Slog.w(TAG, "Cannot suspend package \"" + packageName
-                        + "\": required for package installation");
-                return false;
-            }
-
-            if (packageName.equals(mRequiredUninstallerPackage)) {
-                Slog.w(TAG, "Cannot suspend package \"" + packageName
-                        + "\": required for package uninstallation");
-                return false;
-            }
-
-            if (packageName.equals(mRequiredVerifierPackage)) {
-                Slog.w(TAG, "Cannot suspend package \"" + packageName
-                        + "\": required for package verification");
-                return false;
-            }
-
-            if (packageName.equals(getDefaultDialerPackageName(userId))) {
-                Slog.w(TAG, "Cannot suspend package \"" + packageName
-                        + "\": is the default dialer");
-                return false;
-            }
-
-            if (packageName.equals(mRequiredPermissionControllerPackage)) {
-                Slog.w(TAG, "Cannot suspend package \"" + packageName
-                        + "\": required for permissions management");
-                return false;
-            }
-
-            synchronized (mPackages) {
-                if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+                if (isPackageDeviceAdmin(packageName, userId)) {
                     Slog.w(TAG, "Cannot suspend package \"" + packageName
-                            + "\": protected package");
-                    return false;
+                            + "\": has an active device admin");
+                    continue;
                 }
-
-                // Cannot suspend static shared libs as they are considered
-                // a part of the using app (emulating static linking). Also
-                // static libs are installed always on internal storage.
-                PackageParser.Package pkg = mPackages.get(packageName);
-                if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
-                    Slog.w(TAG, "Cannot suspend package: " + packageName
-                            + " providing static shared library: "
-                            + pkg.staticSharedLibName);
-                    return false;
+                if (packageName.equals(activeLauncherPackageName)) {
+                    Slog.w(TAG, "Cannot suspend package \"" + packageName
+                            + "\": contains the active launcher");
+                    continue;
                 }
-            }
+                if (packageName.equals(mRequiredInstallerPackage)) {
+                    Slog.w(TAG, "Cannot suspend package \"" + packageName
+                            + "\": required for package installation");
+                    continue;
+                }
+                if (packageName.equals(mRequiredUninstallerPackage)) {
+                    Slog.w(TAG, "Cannot suspend package \"" + packageName
+                            + "\": required for package uninstallation");
+                    continue;
+                }
+                if (packageName.equals(mRequiredVerifierPackage)) {
+                    Slog.w(TAG, "Cannot suspend package \"" + packageName
+                            + "\": required for package verification");
+                    continue;
+                }
+                if (packageName.equals(dialerPackageName)) {
+                    Slog.w(TAG, "Cannot suspend package \"" + packageName
+                            + "\": is the default dialer");
+                    continue;
+                }
+                if (packageName.equals(mRequiredPermissionControllerPackage)) {
+                    Slog.w(TAG, "Cannot suspend package \"" + packageName
+                            + "\": required for permissions management");
+                    continue;
+                }
+                synchronized (mPackages) {
+                    if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+                        Slog.w(TAG, "Cannot suspend package \"" + packageName
+                                + "\": protected package");
+                        continue;
+                    }
 
-            if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
-                Slog.w(TAG, "Cannot suspend the platform package: " + packageName);
-                return false;
+                    // Cannot suspend static shared libs as they are considered
+                    // a part of the using app (emulating static linking). Also
+                    // static libs are installed always on internal storage.
+                    PackageParser.Package pkg = mPackages.get(packageName);
+                    if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
+                        Slog.w(TAG, "Cannot suspend package: " + packageName
+                                + " providing static shared library: "
+                                + pkg.staticSharedLibName);
+                        continue;
+                    }
+                }
+                if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
+                    Slog.w(TAG, "Cannot suspend the platform package: " + packageName);
+                    continue;
+                }
+                canSuspend[i] = true;
             }
-            return true;
         } finally {
             Binder.restoreCallingIdentity(callingId);
         }
+        return canSuspend;
     }
 
     private String getActiveLauncherPackageName(int userId) {
@@ -17904,7 +17921,8 @@
                 return;
             }
             Bundle extras = new Bundle(2);
-            extras.putInt(Intent.EXTRA_UID, removedAppId >= 0  ? removedAppId : uid);
+            final int removedUid = removedAppId >= 0  ? removedAppId : uid;
+            extras.putInt(Intent.EXTRA_UID, removedUid);
             extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
             extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
             if (isUpdate || isRemovedPackageSystemUpdate) {
@@ -17925,7 +17943,7 @@
                         removedPackage, extras,
                         Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,
                         null, null, broadcastUsers, instantUserIds);
-                    packageSender.notifyPackageRemoved(removedPackage);
+                    packageSender.notifyPackageRemoved(removedPackage, removedUid);
                 }
             }
             if (removedAppId >= 0) {
@@ -23901,6 +23919,50 @@
                 mDefaultHomeProvider = provider;
             }
         }
+
+        @Override
+        public boolean isApexPackage(String packageName) {
+            return PackageManagerService.this.mApexManager.isApexPackage(packageName);
+        }
+
+        @Override
+        public void uninstallApex(String packageName, long versionCode, int userId,
+                IntentSender intentSender) {
+            final int callerUid = Binder.getCallingUid();
+            if (callerUid != Process.ROOT_UID && callerUid != Process.SHELL_UID) {
+                throw new SecurityException("Not allowed to uninstall apexes");
+            }
+            PackageInstallerService.PackageDeleteObserverAdapter adapter =
+                    new PackageInstallerService.PackageDeleteObserverAdapter(
+                            PackageManagerService.this.mContext, intentSender, packageName,
+                            false, userId);
+            if (userId != UserHandle.USER_ALL) {
+                adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED,
+                        "Can't uninstall an apex for a single user");
+                return;
+            }
+            final ApexManager am = PackageManagerService.this.mApexManager;
+            PackageInfo activePackage = am.getActivePackage(packageName);
+            if (activePackage == null) {
+                adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED,
+                        packageName + " is not an apex package");
+                return;
+            }
+            if (versionCode != PackageManager.VERSION_CODE_HIGHEST
+                    && activePackage.getLongVersionCode() != versionCode) {
+                adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED,
+                        "Active version " + activePackage.getLongVersionCode()
+                                + " is not equal to " + versionCode + "]");
+                return;
+            }
+            if (!am.uninstallApex(activePackage.applicationInfo.sourceDir)) {
+                adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED,
+                        "Failed to uninstall apex " + packageName);
+            } else {
+                adapter.onPackageDeleted(packageName, PackageManager.DELETE_SUCCEEDED,
+                        null);
+            }
+        }
     }
 
     @GuardedBy("mPackages")
@@ -24410,6 +24472,6 @@
         final IIntentReceiver finishedReceiver, final int[] userIds, int[] instantUserIds);
     void sendPackageAddedForNewUsers(String packageName, boolean sendBootCompleted,
         boolean includeStopped, int appId, int[] userIds, int[] instantUserIds);
-    void notifyPackageAdded(String packageName);
-    void notifyPackageRemoved(String packageName);
+    void notifyPackageAdded(String packageName, int uid);
+    void notifyPackageRemoved(String packageName, int uid);
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 912a50e..2d1afa7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1619,30 +1619,36 @@
         }
 
         userId = translateUserId(userId, true /*allowAll*/, "runUninstall");
-        if (userId == UserHandle.USER_ALL) {
-            userId = UserHandle.USER_SYSTEM;
-            flags |= PackageManager.DELETE_ALL_USERS;
-        } else {
-            final PackageInfo info = mInterface.getPackageInfo(packageName,
-                    PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
-            if (info == null) {
-                pw.println("Failure [not installed for " + userId + "]");
-                return 1;
-            }
-            final boolean isSystem =
-                    (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-            // If we are being asked to delete a system app for just one
-            // user set flag so it disables rather than reverting to system
-            // version of the app.
-            if (isSystem) {
-                flags |= PackageManager.DELETE_SYSTEM_APP;
-            }
-        }
-
         final LocalIntentReceiver receiver = new LocalIntentReceiver();
-        mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName,
-                versionCode), null /*callerPackageName*/, flags,
-                receiver.getIntentSender(), userId);
+        PackageManagerInternal internal = LocalServices.getService(PackageManagerInternal.class);
+
+        if (internal.isApexPackage(packageName)) {
+            internal.uninstallApex(packageName, versionCode, userId, receiver.getIntentSender());
+        } else {
+            if (userId == UserHandle.USER_ALL) {
+                userId = UserHandle.USER_SYSTEM;
+                flags |= PackageManager.DELETE_ALL_USERS;
+            } else {
+                final PackageInfo info = mInterface.getPackageInfo(packageName,
+                        PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
+                if (info == null) {
+                    pw.println("Failure [not installed for " + userId + "]");
+                    return 1;
+                }
+                final boolean isSystem =
+                        (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+                // If we are being asked to delete a system app for just one
+                // user set flag so it disables rather than reverting to system
+                // version of the app.
+                if (isSystem) {
+                    flags |= PackageManager.DELETE_SYSTEM_APP;
+                }
+            }
+
+            mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName,
+                            versionCode), null /*callerPackageName*/, flags,
+                    receiver.getIntentSender(), userId);
+        }
 
         final Intent result = receiver.getResult();
         final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 4ee6eaf..39c731c 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.apex.ApexInfo;
 import android.apex.ApexInfoList;
 import android.apex.ApexSessionInfo;
@@ -68,7 +69,6 @@
     private static final String TAG = "StagingManager";
 
     private final PackageInstallerService mPi;
-    private final PackageManagerService mPm;
     private final ApexManager mApexManager;
     private final PowerManager mPowerManager;
     private final Handler mBgHandler;
@@ -76,9 +76,7 @@
     @GuardedBy("mStagedSessions")
     private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
 
-    StagingManager(PackageManagerService pm, PackageInstallerService pi, ApexManager am,
-            Context context) {
-        mPm = pm;
+    StagingManager(PackageInstallerService pi, ApexManager am, Context context) {
         mPi = pi;
         mApexManager = am;
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -484,6 +482,27 @@
         mBgHandler.post(() -> preRebootVerification(session));
     }
 
+    @Nullable
+    PackageInstallerSession getActiveSession() {
+        synchronized (mStagedSessions) {
+            for (int i = 0; i < mStagedSessions.size(); i++) {
+                final PackageInstallerSession session = mStagedSessions.valueAt(i);
+                if (!session.isCommitted()) {
+                    continue;
+                }
+                if (session.hasParentSessionId()) {
+                    // Staging manager will finalize only parent session. Ignore child sessions
+                    // picking the active.
+                    continue;
+                }
+                if (!session.isStagedSessionApplied() && !session.isStagedSessionFailed()) {
+                    return session;
+                }
+            }
+        }
+        return null;
+    }
+
     void createSession(@NonNull PackageInstallerSession sessionInfo) {
         synchronized (mStagedSessions) {
             mStagedSessions.append(sessionInfo.sessionId, sessionInfo);
@@ -498,7 +517,7 @@
 
     void abortCommittedSession(@NonNull PackageInstallerSession session) {
         if (session.isStagedSessionApplied()) {
-            Slog.w(TAG, "Cannot abort applied session!");
+            Slog.w(TAG, "Cannot abort applied session : " + session.sessionId);
             return;
         }
         abortSession(session);
@@ -574,6 +593,10 @@
     }
 
     private void checkStateAndResume(@NonNull PackageInstallerSession session) {
+        if (!session.isCommitted()) {
+            // Session hasn't been committed yet, ignore.
+            return;
+        }
         // Check the state of the session and decide what to do next.
         if (session.isStagedSessionFailed() || session.isStagedSessionApplied()) {
             // Final states, nothing to do.
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 24b38e7..15dc6ae 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -12,7 +12,7 @@
   ],
   "imports": [
     {
-      "path": "system/apex/tests"
+      "path": "frameworks/base/core/java/android/content/pm"
     }
   ]
 }
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 b877fe7..e9077a9 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -155,11 +155,6 @@
         ACTIVITY_RECOGNITION_PERMISSIONS.add(Manifest.permission.ACTIVITY_RECOGNITION);
     }
 
-    private static final Set<String> COARSE_LOCATION_PERMISSIONS = new ArraySet<>();
-    static {
-        COARSE_LOCATION_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
-    }
-
     private static final Set<String> CALENDAR_PERMISSIONS = new ArraySet<>();
     static {
         CALENDAR_PERMISSIONS.add(Manifest.permission.READ_CALENDAR);
@@ -709,6 +704,12 @@
                         TelephonyManager.ACTION_EMERGENCY_ASSISTANCE, userId),
                 userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
 
+        // STOPSHIP(b/128289173): remove once EmergencyInfo app was replaced.
+        grantSystemFixedPermissionsToSystemPackage(
+                getDefaultSystemHandlerActivityPackage(
+                        "com.android.emergency.action.EMERGENCY_ASSISTANCE", userId),
+                userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
+
         // NFC Tag viewer
         Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW)
                 .setType("vnd.android.cursor.item/ndef_msg");
@@ -803,8 +804,7 @@
 
     private void grantDefaultPermissionsToDefaultSystemUseOpenWifiApp(
             String useOpenWifiPackage, int userId) {
-        grantPermissionsToSystemPackage(
-                useOpenWifiPackage, userId, COARSE_LOCATION_PERMISSIONS);
+        grantPermissionsToSystemPackage(useOpenWifiPackage, userId, ALWAYS_LOCATION_PERMISSIONS);
     }
 
     public void grantDefaultPermissionsToDefaultSmsApp(String packageName, int userId) {
@@ -824,7 +824,7 @@
 
     public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
         Log.i(TAG, "Granting permissions to default Use Open WiFi app for user:" + userId);
-        grantIgnoringSystemPackage(packageName, userId, COARSE_LOCATION_PERMISSIONS);
+        grantIgnoringSystemPackage(packageName, userId, ALWAYS_LOCATION_PERMISSIONS);
     }
 
     public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c0e5974..5810636 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -44,7 +44,6 @@
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SYSTEM_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
@@ -127,7 +126,6 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.database.ContentObserver;
-import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManager;
@@ -211,7 +209,6 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ScreenshotHelper;
-import com.android.internal.widget.PointerLocationView;
 import com.android.server.ExtconStateObserver;
 import com.android.server.ExtconUEventObserver;
 import com.android.server.GestureLauncherService;
@@ -494,9 +491,6 @@
 
     private boolean mHandleVolumeKeysInWM;
 
-    int mPointerLocationMode = 0; // guarded by mLock
-    PointerLocationView mPointerLocationView;
-
     private boolean mPendingKeyguardOccluded;
     private boolean mKeyguardOccludedChanged;
     private boolean mNotifyUserActivity;
@@ -619,8 +613,6 @@
     private boolean mPerDisplayFocusEnabled = false;
     private volatile int mTopFocusedDisplayId = INVALID_DISPLAY;
 
-    private static final int MSG_ENABLE_POINTER_LOCATION = 1;
-    private static final int MSG_DISABLE_POINTER_LOCATION = 2;
     private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
     private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
     private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5;
@@ -651,12 +643,6 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case MSG_ENABLE_POINTER_LOCATION:
-                    enablePointerLocation();
-                    break;
-                case MSG_DISABLE_POINTER_LOCATION:
-                    disablePointerLocation();
-                    break;
                 case MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK:
                     dispatchMediaKeyWithWakeLock((KeyEvent)msg.obj);
                     break;
@@ -779,9 +765,6 @@
             resolver.registerContentObserver(Settings.System.getUriFor(
                     Settings.System.SCREEN_OFF_TIMEOUT), false, this,
                     UserHandle.USER_ALL);
-            resolver.registerContentObserver(Settings.System.getUriFor(
-                    Settings.System.POINTER_LOCATION), false, this,
-                    UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
                     UserHandle.USER_ALL);
@@ -2007,15 +1990,6 @@
                 updateWakeGestureListenerLp();
             }
 
-            if (mSystemReady) {
-                int pointerLocation = Settings.System.getIntForUser(resolver,
-                        Settings.System.POINTER_LOCATION, 0, UserHandle.USER_CURRENT);
-                if (mPointerLocationMode != pointerLocation) {
-                    mPointerLocationMode = pointerLocation;
-                    mHandler.sendEmptyMessage(pointerLocation != 0 ?
-                            MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
-                }
-            }
             // use screen off timeout setting as the timeout for the lockscreen
             mLockScreenTimeout = Settings.System.getIntForUser(resolver,
                     Settings.System.SCREEN_OFF_TIMEOUT, 0, UserHandle.USER_CURRENT);
@@ -2047,46 +2021,6 @@
                 && mWakeGestureListener.isSupported();
     }
 
-    private void enablePointerLocation() {
-        if (mPointerLocationView == null) {
-            mPointerLocationView = new PointerLocationView(mContext);
-            mPointerLocationView.setPrintCoords(false);
-            WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                    WindowManager.LayoutParams.MATCH_PARENT,
-                    WindowManager.LayoutParams.MATCH_PARENT);
-            lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
-            lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
-                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-            lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-            if (ActivityManager.isHighEndGfx()) {
-                lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-                lp.privateFlags |=
-                        WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
-            }
-            lp.format = PixelFormat.TRANSLUCENT;
-            lp.setTitle("PointerLocation");
-            WindowManager wm = (WindowManager) mContext.getSystemService(WINDOW_SERVICE);
-            lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
-            wm.addView(mPointerLocationView, lp);
-            //TODO (b/111365687) : make system context per display.
-            mWindowManagerFuncs.registerPointerEventListener(mPointerLocationView, DEFAULT_DISPLAY);
-        }
-    }
-
-    private void disablePointerLocation() {
-        if (mPointerLocationView != null) {
-            //TODO (b/111365687) : make system context per display.
-            mWindowManagerFuncs.unregisterPointerEventListener(mPointerLocationView,
-                    DEFAULT_DISPLAY);
-            WindowManager wm = (WindowManager) mContext.getSystemService(WINDOW_SERVICE);
-            wm.removeView(mPointerLocationView);
-            mPointerLocationView = null;
-        }
-    }
-
-
     /** {@inheritDoc} */
     @Override
     public int checkAddPermission(WindowManager.LayoutParams attrs, int[] outAppOp) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index d58707c..2af2342 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -443,7 +443,7 @@
          * Returns true if the window is current in multi-windowing mode. i.e. it shares the
          * screen with other application windows.
          */
-        public boolean isInMultiWindowMode();
+        boolean inMultiWindowMode();
 
         public int getRotationAnimationHint();
 
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index bb23bc0..9b427f5 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -4474,7 +4474,7 @@
         }
 
         @Override // Binder call
-        public boolean setPowerSaveMode(boolean enabled) {
+        public boolean setPowerSaveModeEnabled(boolean enabled) {
             if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER)
                     != PackageManager.PERMISSION_GRANTED) {
                 mContext.enforceCallingOrSelfPermission(
diff --git a/services/core/java/com/android/server/power/PowerManagerShellCommand.java b/services/core/java/com/android/server/power/PowerManagerShellCommand.java
index 18b8f0e..edaa6d9 100644
--- a/services/core/java/com/android/server/power/PowerManagerShellCommand.java
+++ b/services/core/java/com/android/server/power/PowerManagerShellCommand.java
@@ -68,7 +68,7 @@
             pw.println("Error: " + ex.toString());
             return -1;
         }
-        mInterface.setPowerSaveMode(mode == LOW_POWER_MODE_ON);
+        mInterface.setPowerSaveModeEnabled(mode == LOW_POWER_MODE_ON);
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index af78995..af5d40bf 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -524,7 +524,7 @@
 
     /**
      * {@link com.android.server.power.PowerManagerService} calls it when
-     * {@link android.os.PowerManager#setPowerSaveMode} is called.
+     * {@link android.os.PowerManager#setPowerSaveModeEnabled} is called.
      *
      * Note this could? be called before {@link #onBootCompleted} too.
      */
diff --git a/services/core/java/com/android/server/rollback/RollbackData.java b/services/core/java/com/android/server/rollback/RollbackData.java
index 8a95877..b37e268 100644
--- a/services/core/java/com/android/server/rollback/RollbackData.java
+++ b/services/core/java/com/android/server/rollback/RollbackData.java
@@ -23,9 +23,11 @@
 import java.io.File;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.text.ParseException;
 import java.time.Instant;
 import java.util.ArrayList;
 
+
 /**
  * Information about a rollback available for a set of atomically installed
  * packages.
@@ -138,4 +140,27 @@
     public boolean isStaged() {
         return info.isStaged();
     }
+
+    static String rollbackStateToString(@RollbackState int state) {
+        switch (state) {
+            case RollbackData.ROLLBACK_STATE_ENABLING: return "enabling";
+            case RollbackData.ROLLBACK_STATE_AVAILABLE: return "available";
+            case RollbackData.ROLLBACK_STATE_COMMITTED: return "committed";
+        }
+        throw new AssertionError("Invalid rollback state: " + state);
+    }
+
+    static @RollbackState int rollbackStateFromString(String state)
+            throws ParseException {
+        switch (state) {
+            case "enabling": return RollbackData.ROLLBACK_STATE_ENABLING;
+            case "available": return RollbackData.ROLLBACK_STATE_AVAILABLE;
+            case "committed": return RollbackData.ROLLBACK_STATE_COMMITTED;
+        }
+        throw new ParseException("Invalid rollback state: " + state, 0);
+    }
+
+    public String getStateAsString() {
+        return rollbackStateToString(state);
+    }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 952399b..83d18a6 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -50,11 +50,14 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.pm.Installer;
 
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.security.SecureRandom;
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
@@ -873,6 +876,11 @@
             return false;
         }
 
+        if (session.resolvedBaseCodePath == null) {
+            Log.e(TAG, "Session code path has not been resolved.");
+            return false;
+        }
+
         // Get information about the package to be installed.
         PackageParser.PackageLite newPackage = null;
         try {
@@ -1268,4 +1276,39 @@
                     + rollbackData.info.getRollbackId(), ioe);
         }
     }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+        synchronized (mLock) {
+            for (RollbackData data : mRollbacks) {
+                RollbackInfo info = data.info;
+                ipw.println(info.getRollbackId() + ":");
+                ipw.increaseIndent();
+                ipw.println("-state: " + data.getStateAsString());
+                ipw.println("-timestamp: " + data.timestamp);
+                if (data.stagedSessionId != -1) {
+                    ipw.println("-stagedSessionId: " + data.stagedSessionId);
+                }
+                ipw.println("-packages:");
+                ipw.increaseIndent();
+                for (PackageRollbackInfo pkg : info.getPackages()) {
+                    ipw.println(pkg.getPackageName()
+                            + " " + pkg.getVersionRolledBackFrom().getLongVersionCode()
+                            + " -> " + pkg.getVersionRolledBackTo().getLongVersionCode());
+                }
+                ipw.decreaseIndent();
+                if (data.state == RollbackData.ROLLBACK_STATE_COMMITTED) {
+                    ipw.println("-causePackages:");
+                    ipw.increaseIndent();
+                    for (VersionedPackage cPkg : info.getCausePackages()) {
+                        ipw.println(cPkg.getPackageName() + " " + cPkg.getLongVersionCode());
+                    }
+                    ipw.decreaseIndent();
+                    ipw.println("-committedSessionId: " + info.getCommittedSessionId());
+                }
+                ipw.decreaseIndent();
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 4f8f685..2cfa465 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -16,6 +16,9 @@
 
 package com.android.server.rollback;
 
+import static com.android.server.rollback.RollbackData.rollbackStateFromString;
+import static com.android.server.rollback.RollbackData.rollbackStateToString;
+
 import android.annotation.NonNull;
 import android.content.pm.VersionedPackage;
 import android.content.rollback.PackageRollbackInfo;
@@ -401,23 +404,4 @@
             file.delete();
         }
     }
-
-    private static String rollbackStateToString(@RollbackData.RollbackState int state) {
-        switch (state) {
-            case RollbackData.ROLLBACK_STATE_ENABLING: return "enabling";
-            case RollbackData.ROLLBACK_STATE_AVAILABLE: return "available";
-            case RollbackData.ROLLBACK_STATE_COMMITTED: return "committed";
-        }
-        throw new AssertionError("Invalid rollback state: " + state);
-    }
-
-    private static @RollbackData.RollbackState int rollbackStateFromString(String state)
-            throws ParseException {
-        switch (state) {
-            case "enabling": return RollbackData.ROLLBACK_STATE_ENABLING;
-            case "available": return RollbackData.ROLLBACK_STATE_AVAILABLE;
-            case "committed": return RollbackData.ROLLBACK_STATE_COMMITTED;
-        }
-        throw new ParseException("Invalid rollback state: " + state, 0);
-    }
 }
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 4815e5c..2b17d19 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -24,6 +24,7 @@
 import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs;
 import static com.android.server.am.MemoryStatUtil.readRssHighWaterMarkFromProcfs;
+import static com.android.server.am.MemoryStatUtil.readSystemIonHeapSizeFromDebugfs;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -1182,6 +1183,15 @@
         SystemProperties.set("sys.rss_hwm_reset.on", "1");
     }
 
+    private void pullSystemIonHeapSize(
+            int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
+        final long systemIonHeapSizeInBytes = readSystemIonHeapSizeFromDebugfs();
+        StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+        e.writeLong(systemIonHeapSizeInBytes);
+        pulledData.add(e);
+    }
+
     private void pullBinderCallsStats(
             int tagId, long elapsedNanos, long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
@@ -2068,6 +2078,10 @@
                 pullProcessMemoryHighWaterMark(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+            case StatsLog.SYSTEM_ION_HEAP_SIZE: {
+                pullSystemIonHeapSize(tagId, elapsedNanos, wallClockNanos, ret);
+                break;
+            }
             case StatsLog.BINDER_CALLS: {
                 pullBinderCallsStats(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
diff --git a/services/core/java/com/android/server/testharness/TestHarnessModeService.java b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
index ec62ec7..9f9b797 100644
--- a/services/core/java/com/android/server/testharness/TestHarnessModeService.java
+++ b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
@@ -18,6 +18,8 @@
 
 import android.annotation.Nullable;
 import android.app.KeyguardManager;
+import android.app.Notification;
+import android.app.NotificationManager;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -35,6 +37,8 @@
 import android.provider.Settings;
 import android.util.Slog;
 
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
 import com.android.server.LocalServices;
 import com.android.server.PersistentDataBlockManagerInternal;
 import com.android.server.SystemService;
@@ -87,6 +91,7 @@
             case PHASE_BOOT_COMPLETED:
                 disableAutoSync();
                 configureSettings();
+                showNotification();
                 break;
         }
         super.onBootPhase(phase);
@@ -99,19 +104,29 @@
             // There's no data to apply, so leave it as-is.
             return;
         }
+        PersistentData persistentData;
+        try {
+            persistentData = PersistentData.fromBytes(testHarnessModeData);
+        } catch (SetUpTestHarnessModeException e) {
+            Slog.e(TAG, "Failed to set up Test Harness Mode. Bad data.", e);
+            return;
+        } finally {
+            // Clear out the Test Harness Mode data. It's now in memory if successful or we should
+            // skip setting up.
+            getPersistentDataBlock().clearTestHarnessModeData();
+        }
         mShouldSetUpTestHarnessMode = true;
-        setUpAdb(testHarnessModeData);
+        setUpAdb(persistentData);
         setDeviceProvisioned();
     }
 
-    private void setUpAdb(byte[] testHarnessModeData) {
+    private void setUpAdb(PersistentData persistentData) {
         ContentResolver cr = getContext().getContentResolver();
+
         // Disable the TTL for ADB keys before enabling ADB
         Settings.Global.putLong(cr, Settings.Global.ADB_ALLOWED_CONNECTION_TIME, 0);
 
-        PersistentData persistentData = PersistentData.fromBytes(testHarnessModeData);
-
-        SystemProperties.set(TEST_HARNESS_MODE_PROPERTY, persistentData.mEnabled ? "1" : "0");
+        SystemProperties.set(TEST_HARNESS_MODE_PROPERTY, "1");
         writeAdbKeysFile(persistentData);
     }
 
@@ -145,9 +160,6 @@
 
         writeBytesToFile(persistentData.mAdbKeys, adbManager.getAdbKeysFile().toPath());
         writeBytesToFile(persistentData.mAdbTempKeys, adbManager.getAdbTempKeysFile().toPath());
-
-        // Clear out the data block so that we don't revert the ADB keys on every boot.
-        getPersistentDataBlock().clearTestHarnessModeData();
     }
 
     private void writeBytesToFile(byte[] keys, Path adbKeys) {
@@ -177,6 +189,36 @@
                 UserHandle.USER_CURRENT);
     }
 
+    private void showNotification() {
+        if (!SystemProperties.getBoolean(TEST_HARNESS_MODE_PROPERTY, false)) {
+            return;
+        }
+        String title = getContext()
+                .getString(com.android.internal.R.string.test_harness_mode_notification_title);
+        String message = getContext()
+                .getString(com.android.internal.R.string.test_harness_mode_notification_message);
+
+        Notification notification =
+                new Notification.Builder(getContext(), SystemNotificationChannels.DEVELOPER)
+                        .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                        .setWhen(0)
+                        .setOngoing(true)
+                        .setTicker(title)
+                        .setDefaults(0)  // please be quiet
+                        .setColor(getContext().getColor(
+                                com.android.internal.R.color
+                                        .system_notification_accent_color))
+                        .setContentTitle(title)
+                        .setContentText(message)
+                        .setVisibility(Notification.VISIBILITY_PUBLIC)
+                        .build();
+
+        NotificationManager notificationManager =
+                getContext().getSystemService(NotificationManager.class);
+        notificationManager.notifyAsUser(
+                null, SystemMessage.NOTE_TEST_HARNESS_MODE_ENABLED, notification, UserHandle.ALL);
+    }
+
     @Nullable
     private PersistentDataBlockManagerInternal getPersistentDataBlock() {
         if (mPersistentDataBlockManagerInternal == null) {
@@ -248,8 +290,7 @@
                 byte[] adbKeysBytes = getBytesFromFile(adbKeys);
                 byte[] adbTempKeysBytes = getBytesFromFile(adbTempKeys);
 
-                PersistentData persistentData =
-                        new PersistentData(true, adbKeysBytes, adbTempKeysBytes);
+                PersistentData persistentData = new PersistentData(adbKeysBytes, adbTempKeysBytes);
                 getPersistentDataBlock().setTestHarnessModeData(persistentData.toBytes());
             } catch (IOException e) {
                 Slog.e(TAG, "Failed to store ADB keys.", e);
@@ -316,37 +357,40 @@
      */
     public static class PersistentData {
         static final byte VERSION_1 = 1;
+        static final byte VERSION_2 = 2;
 
         final int mVersion;
-        final boolean mEnabled;
         final byte[] mAdbKeys;
         final byte[] mAdbTempKeys;
 
-        PersistentData(boolean enabled, byte[] adbKeys, byte[] adbTempKeys) {
-            this(VERSION_1, enabled, adbKeys, adbTempKeys);
+        PersistentData(byte[] adbKeys, byte[] adbTempKeys) {
+            this(VERSION_2, adbKeys, adbTempKeys);
         }
 
-        PersistentData(int version, boolean enabled, byte[] adbKeys, byte[] adbTempKeys) {
+        PersistentData(int version, byte[] adbKeys, byte[] adbTempKeys) {
             this.mVersion = version;
-            this.mEnabled = enabled;
             this.mAdbKeys = adbKeys;
             this.mAdbTempKeys = adbTempKeys;
         }
 
-        static PersistentData fromBytes(byte[] bytes) {
+        static PersistentData fromBytes(byte[] bytes) throws SetUpTestHarnessModeException {
             try {
                 DataInputStream is = new DataInputStream(new ByteArrayInputStream(bytes));
                 int version = is.readInt();
-                boolean enabled = is.readBoolean();
+                if (version == VERSION_1) {
+                    // Version 1 of Test Harness Mode contained an "enabled" bit that we need to
+                    // skip. If we don't, the binary format will be bad and it will fail to set up.
+                    is.readBoolean();
+                }
                 int adbKeysLength = is.readInt();
                 byte[] adbKeys = new byte[adbKeysLength];
                 is.readFully(adbKeys);
                 int adbTempKeysLength = is.readInt();
                 byte[] adbTempKeys = new byte[adbTempKeysLength];
                 is.readFully(adbTempKeys);
-                return new PersistentData(version, enabled, adbKeys, adbTempKeys);
+                return new PersistentData(version, adbKeys, adbTempKeys);
             } catch (IOException e) {
-                throw new RuntimeException(e);
+                throw new SetUpTestHarnessModeException(e);
             }
         }
 
@@ -354,8 +398,7 @@
             try {
                 ByteArrayOutputStream os = new ByteArrayOutputStream();
                 DataOutputStream dos = new DataOutputStream(os);
-                dos.writeInt(VERSION_1);
-                dos.writeBoolean(mEnabled);
+                dos.writeInt(VERSION_2);
                 dos.writeInt(mAdbKeys.length);
                 dos.write(mAdbKeys);
                 dos.writeInt(mAdbTempKeys.length);
@@ -367,4 +410,18 @@
             }
         }
     }
+
+    /**
+     * An exception thrown when Test Harness Mode fails to set up.
+     *
+     * <p>In the event that Test Harness Mode fails to set up, all of the data should be discarded
+     * and the Test Harness Mode portion of the persistent data block should be wiped. This will
+     * prevent the device from becoming stuck, as there is no way (without rooting the device) to
+     * clear the persistent data block.
+     */
+    private static class SetUpTestHarnessModeException extends Exception {
+        SetUpTestHarnessModeException(Exception e) {
+            super(e);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 9a5ec2a..7cea458 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2736,6 +2736,9 @@
         if (activityOptions != null) {
             activityType = activityOptions.getLaunchActivityType();
             windowingMode = activityOptions.getLaunchWindowingMode();
+            if (activityOptions.freezeRecentTasksReordering()) {
+                mRecentTasks.setFreezeTaskListReordering();
+            }
         }
         if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
             throw new IllegalArgumentException("startActivityFromRecents: Task "
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index bb5a221..af05a27 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -2237,6 +2237,10 @@
                 || transit == TRANSIT_ACTIVITY_RELAUNCH;
     }
 
+    static boolean isChangeTransit(int transit) {
+        return transit == TRANSIT_TASK_CHANGE_WINDOWING_MODE;
+    }
+
     /**
      * @return whether the transition should show the thumbnail being scaled down.
      */
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 8f0a7c0..f6326957 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -513,8 +513,11 @@
         // Given no app transition pass it through instead of a wallpaper transition.
         // Never convert the crashing transition.
         // Never update the transition for the wallpaper if we are just docking from recents
+        // Never convert a change transition since the top activity isn't changing and will likely
+        // still be above an opening wallpaper.
         if (transit == TRANSIT_NONE || transit == TRANSIT_CRASHING_ACTIVITY_CLOSE
-                || transit == TRANSIT_DOCK_TASK_FROM_RECENTS) {
+                || transit == TRANSIT_DOCK_TASK_FROM_RECENTS
+                || AppTransition.isChangeTransit(transit)) {
             return transit;
         }
 
@@ -601,6 +604,10 @@
      */
     @VisibleForTesting
     int maybeUpdateTransitToTranslucentAnim(int transit) {
+        if (AppTransition.isChangeTransit(transit)) {
+            // There's no special animation to handle change animations with translucent apps
+            return transit;
+        }
         final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
                 || AppTransition.isActivityTransit(transit);
         boolean allOpeningVisible = true;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 220370c..ea3a7d5 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1747,7 +1747,7 @@
     }
 
     boolean isInChangeTransition() {
-        return mTransitChangeLeash != null || isChangeTransition(mTransit);
+        return mTransitChangeLeash != null || AppTransition.isChangeTransit(mTransit);
     }
 
     @VisibleForTesting
@@ -1979,7 +1979,14 @@
                 mLetterbox.attachInput(w);
             }
             getPosition(mTmpPoint);
-            mLetterbox.layout(getParent().getBounds(), w.getFrameLw(), mTmpPoint);
+            // Get the bounds of the "space-to-fill". We union the Task and the Stack bounds here
+            // to handle both split window (where task-bounds can be larger) and orientation
+            // letterbox (where the task is letterboxed within stack).
+            Rect spaceToFill = getTask().getBounds();
+            if (getStack() != null) {
+                spaceToFill.union(getStack().getBounds());
+            }
+            mLetterbox.layout(spaceToFill, w.getFrameLw(), mTmpPoint);
         } else if (mLetterbox != null) {
             mLetterbox.hide();
         }
@@ -2448,30 +2455,6 @@
         return boundsLayer;
     }
 
-    /** Get position and crop region of animation. */
-    @VisibleForTesting
-    void getAnimationBounds(Point outPosition, Rect outBounds) {
-        outPosition.set(0, 0);
-        outBounds.setEmpty();
-
-        final TaskStack stack = getStack();
-        final Task task = getTask();
-        if (task != null && task.inFreeformWindowingMode()) {
-            task.getRelativeDisplayedPosition(outPosition);
-        } else if (stack != null) {
-            stack.getRelativeDisplayedPosition(outPosition);
-        }
-
-        // Always use stack bounds in order to have the ability to animate outside the task region.
-        // It also needs to be consistent when {@link #mNeedsAnimationBoundsLayer} is set that crops
-        // according to the bounds.
-        if (stack != null) {
-            stack.getBounds(outBounds);
-        }
-        // We have the relative position so the local position can be removed from bounds.
-        outBounds.offsetTo(0, 0);
-    }
-
     @Override
     Rect getDisplayedBounds() {
         final Task task = getTask();
@@ -2484,10 +2467,6 @@
         return getBounds();
     }
 
-    private static boolean isChangeTransition(int transit) {
-        return transit == TRANSIT_TASK_CHANGE_WINDOWING_MODE;
-    }
-
     boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
             boolean isVoiceInteraction) {
 
@@ -2507,9 +2486,15 @@
         if (okToAnimate()) {
             final AnimationAdapter adapter;
             AnimationAdapter thumbnailAdapter = null;
-            getAnimationBounds(mTmpPoint, mTmpRect);
 
-            boolean isChanging = isChangeTransition(transit) && enter;
+            // Separate position and size for use in animators. Use task-bounds for now so
+            // that activity-level letterbox (maxAspectRatio) is included in the animation.
+            mTmpRect.set(getTask() != null ? getTask().getBounds() : getBounds());
+            mTmpPoint.set(mTmpRect.left, mTmpRect.top);
+            mTmpRect.offsetTo(0, 0);
+
+            final boolean isChanging = AppTransition.isChangeTransit(transit) && enter
+                    && getDisplayContent().mChangingApps.contains(this);
 
             // Delaying animation start isn't compatible with remote animations at all.
             if (getDisplayContent().mAppTransition.getRemoteAnimationController() != null
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index db59030..bcfbefe 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -41,12 +41,14 @@
 import static android.view.WindowManager.DOCKED_BOTTOM;
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.DOCKED_TOP;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE;
 import static android.view.WindowManager.LayoutParams.NEEDS_MENU_UNSET;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
@@ -182,6 +184,8 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.internal.util.function.TriConsumer;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.AnimationThread;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.utils.DisplayRotationUtil;
@@ -887,6 +891,10 @@
         mTapDetector = new TaskTapPointerEventListener(mWmService, this);
         registerPointerEventListener(mTapDetector);
         registerPointerEventListener(mWmService.mMousePositionTracker);
+        if (mWmService.mAtmService.getRecentTasks() != null) {
+            registerPointerEventListener(
+                    mWmService.mAtmService.getRecentTasks().getInputListener());
+        }
 
         mDisplayPolicy = new DisplayPolicy(service, this);
         mDisplayRotation = new DisplayRotation(service, this);
@@ -2381,6 +2389,27 @@
     }
 
     /**
+     * Returns true if the input point is within an app window.
+     */
+    boolean pointWithinAppWindow(int x, int y) {
+        final int[] targetWindowType = {-1};
+        final Consumer fn = PooledLambda.obtainConsumer((w, nonArg) -> {
+            if (targetWindowType[0] != -1) {
+                return;
+            }
+
+            if (w.isOnScreen() && w.isVisibleLw() && w.getFrameLw().contains(x, y)) {
+                targetWindowType[0] = w.mAttrs.type;
+                return;
+            }
+        }, PooledLambda.__(WindowState.class), mTmpRect);
+        forAllWindows(fn, true /* traverseTopToBottom */);
+        ((PooledConsumer) fn).recycle();
+        return FIRST_APPLICATION_WINDOW <= targetWindowType[0]
+                        && targetWindowType[0] <= LAST_APPLICATION_WINDOW;
+    }
+
+    /**
      * Find the task whose outside touch area (for resizing) (x, y) falls within.
      * Returns null if the touch doesn't fall into a resizing area.
      */
@@ -3271,8 +3300,11 @@
         // Attach it to app if the target is part of an app and such app is covering the entire
         // screen. If it's not covering the entire screen the IME might extend beyond the apps
         // bounds.
-        if (mInputMethodTarget != null && mInputMethodTarget.mAppToken != null &&
-                mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
+        if (mInputMethodTarget != null && mInputMethodTarget.mAppToken != null
+                && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+                // An activity with override bounds should be letterboxed inside its parent bounds,
+                // so it doesn't fill the screen.
+                && mInputMethodTarget.mAppToken.matchParentBounds()) {
             return mInputMethodTarget.mAppToken.getSurfaceControl();
         }
 
@@ -4885,12 +4917,11 @@
      * @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
      */
     boolean supportsSystemDecorations() {
-        return mWmService.mDisplayWindowSettings.shouldShowSystemDecorsLocked(this)
+        return (mWmService.mDisplayWindowSettings.shouldShowSystemDecorsLocked(this)
                 || (mDisplay.getFlags() & FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0
-                // TODO (b/111363427): Remove this and set the new FLAG_SHOULD_SHOW_LAUNCHER flag
-                // whenever vr 2d display id is set.
-                || mDisplayId == mWmService.mVr2dDisplayId
-                || mWmService.mForceDesktopModeOnExternalDisplays;
+                || mWmService.mForceDesktopModeOnExternalDisplays)
+                // VR virtual display will be used to run and render 2D app within a VR experience.
+                && mDisplayId != mWmService.mVr2dDisplayId;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index e48361f..ba1dfbb 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -44,8 +44,8 @@
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR;
@@ -113,6 +113,7 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.graphics.Insets;
+import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.hardware.input.InputManager;
 import android.hardware.power.V1_0.PowerHint;
@@ -149,6 +150,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ScreenShapeHelper;
 import com.android.internal.util.ScreenshotHelper;
+import com.android.internal.widget.PointerLocationView;
 import com.android.server.LocalServices;
 import com.android.server.UiThread;
 import com.android.server.policy.WindowManagerPolicy;
@@ -343,6 +345,8 @@
 
     private InputConsumer mInputConsumer = null;
 
+    private PointerLocationView mPointerLocationView;
+
     /**
      * The area covered by system windows which belong to another display. Forwarded insets is set
      * in case this is a virtual display, this is displayed on another display that has insets, and
@@ -357,6 +361,8 @@
     private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1;
     private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
     private static final int MSG_DISPOSE_INPUT_CONSUMER = 3;
+    private static final int MSG_ENABLE_POINTER_LOCATION = 4;
+    private static final int MSG_DISABLE_POINTER_LOCATION = 5;
 
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
@@ -383,6 +389,12 @@
                 case MSG_DISPOSE_INPUT_CONSUMER:
                     disposeInputConsumer((InputConsumer) msg.obj);
                     break;
+                case MSG_ENABLE_POINTER_LOCATION:
+                    enablePointerLocation();
+                    break;
+                case MSG_DISABLE_POINTER_LOCATION:
+                    disablePointerLocation();
+                    break;
             }
         }
     }
@@ -541,6 +553,9 @@
 
     void systemReady() {
         mSystemGestures.systemReady();
+        if (mService.mPointerLocationEnabled) {
+            setPointerLocationEnabled(true);
+        }
     }
 
     private int getDisplayId() {
@@ -747,7 +762,7 @@
             case TYPE_WALLPAPER:
                 // Dreams and wallpapers don't have an app window token and can thus not be
                 // letterboxed. Hence always let them extend under the cutout.
-                attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+                attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
                 break;
             case TYPE_STATUS_BAR:
 
@@ -2095,7 +2110,7 @@
 
         // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
         // the cutout safe zone.
-        if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
+        if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
             final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
             displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
             if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
@@ -2146,7 +2161,7 @@
         // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
         // Also, we don't allow windows in multi-window mode to extend out of the screen.
         if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
-                && !win.isInMultiWindowMode()) {
+                && !win.inMultiWindowMode()) {
             df.left = df.top = -10000;
             df.right = df.bottom = 10000;
             if (type != TYPE_WALLPAPER) {
@@ -3414,4 +3429,57 @@
         pw.print(prefix); pw.println("Looper state:");
         mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + "  ");
     }
+
+    private boolean supportsPointerLocation() {
+        return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate();
+    }
+
+    void setPointerLocationEnabled(boolean pointerLocationEnabled) {
+        if (!supportsPointerLocation()) {
+            return;
+        }
+
+        mHandler.sendEmptyMessage(pointerLocationEnabled
+                ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
+    }
+
+    private void enablePointerLocation() {
+        if (mPointerLocationView != null) {
+            return;
+        }
+
+        mPointerLocationView = new PointerLocationView(mContext);
+        mPointerLocationView.setPrintCoords(false);
+        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                WindowManager.LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.MATCH_PARENT);
+        lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
+        lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
+                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+        lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+        if (ActivityManager.isHighEndGfx()) {
+            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+            lp.privateFlags |=
+                    WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
+        }
+        lp.format = PixelFormat.TRANSLUCENT;
+        lp.setTitle("PointerLocation - display " + getDisplayId());
+        lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
+        final WindowManager wm = mContext.getSystemService(WindowManager.class);
+        wm.addView(mPointerLocationView, lp);
+        mDisplayContent.registerPointerEventListener(mPointerLocationView);
+    }
+
+    private void disablePointerLocation() {
+        if (mPointerLocationView == null) {
+            return;
+        }
+
+        mDisplayContent.unregisterPointerEventListener(mPointerLocationView);
+        final WindowManager wm = mContext.getSystemService(WindowManager.class);
+        wm.removeView(mPointerLocationView);
+        mPointerLocationView = null;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index a667d67..716e4ef 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -73,17 +73,6 @@
         return mDragState != null && !mDragState.isClosing();
     }
 
-    void showInputSurface(SurfaceControl.Transaction t, int displayId) {
-        mDragState.showInputSurface(t, displayId);
-    }
-
-    void hideInputSurface(SurfaceControl.Transaction t, int displayId) {
-        if (mDragState != null) {
-            // TODO: Are we guaranteed to get here?
-            mDragState.hideInputSurface(t, displayId);
-        }
-    }
-
     void registerCallback(IDragDropCallback callback) {
         Preconditions.checkNotNull(callback);
         mCallback.set(callback);
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 2b2231a..c438966 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -120,7 +120,7 @@
     // A surface used to catch input events for the drag-and-drop operation.
     SurfaceControl mInputSurface;
 
-    private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+    private final SurfaceControl.Transaction mTransaction;
 
     private final Rect mTmpClipRect = new Rect();
 
@@ -140,31 +140,24 @@
         mFlags = flags;
         mLocalWin = localWin;
         mNotifiedWindows = new ArrayList<WindowState>();
-
+        mTransaction = service.mTransactionFactory.make();
     }
 
     boolean isClosing() {
         return mIsClosing;
     }
 
-    void hideInputSurface(SurfaceControl.Transaction t, int displayId) {
-        if (displayId != mDisplayContent.getDisplayId()) {
-            return;
-        }
-
+    private void hideInputSurface() {
         if (mInputSurface != null) {
-            t.hide(mInputSurface);
+            mTransaction.hide(mInputSurface).apply();
         }
     }
 
-    void showInputSurface(SurfaceControl.Transaction t, int displayId) {
-        if (displayId != mDisplayContent.getDisplayId()) {
-            return;
-        }
-
+    private void showInputSurface() {
         if (mInputSurface == null) {
-            mInputSurface = mService.makeSurfaceBuilder(mService.mRoot.getDisplayContent(displayId)
-                    .getSession()).setContainerLayer()
+            mInputSurface = mService.makeSurfaceBuilder(
+                    mService.mRoot.getDisplayContent(mDisplayContent.getDisplayId()).getSession())
+                    .setContainerLayer()
                     .setName("Drag and Drop Input Consumer").build();
         }
         final InputWindowHandle h = getInputWindowHandle();
@@ -174,14 +167,16 @@
             return;
         }
 
-        t.show(mInputSurface);
-        t.setInputWindowInfo(mInputSurface, h);
-        t.setLayer(mInputSurface, Integer.MAX_VALUE);
+        mTransaction.show(mInputSurface);
+        mTransaction.setInputWindowInfo(mInputSurface, h);
+        mTransaction.setLayer(mInputSurface, Integer.MAX_VALUE);
 
         mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
-        t.setWindowCrop(mInputSurface, mTmpClipRect);
-        t.transferTouchFocus(mTransferTouchFromToken, h.token);
+        mTransaction.setWindowCrop(mInputSurface, mTmpClipRect);
+        mTransaction.transferTouchFocus(mTransferTouchFromToken, h.token);
         mTransferTouchFromToken = null;
+
+        mTransaction.apply();
     }
 
     /**
@@ -199,9 +194,10 @@
             mDragDropController.sendHandlerMessage(
                     MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT, mInputInterceptor);
             mInputInterceptor = null;
-            mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
         }
 
+        hideInputSurface();
+
         // Send drag end broadcast if drag start has been sent.
         if (mDragInProgress) {
             final int myPid = Process.myPid();
@@ -352,7 +348,7 @@
             Slog.e(TAG_WM, "Duplicate register of drag input channel");
         } else {
             mInputInterceptor = new InputInterceptor(display);
-            mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
+            showInputSurface();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 2a9c2b0..5669451 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -25,7 +25,6 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
@@ -129,15 +128,6 @@
 
                 // If there's a drag in flight, provide a pseudo-window to catch drag input
                 final boolean inDrag = mService.mDragDropController.dragDropActiveLocked();
-                if (inDrag) {
-                    if (DEBUG_DRAG) {
-                        Log.d(TAG_WM, "Inserting drag window");
-                    }
-                    mService.mDragDropController.showInputSurface(mInputTransaction, mDisplayId);
-                } else {
-                    mService.mDragDropController.hideInputSurface(mInputTransaction, mDisplayId);
-                }
-
                 final boolean inPositioning =
                         mService.mTaskPositioningController.isPositioningLocked();
                 if (inPositioning) {
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 86dc66d..d364a37 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -306,10 +306,10 @@
 
     private class PackageListObserver implements PackageManagerInternal.PackageListObserver {
         @Override
-        public void onPackageAdded(String packageName) { }
+        public void onPackageAdded(String packageName, int uid) { }
 
         @Override
-        public void onPackageRemoved(String packageName) {
+        public void onPackageRemoved(String packageName, int uid) {
             removeRecordForPackage(packageName);
         }
     }
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 0480d43..d69ae3d 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -60,6 +60,7 @@
 import android.os.Environment;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -67,8 +68,11 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.view.MotionEvent;
+import android.view.WindowManagerPolicyConstants.PointerEventListener;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.am.ActivityManagerService;
 
 import com.google.android.collect.Sets;
@@ -109,8 +113,11 @@
 
     private static final int DEFAULT_INITIAL_CAPACITY = 5;
 
-    // Whether or not to move all affiliated tasks to the front when one of the tasks is launched
-    private static final boolean MOVE_AFFILIATED_TASKS_TO_FRONT = false;
+    // The duration of time after freezing the recent tasks list where getRecentTasks() will return
+    // a stable ordering of the tasks. Upon the next call to getRecentTasks() beyond this duration,
+    // the task list will be unfrozen and committed (the current top task will be moved to the
+    // front of the list)
+    private static final long FREEZE_TASK_LIST_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
 
     // Comparator to sort by taskId
     private static final Comparator<TaskRecord> TASK_ID_COMPARATOR =
@@ -174,12 +181,45 @@
     private int mMaxNumVisibleTasks;
     private long mActiveTasksSessionDurationMs;
 
+    // When set, the task list will not be reordered as tasks within the list are moved to the
+    // front. Newly created tasks, or tasks that are removed from the list will continue to change
+    // the list.  This does not affect affiliated tasks.
+    private boolean mFreezeTaskListReordering;
+    private long mFreezeTaskListReorderingTime;
+    private long mFreezeTaskListTimeoutMs = FREEZE_TASK_LIST_TIMEOUT_MS;
+
     // Mainly to avoid object recreation on multiple calls.
     private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<>();
     private final HashMap<ComponentName, ActivityInfo> mTmpAvailActCache = new HashMap<>();
     private final HashMap<String, ApplicationInfo> mTmpAvailAppCache = new HashMap<>();
     private final SparseBooleanArray mTmpQuietProfileUserIds = new SparseBooleanArray();
 
+    // TODO(b/127498985): This is currently a rough heuristic for interaction inside an app
+    private final PointerEventListener mListener = new PointerEventListener() {
+        @Override
+        public void onPointerEvent(MotionEvent ev) {
+            if (!mFreezeTaskListReordering || ev.getAction() != MotionEvent.ACTION_DOWN) {
+                // Skip if we aren't freezing or starting a gesture
+                return;
+            }
+            int displayId = ev.getDisplayId();
+            int x = (int) ev.getX();
+            int y = (int) ev.getY();
+            mService.mH.post(PooledLambda.obtainRunnable((nonArg) -> {
+                synchronized (mService.mGlobalLock) {
+                    // Unfreeze the task list once we touch down in a task
+                    final RootActivityContainer rac = mService.mRootActivityContainer;
+                    final DisplayContent dc = rac.getActivityDisplay(displayId).mDisplayContent;
+                    if (dc.pointWithinAppWindow(x, y)) {
+                        final ActivityStack stack = mService.getTopDisplayFocusedStack();
+                        final TaskRecord topTask = stack != null ? stack.topTask() : null;
+                        resetFreezeTaskListReordering(topTask);
+                    }
+                }
+            }, null).recycleOnUse());
+        }
+    };
+
     @VisibleForTesting
     RecentTasks(ActivityTaskManagerService service, TaskPersister taskPersister) {
         mService = service;
@@ -214,6 +254,73 @@
         mGlobalMaxNumTasks = globalMaxNumTasks;
     }
 
+    @VisibleForTesting
+    void setFreezeTaskListTimeoutParams(long reorderingTime, long timeoutMs) {
+        mFreezeTaskListReorderingTime = reorderingTime;
+        mFreezeTaskListTimeoutMs = timeoutMs;
+    }
+
+    PointerEventListener getInputListener() {
+        return mListener;
+    }
+
+    /**
+     * Freezes the current recent task list order until either a user interaction with the current
+     * app, or a timeout occurs.
+     */
+    void setFreezeTaskListReordering() {
+        // Always update the reordering time when this is called to ensure that the timeout
+        // is reset
+        mFreezeTaskListReordering = true;
+        mFreezeTaskListReorderingTime = SystemClock.elapsedRealtime();
+    }
+
+    /**
+     * Commits the frozen recent task list order, moving the provided {@param topTask} to the
+     * front of the list.
+     */
+    void resetFreezeTaskListReordering(TaskRecord topTask) {
+        if (!mFreezeTaskListReordering) {
+            return;
+        }
+
+        // Once we end freezing the task list, reset the existing task order to the stable state
+        mFreezeTaskListReordering = false;
+
+        // If the top task is provided, then restore the top task to the front of the list
+        if (topTask != null) {
+            mTasks.remove(topTask);
+            mTasks.add(0, topTask);
+        }
+
+        // Resume trimming tasks
+        trimInactiveRecentTasks();
+    }
+
+    /**
+     * Resets the frozen recent task list order if the timeout has passed. This should be called
+     * before we need to iterate the task list in order (either for purposes of returning the list
+     * to SystemUI or if we need to trim tasks in order)
+     */
+    void resetFreezeTaskListReorderingOnTimeout() {
+        // Unfreeze the recent task list if the time heuristic has passed
+        if (mFreezeTaskListReorderingTime
+                > (SystemClock.elapsedRealtime() - mFreezeTaskListTimeoutMs)) {
+            return;
+        }
+
+        final ActivityStack focusedStack = mService.getTopDisplayFocusedStack();
+        final TaskRecord topTask = focusedStack != null
+                ? focusedStack.topTask()
+                : null;
+        resetFreezeTaskListReordering(topTask);
+    }
+
+    @VisibleForTesting
+    boolean isFreezeTaskListReorderingSet() {
+        return mFreezeTaskListReordering;
+    }
+
     /**
      * Loads the parameters from the system resources.
      */
@@ -351,7 +458,8 @@
         }
 
         Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
-        mTasks.addAll(mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks));
+        List<TaskRecord> tasks = mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks);
+        mTasks.addAll(tasks);
         cleanupLocked(userId);
         mUsersWithRecentsLoaded.put(userId, true);
 
@@ -746,11 +854,10 @@
                 getDetailedTasks, userId, callingUid));
     }
 
-
     /**
      * @return the list of recent tasks for presentation.
      */
-    ArrayList<ActivityManager.RecentTaskInfo> getRecentTasksImpl(int maxNum, int flags,
+    private ArrayList<ActivityManager.RecentTaskInfo> getRecentTasksImpl(int maxNum, int flags,
             boolean getTasksAllowed, boolean getDetailedTasks, int userId, int callingUid) {
         final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0;
 
@@ -763,6 +870,9 @@
         final Set<Integer> includedUsers = getProfileIds(userId);
         includedUsers.add(Integer.valueOf(userId));
 
+        // Check if the frozen task list has timed out
+        resetFreezeTaskListReorderingOnTimeout();
+
         final ArrayList<ActivityManager.RecentTaskInfo> res = new ArrayList<>();
         final int size = mTasks.size();
         int numVisibleTasks = 0;
@@ -946,24 +1056,20 @@
         if (task.inRecents) {
             int taskIndex = mTasks.indexOf(task);
             if (taskIndex >= 0) {
-                if (!isAffiliated || !MOVE_AFFILIATED_TASKS_TO_FRONT) {
-                    // Simple case: this is not an affiliated task, so we just move it to the front.
-                    mTasks.remove(taskIndex);
-                    mTasks.add(0, task);
-                    notifyTaskPersisterLocked(task, false);
-                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
-                            + " from " + taskIndex);
-                    return;
-                } else {
-                    // More complicated: need to keep all affiliated tasks together.
-                    if (moveAffiliatedTasksToFront(task, taskIndex)) {
-                        // All went well.
-                        return;
-                    }
+                if (!isAffiliated) {
+                    if (!mFreezeTaskListReordering) {
+                        // Simple case: this is not an affiliated task, so we just move it to the
+                        // front unless overridden by the provided activity options
+                        mTasks.remove(taskIndex);
+                        mTasks.add(0, task);
 
-                    // Uh oh...  something bad in the affiliation chain, try to rebuild
-                    // everything and then go through our general path of adding a new task.
-                    needAffiliationFix = true;
+                        if (DEBUG_RECENTS) {
+                            Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
+                                    + " from " + taskIndex);
+                        }
+                    }
+                    notifyTaskPersisterLocked(task, false);
+                    return;
                 }
             } else {
                 Slog.wtf(TAG, "Task with inRecent not in recents: " + task);
@@ -1063,6 +1169,11 @@
      * Trims the recents task list to the global max number of recents.
      */
     private void trimInactiveRecentTasks() {
+        if (mFreezeTaskListReordering) {
+            // Defer trimming inactive recent tasks until we are unfrozen
+            return;
+        }
+
         int recentsCount = mTasks.size();
 
         // Remove from the end of the list until we reach the max number of recents
@@ -1086,7 +1197,7 @@
                     + " quiet=" + mTmpQuietProfileUserIds.get(userId));
         }
 
-        // Remove any inactive tasks, calculate the latest set of visible tasks
+        // Remove any inactive tasks, calculate the latest set of visible tasks.
         int numVisibleTasks = 0;
         for (int i = 0; i < mTasks.size();) {
             final TaskRecord task = mTasks.get(i);
@@ -1300,6 +1411,11 @@
      * list (if any).
      */
     private int findRemoveIndexForAddTask(TaskRecord task) {
+        if (mFreezeTaskListReordering) {
+            // Defer removing tasks due to the addition of new tasks until the task list is unfrozen
+            return -1;
+        }
+
         final int recentsCount = mTasks.size();
         final Intent intent = task.intent;
         final boolean document = intent != null && intent.isDocument();
@@ -1536,6 +1652,9 @@
         pw.println("ACTIVITY MANAGER RECENT TASKS (dumpsys activity recents)");
         pw.println("mRecentsUid=" + mRecentsUid);
         pw.println("mRecentsComponent=" + mRecentsComponent);
+        pw.println("mFreezeTaskListReordering=" + mFreezeTaskListReordering);
+        pw.println("mFreezeTaskListReorderingTime (time since)="
+                + (SystemClock.elapsedRealtime() - mFreezeTaskListReorderingTime) + "ms");
         if (mTasks.isEmpty()) {
             return;
         }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 300cd17..db7613a 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -193,8 +193,8 @@
     }
 
     DisplayContent getTopFocusedDisplayContent() {
-        return getDisplayContent(mTopFocusedDisplayId == INVALID_DISPLAY
-                ? DEFAULT_DISPLAY : mTopFocusedDisplayId);
+        final DisplayContent dc = getDisplayContent(mTopFocusedDisplayId);
+        return dc != null ? dc : getDisplayContent(DEFAULT_DISPLAY);
     }
 
     @Override
@@ -1045,6 +1045,15 @@
         mWmService.scheduleAnimationLocked();
     }
 
+    @Override
+    protected void removeChild(DisplayContent dc) {
+        super.removeChild(dc);
+        if (mTopFocusedDisplayId == dc.getDisplayId()) {
+            mWmService.updateFocusedWindowLocked(
+                    UPDATE_FOCUS_NORMAL, true /* updateInputWindows */);
+        }
+    }
+
     /**
      * For all display at or below this call the callback.
      *
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 499cbaf..bb7867c 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -433,29 +433,6 @@
         }
     }
 
-    /** Return true if the current bound can get outputted to the rest of the system as-is. */
-    private boolean useCurrentBounds() {
-        final DisplayContent displayContent = getDisplayContent();
-        return matchParentBounds()
-                || !inSplitScreenSecondaryWindowingMode()
-                || displayContent == null
-                || displayContent.getSplitScreenPrimaryStackIgnoringVisibility() != null;
-    }
-
-    @Override
-    public void getBounds(Rect out) {
-        if (useCurrentBounds()) {
-            // No need to adjust the output bounds if fullscreen or the docked stack is visible
-            // since it is already what we want to represent to the rest of the system.
-            super.getBounds(out);
-            return;
-        }
-
-        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
-        // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
-        mStack.getDisplayContent().getBounds(out);
-    }
-
     @Override
     public Rect getDisplayedBounds() {
         if (mOverrideDisplayedBounds.isEmpty()) {
@@ -506,36 +483,28 @@
         // a DimLayer anyway if we weren't visible.
         final boolean dockedResizing = displayContent != null
                 && displayContent.mDividerControllerLocked.isResizing();
-        if (useCurrentBounds()) {
-            if (inFreeformWindowingMode() && getMaxVisibleBounds(out)) {
-                return;
-            }
-
-            if (!matchParentBounds()) {
-                // When minimizing the docked stack when going home, we don't adjust the task bounds
-                // so we need to intersect the task bounds with the stack bounds here.
-                //
-                // If we are Docked Resizing with snap points, the task bounds could be smaller than the stack
-                // bounds and so we don't even want to use them. Even if the app should not be resized the Dim
-                // should keep up with the divider.
-                if (dockedResizing) {
-                    mStack.getBounds(out);
-                } else {
-                    mStack.getBounds(mTmpRect);
-                    mTmpRect.intersect(getBounds());
-                    out.set(mTmpRect);
-                }
-            } else {
-                out.set(getBounds());
-            }
+        if (inFreeformWindowingMode() && getMaxVisibleBounds(out)) {
             return;
         }
 
-        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
-        // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
-        if (displayContent != null) {
-            displayContent.getBounds(out);
+        if (!matchParentBounds()) {
+            // When minimizing the docked stack when going home, we don't adjust the task bounds
+            // so we need to intersect the task bounds with the stack bounds here.
+            //
+            // If we are Docked Resizing with snap points, the task bounds could be smaller than the
+            // stack bounds and so we don't even want to use them. Even if the app should not be
+            // resized the Dim should keep up with the divider.
+            if (dockedResizing) {
+                mStack.getBounds(out);
+            } else {
+                mStack.getBounds(mTmpRect);
+                mTmpRect.intersect(getBounds());
+                out.set(mTmpRect);
+            }
+        } else {
+            out.set(getBounds());
         }
+        return;
     }
 
     void setDragResizing(boolean dragResizing, int dragResizeMode) {
@@ -702,16 +671,6 @@
         positionChildAt(position, aToken, false /* includeParents */);
     }
 
-    boolean isFullscreen() {
-        if (useCurrentBounds()) {
-            return matchParentBounds();
-        }
-        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
-        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
-        // system.
-        return true;
-    }
-
     void forceWindowsScaleable(boolean force) {
         mWmService.openSurfaceTransaction();
         try {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 241f14e..e6b8112 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -303,17 +303,6 @@
         return super.getBounds();
     }
 
-    /** Return true if the current bound can get outputted to the rest of the system as-is. */
-    private boolean useCurrentBounds() {
-        if (matchParentBounds()
-                || !inSplitScreenSecondaryWindowingMode()
-                || mDisplayContent == null
-                || mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() != null) {
-            return true;
-        }
-        return false;
-    }
-
     @Override
     public void getBounds(Rect bounds) {
         bounds.set(getBounds());
@@ -321,22 +310,15 @@
 
     @Override
     public Rect getBounds() {
-        if (useCurrentBounds()) {
-            // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
-            // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
-            // stack is visible since it is already what we want to represent to the rest of the
-            // system.
-            if (!mAdjustedBounds.isEmpty()) {
-                return mAdjustedBounds;
-            } else {
-                return super.getBounds();
-            }
-        }
-
-        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
-        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
+        // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
+        // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
+        // stack is visible since it is already what we want to represent to the rest of the
         // system.
-        return mDisplayContent.getBounds();
+        if (!mAdjustedBounds.isEmpty()) {
+            return mAdjustedBounds;
+        } else {
+            return super.getBounds();
+        }
     }
 
     /**
@@ -1425,13 +1407,7 @@
 
     @Override
     boolean fillsParent() {
-        if (useCurrentBounds()) {
-            return matchParentBounds();
-        }
-        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
-        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
-        // system.
-        return true;
+        return matchParentBounds();
     }
 
     @Override
@@ -1516,7 +1492,7 @@
 
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final Task task = mChildren.get(i);
-            if (task.isFullscreen()) {
+            if (task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
                 results.searchDone = true;
                 return;
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e3a8be5..a6c9257 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -689,6 +689,8 @@
                 Settings.Secure.getUriFor(Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS);
         private final Uri mPolicyControlUri =
                 Settings.Global.getUriFor(Settings.Global.POLICY_CONTROL);
+        private final Uri mPointerLocationUri =
+                Settings.System.getUriFor(Settings.System.POINTER_LOCATION);
 
         public SettingsObserver() {
             super(new Handler());
@@ -703,8 +705,8 @@
                     UserHandle.USER_ALL);
             resolver.registerContentObserver(mImmersiveModeConfirmationsUri, false, this,
                     UserHandle.USER_ALL);
-            resolver.registerContentObserver(mPolicyControlUri, false, this,
-                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(mPolicyControlUri, false, this, UserHandle.USER_ALL);
+            resolver.registerContentObserver(mPointerLocationUri, false, this, UserHandle.USER_ALL);
         }
 
         @Override
@@ -723,6 +725,11 @@
                 return;
             }
 
+            if (mPointerLocationUri.equals(uri)) {
+                updatePointerLocation();
+                return;
+            }
+
             @UpdateAnimationScaleMode
             final int mode;
             if (mWindowAnimationScaleUri.equals(uri)) {
@@ -749,6 +756,22 @@
                 updateRotation(false /* alwaysSendConfiguration */, false /* forceRelayout */);
             }
         }
+
+        void updatePointerLocation() {
+            ContentResolver resolver = mContext.getContentResolver();
+            final boolean enablePointerLocation = Settings.System.getIntForUser(resolver,
+                    Settings.System.POINTER_LOCATION, 0, UserHandle.USER_CURRENT) != 0;
+
+            if (mPointerLocationEnabled == enablePointerLocation) {
+                return;
+            }
+            mPointerLocationEnabled = enablePointerLocation;
+            synchronized (mGlobalLock) {
+                mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
+                        DisplayPolicy::setPointerLocationEnabled, PooledLambda.__(),
+                        mPointerLocationEnabled));
+            }
+        }
     }
 
     PowerManager mPowerManager;
@@ -758,6 +781,7 @@
     private float mTransitionAnimationScaleSetting = 1.0f;
     private float mAnimatorDurationScaleSetting = 1.0f;
     private boolean mAnimationsDisabled = false;
+    boolean mPointerLocationEnabled = false;
 
     final InputManagerService mInputManager;
     final DisplayManagerInternal mDisplayManagerInternal;
@@ -4363,6 +4387,7 @@
         mHasWideColorGamutSupport = queryWideColorGamutSupport();
         mHasHdrSupport = queryHdrSupport();
         UiThread.getHandler().post(mSettingsObserver::updateSystemUiSettings);
+        UiThread.getHandler().post(mSettingsObserver::updatePointerLocation);
         IVrManager vrManager = IVrManager.Stub.asInterface(
                 ServiceManager.getService(Context.VR_SERVICE));
         if (vrManager != null) {
@@ -7447,13 +7472,26 @@
 
     @Override
     public boolean injectInputAfterTransactionsApplied(InputEvent ev, int mode) {
-        waitForAnimationsToComplete();
-
-        synchronized (mGlobalLock) {
-            mWindowPlacerLocked.performSurfacePlacementIfScheduled();
+        boolean shouldWaitForAnimComplete = false;
+        if (ev instanceof KeyEvent) {
+            KeyEvent keyEvent = (KeyEvent) ev;
+            shouldWaitForAnimComplete = keyEvent.getSource() == InputDevice.SOURCE_MOUSE
+                    || keyEvent.getAction() == KeyEvent.ACTION_DOWN;
+        } else if (ev instanceof MotionEvent) {
+            MotionEvent motionEvent = (MotionEvent) ev;
+            shouldWaitForAnimComplete = motionEvent.getSource() == InputDevice.SOURCE_MOUSE
+                    || motionEvent.getAction() == MotionEvent.ACTION_DOWN;
         }
 
-        new SurfaceControl.Transaction().syncInputWindows().apply(true);
+        if (shouldWaitForAnimComplete) {
+            waitForAnimationsToComplete();
+
+            synchronized (mGlobalLock) {
+                mWindowPlacerLocked.performSurfacePlacementIfScheduled();
+            }
+
+            new SurfaceControl.Transaction().syncInputWindows().apply(true);
+        }
 
         return LocalServices.getService(InputManagerInternal.class).injectInputEvent(ev, mode);
     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 20cca66..ee445d8 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -826,7 +826,7 @@
         mHaveFrame = true;
 
         final Task task = getTask();
-        final boolean inFullscreenContainer = inFullscreenContainer();
+        final boolean isFullscreenAndFillsDisplay = !inMultiWindowMode() && matchesDisplayBounds();
         final boolean windowsAreFloating = task != null && task.isFloating();
         final DisplayContent dc = getDisplayContent();
 
@@ -845,7 +845,7 @@
         final WindowState imeWin = mWmService.mRoot.getCurrentInputMethodWindow();
         final boolean isImeTarget =
                 imeWin != null && imeWin.isVisibleNow() && isInputMethodTarget();
-        if (inFullscreenContainer || layoutInParentFrame()) {
+        if (isFullscreenAndFillsDisplay || layoutInParentFrame()) {
             // We use the parent frame as the containing frame for fullscreen and child windows
             mWindowFrames.mContainingFrame.set(mWindowFrames.mParentFrame);
             layoutDisplayFrame = mWindowFrames.mDisplayFrame;
@@ -983,7 +983,7 @@
                     Math.min(mWindowFrames.mStableFrame.bottom, mWindowFrames.mFrame.bottom));
         }
 
-        if (inFullscreenContainer && !windowsAreFloating) {
+        if (isFullscreenAndFillsDisplay && !windowsAreFloating) {
             // Windows that are not fullscreen can be positioned outside of the display frame,
             // but that is not a reason to provide them with overscan insets.
             InsetUtils.insetsBetweenFrames(layoutContainingFrame, mWindowFrames.mOverscanFrame,
@@ -996,7 +996,8 @@
             mWindowFrames.calculateDockedDividerInsets(c.getDisplayCutout().getSafeInsets());
         } else {
             getDisplayContent().getBounds(mTmpRect);
-            mWindowFrames.calculateInsets(windowsAreFloating, inFullscreenContainer, mTmpRect);
+            mWindowFrames.calculateInsets(
+                    windowsAreFloating, isFullscreenAndFillsDisplay, mTmpRect);
         }
 
         mWindowFrames.setDisplayCutout(
@@ -1038,9 +1039,7 @@
     // TODO: Look into whether this override is still necessary.
     @Override
     public Rect getBounds() {
-        if (isInMultiWindowMode()) {
-            return getTask().getBounds();
-        } else if (mAppToken != null){
+        if (mAppToken != null) {
             return mAppToken.getBounds();
         } else {
             return super.getBounds();
@@ -1751,6 +1750,10 @@
                 && mWindowFrames.mFrame.bottom >= displayInfo.appHeight;
     }
 
+    private boolean matchesDisplayBounds() {
+        return getDisplayContent().getBounds().equals(getBounds());
+    }
+
     /** Returns true if last applied config was not yet requested by client. */
     boolean isConfigChanged() {
         return !getLastReportedConfiguration().equals(getConfiguration());
@@ -3114,20 +3117,16 @@
         return getDisplayContent().mCurrentFocus == this;
     }
 
-    @Override
-    public boolean isInMultiWindowMode() {
-        final Task task = getTask();
-        return task != null && !task.isFullscreen();
-    }
 
     /** Is this window in a container that takes up the entire screen space? */
-    private boolean inFullscreenContainer() {
-        return mAppToken == null || (mAppToken.matchParentBounds() && !isInMultiWindowMode());
+    private boolean inAppWindowThatMatchesParentBounds() {
+        return mAppToken == null || (mAppToken.matchParentBounds() && !inMultiWindowMode());
     }
 
-    /** @return true when the window is in fullscreen task, but has non-fullscreen bounds set. */
+    /** @return true when the window is in fullscreen mode, but has non-fullscreen bounds set, or
+     *          is transitioning into/out-of fullscreen. */
     boolean isLetterboxedAppWindow() {
-        return !isInMultiWindowMode() && mAppToken != null && !mAppToken.matchParentBounds()
+        return !inMultiWindowMode() && !matchesDisplayBounds()
                 || isLetterboxedForDisplayCutoutLw();
     }
 
@@ -3494,7 +3493,7 @@
         final int pw = containingFrame.width();
         final int ph = containingFrame.height();
         final Task task = getTask();
-        final boolean inNonFullscreenContainer = !inFullscreenContainer();
+        final boolean inNonFullscreenContainer = !inAppWindowThatMatchesParentBounds();
         final boolean noLimits = (mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0;
 
         // We need to fit it to the display if either
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 92bb082..780d471 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -26,7 +26,6 @@
 
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
@@ -792,16 +791,10 @@
         if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
                 + w.getDecorFrame() + " mSystemDecorRect=" + mSystemDecorRect);
 
-        final Task task = w.getTask();
-        final boolean fullscreen = w.fillsDisplay() || (task != null && task.isFullscreen());
-        final boolean isFreeformResizing =
-                w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM;
-
         // We use the clip rect as provided by the tranformation for non-fullscreen windows to
         // avoid premature clipping with the system decor rect.
         clipRect.set(mSystemDecorRect);
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect
-                + " fullscreen=" + fullscreen);
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect);
 
         w.expandForSurfaceInsets(clipRect);
 
diff --git a/services/core/java/com/android/server/wm/WindowTraceBuffer.java b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
index a4ee907..8c65884 100644
--- a/services/core/java/com/android/server/wm/WindowTraceBuffer.java
+++ b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
@@ -93,8 +93,8 @@
     void writeTraceToFile(File traceFile) throws IOException {
         synchronized (mBufferLock) {
             traceFile.delete();
-            traceFile.setReadable(true, false);
             try (OutputStream os = new FileOutputStream(traceFile)) {
+                traceFile.setReadable(true /* readable */, false /* ownerOnly */);
                 ProtoOutputStream proto = new ProtoOutputStream();
                 proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
                 os.write(proto.getBytes());
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index bce3e98..caba3af 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -335,6 +335,8 @@
 const char *const JavaMethodHelper<double>::signature_ = "(D)V";
 template<>
 const char *const JavaMethodHelper<bool>::signature_ = "(Z)V";
+template<>
+const char *const JavaMethodHelper<jstring>::signature_ = "(Ljava/lang/String;)V";
 
 #define SET(setter, value) object.callSetter("set" # setter, (value))
 
@@ -1056,9 +1058,10 @@
         <IGnssMeasurementCallback_V2_0::GnssMeasurement>(
         const IGnssMeasurementCallback_V2_0::GnssMeasurement* measurement_V2_0,
         JavaObject& object) {
+    JNIEnv* env = getJniEnv();
     translateSingleGnssMeasurement(&(measurement_V2_0->v1_1), object);
 
-    SET(CodeType, static_cast<int32_t>(measurement_V2_0->codeType));
+    SET(CodeType, env->NewStringUTF(measurement_V2_0->codeType.c_str()));
 
     // Overwrite with v2_0.state since v2_0->v1_1->v1_0.state is deprecated.
     SET(State, static_cast<int32_t>(measurement_V2_0->state));
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3999edd..f6de82d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5912,10 +5912,13 @@
         delegateReceiver = resolveDelegateReceiver(DELEGATION_CERT_SELECTION,
                 DeviceAdminReceiver.ACTION_CHOOSE_PRIVATE_KEY_ALIAS, caller.getIdentifier());
 
+        final boolean isDelegate;
         if (delegateReceiver != null) {
             intent.setComponent(delegateReceiver);
+            isDelegate = true;
         } else {
             intent.setComponent(aliasChooser);
+            isDelegate = false;
         }
 
         final long id = mInjector.binderClearCallingIdentity();
@@ -5927,11 +5930,10 @@
                     sendPrivateKeyAliasResponse(chosenAlias, response);
                 }
             }, null, Activity.RESULT_OK, null, null);
-            final String adminPackageName =
-                    (aliasChooser != null ? aliasChooser.getPackageName() : null);
             DevicePolicyEventLogger
                     .createEvent(DevicePolicyEnums.CHOOSE_PRIVATE_KEY_ALIAS)
-                    .setAdmin(adminPackageName)
+                    .setAdmin(intent.getComponent())
+                    .setBoolean(isDelegate)
                     .write();
         } finally {
             mInjector.binderRestoreCallingIdentity(id);
@@ -13091,6 +13093,14 @@
             saveSettingsLocked(mInjector.userHandleGetCallingUserId());
 
             setNetworkLoggingActiveInternal(enabled);
+
+            final boolean isDelegate = (admin == null);
+            DevicePolicyEventLogger
+                    .createEvent(DevicePolicyEnums.SET_NETWORK_LOGGING_ENABLED)
+                    .setAdmin(packageName)
+                    .setBoolean(isDelegate)
+                    .setInt(enabled ? 1 : 0)
+                    .write();
         }
     }
 
@@ -13222,6 +13232,12 @@
                     || !isNetworkLoggingEnabledInternalLocked()) {
                 return null;
             }
+            final boolean isDelegate = (admin == null);
+            DevicePolicyEventLogger
+                    .createEvent(DevicePolicyEnums.RETRIEVE_NETWORK_LOGS)
+                    .setAdmin(packageName)
+                    .setBoolean(isDelegate)
+                    .write();
 
             final long currentTime = System.currentTimeMillis();
             DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3de3152..3f323d9 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1247,6 +1247,14 @@
             mSystemServiceManager.startService(ClipboardService.class);
             traceEnd();
 
+            traceBeginAndSlog("InitNetworkStackClient");
+            try {
+                NetworkStackClient.getInstance().init();
+            } catch (Throwable e) {
+                reportWtf("initializing NetworkStackClient", e);
+            }
+            traceEnd();
+
             traceBeginAndSlog("StartNetworkManagementService");
             try {
                 networkManagement = NetworkManagementService.create(context);
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index a8f4a77..fe447fc 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -165,6 +165,15 @@
     }
 
     /**
+     * Initialize the network stack. Should be called only once on device startup, before any
+     * client attempts to use the network stack.
+     */
+    public void init() {
+        log("Network stack init");
+        mNetworkStackStartRequested = true;
+    }
+
+    /**
      * Start the network stack. Should be called only once on device startup.
      *
      * <p>This method will start the network stack either in the network stack process, or inside
@@ -174,8 +183,6 @@
      */
     public void start(Context context) {
         log("Starting network stack");
-        mNetworkStackStartRequested = true;
-
         final PackageManager pm = context.getPackageManager();
 
         // Try to bind in-process if the device was shipped with an in-process version
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index 66d9345..2ed25ea 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -99,8 +99,8 @@
     public void bind_requestsContextToBindService() {
         mConnection.bindLocked();
         verify(mMockContext).bindServiceAsUser(any(Intent.class), eq(mConnection),
-                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE),
-                any(UserHandle.class));
+                eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+                | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS), any(UserHandle.class));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
index 93cac08..71b4397 100644
--- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
@@ -21,6 +21,7 @@
 import static com.android.server.am.MemoryStatUtil.MemoryStat;
 import static com.android.server.am.MemoryStatUtil.PAGE_SIZE;
 import static com.android.server.am.MemoryStatUtil.parseCmdlineFromProcfs;
+import static com.android.server.am.MemoryStatUtil.parseIonHeapSizeFromDebugfs;
 import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg;
 import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromProcfs;
 import static com.android.server.am.MemoryStatUtil.parseVmHWMFromProcfs;
@@ -178,6 +179,33 @@
             + "voluntary_ctxt_switches:\t903\n"
             + "nonvoluntary_ctxt_switches:\t104\n";
 
+    private static final String DEBUG_SYSTEM_ION_HEAP_CONTENTS = String.join(
+            "          client              pid             size\n",
+            "----------------------------------------------------\n",
+            " audio@2.0-servi              765             4096\n",
+            " audio@2.0-servi              765            61440\n",
+            " audio@2.0-servi              765             4096\n",
+            "     voip_client               96             8192\n",
+            "     voip_client               96             4096\n",
+            "   system_server             1232         16728064\n",
+            "  surfaceflinger              611         50642944\n",
+            "----------------------------------------------------\n",
+            "orphaned allocations (info is from last known client):\n",
+            "----------------------------------------------------\n",
+            "  total orphaned                0\n",
+            "          total          55193600\n",
+            "   deferred free                0\n",
+            "----------------------------------------------------\n",
+            "0 order 4 highmem pages in uncached pool = 0 total\n",
+            "0 order 4 lowmem pages in uncached pool = 0 total\n",
+            "1251 order 4 lowmem pages in cached pool = 81985536 total\n",
+            "VMID 8: 0 order 4 highmem pages in secure pool = 0 total\n",
+            "VMID  8: 0 order 4 lowmem pages in secure pool = 0 total\n",
+            "--------------------------------------------\n",
+            "uncached pool = 4096 cached pool = 83566592 secure pool = 0\n",
+            "pool total (uncached + cached + secure) = 83570688\n",
+            "--------------------------------------------\n");
+
     @Test
     public void testParseMemoryStatFromMemcg_parsesCorrectValues() {
         MemoryStat stat = parseMemoryStatFromMemcg(MEMORY_STAT_CONTENTS);
@@ -271,4 +299,21 @@
         output.write(bytes, 0, bytes.length);
         return output.toString();
     }
+
+    @Test
+    public void testParseIonHeapSizeFromDebugfs_emptyContents() {
+        assertEquals(0, parseIonHeapSizeFromDebugfs(""));
+
+        assertEquals(0, parseIonHeapSizeFromDebugfs(null));
+    }
+
+    @Test
+    public void testParseIonHeapSizeFromDebugfs_invalidValue() {
+        assertEquals(0, parseIonHeapSizeFromDebugfs("<<no-value>>"));
+    }
+
+    @Test
+    public void testParseIonHeapSizeFromDebugfs_correctValue() {
+        assertEquals(55193600, parseIonHeapSizeFromDebugfs(DEBUG_SYSTEM_ION_HEAP_CONTENTS));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 28a815e..bd7774a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -5021,8 +5021,7 @@
         configureContextForAccess(mContext, false);
 
         assertExpectException(SecurityException.class, /* messageRegex= */ null,
-                () -> dpm.setProfileOwnerCanAccessDeviceIdsForUser(admin2,
-                        UserHandle.of(DpmMockContext.CALLER_UID)));
+                () -> dpm.setProfileOwnerCanAccessDeviceIds(admin2));
     }
 
     public void testGrantDeviceIdsAccess_notByAuthorizedCaller() throws Exception {
@@ -5030,8 +5029,7 @@
         configureContextForAccess(mContext, false);
 
         assertExpectException(SecurityException.class, /* messageRegex= */ null,
-                () -> dpm.setProfileOwnerCanAccessDeviceIdsForUser(admin1,
-                        UserHandle.of(DpmMockContext.CALLER_UID)));
+                () -> dpm.setProfileOwnerCanAccessDeviceIds(admin1));
     }
 
     public void testGrantDeviceIdsAccess_byAuthorizedSystemCaller() throws Exception {
@@ -5060,8 +5058,7 @@
                         DpmMockContext.CALLER_MANAGED_PROVISIONING_UID);
         try {
             runAsCaller(mServiceContext, dpms, dpm -> {
-                dpm.setProfileOwnerCanAccessDeviceIdsForUser(admin1,
-                        UserHandle.of(DpmMockContext.CALLER_USER_HANDLE));
+                dpm.setProfileOwnerCanAccessDeviceIds(admin1);
             });
         } finally {
             mServiceContext.binder.restoreCallingIdentity(ident);
@@ -5314,7 +5311,7 @@
         mServiceContext.binder.callingUid =
                 UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
         runAsCaller(mServiceContext, dpms, dpm -> {
-            dpm.setProfileOwnerCanAccessDeviceIdsForUser(who, UserHandle.of(userId));
+            dpm.setProfileOwnerCanAccessDeviceIds(who);
         });
         mServiceContext.binder.restoreCallingIdentity(ident);
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index 26722fd..d3f33a1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -167,6 +167,7 @@
                 /* stageDir */ mTmpDir,
                 /* stageCid */ null,
                 /* prepared */ true,
+                /* committed */ true,
                 /* sealed */ false,  // Setting to true would trigger some PM logic.
                 /* childSessionIds */ childSessionIds != null ? childSessionIds : new int[0],
                 /* parentSessionId */ parentSessionId,
@@ -300,6 +301,7 @@
         assertEquals(expected.getStagedSessionErrorMessage(),
                 actual.getStagedSessionErrorMessage());
         assertEquals(expected.isPrepared(), actual.isPrepared());
+        assertEquals(expected.isCommitted(), actual.isCommitted());
         assertEquals(expected.isSealed(), actual.isSealed());
         assertEquals(expected.isMultiPackage(), actual.isMultiPackage());
         assertEquals(expected.hasParentSessionId(), actual.hasParentSessionId());
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index 111fb74..4cfd098 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -56,11 +56,11 @@
             }
 
             @Override
-            public void notifyPackageAdded(String packageName) {
+            public void notifyPackageAdded(String packageName, int uid) {
             }
 
             @Override
-            public void notifyPackageRemoved(String packageName) {
+            public void notifyPackageRemoved(String packageName, int uid) {
             }
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
index 1f86171..958b23f 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
@@ -175,9 +175,9 @@
     /** Verify app usage limit observer is added */
     @Test
     public void testAppUsageLimitObserver_AddObserver() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1));
-        addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, 0);
         assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID2));
         assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1));
     }
@@ -203,7 +203,7 @@
     /** Verify app usage limit observer is removed */
     @Test
     public void testAppUsageLimitObserver_RemoveObserver() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1));
         mController.removeAppUsageLimitObserver(UID, OBS_ID1, USER_ID);
         assertFalse("Observer wasn't removed", hasAppUsageLimitObserver(UID, OBS_ID1));
@@ -290,9 +290,9 @@
     /** Re-adding an observer should result in only one copy */
     @Test
     public void testAppUsageLimitObserver_ObserverReAdd() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1));
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, TIME_10_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, 0);
         assertTrue("Observer wasn't added",
                 getAppUsageLimitObserver(UID, OBS_ID1).getTimeLimitMs() == TIME_10_MIN);
         mController.removeAppUsageLimitObserver(UID, OBS_ID1, USER_ID);
@@ -304,7 +304,7 @@
     public void testAllObservers_ExclusiveObserverIds() {
         addAppUsageObserver(OBS_ID1, GROUP1, TIME_10_MIN);
         addUsageSessionObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_1_MIN);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, TIME_10_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_10_MIN, 0);
         assertTrue("Observer wasn't added", hasAppUsageObserver(UID, OBS_ID1));
         assertTrue("Observer wasn't added", hasUsageSessionObserver(UID, OBS_ID1));
         assertTrue("Observer wasn't added", hasAppUsageLimitObserver(UID, OBS_ID1));
@@ -396,7 +396,7 @@
     @Test
     public void testAppUsageLimitObserver_Accumulation() throws Exception {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         startUsage(PKG_SOC1);
         // Add 10 mins
         setTime(TIME_10_MIN);
@@ -456,7 +456,7 @@
     @Test
     public void testAppUsageLimitObserver_TimeoutOtherApp() throws Exception {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 4_000L);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 0);
         startUsage(PKG_SOC2);
         assertFalse(mLimitReachedLatch.await(6_000L, TimeUnit.MILLISECONDS));
         setTime(6_000L);
@@ -498,7 +498,7 @@
     @Test
     public void testAppUsageLimitObserver_Timeout() throws Exception {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 4_000L);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, 4_000L, 0);
         startUsage(PKG_SOC1);
         setTime(6_000L);
         assertTrue(mLimitReachedLatch.await(6_000L, TimeUnit.MILLISECONDS));
@@ -551,7 +551,7 @@
         setTime(TIME_10_MIN);
         startUsage(PKG_GAME1);
         setTime(TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN, 0);
         setTime(TIME_30_MIN + TIME_10_MIN);
         stopUsage(PKG_GAME1);
         assertFalse(mLimitReachedLatch.await(1_000L, TimeUnit.MILLISECONDS));
@@ -612,7 +612,7 @@
         startUsage(PKG_SOC1);
         setTime(TIME_10_MIN);
         // 10 second time limit
-        addAppUsageLimitObserver(OBS_ID1, GROUP_SOC, 10_000L, 10_000L);
+        addAppUsageLimitObserver(OBS_ID1, GROUP_SOC, 10_000L, 0);
         setTime(TIME_10_MIN + 5_000L);
         // Shouldn't call back in 6 seconds
         assertFalse(mLimitReachedLatch.await(6_000L, TimeUnit.MILLISECONDS));
@@ -692,23 +692,23 @@
     public void testAppUsageLimitObserver_MaxObserverLimit() throws Exception {
         boolean receivedException = false;
         int ANOTHER_UID = UID + 1;
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID2, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID3, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID4, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID6, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID7, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID8, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID9, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID10, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID2, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID3, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID4, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID6, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID7, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID8, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID9, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID10, GROUP1, TIME_30_MIN, 0);
         // Readding an observer should not cause an IllegalStateException
-        addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID5, GROUP1, TIME_30_MIN, 0);
         // Adding an observer for a different uid shouldn't cause an IllegalStateException
         mController.addAppUsageLimitObserver(
-                ANOTHER_UID, OBS_ID11, GROUP1, TIME_30_MIN, TIME_30_MIN, null, USER_ID);
+                ANOTHER_UID, OBS_ID11, GROUP1, TIME_30_MIN, 0, null, USER_ID);
         try {
-            addAppUsageLimitObserver(OBS_ID11, GROUP1, TIME_30_MIN, TIME_30_MIN);
+            addAppUsageLimitObserver(OBS_ID11, GROUP1, TIME_30_MIN, 0);
         } catch (IllegalStateException ise) {
             receivedException = true;
         }
@@ -748,9 +748,9 @@
     public void testAppUsageLimitObserver_MinimumTimeLimit() throws Exception {
         boolean receivedException = false;
         // adding an observer with a one minute time limit should not cause an exception
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT, MIN_TIME_LIMIT);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT, 0);
         try {
-            addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT - 1, MIN_TIME_LIMIT - 1);
+            addAppUsageLimitObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT - 1, 0);
         } catch (IllegalArgumentException iae) {
             receivedException = true;
         }
@@ -807,7 +807,7 @@
     @Test
     public void testAppUsageLimitObserver_ConcurrentUsage() throws Exception {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         AppTimeLimitController.UsageGroup group = getAppUsageLimitObserver(UID, OBS_ID1);
         startUsage(PKG_SOC1);
         // Add 10 mins
@@ -967,7 +967,7 @@
     /** Verify app usage limit observer added correctly reports its total usage limit */
     @Test
     public void testAppUsageLimitObserver_GetTotalUsageLimit() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1);
         assertNotNull("Observer wasn't added", group);
         assertEquals("Observer didn't correctly report total usage limit",
@@ -978,7 +978,7 @@
     @Test
     public void testAppUsageLimitObserver_GetUsageRemaining() {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
         startUsage(PKG_SOC1);
         setTime(TIME_10_MIN);
         stopUsage(PKG_SOC1);
@@ -993,8 +993,8 @@
      */
     @Test
     public void testAppUsageLimitObserver_GetAppUsageLimit() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, TIME_10_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, 0);
         UsageStatsManagerInternal.AppUsageLimitData group = getAppUsageLimit(PKG_SOC1);
         assertEquals("Observer with the smallest usage limit remaining wasn't returned",
                 TIME_10_MIN, group.getTotalUsageLimit());
@@ -1006,8 +1006,8 @@
     @Test
     public void testAppUsageLimitObserver_GetAppUsageLimitUsed() {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, TIME_10_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, 0);
         startUsage(PKG_GAME1);
         setTime(TIME_10_MIN * 2 + TIME_1_MIN);
         stopUsage(PKG_GAME1);
@@ -1024,8 +1024,8 @@
     @Test
     public void testAppUsageLimitObserver_GetAppUsageLimitAllUsed() {
         setTime(0L);
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, TIME_30_MIN);
-        addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, TIME_10_MIN);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID2, GROUP_SOC, TIME_10_MIN, 0);
         startUsage(PKG_SOC1);
         setTime(TIME_10_MIN);
         stopUsage(PKG_SOC1);
@@ -1046,10 +1046,10 @@
         }
     }
 
-    /** Verify that a limit of 0 is allowed for the special case of re-registering an observer. */
+    /** Verify that timeUsed can be the same as timeLimit (for re-registering observers). */
     @Test
     public void testAppUsageLimitObserver_ZeroTimeRemainingIsAllowed() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_1_MIN, 0);
+        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_1_MIN, TIME_1_MIN);
         AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1);
         assertNotNull("Observer wasn't added", group);
         assertEquals("Usage remaining was not 0.", 0, group.getUsageRemaining());
@@ -1078,8 +1078,8 @@
     }
 
     private void addAppUsageLimitObserver(int observerId, String[] packages, long timeLimit,
-            long timeRemaining) {
-        mController.addAppUsageLimitObserver(UID, observerId, packages, timeLimit, timeRemaining,
+            long timeUsed) {
+        mController.addAppUsageLimitObserver(UID, observerId, packages, timeLimit, timeUsed,
                 null, USER_ID);
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 7df52b2..4626840 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -117,6 +117,7 @@
 import android.util.AtomicFile;
 
 import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
 
 import com.android.internal.R;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
@@ -311,6 +312,9 @@
 
     @Before
     public void setUp() throws Exception {
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+                "android.permission.WRITE_DEVICE_CONFIG", "android.permission.READ_DEVICE_CONFIG");
+
         MockitoAnnotations.initMocks(this);
 
         LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
@@ -392,6 +396,8 @@
     public void tearDown() throws Exception {
         mFile.delete();
         clearDeviceConfig();
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation().dropShellPermissionIdentity();
     }
 
     public void waitForIdle() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index c072d4e..83c0af9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -59,7 +59,7 @@
     public void setUpOnDisplay(DisplayContent dc) {
         mStack = createTaskStackOnDisplay(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, dc);
         mTask = createTaskInStack(mStack, 0 /* userId */);
-        mToken = WindowTestUtils.createTestAppWindowToken(dc, false /* skipOnParentChanged */);
+        mToken = WindowTestUtils.createTestAppWindowToken(dc);
 
         mTask.addChild(mToken, 0);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 5e12a95..81133d1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -18,6 +18,7 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
 import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
 import static android.view.WindowManager.TRANSIT_TASK_OPEN;
 
@@ -77,4 +78,21 @@
                             TRANSIT_TASK_CLOSE));
         }
     }
+
+    @Test
+    public void testChangeIsNotOverwritten() {
+        synchronized (mWm.mGlobalLock) {
+            final AppWindowToken behind = createAppWindowToken(mDisplayContent,
+                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+            final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent,
+                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+            translucentOpening.setFillsParent(false);
+            translucentOpening.setHidden(true);
+            mDisplayContent.mOpeningApps.add(behind);
+            mDisplayContent.mOpeningApps.add(translucentOpening);
+            assertEquals(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
+                    mAppTransitionController.maybeUpdateTransitToTranslucentAnim(
+                            TRANSIT_TASK_CHANGE_WINDOWING_MODE));
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index a98a604..db04f11 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -60,7 +60,7 @@
         MockitoAnnotations.initMocks(this);
 
         mToken = createTestAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
-                ACTIVITY_TYPE_STANDARD, false /* skipOnParentChanged */);
+                ACTIVITY_TYPE_STANDARD);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 68b40b9..d17e5c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -16,8 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
@@ -48,7 +46,6 @@
 import static org.mockito.Mockito.verify;
 
 import android.content.res.Configuration;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.view.Display;
@@ -81,8 +78,7 @@
     public void setUp() throws Exception {
         mStack = createTaskStackOnDisplay(mDisplayContent);
         mTask = createTaskInStack(mStack, 0 /* userId */);
-        mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent,
-                false /* skipOnParentChanged */);
+        mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
 
         mTask.addChild(mToken, 0);
     }
@@ -219,9 +215,6 @@
 
     @Test
     public void testSizeCompatBounds() {
-        // The real surface transaction is unnecessary.
-        mToken.setSkipPrepareSurfaces(true);
-
         final Rect fixedBounds = mToken.getRequestedOverrideConfiguration().windowConfiguration
                 .getBounds();
         fixedBounds.set(0, 0, 1200, 1600);
@@ -479,32 +472,6 @@
         assertHasStartingWindow(tokenBottom);
     }
 
-    @Test
-    public void testTransitionAnimationPositionAndBounds() {
-        final Rect stackBounds = new Rect(
-                0/* left */, 0 /* top */, 1000 /* right */, 1000 /* bottom */);
-        final Rect taskBounds = new Rect(
-                100/* left */, 200 /* top */, 600 /* right */, 600 /* bottom */);
-        mStack.setBounds(stackBounds);
-        mTask.setBounds(taskBounds);
-
-        mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        assertTransitionAnimationPositionAndBounds(taskBounds.left, taskBounds.top, stackBounds);
-
-        mTask.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
-        assertTransitionAnimationPositionAndBounds(stackBounds.left, stackBounds.top, stackBounds);
-    }
-
-    private void assertTransitionAnimationPositionAndBounds(int expectedX, int expectedY,
-            Rect expectedBounds) {
-        final Point outPosition = new Point();
-        final Rect outBounds = new Rect();
-        mToken.getAnimationBounds(outPosition, outBounds);
-        assertEquals(expectedX, outPosition.x);
-        assertEquals(expectedY, outPosition.y);
-        assertEquals(expectedBounds, outBounds);
-    }
-
     private void assertHasStartingWindow(AppWindowToken atoken) {
         assertNotNull(atoken.startingSurface);
         assertNotNull(atoken.startingData);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index b26aa05..98333b2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -34,11 +34,12 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.same;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -663,6 +664,15 @@
     }
 
     @Test
+    public void testComputeImeParent_app_notMatchParentBounds() {
+        spyOn(mAppWindow.mAppToken);
+        doReturn(false).when(mAppWindow.mAppToken).matchParentBounds();
+        mDisplayContent.mInputMethodTarget = mAppWindow;
+        // The surface parent of IME should be the display instead of app window.
+        assertEquals(mDisplayContent.getWindowingLayer(), mDisplayContent.computeImeParent());
+    }
+
+    @Test
     public void testComputeImeParent_noApp() throws Exception {
         try (final InsetsModeSession session =
                      new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index aeda473..e4d3770 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -316,7 +316,7 @@
     public void testClearsRecordInMemoryOnPackageUninstalled() {
         mTarget.saveTask(mTestTask);
 
-        mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName());
+        mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName(), TEST_USER_ID);
 
         mTarget.getLaunchParams(mTestTask, null, mResult);
 
@@ -327,7 +327,7 @@
     public void testClearsWriteQueueItemOnPackageUninstalled() {
         mTarget.saveTask(mTestTask);
 
-        mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName());
+        mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName(), TEST_USER_ID);
 
         final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor,
                 mUserFolderGetter);
@@ -344,7 +344,7 @@
         mTarget.saveTask(mTestTask);
         mPersisterQueue.flush();
 
-        mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName());
+        mObserver.onPackageRemoved(TEST_COMPONENT.getPackageName(), TEST_USER_ID);
 
         final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor,
                 mUserFolderGetter);
diff --git a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
index 8327440..a166444 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
@@ -28,6 +28,7 @@
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
 
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
 
 import org.junit.After;
@@ -157,6 +158,7 @@
     }
 
     @Test
+    @FlakyTest(bugId = 128526085)
     public void testProcessTwoItems_OneAfterAnother() throws Exception {
         // First item
         mLatch = new CountDownLatch(1);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index fc1eb1c..68e7470 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -583,6 +583,114 @@
     }
 
     @Test
+    public void testFreezeTaskListOrder_reorderExistingTask() {
+        // Add some tasks
+        mRecentTasks.add(mTasks.get(0));
+        mRecentTasks.add(mTasks.get(1));
+        mRecentTasks.add(mTasks.get(2));
+        mRecentTasks.add(mTasks.get(3));
+        mRecentTasks.add(mTasks.get(4));
+        mCallbacksRecorder.clear();
+
+        // Freeze the list
+        mRecentTasks.setFreezeTaskListReordering();
+        assertTrue(mRecentTasks.isFreezeTaskListReorderingSet());
+
+        // Relaunch a few tasks
+        mRecentTasks.add(mTasks.get(3));
+        mRecentTasks.add(mTasks.get(2));
+
+        // Commit the task ordering with a specific task focused
+        mRecentTasks.resetFreezeTaskListReordering(mTasks.get(2));
+        assertFalse(mRecentTasks.isFreezeTaskListReorderingSet());
+
+        // Ensure that the order of the task list is the same as before, but with the focused task
+        // at the front
+        assertRecentTasksOrder(mTasks.get(2),
+                mTasks.get(4),
+                mTasks.get(3),
+                mTasks.get(1),
+                mTasks.get(0));
+
+        assertThat(mCallbacksRecorder.mAdded).isEmpty();
+        assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
+        assertThat(mCallbacksRecorder.mRemoved).isEmpty();
+    }
+
+    @Test
+    public void testFreezeTaskListOrder_addRemoveTasks() {
+        // Add some tasks
+        mRecentTasks.add(mTasks.get(0));
+        mRecentTasks.add(mTasks.get(1));
+        mRecentTasks.add(mTasks.get(2));
+        mCallbacksRecorder.clear();
+
+        // Freeze the list
+        mRecentTasks.setFreezeTaskListReordering();
+        assertTrue(mRecentTasks.isFreezeTaskListReorderingSet());
+
+        // Add and remove some tasks
+        mRecentTasks.add(mTasks.get(3));
+        mRecentTasks.add(mTasks.get(4));
+        mRecentTasks.remove(mTasks.get(0));
+        mRecentTasks.remove(mTasks.get(1));
+
+        // Unfreeze the list
+        mRecentTasks.resetFreezeTaskListReordering(null);
+        assertFalse(mRecentTasks.isFreezeTaskListReorderingSet());
+
+        // Ensure that the order of the task list accounts for the added and removed tasks (added
+        // at the end)
+        assertRecentTasksOrder(mTasks.get(4),
+                mTasks.get(3),
+                mTasks.get(2));
+
+        assertThat(mCallbacksRecorder.mAdded).hasSize(2);
+        assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(3));
+        assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(4));
+        assertThat(mCallbacksRecorder.mRemoved).hasSize(2);
+        assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(0));
+        assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(1));
+    }
+
+    @Test
+    public void testFreezeTaskListOrder_timeout() {
+        // Add some tasks
+        mRecentTasks.add(mTasks.get(0));
+        mRecentTasks.add(mTasks.get(1));
+        mRecentTasks.add(mTasks.get(2));
+        mRecentTasks.add(mTasks.get(3));
+        mRecentTasks.add(mTasks.get(4));
+
+        // Freeze the list
+        long freezeTime = SystemClock.elapsedRealtime();
+        mRecentTasks.setFreezeTaskListReordering();
+        assertTrue(mRecentTasks.isFreezeTaskListReorderingSet());
+
+        // Relaunch a few tasks
+        mRecentTasks.add(mTasks.get(2));
+        mRecentTasks.add(mTasks.get(1));
+
+        // Override the freeze timeout params to simulate the timeout (simulate the freeze at 100ms
+        // ago with a timeout of 1ms)
+        mRecentTasks.setFreezeTaskListTimeoutParams(freezeTime - 100, 1);
+
+        ActivityStack stack = mTasks.get(2).getStack();
+        stack.moveToFront("", mTasks.get(2));
+        doReturn(stack).when(mTestService.mRootActivityContainer).getTopDisplayFocusedStack();
+        mRecentTasks.resetFreezeTaskListReorderingOnTimeout();
+        assertFalse(mRecentTasks.isFreezeTaskListReorderingSet());
+
+        // Ensure that the order of the task list is the same as before, but with the focused task
+        // at the front
+        assertRecentTasksOrder(mTasks.get(2),
+                mTasks.get(4),
+                mTasks.get(3),
+                mTasks.get(1),
+                mTasks.get(0));
+    }
+
+    @Test
     public void testBackStackTasks_expectNoTrim() {
         mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
 
@@ -721,6 +829,18 @@
                         true /* showRecents */));
     }
 
+    /**
+     * Ensures that the recent tasks list is in the provided order. Note that the expected tasks
+     * should be ordered from least to most recent.
+     */
+    private void assertRecentTasksOrder(TaskRecord... expectedTasks) {
+        ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks();
+        assertTrue(expectedTasks.length == tasks.size());
+        for (int i = 0; i < tasks.size(); i++)  {
+            assertTrue(expectedTasks[i] == tasks.get(i));
+        }
+    }
+
     private void assertNotRestoreTask(Runnable action) {
         // Verify stack count doesn't change because task with fullscreen mode and standard type
         // would have its own stack.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index b140da5..b9e9909 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -100,6 +100,7 @@
     }
 
     @Test
+    @Presubmit
     public void testTaskDescriptionChanged() throws Exception {
         final Object[] params = new Object[2];
         final CountDownLatch latch = new CountDownLatch(1);
@@ -132,6 +133,7 @@
     }
 
     @Test
+    @Presubmit
     public void testActivityRequestedOrientationChanged() throws Exception {
         final int[] params = new int[2];
         final CountDownLatch latch = new CountDownLatch(1);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 2ccdb9e..78fca0f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -19,6 +19,7 @@
 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_SPLIT_SCREEN_SECONDARY;
 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
 import static android.view.DisplayCutout.fromBoundingRect;
 import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
@@ -27,7 +28,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 
-import android.app.ActivityManager.TaskDescription;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
@@ -54,23 +54,15 @@
 @Presubmit
 public class WindowFrameTests extends WindowTestsBase {
 
-    private WindowToken mWindowToken;
     private final IWindow mIWindow = new TestIWindow();
     private final Rect mEmptyRect = new Rect();
 
-    static class WindowStateWithTask extends WindowState {
-        final Task mTask;
+    static class FrameTestWindowState extends WindowState {
         boolean mDockedResizingForTest = false;
-        WindowStateWithTask(WindowManagerService wm, IWindow iWindow, WindowToken windowToken,
-                WindowManager.LayoutParams attrs, Task t) {
+        FrameTestWindowState(WindowManagerService wm, IWindow iWindow, WindowToken windowToken,
+                WindowManager.LayoutParams attrs) {
             super(wm, mock(Session.class), iWindow, windowToken, null, 0, 0, attrs, 0, 0,
                     false /* ownerCanAddInternalSystemWindow */);
-            mTask = t;
-        }
-
-        @Override
-        Task getTask() {
-            return mTask;
         }
 
         @Override
@@ -79,52 +71,10 @@
         }
     }
 
-    private static class TaskWithBounds extends Task {
-        Rect mBounds;
-        final Rect mOverrideDisplayedBounds = new Rect();
-        boolean mFullscreenForTest = true;
-
-        TaskWithBounds(TaskStack stack, WindowManagerService wm, Rect bounds) {
-            super(0, stack, 0, wm, 0, false, new TaskDescription(), null);
-            setBounds(bounds);
-        }
-
-        @Override
-        public int setBounds(Rect bounds) {
-            mBounds = bounds;
-            return super.setBounds(bounds);
-        }
-
-        @Override
-        public Rect getBounds() {
-            return mBounds;
-        }
-
-        @Override
-        public void getBounds(Rect out) {
-            out.set(mBounds);
-        }
-
-        @Override
-        public void getRequestedOverrideBounds(Rect outBounds) {
-            outBounds.set(mBounds);
-        }
-        @Override
-        Rect getOverrideDisplayedBounds() {
-            return mOverrideDisplayedBounds;
-        }
-        @Override
-        boolean isFullscreen() {
-            return mFullscreenForTest;
-        }
-    }
-
     TaskStack mStubStack;
 
     @Before
     public void setUp() throws Exception {
-        mWindowToken = createAppWindowToken(mWm.getDefaultDisplayContentLocked(),
-                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
         mStubStack = mock(TaskStack.class);
     }
 
@@ -168,7 +118,8 @@
                 expectedRect.bottom);
     }
 
-    private void assertPolicyCrop(WindowStateWithTask w, int left, int top, int right, int bottom) {
+    private void assertPolicyCrop(
+            FrameTestWindowState w, int left, int top, int right, int bottom) {
         Rect policyCrop = new Rect();
         w.calculatePolicyCrop(policyCrop);
         assertRect(policyCrop, left, top, right, bottom);
@@ -177,8 +128,7 @@
     @Test
     public void testLayoutInFullscreenTaskInsets() {
         // fullscreen task doesn't use bounds for computeFrame
-        final Task task = new TaskWithBounds(mStubStack, mWm, null);
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final int bottomContentInset = 100;
@@ -235,8 +185,7 @@
     @Test
     public void testLayoutInFullscreenTaskNoInsets() {
         // fullscreen task doesn't use bounds for computeFrame
-        final Task task = new TaskWithBounds(mStubStack, mWm, null);
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         // With no insets or system decor all the frames incoming from PhoneWindowManager
@@ -323,9 +272,11 @@
         final int taskRight = logicalWidth / 4 * 3;
         final int taskBottom = logicalHeight / 4 * 3;
         final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
-        final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm, taskBounds);
-        task.mFullscreenForTest = false;
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        final Task task = w.getTask();
+        // Use split-screen because it is non-fullscreen, but also not floating
+        task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+        task.setBounds(taskBounds);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
@@ -359,8 +310,8 @@
         final int insetTop = logicalHeight / 5;
         final int insetRight = insetLeft + (taskRight - taskLeft);
         final int insetBottom = insetTop + (taskBottom - taskTop);
-        task.mOverrideDisplayedBounds.set(taskBounds);
-        task.mBounds.set(insetLeft, insetTop, insetRight, insetBottom);
+        task.setOverrideDisplayedBounds(taskBounds);
+        task.setBounds(insetLeft, insetTop, insetRight, insetBottom);
         windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
         w.computeFrameLw();
         assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
@@ -373,8 +324,7 @@
 
     @Test
     public void testCalculatePolicyCrop() {
-        final WindowStateWithTask w = createWindow(
-                new TaskWithBounds(mStubStack, mWm, null), MATCH_PARENT, MATCH_PARENT);
+        final FrameTestWindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
@@ -439,9 +389,11 @@
         final int taskRight = logicalWidth / 4 * 3;
         final int taskBottom = logicalHeight / 4 * 3;
         final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
-        final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm, taskBounds);
-        task.mFullscreenForTest = false;
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        final Task task = w.getTask();
+        // Use split-screen because it is non-fullscreen, but also not floating
+        task.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+        task.setBounds(taskBounds);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
@@ -461,7 +413,8 @@
         config.windowConfiguration.setBounds(cf);
         w.mAppToken.onRequestedOverrideConfigurationChanged(config);
         pf.set(0, 0, logicalWidth, logicalHeight);
-        task.mFullscreenForTest = true;
+        task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        task.setBounds(null);
         windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
         w.computeFrameLw();
         assertFrame(w, cf.left, cf.top, cf.right, cf.bottom);
@@ -472,8 +425,7 @@
     @Test
     public void testDisplayCutout() {
         // Regular fullscreen task and window
-        final Task task = new TaskWithBounds(mStubStack, mWm, null);
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, 0, 1000, 2000);
@@ -496,11 +448,10 @@
     @Test
     public void testDisplayCutout_tempDisplayedBounds() {
         // Regular fullscreen task and window
-        final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm,
-                new Rect(0, 0, 1000, 2000));
-        task.mFullscreenForTest = false;
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        final Task task = w.getTask();
+        task.setBounds(new Rect(0, 0, 1000, 2000));
         task.setOverrideDisplayedBounds(new Rect(0, -500, 1000, 1500));
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
 
         final Rect pf = new Rect(0, -500, 1000, 1500);
@@ -523,12 +474,10 @@
     @Test
     public void testFreeformContentInsets() {
         // fullscreen task doesn't use bounds for computeFrame
-        final Task task = new TaskWithBounds(mStubStack, mWm, null);
-        WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
+        WindowState w = createWindow(MATCH_PARENT, MATCH_PARENT);
+        final Task task = w.getTask();
         w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
         task.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        ((TaskWithBounds) task).mFullscreenForTest = false;
-        w.setWindowingMode(WINDOWING_MODE_FREEFORM);
 
         DisplayContent dc = mWm.getDefaultDisplayContentLocked();
         dc.mInputMethodTarget = w;
@@ -551,7 +500,6 @@
         final Rect winRect = new Rect(200, 200, 300, 500);
 
         task.setBounds(winRect);
-        w.setBounds(winRect);
         w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
         w.computeFrameLw();
 
@@ -580,11 +528,16 @@
         assertEquals(winRect, w.getFrameLw());
     }
 
-    private WindowStateWithTask createWindow(Task task, int width, int height) {
+    private FrameTestWindowState createWindow(int width, int height) {
         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
         attrs.width = width;
         attrs.height = height;
 
-        return new WindowStateWithTask(mWm, mIWindow, mWindowToken, attrs, task);
+        AppWindowToken token = createAppWindowToken(mWm.getDefaultDisplayContentLocked(),
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+
+        FrameTestWindowState ws = new FrameTestWindowState(mWm, mIWindow, token, attrs);
+        token.addWindow(ws);
+        return ws;
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 0dec8ee..a7a785d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -56,24 +56,15 @@
 
     static TestAppWindowToken createTestAppWindowToken(DisplayContent dc) {
         synchronized (dc.mWmService.mGlobalLock) {
-            return new TestAppWindowToken(dc, true /* skipOnParentChanged */);
-        }
-    }
-
-    static TestAppWindowToken createTestAppWindowToken(DisplayContent dc,
-            boolean skipOnParentChanged) {
-        synchronized (dc.mWmService.mGlobalLock) {
-            return new TestAppWindowToken(dc, skipOnParentChanged);
+            return new TestAppWindowToken(dc);
         }
     }
 
     /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
     static class TestAppWindowToken extends AppWindowToken {
         boolean mOnTop = false;
-        private boolean mSkipPrepareSurfaces;
-        boolean mSkipOnParentChanged = true;
 
-        private TestAppWindowToken(DisplayContent dc, boolean skipOnParentChanged) {
+        private TestAppWindowToken(DisplayContent dc) {
             super(dc.mWmService, new IApplicationToken.Stub() {
                 @Override
                 public String getName() {
@@ -81,7 +72,6 @@
                 }
             }, new ComponentName("", ""), false, dc, true /* fillsParent */);
             mTargetSdk = Build.VERSION_CODES.CUR_DEVELOPMENT;
-            mSkipOnParentChanged = skipOnParentChanged;
             mActivityRecord = mock(ActivityRecord.class);
             mActivityRecord.app = mock(WindowProcessController.class);
         }
@@ -103,44 +93,10 @@
         }
 
         @Override
-        void onParentChanged() {
-            if (!mSkipOnParentChanged) {
-                super.onParentChanged();
-            } else {
-                updateConfigurationFromParent(this);
-            }
-        }
-
-        @Override
         boolean isOnTop() {
             return mOnTop;
         }
 
-        @Override
-        void prepareSurfaces() {
-            if (!mSkipPrepareSurfaces) {
-                super.prepareSurfaces();
-            }
-        }
-
-        void setSkipPrepareSurfaces(boolean ignore) {
-            mSkipPrepareSurfaces = ignore;
-        }
-    }
-
-    /**
-     * Used when we don't want to perform surface related operation in
-     * {@link WindowContainer#onParentChanged} or the overridden method, but the configuration
-     * still needs to propagate from parent.
-     *
-     * @see ConfigurationContainer#onParentChanged
-     */
-    static void updateConfigurationFromParent(WindowContainer container) {
-        final WindowContainer parent = container.getParent();
-        if (parent != null) {
-            container.onConfigurationChanged(parent.getConfiguration());
-            container.onMergedOverrideConfigurationChanged();
-        }
     }
 
     static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
@@ -246,10 +202,5 @@
 
             mHasSurface = hadSurface;
         }
-
-        @Override
-        void onParentChanged() {
-            updateConfigurationFromParent(this);
-        }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 032eba1..8c37ca5e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -229,10 +229,11 @@
         } catch (Exception e) {
             Log.e(TAG, "Failed to tear down test", e);
             throw e;
+        } finally {
+            mMockTracker.close();
+            mMockTracker = null;
         }
 
-        mMockTracker.close();
-        mMockTracker = null;
     }
 
     private WindowState createCommonWindow(WindowState parent, int type, String name) {
@@ -269,16 +270,10 @@
 
     WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
             windowingMode, int activityType) {
-        return createTestAppWindowToken(dc, windowingMode, activityType,
-                false /*skipOnParentChanged */);
-    }
-
-    WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
-            windowingMode, int activityType, boolean skipOnParentChanged) {
         final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
         final Task task = createTaskInStack(stack, 0 /* userId */);
         final WindowTestUtils.TestAppWindowToken appWindowToken =
-                WindowTestUtils.createTestAppWindowToken(dc, skipOnParentChanged);
+                WindowTestUtils.createTestAppWindowToken(dc);
         task.addChild(appWindowToken, 0);
         return appWindowToken;
     }
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index f3d6387..6861ad1 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -511,10 +511,10 @@
 
     class AppUsageLimitGroup extends UsageGroup {
         public AppUsageLimitGroup(UserData user, ObserverAppData observerApp, int observerId,
-                String[] observed, long timeLimitMs, long timeRemainingMs,
+                String[] observed, long timeLimitMs, long timeUsedMs,
                 PendingIntent limitReachedCallback) {
             super(user, observerApp, observerId, observed, timeLimitMs, limitReachedCallback);
-            mUsageTimeMs = timeLimitMs - timeRemainingMs;
+            mUsageTimeMs = timeUsedMs;
         }
 
         @Override
@@ -841,7 +841,7 @@
      * Existing app usage limit observer with the same observerId will be removed.
      */
     public void addAppUsageLimitObserver(int requestingUid, int observerId, String[] observed,
-            long timeLimit, long timeRemaining, PendingIntent callbackIntent,
+            long timeLimit, long timeUsed, PendingIntent callbackIntent,
             @UserIdInt int userId) {
         if (timeLimit < getMinTimeLimit()) {
             throw new IllegalArgumentException("Time limit must be >= " + getMinTimeLimit());
@@ -861,7 +861,7 @@
                         "Too many app usage observers added by uid " + requestingUid);
             }
             group = new AppUsageLimitGroup(user, observerApp, observerId, observed, timeLimit,
-                    timeRemaining, timeRemaining == 0L ? null : callbackIntent);
+                    timeUsed, timeUsed >= timeLimit ? null : callbackIntent);
             observerApp.appUsageLimitGroups.append(observerId, group);
 
             if (DEBUG) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 27fdbcb..1ec680f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1399,7 +1399,7 @@
 
         @Override
         public void registerAppUsageLimitObserver(int observerId, String[] packages,
-                long timeLimitMs, long timeRemainingMs, PendingIntent callbackIntent,
+                long timeLimitMs, long timeUsedMs, PendingIntent callbackIntent,
                 String callingPackage) {
             if (!hasPermissions(callingPackage,
                     Manifest.permission.SUSPEND_APPS, Manifest.permission.OBSERVE_APP_USAGE)) {
@@ -1410,11 +1410,7 @@
             if (packages == null || packages.length == 0) {
                 throw new IllegalArgumentException("Must specify at least one package");
             }
-            if (timeRemainingMs > timeLimitMs) {
-                throw new IllegalArgumentException(
-                        "Remaining time can't be greater than total time.");
-            }
-            if (callbackIntent == null && timeRemainingMs != 0L) {
+            if (callbackIntent == null && timeUsedMs < timeLimitMs) {
                 throw new NullPointerException("callbackIntent can't be null");
             }
             final int callingUid = Binder.getCallingUid();
@@ -1422,7 +1418,7 @@
             final long token = Binder.clearCallingIdentity();
             try {
                 UsageStatsService.this.registerAppUsageLimitObserver(callingUid, observerId,
-                        packages, timeLimitMs, timeRemainingMs, callbackIntent, userId);
+                        packages, timeLimitMs, timeUsedMs, callbackIntent, userId);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -1550,9 +1546,9 @@
     }
 
     void registerAppUsageLimitObserver(int callingUid, int observerId, String[] packages,
-            long timeLimitMs, long timeRemainingMs, PendingIntent callbackIntent, int userId) {
+            long timeLimitMs, long timeUsedMs, PendingIntent callbackIntent, int userId) {
         mAppTimeLimit.addAppUsageLimitObserver(callingUid, observerId, packages,
-                timeLimitMs, timeRemainingMs, callbackIntent, userId);
+                timeLimitMs, timeUsedMs, callbackIntent, userId);
     }
 
     void unregisterAppUsageLimitObserver(int callingUid, int observerId, int userId) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 61d7d6c..8d2cbca 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -357,7 +357,8 @@
         Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
         intent.setComponent(mComponent);
         mBound = mContext.bindServiceAsUser(intent, mConnection,
-                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, new UserHandle(mUser));
+                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+                | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, new UserHandle(mUser));
         if (!mBound) {
             Slog.w(TAG, "Failed binding to voice interaction service " + mComponent);
         }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 1bf0723..24690f5 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -159,7 +159,8 @@
         mBindIntent.setComponent(mSessionComponentName);
         mBound = mContext.bindServiceAsUser(mBindIntent, this,
                 Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY
-                        | Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser));
+                        | Context.BIND_ALLOW_OOM_MANAGEMENT
+                        | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, new UserHandle(mUser));
         if (mBound) {
             try {
                 mIWindowManager.addWindowToken(mToken, TYPE_VOICE_INTERACTION, DEFAULT_DISPLAY);
@@ -191,7 +192,8 @@
             if (!mFullyBound) {
                 mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
                         Context.BIND_AUTO_CREATE | Context.BIND_TREAT_LIKE_ACTIVITY
-                                | Context.BIND_FOREGROUND_SERVICE,
+                                | Context.BIND_FOREGROUND_SERVICE
+                                | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS,
                         new UserHandle(mUser));
             }
 
diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java
index 4e74395..6b9b83d 100644
--- a/telecomm/java/android/telecom/AudioState.java
+++ b/telecomm/java/android/telecom/AudioState.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -54,11 +55,11 @@
     private static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
             ROUTE_SPEAKER;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
     private final boolean isMuted;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
     private final int route;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
     private final int supportedRouteMask;
 
     public AudioState(boolean muted, int route, int supportedRouteMask) {
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index 3299117..d01c889 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -17,6 +17,7 @@
 package android.telecom;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.app.Service;
 import android.content.Intent;
@@ -62,16 +63,20 @@
     private ICallRedirectionAdapter mCallRedirectionAdapter;
 
     /**
-     * Telecom calls this method to inform the implemented {@link CallRedirectionService} of
-     * a new outgoing call which is being placed. Telecom does not request to redirect emergency
-     * calls and does not request to redirect calls with gateway information.
+     * Telecom calls this method once upon binding to a {@link CallRedirectionService} to inform
+     * it of a new outgoing call which is being placed. Telecom does not request to redirect
+     * emergency calls and does not request to redirect calls with gateway information.
      *
      * <p>Telecom will cancel the call if Telecom does not receive a response in 5 seconds from
      * the implemented {@link CallRedirectionService} set by users.
      *
      * <p>The implemented {@link CallRedirectionService} can call {@link #placeCallUnmodified()},
      * {@link #redirectCall(Uri, PhoneAccountHandle, boolean)}, and {@link #cancelCall()} only
-     * from here.
+     * from here. Calls to these methods are assumed by the Telecom framework to be the response
+     * for the phone call for which {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} was
+     * invoked by Telecom. The Telecom framework will only invoke
+     * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)} once each time it binds to a
+     * {@link CallRedirectionService}.
      *
      * @param handle the phone number dialed by the user, represented in E.164 format if possible
      * @param initialPhoneAccount the {@link PhoneAccountHandle} on which the call will be placed.
@@ -91,13 +96,15 @@
      * no changes are required to the outgoing call, and that the call should be placed as-is.
      *
      * <p>This can only be called from implemented
-     * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
+     * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. The response corresponds to the
+     * latest request via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
      *
      */
     public final void placeCallUnmodified() {
         try {
             mCallRedirectionAdapter.placeCallUnmodified();
         } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
         }
     }
 
@@ -109,7 +116,8 @@
      * replies Telecom a handle for an emergency number.
      *
      * <p>This can only be called from implemented
-     * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
+     * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. The response corresponds to the
+     * latest request via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
      *
      * @param handle the new phone number to dial
      * @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
@@ -126,6 +134,7 @@
         try {
             mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount, confirmFirst);
         } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
         }
     }
 
@@ -135,13 +144,15 @@
      * an outgoing call should be canceled entirely.
      *
      * <p>This can only be called from implemented
-     * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
+     * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. The response corresponds to the
+     * latest request via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
      *
      */
     public final void cancelCall() {
         try {
             mCallRedirectionAdapter.cancelCall();
         } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
         }
     }
 
@@ -196,12 +207,12 @@
     }
 
     @Override
-    public final IBinder onBind(Intent intent) {
+    public final @Nullable IBinder onBind(@NonNull Intent intent) {
         return new CallRedirectionBinder();
     }
 
     @Override
-    public final boolean onUnbind(Intent intent) {
+    public final boolean onUnbind(@NonNull Intent intent) {
         return false;
     }
 }
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index ae12a17..28e6596 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -555,6 +555,15 @@
     public static final String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
 
     /**
+     * Connection event used to inform Telecom when a hold operation on a call has failed.
+     * Not intended for use by the UI at this time.
+     * Sent via {@link #sendConnectionEvent(String, Bundle)}.  The {@link Bundle} parameter is
+     * expected to be null when this connection event is used.
+     * @hide
+     */
+    public static final String EVENT_CALL_HOLD_FAILED = "android.telecom.event.CALL_HOLD_FAILED";
+
+    /**
      * Connection event used to inform {@link InCallService}s when the process of merging a
      * Connection into a conference has begun.
      * <p>
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index d3ccd2c..0cc052e 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -19,6 +19,7 @@
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.bluetooth.BluetoothDevice;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.util.ArrayMap;
@@ -328,10 +329,12 @@
      * become active, and the touch screen and display will be turned off when the user's face
      * is detected to be in close proximity to the screen. This operation is a no-op on devices
      * that do not have a proximity sensor.
-     *
+     * <p>
+     * This API does not actually turn on the proximity sensor; apps should do this on their own if
+     * required.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
     public final void setProximitySensorOn() {
         mInCallAdapter.turnProximitySensorOn();
     }
@@ -344,10 +347,12 @@
      * @param screenOnImmediately If true, the screen will be turned on immediately if it was
      * previously off. Otherwise, the screen will only be turned on after the proximity sensor
      * is no longer triggered.
-     *
+     * <p>
+     * This API does not actually turn of the proximity sensor; apps should do this on their own if
+     * required.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
     public final void setProximitySensorOff(boolean screenOnImmediately) {
         mInCallAdapter.turnProximitySensorOff(screenOnImmediately);
     }
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index a84ce55..71a28b5 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -42,7 +42,7 @@
  * See {@link PhoneAccount}, {@link TelecomManager}.
  */
 public final class PhoneAccountHandle implements Parcelable {
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
     private final ComponentName mComponentName;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final String mId;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 52c5425..3d0a3c5 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1589,7 +1589,7 @@
                                 Build.VERSION_CODES.O_MR1) {
                     Log.e("TAG", "addNewIncomingCall failed. Use public api " +
                             "acceptHandover for API > O-MR1");
-                    // TODO add "return" after DUO team adds support for new handover API
+                    return;
                 }
                 getTelecomService().addNewIncomingCall(
                         phoneAccount, extras == null ? new Bundle() : extras);
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index 2c7fecb..cb74012 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -18,6 +18,7 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -218,7 +219,7 @@
         mTargetSdkVersion = sdkVersion;
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
     public void destroy() {
         unregisterCallback(mCallback);
     }
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 75165af..81553a3 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -16,13 +16,59 @@
 
 package android.telephony;
 
+import android.annotation.IntDef;
 import android.annotation.SystemApi;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Contains access network related constants.
  */
 public final class AccessNetworkConstants {
 
+    /**
+     * Wireless transportation type
+     *
+     * @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"TRANSPORT_TYPE_"},
+            value = {
+                    TRANSPORT_TYPE_INVALID,
+                    TRANSPORT_TYPE_WWAN,
+                    TRANSPORT_TYPE_WLAN})
+    public @interface TransportType {}
+
+    /**
+     * Invalid transport type
+     * @hide
+     */
+    @SystemApi
+    public static final int TRANSPORT_TYPE_INVALID = -1;
+
+    /**
+     * Transport type for Wireless Wide Area Networks (i.e. Cellular)
+     * @hide
+     */
+    @SystemApi
+    public static final int TRANSPORT_TYPE_WWAN = 1;
+
+    /**
+     * Transport type for Wireless Local Area Networks (i.e. Wifi)
+     * @hide
+     */
+    @SystemApi
+    public static final int TRANSPORT_TYPE_WLAN = 2;
+
+    /** @hide */
+    public static String transportTypeToString(@TransportType int transportType) {
+        switch (transportType) {
+            case TRANSPORT_TYPE_WWAN: return "WWAN";
+            case TRANSPORT_TYPE_WLAN: return "WLAN";
+            default: return Integer.toString(transportType);
+        }
+    }
+
     public static final class AccessNetworkType {
         public static final int UNKNOWN = 0;
         public static final int GERAN = 1;
@@ -49,39 +95,7 @@
     }
 
     /**
-     * Wireless transportation type
-     * @hide
-     */
-    @SystemApi
-    public static final class TransportType {
-        /**
-         * Invalid transport type.
-         * @hide
-         */
-        public static final int INVALID = -1;
-
-        /** Wireless Wide Area Networks (i.e. Cellular) */
-        public static final int WWAN = 1;
-
-        /** Wireless Local Area Networks (i.e. Wifi) */
-        public static final int WLAN = 2;
-
-        /** @hide */
-        private TransportType() {}
-
-        /** @hide */
-        public static String toString(int type) {
-            switch (type) {
-                case INVALID: return "INVALID";
-                case WWAN: return "WWAN";
-                case WLAN: return "WLAN";
-                default: return Integer.toString(type);
-            }
-        }
-    }
-
-    /**
-     * Frenquency bands for GERAN.
+     * Frequency bands for GERAN.
      * http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf
      */
     public static final class GeranBand {
diff --git a/telephony/java/android/telephony/DebugEventReporter.java b/telephony/java/android/telephony/AnomalyReporter.java
similarity index 82%
rename from telephony/java/android/telephony/DebugEventReporter.java
rename to telephony/java/android/telephony/AnomalyReporter.java
index 14b7dd6..9753d8b 100644
--- a/telephony/java/android/telephony/DebugEventReporter.java
+++ b/telephony/java/android/telephony/AnomalyReporter.java
@@ -29,7 +29,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.List;
-import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
@@ -37,7 +36,7 @@
 /**
  * A Simple Surface for Telephony to notify a loosely-coupled debugger of particular issues.
  *
- * DebugEventReporter allows an optional external logging component to receive events detected by
+ * AnomalyReporter allows an optional external logging component to receive events detected by
  * the framework and take action. This log surface is designed to provide maximium flexibility
  * to the receiver of these events. Envisioned use cases of this include notifying a vendor
  * component of: an event that necessitates (timely) log collection on non-AOSP components;
@@ -49,8 +48,8 @@
  *
  * @hide
  */
-public final class DebugEventReporter {
-    private static final String TAG = "DebugEventReporter";
+public final class AnomalyReporter {
+    private static final String TAG = "AnomalyReporter";
 
     private static Context sContext = null;
 
@@ -63,12 +62,12 @@
      */
     private static String sDebugPackageName = null;
 
-    private DebugEventReporter() {};
+    private AnomalyReporter() {};
 
     /**
      * If enabled, build and send an intent to a Debug Service for logging.
      *
-     * This method sends the {@link TelephonyManager#DEBUG_EVENT DEBUG_EVENT} broadcast, which is
+     * This method sends the {@link TelephonyManager#ACTION_ANOMALY_REPORTED} broadcast, which is
      * system protected. Invoking this method unless you are the system will result in an error.
      *
      * @param eventId a fixed event ID that will be sent for each instance of the same event. This
@@ -77,9 +76,9 @@
      *        identification and discussion of this event. This description should ideally be
      *        static and must not contain any sensitive information (especially PII).
      */
-    public static void sendEvent(@NonNull UUID eventId, String description) {
+    public static void reportAnomaly(@NonNull UUID eventId, String description) {
         if (sContext == null) {
-            Rlog.w(TAG, "DebugEventReporter not yet initialized, dropping event=" + eventId);
+            Rlog.w(TAG, "AnomalyReporter not yet initialized, dropping event=" + eventId);
             return;
         }
 
@@ -94,28 +93,28 @@
         // so drop these events silently.
         if (sDebugPackageName == null) return;
 
-        Intent dbgIntent = new Intent(TelephonyManager.ACTION_DEBUG_EVENT);
-        dbgIntent.putExtra(TelephonyManager.EXTRA_DEBUG_EVENT_ID, new ParcelUuid(eventId));
+        Intent dbgIntent = new Intent(TelephonyManager.ACTION_ANOMALY_REPORTED);
+        dbgIntent.putExtra(TelephonyManager.EXTRA_ANOMALY_ID, new ParcelUuid(eventId));
         if (description != null) {
-            dbgIntent.putExtra(TelephonyManager.EXTRA_DEBUG_EVENT_DESCRIPTION, description);
+            dbgIntent.putExtra(TelephonyManager.EXTRA_ANOMALY_DESCRIPTION, description);
         }
         dbgIntent.setPackage(sDebugPackageName);
         sContext.sendBroadcast(dbgIntent, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
     }
 
     /**
-     * Initialize the DebugEventReporter with the current context.
+     * Initialize the AnomalyReporter with the current context.
      *
-     * This method must be invoked before any calls to sendEvent() will succeed. This method should
-     * only be invoked at most once.
+     * This method must be invoked before any calls to reportAnomaly() will succeed. This method
+     * should only be invoked at most once.
      *
-     * @param context a Context object used to initialize this singleton DebugEventReporter in
+     * @param context a Context object used to initialize this singleton AnomalyReporter in
      *        the current process.
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public static void initialize(@NonNull Context context) {
         if (context == null) {
-            throw new IllegalArgumentException("DebugEventReporter needs a non-null context.");
+            throw new IllegalArgumentException("AnomalyReporter needs a non-null context.");
         }
 
         // Ensure that this context has sufficient permissions to send debug events.
@@ -129,13 +128,13 @@
         PackageManager pm = sContext.getPackageManager();
         if (pm == null) return;
         List<ResolveInfo> packages = pm.queryBroadcastReceivers(
-                new Intent(TelephonyManager.ACTION_DEBUG_EVENT),
+                new Intent(TelephonyManager.ACTION_ANOMALY_REPORTED),
                 PackageManager.MATCH_SYSTEM_ONLY
                         | PackageManager.MATCH_DIRECT_BOOT_AWARE
                         | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
         if (packages == null || packages.isEmpty()) return;
         if (packages.size() > 1) {
-            Rlog.e(TAG, "Multiple DebugEvent Receivers installed.");
+            Rlog.e(TAG, "Multiple Anomaly Receivers installed.");
         }
 
         for (ResolveInfo r : packages) {
@@ -156,14 +155,14 @@
         // Initialization may only be performed once.
     }
 
-    /** Dump the contents of the DebugEventReporter */
+    /** Dump the contents of the AnomalyReporter */
     public static void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
         if (sContext == null) return;
         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
         sContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Requires DUMP");
         pw.println("Initialized=" + (sContext != null ? "Yes" : "No"));
         pw.println("Debug Package=" + sDebugPackageName);
-        pw.println("Event Counts:");
+        pw.println("Anomaly Counts:");
         pw.increaseIndent();
         for (UUID event : sEvents.keySet()) {
             pw.println(event + ": " + sEvents.get(event));
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 6c835dc..e5aadad 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -86,7 +86,7 @@
         }
 
         if ((mMccStr != null && mMncStr == null) || (mMccStr == null && mMncStr != null)) {
-            DebugEventReporter.sendEvent(
+            AnomalyReporter.reportAnomaly(
                     UUID.fromString("a3ab0b9d-f2aa-4baf-911d-7096c0d4645a"),
                     "CellIdentity Missing Half of PLMN ID");
         }
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 5a89ae8..4be52a3 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -16,13 +16,15 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.telephony.gsm.GsmCellLocation;
 
 import java.util.Objects;
 
 /**
- * Information to represent a unique 5G NR cell.
+ * Information to represent a unique NR(New Radio 5G) cell.
  */
 public final class CellIdentityNr extends CellIdentity {
     private static final String TAG = "CellIdentityNr";
@@ -79,7 +81,7 @@
     }
 
     /**
-     * Get the NR Cell Identity.
+     * Get the NR(New Radio 5G) Cell Identity.
      *
      * @return The 36-bit NR Cell Identity in range [0, 68719476735] or
      *         {@link CellInfo#UNAVAILABLE_LONG} if unknown.
@@ -96,6 +98,7 @@
      *
      * @return Integer value in range [0, 3279165] or {@link CellInfo#UNAVAILABLE} if unknown.
      */
+    @IntRange(from = 0, to = 3279165)
     public int getNrarfcn() {
         return mNrArfcn;
     }
@@ -104,6 +107,7 @@
      * Get the physical cell id.
      * @return Integer value in range [0, 1007] or {@link CellInfo#UNAVAILABLE} if unknown.
      */
+    @IntRange(from = 0, to = 1007)
     public int getPci() {
         return mPci;
     }
@@ -112,6 +116,7 @@
      * Get the tracking area code.
      * @return a 16 bit integer or {@link CellInfo#UNAVAILABLE} if unknown.
      */
+    @IntRange(from = 0, to = 65535)
     public int getTac() {
         return mTac;
     }
@@ -119,6 +124,7 @@
     /**
      * @return Mobile Country Code in string format, or {@code null} if unknown.
      */
+    @Nullable
     public String getMccString() {
         return mMccStr;
     }
@@ -126,6 +132,7 @@
     /**
      * @return Mobile Network Code in string fomrat, or {@code null} if unknown.
      */
+    @Nullable
     public String getMncString() {
         return mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
index fb147ce..0227610 100644
--- a/telephony/java/android/telephony/CellInfoNr.java
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 
 import java.util.Objects;
@@ -36,11 +37,13 @@
     }
 
     @Override
+    @NonNull
     public CellIdentity getCellIdentity() {
         return mCellIdentity;
     }
 
     @Override
+    @NonNull
     public CellSignalStrength getCellSignalStrength() {
         return mCellSignalStrength;
     }
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index ca264f7..f0a26f5 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -318,8 +318,8 @@
     public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 0x7FC;
     /** APN has been disabled. */
     public static final int APN_DISABLED = 0x7FD;
-    /** Maximum PPP inactivity timer expired. */
-    public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE;
+    /** PPP inactivity timer expired. */
+    public static final int PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE;
     /** IPv6 address transfer failed. */
     public static final int IPV6_ADDRESS_TRANSFER_FAILED = 0x7FF;
     /** Target RAT swap failed. */
@@ -339,12 +339,12 @@
      * IPv4 data call bring up is rejected because the UE already maintains the allotted maximum
      * number of IPv4 data connections.
      */
-    public static final int MAX_IPV4_CONNECTIONS = 0x804;
+    public static final int IPV4_CONNECTIONS_LIMIT_REACHED = 0x804;
     /**
      * IPv6 data call bring up is rejected because the UE already maintains the allotted maximum
      * number of IPv6 data connections.
      */
-    public static final int MAX_IPV6_CONNECTIONS = 0x805;
+    public static final int IPV6_CONNECTIONS_LIMIT_REACHED = 0x805;
     /**
      * New PDN bring up is rejected during interface selection because the UE has already allotted
      * the available interfaces for other PDNs.
@@ -416,7 +416,7 @@
      */
     public static final int CHANNEL_ACQUISITION_FAILURE = 0x81E;
     /** Maximum access probes transmitted. */
-    public static final int MAX_ACCESS_PROBE = 0x81F;
+    public static final int ACCESS_PROBE_LIMIT_REACHED = 0x81F;
     /** Concurrent service is not supported by base station. */
     public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 0x820;
     /** There was no response received from the base station. */
@@ -1079,14 +1079,14 @@
             SIM_CARD_CHANGED,
             LOW_POWER_MODE_OR_POWERING_DOWN,
             APN_DISABLED,
-            MAX_PPP_INACTIVITY_TIMER_EXPIRED,
+            PPP_INACTIVITY_TIMER_EXPIRED,
             IPV6_ADDRESS_TRANSFER_FAILED,
             TRAT_SWAP_FAILED,
             EHRPD_TO_HRPD_FALLBACK,
             MIP_CONFIG_FAILURE,
             PDN_INACTIVITY_TIMER_EXPIRED,
-            MAX_IPV4_CONNECTIONS,
-            MAX_IPV6_CONNECTIONS,
+            IPV4_CONNECTIONS_LIMIT_REACHED,
+            IPV6_CONNECTIONS_LIMIT_REACHED,
             APN_MISMATCH,
             IP_VERSION_MISMATCH,
             DUN_CALL_DISALLOWED,
@@ -1112,7 +1112,7 @@
             CDMA_INCOMING_CALL,
             CDMA_ALERT_STOP,
             CHANNEL_ACQUISITION_FAILURE,
-            MAX_ACCESS_PROBE,
+            ACCESS_PROBE_LIMIT_REACHED,
             CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
             NO_RESPONSE_FROM_BASE_STATION,
             REJECTED_BY_BASE_STATION,
@@ -1447,14 +1447,14 @@
         sFailCauseMap.put(SIM_CARD_CHANGED, "SIM_CARD_CHANGED");
         sFailCauseMap.put(LOW_POWER_MODE_OR_POWERING_DOWN, "LOW_POWER_MODE_OR_POWERING_DOWN");
         sFailCauseMap.put(APN_DISABLED, "APN_DISABLED");
-        sFailCauseMap.put(MAX_PPP_INACTIVITY_TIMER_EXPIRED, "MAX_PPP_INACTIVITY_TIMER_EXPIRED");
+        sFailCauseMap.put(PPP_INACTIVITY_TIMER_EXPIRED, "PPP_INACTIVITY_TIMER_EXPIRED");
         sFailCauseMap.put(IPV6_ADDRESS_TRANSFER_FAILED, "IPV6_ADDRESS_TRANSFER_FAILED");
         sFailCauseMap.put(TRAT_SWAP_FAILED, "TRAT_SWAP_FAILED");
         sFailCauseMap.put(EHRPD_TO_HRPD_FALLBACK, "EHRPD_TO_HRPD_FALLBACK");
         sFailCauseMap.put(MIP_CONFIG_FAILURE, "MIP_CONFIG_FAILURE");
         sFailCauseMap.put(PDN_INACTIVITY_TIMER_EXPIRED, "PDN_INACTIVITY_TIMER_EXPIRED");
-        sFailCauseMap.put(MAX_IPV4_CONNECTIONS, "MAX_IPV4_CONNECTIONS");
-        sFailCauseMap.put(MAX_IPV6_CONNECTIONS, "MAX_IPV6_CONNECTIONS");
+        sFailCauseMap.put(IPV4_CONNECTIONS_LIMIT_REACHED, "IPV4_CONNECTIONS_LIMIT_REACHED");
+        sFailCauseMap.put(IPV6_CONNECTIONS_LIMIT_REACHED, "IPV6_CONNECTIONS_LIMIT_REACHED");
         sFailCauseMap.put(APN_MISMATCH, "APN_MISMATCH");
         sFailCauseMap.put(IP_VERSION_MISMATCH, "IP_VERSION_MISMATCH");
         sFailCauseMap.put(DUN_CALL_DISALLOWED, "DUN_CALL_DISALLOWED");
@@ -1480,7 +1480,7 @@
         sFailCauseMap.put(CDMA_INCOMING_CALL, "CDMA_INCOMING_CALL");
         sFailCauseMap.put(CDMA_ALERT_STOP, "CDMA_ALERT_STOP");
         sFailCauseMap.put(CHANNEL_ACQUISITION_FAILURE, "CHANNEL_ACQUISITION_FAILURE");
-        sFailCauseMap.put(MAX_ACCESS_PROBE, "MAX_ACCESS_PROBE");
+        sFailCauseMap.put(ACCESS_PROBE_LIMIT_REACHED, "ACCESS_PROBE_LIMIT_REACHED");
         sFailCauseMap.put(CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
                 "CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION");
         sFailCauseMap.put(NO_RESPONSE_FROM_BASE_STATION, "NO_RESPONSE_FROM_BASE_STATION");
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java
index a6c81db..eff3285 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -129,7 +129,6 @@
     @Domain
     private final int mDomain;
 
-    /** {@link TransportType} */
     private final int mTransportType;
 
     @RegState
@@ -165,14 +164,15 @@
     private DataSpecificRegistrationStates mDataSpecificStates;
 
     /**
-     * @param domain Network domain. Must be a {@link Domain}. For {@link TransportType#WLAN}
-     * transport, this must set to {@link #DOMAIN_PS}.
-     * @param transportType Transport type. Must be one of the{@link TransportType}.
+     * @param domain Network domain. Must be a {@link Domain}. For transport type
+     * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, this must set to {@link #DOMAIN_PS}.
+     * @param transportType Transport type.
      * @param regState Network registration state. Must be one of the {@link RegState}. For
-     * {@link TransportType#WLAN} transport, only {@link #REG_STATE_HOME} and
-     * {@link #REG_STATE_NOT_REG_NOT_SEARCHING} are valid states.
-     * @param accessNetworkTechnology Access network technology.For {@link TransportType#WLAN}
-     * transport, set to {@link TelephonyManager#NETWORK_TYPE_IWLAN}.
+     * transport type {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, only
+     * {@link #REG_STATE_HOME} and {@link #REG_STATE_NOT_REG_NOT_SEARCHING} are valid states.
+     * @param accessNetworkTechnology Access network technology.For transport type
+     * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, set to
+     * {@link TelephonyManager#NETWORK_TYPE_IWLAN}.
      * @param rejectCause Reason for denial if the registration state is {@link #REG_STATE_DENIED}.
      * Depending on {@code accessNetworkTechnology}, the values are defined in 3GPP TS 24.008
      * 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 A.S0001 6.2.2.44 for CDMA. If
@@ -184,7 +184,8 @@
      * @param cellIdentity The identity representing a unique cell or wifi AP. Set to null if the
      * information is not available.
      */
-    public NetworkRegistrationState(@Domain int domain, int transportType, @RegState int regState,
+    public NetworkRegistrationState(@Domain int domain, @TransportType int transportType,
+                                    @RegState int regState,
                                     @NetworkType int accessNetworkTechnology, int rejectCause,
                                     boolean emergencyOnly,
                                     @NonNull @ServiceType int[] availableServices,
@@ -206,7 +207,7 @@
      * Constructor for voice network registration states.
      * @hide
      */
-    public NetworkRegistrationState(int domain, int transportType, int regState,
+    public NetworkRegistrationState(int domain, @TransportType int transportType, int regState,
             int accessNetworkTechnology, int rejectCause, boolean emergencyOnly,
             int[] availableServices, @Nullable CellIdentity cellIdentity, boolean cssSupported,
             int roamingIndicator, int systemIsInPrl, int defaultRoamingIndicator) {
@@ -221,7 +222,7 @@
      * Constructor for data network registration states.
      * @hide
      */
-    public NetworkRegistrationState(int domain, int transportType, int regState,
+    public NetworkRegistrationState(int domain, @TransportType int transportType, int regState,
             int accessNetworkTechnology, int rejectCause, boolean emergencyOnly,
             int[] availableServices, @Nullable CellIdentity cellIdentity, int maxDataCalls,
             boolean isDcNrRestricted, boolean isNrAvailable, boolean isEndcAvailable,
@@ -434,7 +435,8 @@
     public String toString() {
         return new StringBuilder("NetworkRegistrationState{")
                 .append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS")
-                .append(" transportType=").append(TransportType.toString(mTransportType))
+                .append(" transportType=").append(
+                        AccessNetworkConstants.transportTypeToString(mTransportType))
                 .append(" regState=").append(regStateToString(mRegState))
                 .append(" roamingType=").append(ServiceState.roamingTypeToString(mRoamingType))
                 .append(" accessNetworkTechnology=")
@@ -627,7 +629,7 @@
          *
          * @return The same instance of the builder.
          */
-        public @NonNull Builder setTransportType(int transportType) {
+        public @NonNull Builder setTransportType(@TransportType int transportType) {
             mTransportType = transportType;
             return this;
         }
diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java
index 48c07e8..28f6515 100644
--- a/telephony/java/android/telephony/RadioAccessFamily.java
+++ b/telephony/java/android/telephony/RadioAccessFamily.java
@@ -397,81 +397,4 @@
         }
         return result;
     }
-
-    /**
-     * convert RAF from {@link android.hardware.radio.V1_0.RadioAccessFamily} to
-     * {@link TelephonyManager.NetworkTypeBitMask}, the bitmask represented by
-     * {@link TelephonyManager.NetworkType}.
-     *
-     * @param raf {@link android.hardware.radio.V1_0.RadioAccessFamily}
-     * @return {@link TelephonyManager.NetworkTypeBitMask}
-     */
-    public static int convertToNetworkTypeBitMask(int raf) {
-        int networkTypeRaf = 0;
-
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.GSM) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_GSM;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.GPRS) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_GPRS;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.EDGE) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_EDGE;
-        }
-        // convert both IS95A/IS95B to CDMA as network mode doesn't support CDMA
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.IS95A) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_CDMA;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.IS95B) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_CDMA;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.ONE_X_RTT) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.EVDO_0) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_0;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.EVDO_A) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_A;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.EVDO_B) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_EVDO_B;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.EHRPD) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_EHRPD;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.HSUPA) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_HSUPA;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.HSDPA) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_HSDPA;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.HSPA) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_HSPA;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.HSPAP) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_HSPAP;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.UMTS) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_UMTS;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.TD_SCDMA) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_TD_SCDMA;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.LTE) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_LTE;
-        }
-        if ((raf & android.hardware.radio.V1_0.RadioAccessFamily.LTE_CA) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_LTE_CA;
-        }
-        if ((raf & android.hardware.radio.V1_4.RadioAccessFamily.NR) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_NR;
-        }
-        // TODO: need hal definition
-        if ((raf & (1 << ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) != 0) {
-            networkTypeRaf |= TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN;
-        }
-
-        return (networkTypeRaf == 0) ? TelephonyManager.NETWORK_TYPE_UNKNOWN : networkTypeRaf;
-    }
 }
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index bddf978..687c6f4 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -28,6 +28,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.NetworkRegistrationState.Domain;
 import android.telephony.NetworkRegistrationState.NRStatus;
 import android.text.TextUtils;
@@ -620,7 +621,7 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public @RoamingType int getVoiceRoamingType() {
         final NetworkRegistrationState regState = getNetworkRegistrationState(
-                NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+                NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState != null) {
             return regState.getRoamingType();
         }
@@ -644,7 +645,7 @@
      */
     public boolean getDataRoamingFromRegistration() {
         final NetworkRegistrationState regState = getNetworkRegistrationState(
-                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState != null) {
             return (regState.getRegState() == NetworkRegistrationState.REG_STATE_ROAMING);
         }
@@ -659,7 +660,7 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public @RoamingType int getDataRoamingType() {
         final NetworkRegistrationState regState = getNetworkRegistrationState(
-                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState != null) {
             return regState.getRoamingType();
         }
@@ -837,7 +838,7 @@
                 mVoiceRegState,
                 mDataRegState,
                 mChannelNumber,
-                mCellBandwidths,
+                Arrays.hashCode(mCellBandwidths),
                 mVoiceOperatorAlphaLong,
                 mVoiceOperatorAlphaShort,
                 mVoiceOperatorNumeric,
@@ -1130,10 +1131,10 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setVoiceRoamingType(@RoamingType int type) {
         NetworkRegistrationState regState = getNetworkRegistrationState(
-                NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+                NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState == null) {
             regState = new NetworkRegistrationState(
-                    NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN,
+                    NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                     ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
                     false, null, null);
             addNetworkRegistrationState(regState);
@@ -1151,10 +1152,10 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setDataRoamingType(@RoamingType int type) {
         NetworkRegistrationState regState = getNetworkRegistrationState(
-                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState == null) {
             regState = new NetworkRegistrationState(
-                    NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN,
+                    NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                     ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
                     false, null, null);
             addNetworkRegistrationState(regState);
@@ -1326,10 +1327,10 @@
 
         // sync to network registration state
         NetworkRegistrationState regState = getNetworkRegistrationState(
-                NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+                NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState == null) {
             regState = new NetworkRegistrationState(
-                    NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN,
+                    NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                     ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN,
                     0, false, null, null);
             addNetworkRegistrationState(regState);
@@ -1353,11 +1354,11 @@
 
         // sync to network registration state
         NetworkRegistrationState regState = getNetworkRegistrationState(
-                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
 
         if (regState == null) {
             regState = new NetworkRegistrationState(
-                    NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN,
+                    NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
                     ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN,
                     0, false, null, null);
             addNetworkRegistrationState(regState);
@@ -1391,7 +1392,7 @@
      */
     public @NRStatus int getNrStatus() {
         final NetworkRegistrationState regState = getNetworkRegistrationState(
-                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState == null) return NetworkRegistrationState.NR_STATUS_NONE;
         return regState.getNrStatus();
     }
@@ -1576,7 +1577,7 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public @TelephonyManager.NetworkType int getDataNetworkType() {
         final NetworkRegistrationState iwlanRegState = getNetworkRegistrationState(
-                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WLAN);
+                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
         if (iwlanRegState != null
                 && iwlanRegState.getRegState() == NetworkRegistrationState.REG_STATE_HOME) {
             // If the device is on IWLAN, return IWLAN as the network type. This is to simulate the
@@ -1587,7 +1588,7 @@
         }
 
         final NetworkRegistrationState regState = getNetworkRegistrationState(
-                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState != null) {
             return regState.getAccessNetworkTechnology();
         }
@@ -1598,7 +1599,7 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public @TelephonyManager.NetworkType int getVoiceNetworkType() {
         final NetworkRegistrationState regState = getNetworkRegistrationState(
-                NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+                NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState != null) {
             return regState.getAccessNetworkTechnology();
         }
@@ -1777,11 +1778,11 @@
     /**
      * Get the network registration states for the transport type.
      *
-     * @param transportType The {@link AccessNetworkConstants.TransportType transport type}
+     * @param transportType The transport type
      * @return List of {@link NetworkRegistrationState}
      * @hide
      *
-     * @deprecated Use {@link #getNetworkRegistrationStatesFromTransportType(int)}
+     * @deprecated Use {@link #getNetworkRegistrationStatesForTransportType(int)}
      */
     @NonNull
     @Deprecated
@@ -1793,14 +1794,14 @@
     /**
      * Get the network registration states for the transport type.
      *
-     * @param transportType The {@link AccessNetworkConstants.TransportType transport type}
+     * @param transportType The transport type
      * @return List of {@link NetworkRegistrationState}
      * @hide
      */
     @NonNull
     @SystemApi
     public List<NetworkRegistrationState> getNetworkRegistrationStatesForTransportType(
-            int transportType) {
+            @TransportType int transportType) {
         List<NetworkRegistrationState> list = new ArrayList<>();
 
         synchronized (mNetworkRegistrationStates) {
@@ -1842,7 +1843,7 @@
      * Get the network registration state for the transport type and network domain.
      *
      * @param domain The network {@link NetworkRegistrationState.Domain domain}
-     * @param transportType The {@link AccessNetworkConstants.TransportType transport type}
+     * @param transportType The transport type
      * @return The matching {@link NetworkRegistrationState}
      * @hide
      *
@@ -1852,7 +1853,7 @@
     @Deprecated
     @SystemApi
     public NetworkRegistrationState getNetworkRegistrationStates(@Domain int domain,
-                                                                 int transportType) {
+                                                                 @TransportType int transportType) {
         return getNetworkRegistrationState(domain, transportType);
     }
 
@@ -1860,7 +1861,7 @@
      * Get the network registration state for the transport type and network domain.
      *
      * @param domain The network {@link NetworkRegistrationState.Domain domain}
-     * @param transportType The {@link AccessNetworkConstants.TransportType transport type}
+     * @param transportType The transport type
      * @return The matching {@link NetworkRegistrationState}
      * @hide
      *
@@ -1868,7 +1869,7 @@
     @Nullable
     @SystemApi
     public NetworkRegistrationState getNetworkRegistrationState(@Domain int domain,
-                                                                int transportType) {
+                                                                @TransportType int transportType) {
         synchronized (mNetworkRegistrationStates) {
             for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
                 if (networkRegistrationState.getTransportType() == transportType
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index d9a37c6..3707aa4 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2009,21 +2009,27 @@
     }
 
     /**
-     * Checks if the supplied subscription ID is valid.
-     * Note: a valid subscription ID does not necessarily correspond to an active subscription.
+     * Check if the supplied subscription ID is valid.
+     *
+     * <p>A valid subscription ID is not necessarily an active subscription ID
+     * (see {@link #isActiveSubscriptionId(int)}) or an usable subscription ID
+     * (see {@link #isUsableSubscriptionId(int)}). Unless specifically noted, subscription
+     * APIs work with a valid subscription ID.
      *
      * @param subscriptionId The subscription ID.
-     * @return true if the supplied subscriptionId is valid; false otherwise.
+     * @return {@code true} if the supplied subscriptionId is valid; {@code false} otherwise.
      */
     public static boolean isValidSubscriptionId(int subscriptionId) {
         return subscriptionId > INVALID_SUBSCRIPTION_ID;
     }
 
     /**
-     * Check if the subscription ID is usable.
+     * Check if the supplied 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.
+     * <p>A usable subscription ID is a valid subscription ID, but not necessarily an active
+     * subscription ID (see {@link #isActiveSubscriptionId(int)}). Some subscription APIs
+     * require a usable subscription ID, and this is noted in their documentation; otherwise, a
+     * subscription ID does not need to be usable for subscription functions, only valid.
      *
      * @param subscriptionId the subscription ID
      * @return {@code true} if the subscription ID is usable; {@code false} otherwise.
@@ -2281,7 +2287,8 @@
     }
 
     /**
-     * Checks if the supplied subscription ID corresponds to an active subscription.
+     * Checks if the supplied subscription ID corresponds to a subscription which is actively in
+     * use on the device. An active subscription ID is a valid and usable subscription ID.
      *
      * @param subscriptionId the subscription ID.
      * @return {@code true} if the supplied subscription ID corresponds to an active subscription;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 16dafd6..f7ab921 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1383,41 +1383,42 @@
      * in the application manifest. For performance reasons, if no application to receive these
      * events is detected at boot, then these events will not be sent.
      *
-     * <p>Each event will include an {@link EXTRA_DEBUG_EVENT_ID} that will uniquely identify the
+     * <p>Each event will include an {@link EXTRA_ANOMALY_ID} that will uniquely identify the
      * event that has occurred. Each event will be sent to the diagnostic monitor only once per
      * boot cycle (as another optimization).
      *
-     * @see #EXTRA_DEBUG_EVENT_ID
-     * @see #EXTRA_DEBUG_EVENT_DESCRIPTION
+     * @see #EXTRA_ANOMALY_ID
+     * @see #EXTRA_ANOMALY_DESCRIPTION
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public static final String ACTION_DEBUG_EVENT = "android.telephony.action.DEBUG_EVENT";
+    public static final String ACTION_ANOMALY_REPORTED =
+            "android.telephony.action.ANOMALY_REPORTED";
 
     /**
      * An arbitrary ParcelUuid which should be consistent for each occurrence of a DebugEvent.
      *
-     * This field must be included in all {@link ACTION_DEBUG_EVENT} events.
+     * This field must be included in all {@link ACTION_ANOMALY_REPORTED} events.
      *
-     * @see #ACTION_DEBUG_EVENT
+     * @see #ACTION_ANOMALY_REPORTED
      * @hide
      */
     @SystemApi
-    public static final String EXTRA_DEBUG_EVENT_ID = "android.telephony.extra.DEBUG_EVENT_ID";
+    public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
 
     /**
-     * A freeform string description of the DebugEvent.
+     * A freeform string description of the Anomaly.
      *
-     * This field is optional for all {@link ACTION_DEBUG_EVENT}s, as a guideline should not
+     * This field is optional for all {@link ACTION_ANOMALY_REPORTED}s, as a guideline should not
      * exceed 80 characters, and should be as short as possible to convey the essence of the event.
      *
-     * @see #ACTION_DEBUG_EVENT
+     * @see #ACTION_ANOMALY_REPORTED
      * @hide
      */
     @SystemApi
-    public static final String EXTRA_DEBUG_EVENT_DESCRIPTION =
-            "android.telephony.extra.DEBUG_EVENT_DESCRIPTION";
+    public static final String EXTRA_ANOMALY_DESCRIPTION =
+            "android.telephony.extra.ANOMALY_DESCRIPTION";
 
     //
     //
@@ -3345,26 +3346,25 @@
     }
 
     /**
-     * Get the mapping from logical slots to physical slots. The mapping represent by a pair list.
-     * The key of the piar is the logical slot id and the value of the pair is the physical
-     * slots id mapped to this logical slot id.
+     * Get the mapping from logical slots to physical slots. The key of the map is the logical slot
+     * id and the value is the physical slots id mapped to this logical slot id.
      *
-     * @return an pair list indicates the mapping from logical slots to physical slots. The size of
-     * the list should be {@link #getPhoneCount()} if success, otherwise return an empty list.
+     * @return a map indicates the mapping from logical slots to physical slots. The size of the map
+     * should be {@link #getPhoneCount()} if success, otherwise return an empty map.
      *
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @NonNull
-    public List<Pair<Integer, Integer>> getLogicalToPhysicalSlotMapping() {
-        List<Pair<Integer, Integer>> slotMapping = new ArrayList<>();
+    public Map<Integer, Integer> getLogicalToPhysicalSlotMapping() {
+        Map<Integer, Integer> slotMapping = new HashMap<>();
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 int[] slotMappingArray = telephony.getSlotsMapping();
                 for (int i = 0; i < slotMappingArray.length; i++) {
-                    slotMapping.add(new Pair(i, slotMappingArray[i]));
+                    slotMapping.put(i, slotMappingArray[i]);
                 }
             }
         } catch (RemoteException e) {
@@ -5188,6 +5188,40 @@
     }
 
     /**
+     * Opens a logical channel to the ICC card using the physical slot index.
+     *
+     * Use this method when no subscriptions are available on the SIM and the operation must be
+     * performed using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CCHO command.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     *
+     * @param slotIndex the physical slot index of the ICC card
+     * @param aid Application id. See ETSI 102.221 and 101.220.
+     * @param p2 P2 parameter (described in ISO 7816-4).
+     * @return an IccOpenLogicalChannelResponse object.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @SystemApi
+    @Nullable
+    public IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int slotIndex,
+            @Nullable String aid, int p2) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.iccOpenLogicalChannelBySlot(slotIndex, getOpPackageName(), aid,
+                        p2);
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return null;
+    }
+
+    /**
      * Opens a logical channel to the ICC card.
      *
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
@@ -5231,6 +5265,38 @@
     }
 
     /**
+     * Closes a previously opened logical channel to the ICC card using the physical slot index.
+     *
+     * Use this method when no subscriptions are available on the SIM and the operation must be
+     * performed using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CCHC command.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     *
+     * @param slotIndex the physical slot index of the ICC card
+     * @param channel is the channel id to be closed as returned by a successful
+     *            iccOpenLogicalChannel.
+     * @return true if the channel was closed successfully.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @SystemApi
+    @Nullable
+    public boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.iccCloseLogicalChannelBySlot(slotIndex, channel);
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return false;
+    }
+
+    /**
      * Closes a previously opened logical channel to the ICC card.
      *
      * Input parameters equivalent to TS 27.007 AT+CCHC command.
@@ -5239,7 +5305,7 @@
      * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
      * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
-     * @param channel is the channel id to be closed as retruned by a successful
+     * @param channel is the channel id to be closed as returned by a successful
      *            iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      */
@@ -5257,7 +5323,7 @@
      * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
      * @param subId The subscription to use.
-     * @param channel is the channel id to be closed as retruned by a successful
+     * @param channel is the channel id to be closed as returned by a successful
      *            iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      * @hide
@@ -5274,6 +5340,48 @@
     }
 
     /**
+     * Transmit an APDU to the ICC card over a logical channel using the physical slot index.
+     *
+     * Use this method when no subscriptions are available on the SIM and the operation must be
+     * performed using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CGLA command.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     *
+     * @param slotIndex the physical slot index of the ICC card
+     * @param channel is the channel id to be closed as returned by a successful
+     *            iccOpenLogicalChannel.
+     * @param cla Class of the APDU command.
+     * @param instruction Instruction of the APDU command.
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+     *            is sent to the SIM.
+     * @param data Data to be sent with the APDU.
+     * @return The APDU response from the ICC card with the status appended at
+     *            the end.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @SystemApi
+    @Nullable
+    public String iccTransmitApduLogicalChannelBySlot(int slotIndex, int channel, int cla,
+            int instruction, int p1, int p2, int p3, @Nullable String data) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.iccTransmitApduLogicalChannelBySlot(slotIndex, channel, cla,
+                        instruction, p1, p2, p3, data);
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return null;
+    }
+
+    /**
      * Transmit an APDU to the ICC card over a logical channel.
      *
      * Input parameters equivalent to TS 27.007 AT+CGLA command.
@@ -5337,6 +5445,46 @@
     }
 
     /**
+     * Transmit an APDU to the ICC card over the basic channel using the physical slot index.
+     *
+     * Use this method when no subscriptions are available on the SIM and the operation must be
+     * performed using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CSIM command.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+     *
+     * @param slotIndex the physical slot index of the ICC card to target
+     * @param cla Class of the APDU command.
+     * @param instruction Instruction of the APDU command.
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+     *            is sent to the SIM.
+     * @param data Data to be sent with the APDU.
+     * @return The APDU response from the ICC card with the status appended at
+     *            the end.
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @SystemApi
+    @NonNull
+    public String iccTransmitApduBasicChannelBySlot(int slotIndex, int cla, int instruction, int p1,
+            int p2, int p3, @Nullable String data) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.iccTransmitApduBasicChannelBySlot(slotIndex, getOpPackageName(),
+                        cla, instruction, p1, p2, p3, data);
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return null;
+    }
+
+    /**
      * Transmit an APDU to the ICC card over the basic channel.
      *
      * Input parameters equivalent to TS 27.007 AT+CSIM command.
@@ -6003,7 +6151,7 @@
         // FIXME Need to get it from Telephony Dev Controller when that gets implemented!
         // and then this method shouldn't be used at all!
         if(isMultiSimEnabled()) {
-            return 2;
+            return getPhoneCount();
         } else {
             return 1;
         }
@@ -6625,14 +6773,12 @@
             }
         } catch (RemoteException ex) {
             Rlog.e(TAG, "getPreferredNetworkType RemoteException", ex);
-        } catch (NullPointerException ex) {
-            Rlog.e(TAG, "getPreferredNetworkType NPE", ex);
         }
         return -1;
     }
 
     /**
-     * Get the preferred network type bitmap.
+     * Get the preferred network type bitmask.
      *
      * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
      * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
@@ -6641,13 +6787,13 @@
      * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
      * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
-     * @return The bitmap of preferred network types.
+     * @return The bitmask of preferred network types.
      *
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @SystemApi
-    public @NetworkTypeBitMask long getPreferredNetworkTypeBitmap() {
+    public @NetworkTypeBitMask long getPreferredNetworkTypeBitmask() {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
@@ -6655,9 +6801,7 @@
                         telephony.getPreferredNetworkType(getSubId()));
             }
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "getPreferredNetworkTypeBitmap RemoteException", ex);
-        } catch (NullPointerException ex) {
-            Rlog.e(TAG, "getPreferredNetworkTypeBitmap NPE", ex);
+            Rlog.e(TAG, "getPreferredNetworkTypeBitmask RemoteException", ex);
         }
         return 0;
     }
@@ -6882,14 +7026,12 @@
             }
         } catch (RemoteException ex) {
             Rlog.e(TAG, "setPreferredNetworkType RemoteException", ex);
-        } catch (NullPointerException ex) {
-            Rlog.e(TAG, "setPreferredNetworkType NPE", ex);
         }
         return false;
     }
 
     /**
-     * Set the preferred network type bitmap.
+     * Set the preferred network type bitmask.
      *
      * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
      * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
@@ -6898,24 +7040,22 @@
      * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
      * app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
-     * @param networkTypeBitmap The bitmap of preferred network types.
+     * @param networkTypeBitmask The bitmask of preferred network types.
      * @return true on success; false on any failure.
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     @SystemApi
-    public boolean setPreferredNetworkTypeBitmap(@NetworkTypeBitMask long networkTypeBitmap) {
+    public boolean setPreferredNetworkTypeBitmask(@NetworkTypeBitMask long networkTypeBitmask) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 return telephony.setPreferredNetworkType(
                         getSubId(), RadioAccessFamily.getNetworkTypeFromRaf(
-                                (int) networkTypeBitmap));
+                                (int) networkTypeBitmask));
             }
         } catch (RemoteException ex) {
-            Rlog.e(TAG, "setPreferredNetworkType RemoteException", ex);
-        } catch (NullPointerException ex) {
-            Rlog.e(TAG, "setPreferredNetworkType NPE", ex);
+            Rlog.e(TAG, "setPreferredNetworkTypeBitmask RemoteException", ex);
         }
         return false;
     }
@@ -10115,15 +10255,20 @@
     }
 
     /**
-     * Checks if the supplied number is an emergency number based on current locale, sim, default,
-     * modem and network.
+     * Identifies if the supplied phone number is an emergency number that matches a known
+     * emergency number based on current locale, SIM card(s), Android database, modem, network,
+     * or defaults.
+     *
+     * <p>This method assumes that only dialable phone numbers are passed in; non-dialable
+     * numbers are not considered emergency numbers. A dialable phone number consists only
+     * of characters/digits identified by {@link PhoneNumberUtils#isDialable(char)}.
      *
      * <p>The subscriptions which the identification would be based on, are all the active
      * subscriptions, no matter which subscription could be used to create TelephonyManager.
      *
      * @param number - the number to look up
      * @return {@code true} if the given number is an emergency number based on current locale,
-     * sim, modem and network; {@code false} otherwise.
+     * SIM card(s), Android database, modem, network or defaults; {@code false} otherwise.
      */
     public boolean isEmergencyNumber(@NonNull String number) {
         try {
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 0b1d1fb..d0b52c9 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1641,6 +1641,7 @@
          *
          * @param entryName the entry name to set for the APN
          */
+        @NonNull
         public Builder setEntryName(String entryName) {
             this.mEntryName = entryName;
             return this;
@@ -1651,6 +1652,7 @@
          *
          * @param apnName the name to set for the APN
          */
+        @NonNull
         public Builder setApnName(String apnName) {
             this.mApnName = apnName;
             return this;
@@ -1681,6 +1683,7 @@
          *
          * @param proxy the proxy address to set for the APN
          */
+        @NonNull
         public Builder setProxyAddress(String proxy) {
             this.mProxyAddress = proxy;
             return this;
@@ -1691,6 +1694,7 @@
          *
          * @param port the proxy port to set for the APN
          */
+        @NonNull
         public Builder setProxyPort(int port) {
             this.mProxyPort = port;
             return this;
@@ -1701,6 +1705,7 @@
          *
          * @param mmsc the MMSC Uri to set for the APN
          */
+        @NonNull
         public Builder setMmsc(Uri mmsc) {
             this.mMmsc = mmsc;
             return this;
@@ -1732,6 +1737,7 @@
          *
          * @param mmsProxy the MMS proxy address to set for the APN
          */
+        @NonNull
         public Builder setMmsProxyAddress(String mmsProxy) {
             this.mMmsProxyAddress = mmsProxy;
             return this;
@@ -1742,6 +1748,7 @@
          *
          * @param mmsPort the MMS proxy port to set for the APN
          */
+        @NonNull
         public Builder setMmsProxyPort(int mmsPort) {
             this.mMmsProxyPort = mmsPort;
             return this;
@@ -1752,6 +1759,7 @@
          *
          * @param user the APN username to set for the APN
          */
+        @NonNull
         public Builder setUser(String user) {
             this.mUser = user;
             return this;
@@ -1763,6 +1771,7 @@
          * @see android.provider.Telephony.Carriers#PASSWORD
          * @param password the APN password to set for the APN
          */
+        @NonNull
         public Builder setPassword(String password) {
             this.mPassword = password;
             return this;
@@ -1773,6 +1782,7 @@
          *
          * @param authType the authentication type to set for the APN
          */
+        @NonNull
         public Builder setAuthType(@AuthType int authType) {
             this.mAuthType = authType;
             return this;
@@ -1789,6 +1799,7 @@
          *
          * @param apnTypeBitmask a bitmask describing the types of the APN
          */
+        @NonNull
         public Builder setApnTypeBitmask(@ApnType int apnTypeBitmask) {
             this.mApnTypeBitmask = apnTypeBitmask;
             return this;
@@ -1801,6 +1812,7 @@
          *
          * @param operatorNumeric the numeric operator ID to set for this entry
          */
+        @NonNull
         public Builder setOperatorNumeric(String operatorNumeric) {
             this.mOperatorNumeric = operatorNumeric;
             return this;
@@ -1813,6 +1825,7 @@
          *
          * @param protocol the protocol to set to use to connect to this APN
          */
+        @NonNull
         public Builder setProtocol(@ProtocolType int protocol) {
             this.mProtocol = protocol;
             return this;
@@ -1825,6 +1838,7 @@
          *
          * @param roamingProtocol the protocol to set to use to connect to this APN when roaming
          */
+        @NonNull
         public Builder setRoamingProtocol(@ProtocolType  int roamingProtocol) {
             this.mRoamingProtocol = roamingProtocol;
             return this;
@@ -1835,6 +1849,7 @@
          *
          * @param carrierEnabled the current status to set for this APN
          */
+        @NonNull
         public Builder setCarrierEnabled(boolean carrierEnabled) {
             this.mCarrierEnabled = carrierEnabled;
             return this;
@@ -1845,6 +1860,7 @@
          *
          * @param networkTypeBitmask the Radio Technology (Network Type) info
          */
+        @NonNull
         public Builder setNetworkTypeBitmask(int networkTypeBitmask) {
             this.mNetworkTypeBitmask = networkTypeBitmask;
             return this;
@@ -1855,6 +1871,7 @@
          *
          * @param mvnoType the MVNO match type to set for this APN
          */
+        @NonNull
         public Builder setMvnoType(@MvnoType int mvnoType) {
             this.mMvnoType = mvnoType;
             return this;
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index 173f4ed..fa6cfcb 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -22,6 +22,7 @@
 import android.hardware.radio.V1_4.EmergencyServiceCategory;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.PhoneNumberUtils;
 import android.telephony.Rlog;
 
 import java.lang.annotation.Retention;
@@ -673,11 +674,20 @@
     }
 
     /**
-     * Validate Emergency Number address that only allows '0'-'9', '*', or '#'
+     * Validate Emergency Number address that only contains the dialable character
+     * {@link PhoneNumberUtils#isDialable(char)}
      *
      * @hide
      */
     public static boolean validateEmergencyNumberAddress(String address) {
-        return address.matches("[0-9*#]+");
+        if (address == null) {
+            return false;
+        }
+        for (char c : address.toCharArray()) {
+            if (!PhoneNumberUtils.isDialable(c)) {
+                return false;
+            }
+        }
+        return true;
     }
 }
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index afbf46d..e651783 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -120,6 +120,10 @@
      * enable or disable a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID} and
      * {@link #EXTRA_ENABLE_SUBSCRIPTION}.
      *
+     * Requires the caller to be a privileged process with the
+     * {@link android.permission#CALL_PRIVILEGED} permission for the intent to reach the Telephony
+     * stack.
+     *
      * <p>Unlike {@link #switchToSubscription(int, PendingIntent)}, using this action allows the
      * underlying eUICC service (i.e. the LPA app) to control the UI experience during this
      * operation. The action is received by the Telephony framework, which in turn selects and
@@ -139,6 +143,10 @@
      * Intent action sent by system apps (such as the Settings app) to the Telephony framework to
      * delete a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID}.
      *
+     * Requires the caller to be a privileged process with the
+     * {@link android.permission#CALL_PRIVILEGED} permission for the intent to reach the Telephony
+     * stack.
+     *
      * <p>Unlike {@link #deleteSubscription(int, PendingIntent)}, using this action allows the
      * underlying eUICC service (i.e. the LPA app) to control the UI experience during this
      * operation. The action is received by the Telephony framework, which in turn selects and
@@ -159,6 +167,10 @@
      * rename a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID} and
      * {@link #EXTRA_SUBSCRIPTION_NICKNAME}.
      *
+     * Requires the caller to be a privileged process with the
+     * {@link android.permission#CALL_PRIVILEGED} permission for the intent to reach the Telephony
+     * stack.
+     *
      * <p>Unlike {@link #updateSubscriptionNickname(int, String, PendingIntent)}, using this action
      * allows the the underlying eUICC service (i.e. the LPA app) to control the UI experience
      * during this operation. The action is received by the Telephony framework, which in turn
@@ -258,7 +270,10 @@
 
     /**
      * Key for an extra set on the {@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION} intent for
-     * whether the user choses to use eUICC to set up network in SUW.
+     * whether eSIM provisioning flow is forced to be started or not. If this extra hasn't been
+     * set, eSIM provisioning flow may be skipped and the corresponding carrier's app will be
+     * notified. Otherwise, eSIM provisioning flow will be started when
+     * {@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION} has been received.
      * @hide
      */
     @SystemApi
@@ -758,7 +773,7 @@
      */
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
     public void updateSubscriptionNickname(
-            int subscriptionId, String nickname, PendingIntent callbackIntent) {
+            int subscriptionId, @Nullable String nickname, @NonNull PendingIntent callbackIntent) {
         if (!refreshCardIdIfUninitialized()) {
             sendUnavailableError(callbackIntent);
             return;
diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java
index bdaad5b..02eddf6 100644
--- a/telephony/java/android/telephony/ims/ImsException.java
+++ b/telephony/java/android/telephony/ims/ImsException.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.content.pm.PackageManager;
 import android.text.TextUtils;
 
 import java.lang.annotation.Retention;
@@ -48,7 +49,9 @@
     /**
      * This device or carrier configuration does not support IMS for this subscription.
      * <p>
-     * This is a permanent configuration error and there should be no retry.
+     * This is a permanent configuration error and there should be no retry. Usually this is
+     * because {@link PackageManager#FEATURE_TELEPHONY_IMS} is not available
+     * or the device has no ImsService implementation to service this request.
      */
     public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2;
 
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 58ddf21..e9aede7 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -25,6 +25,8 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.RemoteException;
@@ -107,9 +109,9 @@
                         // case, since it is defined.
                         put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, -1);
                         put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
-                                AccessNetworkConstants.TransportType.WWAN);
+                                AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
                         put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
-                                AccessNetworkConstants.TransportType.WLAN);
+                                AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
                     }};
 
             private final RegistrationCallback mLocalCallback;
@@ -314,7 +316,7 @@
     private int mSubId;
 
     /**
-     * Create an instance of ImsManager for the subscription id specified.
+     * Create an instance of {@link ImsMmTelManager} for the subscription id specified.
      *
      * @param subId The ID of the subscription that this ImsMmTelManager will use.
      * @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList()
@@ -366,12 +368,14 @@
         if (executor == null) {
             throw new IllegalArgumentException("Must include a non-null Executor.");
         }
+        if (!isImsAvailableOnDevice()) {
+            throw new ImsException("IMS not available on device.",
+                    ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
+        }
         c.setExecutor(executor);
         try {
             getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        } catch (IllegalStateException e) {
+        } catch (RemoteException | IllegalStateException e) {
             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
@@ -434,6 +438,10 @@
         if (executor == null) {
             throw new IllegalArgumentException("Must include a non-null Executor.");
         }
+        if (!isImsAvailableOnDevice()) {
+            throw new ImsException("IMS not available on device.",
+                    ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
+        }
         c.setExecutor(executor);
         try {
             getITelephony().registerMmTelCapabilityCallback(mSubId, c.getBinder());
@@ -800,6 +808,22 @@
         }
     }
 
+    private static boolean isImsAvailableOnDevice() {
+        IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+        if (pm == null) {
+            // For some reason package manger is not available.. This will fail internally anyways,
+            // so do not throw error and allow.
+            return true;
+        }
+        try {
+            return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS, 0);
+        } catch (RemoteException e) {
+            // For some reason package manger is not available.. This will fail internally anyways,
+            // so do not throw error and allow.
+        }
+        return true;
+    }
+
     private static ITelephony getITelephony() {
         ITelephony binder = ITelephony.Stub.asInterface(
                 ServiceManager.getService(Context.TELEPHONY_SERVICE));
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index b018491..a478606 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -142,6 +142,11 @@
      * Call was disconnected because a handover is not feasible due to network conditions.
      */
     public static final int CODE_LOCAL_HO_NOT_FEASIBLE = 149;
+    /**
+     * This device does not support IMS.
+     * @hide
+     */
+    public static final int CODE_LOCAL_IMS_NOT_SUPPORTED_ON_DEVICE = 150;
 
     /*
      * TIMEOUT (IMS -> Telephony)
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index d12cda8..8cdf6a2 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -24,6 +24,8 @@
 import android.annotation.SystemApi;
 import android.annotation.WorkerThread;
 import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -209,12 +211,14 @@
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void registerProvisioningChangedCallback(@NonNull @CallbackExecutor Executor executor,
             @NonNull Callback callback) throws ImsException {
+        if (!isImsAvailableOnDevice()) {
+            throw new ImsException("IMS not available on device.",
+                    ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
+        }
         callback.setExecutor(executor);
         try {
             getITelephony().registerImsProvisioningChangedCallback(mSubId, callback.getBinder());
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }  catch (IllegalStateException e) {
+        } catch (RemoteException | IllegalStateException e) {
             throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
         }
     }
@@ -232,8 +236,7 @@
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public void unregisterProvisioningChangedCallback(@NonNull Callback callback) {
         try {
-            getITelephony().unregisterImsProvisioningChangedCallback(mSubId,
-                    callback.getBinder());
+            getITelephony().unregisterImsProvisioningChangedCallback(mSubId, callback.getBinder());
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -373,6 +376,22 @@
         }
     }
 
+    private static boolean isImsAvailableOnDevice() {
+        IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+        if (pm == null) {
+            // For some reason package manger is not available.. This will fail internally anyways,
+            // so do not throw error and allow.
+            return true;
+        }
+        try {
+            return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS, 0);
+        } catch (RemoteException e) {
+            // For some reason package manger is not available.. This will fail internally anyways,
+            // so do not throw error and allow.
+        }
+        return true;
+    }
+
     private static ITelephony getITelephony() {
         ITelephony binder = ITelephony.Stub.asInterface(
                 ServiceManager.getService(Context.TELEPHONY_SERVICE));
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 122747a65..62b92fd 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -553,6 +553,20 @@
     void setCellInfoListRate(int rateInMillis);
 
     /**
+     * Opens a logical channel to the ICC card using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CCHO command.
+     *
+     * @param slotIndex The physical slot index of the target ICC card
+     * @param callingPackage the name of the package making the call.
+     * @param AID Application id. See ETSI 102.221 and 101.220.
+     * @param p2 P2 parameter (described in ISO 7816-4).
+     * @return an IccOpenLogicalChannelResponse object.
+     */
+    IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(
+            int slotIndex, String callingPackage, String AID, int p2);
+
+    /**
      * Opens a logical channel to the ICC card.
      *
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
@@ -567,12 +581,24 @@
             int subId, String callingPackage, String AID, int p2);
 
     /**
+     * Closes a previously opened logical channel to the ICC card using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CCHC command.
+     *
+     * @param slotIndex The physical slot index of the target ICC card
+     * @param channel is the channel id to be closed as returned by a
+     *            successful iccOpenLogicalChannel.
+     * @return true if the channel was closed successfully.
+     */
+    boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel);
+
+    /**
      * Closes a previously opened logical channel to the ICC card.
      *
      * Input parameters equivalent to TS 27.007 AT+CCHC command.
      *
      * @param subId The subscription to use.
-     * @param channel is the channel id to be closed as retruned by a
+     * @param channel is the channel id to be closed as returned by a
      *            successful iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      */
@@ -580,12 +606,33 @@
     boolean iccCloseLogicalChannel(int subId, int channel);
 
     /**
+     * Transmit an APDU to the ICC card over a logical channel using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CGLA command.
+     *
+     * @param slotIndex The physical slot index of the target ICC card
+     * @param channel is the channel id to be closed as returned by a
+     *            successful iccOpenLogicalChannel.
+     * @param cla Class of the APDU command.
+     * @param instruction Instruction of the APDU command.
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+     *            is sent to the SIM.
+     * @param data Data to be sent with the APDU.
+     * @return The APDU response from the ICC card with the status appended at
+     *            the end.
+     */
+    String iccTransmitApduLogicalChannelBySlot(int slotIndex, int channel, int cla, int instruction,
+            int p1, int p2, int p3, String data);
+
+    /**
      * Transmit an APDU to the ICC card over a logical channel.
      *
      * Input parameters equivalent to TS 27.007 AT+CGLA command.
      *
      * @param subId The subscription to use.
-     * @param channel is the channel id to be closed as retruned by a
+     * @param channel is the channel id to be closed as returned by a
      *            successful iccOpenLogicalChannel.
      * @param cla Class of the APDU command.
      * @param instruction Instruction of the APDU command.
@@ -602,6 +649,26 @@
             int p1, int p2, int p3, String data);
 
     /**
+     * Transmit an APDU to the ICC card over the basic channel using the physical slot index.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CSIM command.
+     *
+     * @param slotIndex The physical slot index of the target ICC card
+     * @param callingPackage the name of the package making the call.
+     * @param cla Class of the APDU command.
+     * @param instruction Instruction of the APDU command.
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+     *            is sent to the SIM.
+     * @param data Data to be sent with the APDU.
+     * @return The APDU response from the ICC card with the status appended at
+     *            the end.
+     */
+    String iccTransmitApduBasicChannelBySlot(int slotIndex, String callingPackage, int cla,
+            int instruction, int p1, int p2, int p3, String data);
+
+    /**
      * Transmit an APDU to the ICC card over the basic channel.
      *
      * Input parameters equivalent to TS 27.007 AT+CSIM command.
diff --git a/tests/ActivityManagerPerfTests/test-app/Android.bp b/tests/ActivityManagerPerfTests/test-app/Android.bp
new file mode 100644
index 0000000..ef9d587
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/test-app/Android.bp
@@ -0,0 +1,21 @@
+// 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.
+
+android_test {
+    name: "ActivityManagerPerfTestsTestApp",
+    srcs: ["src/**/*.java"],
+    static_libs: ["ActivityManagerPerfTestsUtils"],
+    min_sdk_version: "25",
+    sdk_version: "current",
+}
diff --git a/tests/ActivityManagerPerfTests/test-app/Android.mk b/tests/ActivityManagerPerfTests/test-app/Android.mk
deleted file mode 100644
index 33d15d2..0000000
--- a/tests/ActivityManagerPerfTests/test-app/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    ActivityManagerPerfTestsUtils
-
-LOCAL_MIN_SDK_VERSION := 25
-
-LOCAL_PACKAGE_NAME := ActivityManagerPerfTestsTestApp
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/tests/ActivityManagerPerfTests/tests/Android.bp b/tests/ActivityManagerPerfTests/tests/Android.bp
new file mode 100644
index 0000000..2ae2cc4
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/tests/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "ActivityManagerPerfTests",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "androidx.test.rules",
+        "apct-perftests-utils",
+        "ActivityManagerPerfTestsUtils",
+    ],
+    platform_apis: true,
+    min_sdk_version: "25",
+    // For android.permission.FORCE_STOP_PACKAGES permission
+    certificate: "platform",
+}
diff --git a/tests/ActivityManagerPerfTests/tests/Android.mk b/tests/ActivityManagerPerfTests/tests/Android.mk
deleted file mode 100644
index e1f56b8..0000000
--- a/tests/ActivityManagerPerfTests/tests/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    apct-perftests-utils \
-    ActivityManagerPerfTestsUtils
-
-LOCAL_PACKAGE_NAME := ActivityManagerPerfTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_MIN_SDK_VERSION := 25
-
-# For android.permission.FORCE_STOP_PACKAGES permission
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/tests/ActivityManagerPerfTests/utils/Android.bp b/tests/ActivityManagerPerfTests/utils/Android.bp
new file mode 100644
index 0000000..300b7ea
--- /dev/null
+++ b/tests/ActivityManagerPerfTests/utils/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_test {
+    name: "ActivityManagerPerfTestsUtils",
+    sdk_version: "current",
+    srcs: [
+        "src/**/*.java",
+        "src/com/android/frameworks/perftests/am/util/ITimeReceiverCallback.aidl",
+    ],
+    static_libs: [
+        "androidx.test.rules",
+        "junit",
+        "ub-uiautomator",
+    ],
+}
diff --git a/tests/ActivityManagerPerfTests/utils/Android.mk b/tests/ActivityManagerPerfTests/utils/Android.mk
deleted file mode 100644
index 7a7471d..0000000
--- a/tests/ActivityManagerPerfTests/utils/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src) \
-    src/com/android/frameworks/perftests/am/util/ITimeReceiverCallback.aidl
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    junit \
-    ub-uiautomator
-
-LOCAL_MODULE := ActivityManagerPerfTestsUtils
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/ActivityViewTest/Android.bp b/tests/ActivityViewTest/Android.bp
new file mode 100644
index 0000000..e7b8c8e
--- /dev/null
+++ b/tests/ActivityViewTest/Android.bp
@@ -0,0 +1,6 @@
+android_test {
+    name: "ActivityViewTest",
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+}
diff --git a/tests/ActivityViewTest/Android.mk b/tests/ActivityViewTest/Android.mk
deleted file mode 100644
index 9c7ca7e..0000000
--- a/tests/ActivityViewTest/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := ActivityViewTest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/tests/AppLaunch/Android.bp b/tests/AppLaunch/Android.bp
new file mode 100644
index 0000000..f90f26f
--- /dev/null
+++ b/tests/AppLaunch/Android.bp
@@ -0,0 +1,13 @@
+android_test {
+    name: "AppLaunch",
+    // Only compile source java files in this apk.
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+    libs: [
+        "android.test.base",
+        "android.test.runner",
+    ],
+    static_libs: ["androidx.test.rules"],
+    test_suites: ["device-tests"],
+}
diff --git a/tests/AppLaunch/Android.mk b/tests/AppLaunch/Android.mk
deleted file mode 100644
index f50bca5..0000000
--- a/tests/AppLaunch/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := AppLaunch
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner
-
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/AppLaunchWear/Android.bp b/tests/AppLaunchWear/Android.bp
new file mode 100644
index 0000000..8d34b6e
--- /dev/null
+++ b/tests/AppLaunchWear/Android.bp
@@ -0,0 +1,13 @@
+android_test {
+    name: "AppLaunchWear",
+    // Only compile source java files in this apk.
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+    libs: [
+        "android.test.base",
+        "android.test.runner",
+    ],
+    static_libs: ["androidx.test.rules"],
+    test_suites: ["device-tests"],
+}
diff --git a/tests/AppLaunchWear/Android.mk b/tests/AppLaunchWear/Android.mk
deleted file mode 100644
index 332b680..0000000
--- a/tests/AppLaunchWear/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := AppLaunchWear
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner
-
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/Android.bp b/tests/BackgroundDexOptServiceIntegrationTests/Android.bp
new file mode 100644
index 0000000..a85d129
--- /dev/null
+++ b/tests/BackgroundDexOptServiceIntegrationTests/Android.bp
@@ -0,0 +1,24 @@
+//
+// 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.
+//
+
+android_test {
+    name: "BackgroundDexOptServiceIntegrationTests",
+    srcs: ["src/**/*.java"],
+    static_libs: ["androidx.test.rules"],
+    platform_apis: true,
+    test_suites: ["device-tests"],
+    certificate: "platform",
+}
diff --git a/tests/BackgroundDexOptServiceIntegrationTests/Android.mk b/tests/BackgroundDexOptServiceIntegrationTests/Android.mk
deleted file mode 100644
index f47cf96..0000000
--- a/tests/BackgroundDexOptServiceIntegrationTests/Android.mk
+++ /dev/null
@@ -1,35 +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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-
-LOCAL_PACKAGE_NAME := BackgroundDexOptServiceIntegrationTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/tests/Compatibility/Android.bp b/tests/Compatibility/Android.bp
new file mode 100644
index 0000000..4ca406e
--- /dev/null
+++ b/tests/Compatibility/Android.bp
@@ -0,0 +1,22 @@
+// Copyright (C) 2012 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: "AppCompatibilityTest",
+    static_libs: ["androidx.test.rules"],
+    // Include all test java files.
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+}
diff --git a/tests/Compatibility/Android.mk b/tests/Compatibility/Android.mk
deleted file mode 100644
index 643f9eb..0000000
--- a/tests/Compatibility/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2012 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)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
-# Include all test java files.
-LOCAL_SRC_FILES := \
-	$(call all-java-files-under, src)
-
-
-LOCAL_PACKAGE_NAME := AppCompatibilityTest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
new file mode 100644
index 0000000..05f0a8e7
--- /dev/null
+++ b/tests/FlickerTests/Android.bp
@@ -0,0 +1,30 @@
+//
+// 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.
+//
+
+android_test {
+    name: "FlickerTests",
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+    test_suites: ["device-tests"],
+    libs: ["android.test.runner"],
+    static_libs: [
+        "flickertestapplib",
+        "flickerlib",
+        "truth-prebuilt",
+        "app-helpers-core",
+    ],
+}
diff --git a/tests/FlickerTests/Android.mk b/tests/FlickerTests/Android.mk
deleted file mode 100644
index 3c70f8b..0000000
--- a/tests/FlickerTests/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := FlickerTests
-LOCAL_MODULE_TAGS := tests optional
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    flickertestapplib \
-    flickerlib \
-    truth-prebuilt \
-    app-helpers-core
-
-include $(BUILD_PACKAGE)
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/tests/FlickerTests/lib/Android.bp b/tests/FlickerTests/lib/Android.bp
new file mode 100644
index 0000000..982fcba
--- /dev/null
+++ b/tests/FlickerTests/lib/Android.bp
@@ -0,0 +1,44 @@
+//
+// 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.
+//
+
+java_test {
+    name: "flickerlib",
+    platform_apis: true,
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "androidx.test.janktesthelper",
+        "cts-amwm-util",
+        "platformprotosnano",
+        "layersprotosnano",
+        "truth-prebuilt",
+        "sysui-helper",
+        "launcher-helper-lib",
+    ],
+}
+
+java_library {
+    name: "flickerautomationhelperlib",
+    sdk_version: "test_current",
+    srcs: [
+        "src/com/android/server/wm/flicker/AutomationUtils.java",
+        "src/com/android/server/wm/flicker/WindowUtils.java",
+    ],
+    static_libs: [
+        "sysui-helper",
+        "launcher-helper-lib",
+        "compatibility-device-util-axt",
+    ],
+}
diff --git a/tests/FlickerTests/lib/Android.mk b/tests/FlickerTests/lib/Android.mk
deleted file mode 100644
index e438822..0000000
--- a/tests/FlickerTests/lib/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := flickerlib
-LOCAL_MODULE_TAGS := tests optional
-# sign this with platform cert, so this test is allowed to call private platform apis
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := \
-   androidx.test.janktesthelper \
-   cts-amwm-util \
-   platformprotosnano \
-   layersprotosnano \
-   truth-prebuilt \
-   sysui-helper \
-   launcher-helper-lib \
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := flickerautomationhelperlib
-LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := src/com/android/server/wm/flicker/AutomationUtils.java \
-    src/com/android/server/wm/flicker/WindowUtils.java
-LOCAL_STATIC_JAVA_LIBRARIES := sysui-helper \
-    launcher-helper-lib \
-    compatibility-device-util-axt
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/FlickerTests/lib/test/Android.bp b/tests/FlickerTests/lib/test/Android.bp
new file mode 100644
index 0000000..bfeb75b2
--- /dev/null
+++ b/tests/FlickerTests/lib/test/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_test {
+    name: "FlickerLibTest",
+    // sign this with platform cert, so this test is allowed to call private platform apis
+    certificate: "platform",
+    platform_apis: true,
+    test_suites: ["tests"],
+    srcs: ["src/**/*.java"],
+    libs: ["android.test.runner"],
+    static_libs: [
+        "androidx.test.rules",
+        "platform-test-annotations",
+        "truth-prebuilt",
+        "platformprotosnano",
+        "layersprotosnano",
+        "flickerlib",
+    ],
+}
diff --git a/tests/FlickerTests/lib/test/Android.mk b/tests/FlickerTests/lib/test/Android.mk
deleted file mode 100644
index 5be89ba..0000000
--- a/tests/FlickerTests/lib/test/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := FlickerLibTest
-LOCAL_MODULE_TAGS := tests optional
-# sign this with platform cert, so this test is allowed to call private platform apis
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := tests
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    platform-test-annotations \
-    truth-prebuilt \
-    platformprotosnano \
-    layersprotosnano \
-    flickerlib
-
-include $(BUILD_PACKAGE)
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/Android.bp b/tests/FlickerTests/test-apps/Android.bp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/FlickerTests/test-apps/Android.bp
diff --git a/tests/FlickerTests/test-apps/Android.mk b/tests/FlickerTests/test-apps/Android.mk
deleted file mode 100644
index 9af9f444..0000000
--- a/tests/FlickerTests/test-apps/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-include $(call all-subdir-makefiles)
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.bp b/tests/FlickerTests/test-apps/flickerapp/Android.bp
new file mode 100644
index 0000000..0bea209
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "FlickerTestApp",
+    srcs: ["**/*.java"],
+    sdk_version: "current",
+    test_suites: ["device-tests"],
+}
+
+java_test {
+    name: "flickertestapplib",
+    sdk_version: "current",
+    srcs: ["src/com/android/server/wm/flicker/testapp/ActivityOptions.java"],
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.mk b/tests/FlickerTests/test-apps/flickerapp/Android.mk
deleted file mode 100644
index b916900..0000000
--- a/tests/FlickerTests/test-apps/flickerapp/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_PACKAGE_NAME := FlickerTestApp
-LOCAL_MODULE_TAGS := tests optional
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
-include $(BUILD_PACKAGE)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := flickertestapplib
-LOCAL_MODULE_TAGS := tests optional
-LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := src/com/android/server/wm/flicker/testapp/ActivityOptions.java
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp
new file mode 100644
index 0000000..4cb9f8d5
--- /dev/null
+++ b/tests/Internal/Android.bp
@@ -0,0 +1,18 @@
+android_test {
+    name: "InternalTests",
+    proto: {
+        type: "nano",
+    },
+    // Include some source files directly to be able to access package members
+    srcs: ["src/**/*.java"],
+    libs: ["android.test.runner"],
+    static_libs: [
+        "junit",
+        "androidx.test.rules",
+        "mockito-target-minus-junit4",
+    ],
+    java_resource_dirs: ["res"],
+    certificate: "platform",
+    platform_apis: true,
+    test_suites: ["device-tests"],
+}
diff --git a/tests/Internal/Android.mk b/tests/Internal/Android.mk
deleted file mode 100644
index 2e26ef1..0000000
--- a/tests/Internal/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-
-# Include some source files directly to be able to access package members
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := junit \
-    androidx.test.rules \
-    mockito-target-minus-junit4
-
-LOCAL_JAVA_RESOURCE_DIRS := res
-LOCAL_CERTIFICATE := platform
-
-LOCAL_PACKAGE_NAME := InternalTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp
new file mode 100644
index 0000000..b079965
--- /dev/null
+++ b/tests/PackageWatchdog/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2019 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.
+
+// PackageWatchdogTest
+android_test {
+    name: "PackageWatchdogTest",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "junit",
+        "frameworks-base-testutils",
+        "androidx.test.rules",
+        "services.core",
+    ],
+    libs: ["android.test.runner"],
+    platform_apis: true,
+    test_suites: ["device-tests"],
+}
diff --git a/tests/PackageWatchdog/Android.mk b/tests/PackageWatchdog/Android.mk
deleted file mode 100644
index 1e4aacc..0000000
--- a/tests/PackageWatchdog/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2019 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)
-
-# PackageWatchdogTest
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_PACKAGE_NAME := PackageWatchdogTest
-LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    junit \
-    frameworks-base-testutils \
-    androidx.test.rules \
-    services.core
-
-LOCAL_JAVA_LIBRARIES := \
-    android.test.runner
-
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RcsTests/Android.bp b/tests/RcsTests/Android.bp
new file mode 100644
index 0000000..8ee4960
--- /dev/null
+++ b/tests/RcsTests/Android.bp
@@ -0,0 +1,17 @@
+android_test {
+    name: "RcsTests",
+    // Only compile source java files in this apk.
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    static_libs: [
+        "junit",
+        "androidx.test.rules",
+        "mockito-target-minus-junit4",
+        "truth-prebuilt",
+    ],
+}
diff --git a/tests/RcsTests/Android.mk b/tests/RcsTests/Android.mk
deleted file mode 100644
index a276584..0000000
--- a/tests/RcsTests/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := RcsTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_STATIC_JAVA_LIBRARIES := junit androidx.test.rules mockito-target-minus-junit4 truth-prebuilt
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index a03fae0..9aed074 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -340,16 +340,26 @@
     }
 
     /**
-     * Asserts that the given RollbackInfo has a single package with expected
-     * package name and versions.
+     * Asserts that the given RollbackInfo has the given packages with expected
+     * package names and all are rolled to and from the same given versions.
      */
-    static void assertRollbackInfoEquals(String packageName,
+    static void assertRollbackInfoEquals(String[] packageNames,
             long versionRolledBackFrom, long versionRolledBackTo,
             RollbackInfo info, VersionedPackage... causePackages) {
         assertNotNull(info);
-        assertEquals(1, info.getPackages().size());
-        assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom, versionRolledBackTo,
-                info.getPackages().get(0));
+        assertEquals(packageNames.length, info.getPackages().size());
+        int foundPackages = 0;
+        for (String packageName : packageNames) {
+            for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
+                if (packageName.equals(pkgRollbackInfo.getPackageName())) {
+                    foundPackages++;
+                    assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom,
+                            versionRolledBackTo, pkgRollbackInfo);
+                    break;
+                }
+            }
+        }
+        assertEquals(packageNames.length, foundPackages);
         assertEquals(causePackages.length, info.getCausePackages().size());
         for (int i = 0; i < causePackages.length; ++i) {
             assertEquals(causePackages[i].getPackageName(),
@@ -360,6 +370,18 @@
     }
 
     /**
+     * Asserts that the given RollbackInfo has a single package with expected
+     * package name and versions.
+     */
+    static void assertRollbackInfoEquals(String packageName,
+            long versionRolledBackFrom, long versionRolledBackTo,
+            RollbackInfo info, VersionedPackage... causePackages) {
+        String[] packageNames = {packageName};
+        assertRollbackInfoEquals(packageNames, versionRolledBackFrom, versionRolledBackTo, info,
+                causePackages);
+    }
+
+    /**
      * Waits for the given session to be marked as ready.
      * Throws an assertion if the session fails.
      */
@@ -453,4 +475,17 @@
             fail(result);
         }
     }
+
+    /**
+     * Return the rollback info for a recently committed rollback, by matching the rollback id, or
+     * return null if no matching rollback is found.
+     */
+    static RollbackInfo getRecentlyCommittedRollbackInfoById(int getRollbackId) {
+        for (RollbackInfo info : getRollbackManager().getRecentlyCommittedRollbacks()) {
+            if (info.getRollbackId() == getRollbackId) {
+                return info;
+            }
+        }
+        return null;
+    }
 }
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 59ae8d9..047451b 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -17,6 +17,7 @@
 package com.android.tests.rollback;
 
 import static com.android.tests.rollback.RollbackTestUtils.assertRollbackInfoEquals;
+import static com.android.tests.rollback.RollbackTestUtils.getRecentlyCommittedRollbackInfoById;
 import static com.android.tests.rollback.RollbackTestUtils.getUniqueRollbackInfoForPackage;
 
 import android.Manifest;
@@ -25,7 +26,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import org.junit.After;
@@ -47,6 +47,8 @@
 
     private static final String TAG = "RollbackTest";
     private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
+    private static final String TEST_APP_A_V1 = "RollbackTestAppAv1.apk";
+    private static final String TEST_APP_A_V2 = "RollbackTestAppAv2.apk";
     private static final String TEST_APEX_PKG = "com.android.tests.rollback.testapex";
     private static final String TEST_APEX_V1 =
             "com.android.tests.rollback.testapex.RollbackTestApexV1.apex";
@@ -82,11 +84,11 @@
         RollbackTestUtils.uninstall(TEST_APP_A);
         assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
-        RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
+        RollbackTestUtils.install(TEST_APP_A_V1, false);
         assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
         RollbackTestUtils.processUserData(TEST_APP_A);
 
-        RollbackTestUtils.installStaged(true, "RollbackTestAppAv2.apk");
+        RollbackTestUtils.installStaged(true, TEST_APP_A_V2);
 
         // At this point, the host test driver will reboot the device and run
         // testApkOnlyCommitRollback().
@@ -142,6 +144,86 @@
     }
 
     /**
+     * Test rollbacks of staged installs an apk and an apex.
+     * Prepare apex (and apk) phase.
+     */
+    @Test
+    public void testApkAndApexPrepare() throws Exception {
+        RollbackTestUtils.uninstall(TEST_APP_A);
+        assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        // Note: can't uninstall the apex. See note in #testApexOnlyPrepareApex().
+        RollbackTestUtils.installStaged(false, TEST_APP_A_V1, TEST_APEX_V1);
+
+        // At this point, the host test driver will reboot the device and run
+        // testApkAndApexEnableRollback().
+    }
+
+    /**
+     * Test rollbacks of staged installs an apk and an apex.
+     * Enable rollback phase.
+     */
+    @Test
+    public void testApkAndApexEnableRollback() throws Exception {
+        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        RollbackTestUtils.installStaged(true, TEST_APP_A_V2, TEST_APEX_V2);
+
+        // At this point, the host test driver will reboot the device and run
+        // testApkAndApexCommitRollback().
+    }
+
+    /**
+     * Test rollbacks of staged installs an apk and an apex.
+     * Commit rollback phase.
+     */
+    @Test
+    public void testApkAndApexCommitRollback() throws Exception {
+        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        RollbackTestUtils.processUserData(TEST_APP_A);
+
+        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+
+        RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+                rm.getAvailableRollbacks(), TEST_APP_A);
+        String[] packagesNames = {TEST_APEX_PKG, TEST_APP_A};
+        assertRollbackInfoEquals(packagesNames, 2, 1, rollback);
+        assertTrue(rollback.isStaged());
+
+        RollbackTestUtils.rollback(rollback.getRollbackId());
+
+        RollbackInfo committed = getRecentlyCommittedRollbackInfoById(rollback.getRollbackId());
+
+        assertRollbackInfoEquals(packagesNames, 2, 1, committed);
+        assertTrue(committed.isStaged());
+        assertNotEquals(-1, committed.getCommittedSessionId());
+
+        RollbackTestUtils.waitForSessionReady(committed.getCommittedSessionId());
+
+        // The apex and apk should not be rolled back until after reboot.
+        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        // At this point, the host test driver will reboot the device and run
+        // testApkAndApexConfirmRollback().
+    }
+
+    /**
+     * Test rollbacks of staged installs an apk and an apex.
+     * Confirm rollback phase.
+     */
+    @Test
+    public void testApkAndApexConfirmRollback() throws Exception {
+        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+        RollbackTestUtils.processUserData(TEST_APP_A);
+    }
+
+    /**
      * Test rollbacks of staged installs involving only apex.
      * Prepare apex phase.
      */
@@ -171,7 +253,7 @@
     }
 
     /**
-     * Test rollbacks of staged installs involving only apks.
+     * Test rollbacks of staged installs involving only apex.
      * Commit rollback phase.
      */
     @Test
@@ -186,18 +268,8 @@
 
         RollbackTestUtils.rollback(rollback.getRollbackId());
 
-        // Note: We can't use getUniqueRollbackInfoForPackage for the apex,
-        // because we can't uninstall the apex (b/123667725), which means
-        // there's no way to clear info about rollbacks from previous tests
-        // run on the device. Look up the info by rollback id instead.
-        RollbackInfo committed = null;
-        for (RollbackInfo info : rm.getRecentlyCommittedRollbacks()) {
-            if (info.getRollbackId() == rollback.getRollbackId()) {
-                assertNull(committed);
-                committed = info;
-                break;
-            }
-        }
+        RollbackInfo committed = getRecentlyCommittedRollbackInfoById(rollback.getRollbackId());
+
         assertRollbackInfoEquals(TEST_APEX_PKG, 2, 1, committed);
         assertTrue(committed.isStaged());
         assertNotEquals(-1, committed.getCommittedSessionId());
@@ -212,7 +284,7 @@
     }
 
     /**
-     * Test rollbacks of staged installs involving only apks.
+     * Test rollbacks of staged installs involving only apex.
      * Confirm rollback phase.
      */
     @Test
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 24a51dc..ac7f634 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -67,4 +67,18 @@
         getDevice().reboot();
         runPhase("testApexOnlyConfirmRollback");
     }
+
+    /**
+     * Tests staged rollbacks involving apk and apex.
+     */
+    @Test
+    public void testApkAndApex() throws Exception {
+        runPhase("testApkAndApexPrepare");
+        getDevice().reboot();
+        runPhase("testApkAndApexEnableRollback");
+        getDevice().reboot();
+        runPhase("testApkAndApexCommitRollback");
+        getDevice().reboot();
+        runPhase("testApkAndApexConfirmRollback");
+    }
 }
diff --git a/tests/ServiceCrashTest/Android.bp b/tests/ServiceCrashTest/Android.bp
new file mode 100644
index 0000000..40a377d
--- /dev/null
+++ b/tests/ServiceCrashTest/Android.bp
@@ -0,0 +1,12 @@
+android_test {
+    name: "ServiceCrashTest",
+    // Only compile source java files in this apk.
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+    libs: ["android.test.base"],
+    static_libs: [
+        "compatibility-device-util-axt",
+        "androidx.test.rules",
+    ],
+}
diff --git a/tests/ServiceCrashTest/Android.mk b/tests/ServiceCrashTest/Android.mk
deleted file mode 100644
index 617ee7c..0000000
--- a/tests/ServiceCrashTest/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := ServiceCrashTest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := android.test.base
-
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt androidx.test.rules
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/SurfaceComposition/Android.bp b/tests/SurfaceComposition/Android.bp
new file mode 100644
index 0000000..53e4d52
--- /dev/null
+++ b/tests/SurfaceComposition/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2015 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: "SurfaceComposition",
+    // Don't include this package in any target
+    // When built, explicitly put it in the data partition.
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+    srcs: ["src/**/*.java"],
+    static_libs: ["junit"],
+    libs: [
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
+    ],
+    sdk_version: "current",
+}
diff --git a/tests/SurfaceComposition/Android.mk b/tests/SurfaceComposition/Android.mk
deleted file mode 100644
index f59458d..0000000
--- a/tests/SurfaceComposition/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (C) 2015 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)
-
-# Don't include this package in any target
-LOCAL_MODULE_TAGS := tests
-# When built, explicitly put it in the data partition.
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-
-LOCAL_PACKAGE_NAME := SurfaceComposition
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/tests/SystemMemoryTest/Android.mk b/tests/SystemMemoryTest/Android.mk
deleted file mode 100644
index 09a1618..0000000
--- a/tests/SystemMemoryTest/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(call all-subdir-makefiles)
diff --git a/tests/SystemMemoryTest/device/Android.bp b/tests/SystemMemoryTest/device/Android.bp
new file mode 100644
index 0000000..2bf0fec
--- /dev/null
+++ b/tests/SystemMemoryTest/device/Android.bp
@@ -0,0 +1,20 @@
+// 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.
+
+android_test_helper_app {
+    name: "SystemMemoryTestDevice",
+    sdk_version: "current",
+    srcs: ["src/**/*.java"],
+    test_suites: ["general-tests"],
+}
diff --git a/tests/SystemMemoryTest/device/Android.mk b/tests/SystemMemoryTest/device/Android.mk
deleted file mode 100644
index 75408df..0000000
--- a/tests/SystemMemoryTest/device/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_PACKAGE_NAME := SystemMemoryTestDevice
-LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_COMPATIBILITY_SUITE := general-tests
-include $(BUILD_PACKAGE)
diff --git a/tests/SystemMemoryTest/host/Android.bp b/tests/SystemMemoryTest/host/Android.bp
new file mode 100644
index 0000000..3bb5489
--- /dev/null
+++ b/tests/SystemMemoryTest/host/Android.bp
@@ -0,0 +1,20 @@
+// 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.
+
+java_test_host {
+    name: "system-memory-test",
+    srcs: ["src/**/*.java"],
+    libs: ["tradefed"],
+    test_suites: ["general-tests"],
+}
diff --git a/tests/SystemMemoryTest/host/Android.mk b/tests/SystemMemoryTest/host/Android.mk
deleted file mode 100644
index a516e38..0000000
--- a/tests/SystemMemoryTest/host/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_MODULE := system-memory-test
-LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := tradefed
-LOCAL_COMPATIBILITY_SUITE := general-tests
-include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tests/UsageReportingTest/Android.bp b/tests/UsageReportingTest/Android.bp
new file mode 100644
index 0000000..0bac5a2
--- /dev/null
+++ b/tests/UsageReportingTest/Android.bp
@@ -0,0 +1,8 @@
+android_test {
+    name: "UsageReportingTest",
+    // Only compile source java files in this apk.
+    srcs: ["src/**/*.java"],
+    static_libs: ["androidx.legacy_legacy-support-v4"],
+    certificate: "platform",
+    platform_apis: true,
+}
diff --git a/tests/UsageReportingTest/Android.mk b/tests/UsageReportingTest/Android.mk
deleted file mode 100644
index afb6e16b1..0000000
--- a/tests/UsageReportingTest/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_USE_AAPT2 := true
-LOCAL_STATIC_ANDROID_LIBRARIES := androidx.legacy_legacy-support-v4
-
-LOCAL_CERTIFICATE := platform
-
-LOCAL_PACKAGE_NAME := UsageReportingTest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
diff --git a/tests/UsageStatsPerfTests/Android.bp b/tests/UsageStatsPerfTests/Android.bp
new file mode 100644
index 0000000..3991fb8
--- /dev/null
+++ b/tests/UsageStatsPerfTests/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "UsageStatsPerfTests",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "androidx.test.rules",
+        "apct-perftests-utils",
+        "services.usage",
+    ],
+    platform_apis: true,
+    // For android.permission.FORCE_STOP_PACKAGES permission
+    certificate: "platform",
+}
diff --git a/tests/UsageStatsPerfTests/Android.mk b/tests/UsageStatsPerfTests/Android.mk
deleted file mode 100644
index 4304fb0..0000000
--- a/tests/UsageStatsPerfTests/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    apct-perftests-utils \
-    services.usage
-
-LOCAL_PACKAGE_NAME := UsageStatsPerfTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-# For android.permission.FORCE_STOP_PACKAGES permission
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
index adcd11a..bb985d7 100644
--- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
+++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
@@ -197,7 +197,7 @@
                     intent.setPackage(getPackageName());
                     intent.putExtra(EXTRA_KEY_TIMEOUT, true);
                     mUsageStatsManager.registerAppUsageLimitObserver(1, packages,
-                            Duration.ofSeconds(60), Duration.ofSeconds(60),
+                            Duration.ofSeconds(60), Duration.ofSeconds(0),
                             PendingIntent.getActivity(UsageStatsActivity.this, 1, intent, 0));
                 }
             }
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp
new file mode 100644
index 0000000..c7e9df0
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.bp
@@ -0,0 +1,27 @@
+// 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: "AoapTestDeviceApp",
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+    platform_apis: true,
+    optimize: {
+        enabled: false,
+    },
+}
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk
deleted file mode 100644
index cd7aaed..0000000
--- a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk
+++ /dev/null
@@ -1,36 +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_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_PACKAGE_NAME := AoapTestDeviceApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
-
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp
new file mode 100644
index 0000000..6fa58cb
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.bp
@@ -0,0 +1,27 @@
+// 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: "AoapTestHostApp",
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+    platform_apis: true,
+    optimize: {
+        enabled: false,
+    },
+}
diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk
deleted file mode 100644
index bd8a51b..0000000
--- a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk
+++ /dev/null
@@ -1,36 +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_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_PACKAGE_NAME := AoapTestHostApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
-
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp
new file mode 100644
index 0000000..edd4205
--- /dev/null
+++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.bp
@@ -0,0 +1,32 @@
+// 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.
+//
+//
+
+//#################################################
+
+// TODO: should this be android_helper_test_app?
+android_app {
+    name: "UsbHostExternalManagementTestApp",
+    srcs: ["src/**/*.java"],
+    resource_dirs: ["res"],
+    platform_apis: true,
+    privileged: true,
+    // TODO remove tests tag
+    //LOCAL_MODULE_TAGS := tests
+    //LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+    optimize: {
+        enabled: false,
+    },
+}
diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk
deleted file mode 100644
index fed454e..0000000
--- a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk
+++ /dev/null
@@ -1,38 +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_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-
-LOCAL_PACKAGE_NAME := UsbHostExternalManagementTestApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_PRIVILEGED_MODULE := true
-# TODO remove tests tag
-#LOCAL_MODULE_TAGS := tests
-#LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
-
diff --git a/tests/UsbTests/Android.bp b/tests/UsbTests/Android.bp
new file mode 100644
index 0000000..1b2cf63
--- /dev/null
+++ b/tests/UsbTests/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_test {
+    name: "UsbTests",
+    srcs: ["**/*.java"],
+    static_libs: [
+        "frameworks-base-testutils",
+        "androidx.test.rules",
+        "mockito-target-inline-minus-junit4",
+        "platform-test-annotations",
+        "services.core",
+        "services.net",
+        "services.usb",
+        "truth-prebuilt",
+    ],
+    jni_libs: ["libdexmakerjvmtiagent"],
+    certificate: "platform",
+    platform_apis: true,
+    test_suites: ["device-tests"],
+}
diff --git a/tests/UsbTests/Android.mk b/tests/UsbTests/Android.mk
deleted file mode 100644
index aef993b..0000000
--- a/tests/UsbTests/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    frameworks-base-testutils \
-    androidx.test.rules \
-    mockito-target-inline-minus-junit4 \
-    platform-test-annotations \
-    services.core \
-    services.net \
-    services.usb \
-    truth-prebuilt \
-
-LOCAL_JNI_SHARED_LIBRARIES := \
-    libdexmakerjvmtiagent \
-
-LOCAL_CERTIFICATE := platform
-
-LOCAL_PACKAGE_NAME := UsbTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/tests/WindowAnimationJank/Android.bp b/tests/WindowAnimationJank/Android.bp
new file mode 100644
index 0000000..50b2297
--- /dev/null
+++ b/tests/WindowAnimationJank/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2015 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: "WindowAnimationJank",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "ub-uiautomator",
+        "androidx.test.janktesthelper",
+        "junit",
+    ],
+    libs: ["android.test.base.stubs"],
+    sdk_version: "current",
+}
diff --git a/tests/WindowAnimationJank/Android.mk b/tests/WindowAnimationJank/Android.mk
deleted file mode 100644
index 1c2d167..0000000
--- a/tests/WindowAnimationJank/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2015 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_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := WindowAnimationJank
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    ub-uiautomator \
-    androidx.test.janktesthelper \
-    junit
-
-LOCAL_JAVA_LIBRARIES := android.test.base.stubs
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/tests/net/java/com/android/internal/util/TestUtils.java b/tests/net/java/com/android/internal/util/TestUtils.java
index 7e5a1d3..57cc172 100644
--- a/tests/net/java/com/android/internal/util/TestUtils.java
+++ b/tests/net/java/com/android/internal/util/TestUtils.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
+import android.annotation.NonNull;
 import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -26,6 +27,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.concurrent.Executor;
+
 public final class TestUtils {
     private TestUtils() { }
 
@@ -54,6 +57,17 @@
         }
     }
 
+    /**
+     * Block until the given Serial Executor becomes idle, or until timeoutMs has passed.
+     */
+    public static void waitForIdleSerialExecutor(@NonNull Executor executor, long timeoutMs) {
+        final ConditionVariable cv = new ConditionVariable();
+        executor.execute(() -> cv.open());
+        if (!cv.block(timeoutMs)) {
+            fail(executor.toString() + " did not become idle after " + timeoutMs + " ms");
+        }
+    }
+
     // TODO : fetch the creator through reflection or something instead of passing it
     public static <T extends Parcelable, C extends Parcelable.Creator<T>>
             void assertParcelingIsLossless(T source, C creator) {
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 985d667..0633322 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -64,6 +64,7 @@
 
 import static com.android.internal.util.TestUtils.waitForIdleHandler;
 import static com.android.internal.util.TestUtils.waitForIdleLooper;
+import static com.android.internal.util.TestUtils.waitForIdleSerialExecutor;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -88,6 +89,7 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import android.annotation.NonNull;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -190,6 +192,8 @@
 
 import java.net.Inet4Address;
 import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -206,6 +210,7 @@
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 /**
@@ -2549,7 +2554,8 @@
         verifyActiveNetwork(TRANSPORT_CELLULAR);
     }
 
-    @Test
+    // TODO: deflake and re-enable
+    // @Test
     public void testPartialConnectivity() {
         // Register network callback.
         NetworkRequest request = new NetworkRequest.Builder()
@@ -3758,7 +3764,7 @@
             }
         }
 
-        private LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
+        private final LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
 
         @Override
         public void onStarted() {
@@ -3833,6 +3839,11 @@
         }
 
         private LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
+        private final Executor mExecutor;
+
+        TestSocketKeepaliveCallback(@NonNull Executor executor) {
+            mExecutor = executor;
+        }
 
         @Override
         public void onStarted() {
@@ -3870,6 +3881,12 @@
         public void expectError(int error) {
             expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
         }
+
+        public void assertNoCallback() {
+            waitForIdleSerialExecutor(mExecutor, TIMEOUT_MS);
+            CallbackValue cv = mCallbacks.peek();
+            assertNull("Unexpected callback: " + cv, cv);
+        }
     }
 
     private Network connectKeepaliveNetwork(LinkProperties lp) {
@@ -3976,19 +3993,6 @@
         myNet = connectKeepaliveNetwork(lp);
         mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
 
-        // Check things work as expected when the keepalive is stopped and the network disconnects.
-        ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
-        callback.expectStarted();
-        ka.stop();
-        mWiFiNetworkAgent.disconnect();
-        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
-        waitForIdle();
-        callback.expectStopped();
-
-        // Reconnect.
-        myNet = connectKeepaliveNetwork(lp);
-        mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
-
         // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
         mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
         ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
@@ -4018,17 +4022,24 @@
         callback3.expectStopped();
     }
 
-    @Test
-    public void testNattSocketKeepalives_SingleThreadExecutor() throws Exception {
+    // Helper method to prepare the executor and run test
+    private void runTestWithSerialExecutors(Consumer<Executor> functor) {
         final ExecutorService executorSingleThread = Executors.newSingleThreadExecutor();
-        doTestNattSocketKeepalivesWithExecutor(executorSingleThread);
+        final Executor executorInline = (Runnable r) -> r.run();
+        functor.accept(executorSingleThread);
         executorSingleThread.shutdown();
+        functor.accept(executorInline);
     }
 
     @Test
-    public void testNattSocketKeepalives_InlineExecutor() throws Exception {
-        final Executor executorInline = (Runnable r) -> r.run();
-        doTestNattSocketKeepalivesWithExecutor(executorInline);
+    public void testNattSocketKeepalives() {
+        runTestWithSerialExecutors(executor -> {
+            try {
+                doTestNattSocketKeepalivesWithExecutor(executor);
+            } catch (Exception e) {
+                fail(e.getMessage());
+            }
+        });
     }
 
     private void doTestNattSocketKeepalivesWithExecutor(Executor executor) throws Exception {
@@ -4057,7 +4068,7 @@
         Network notMyNet = new Network(61234);
         Network myNet = connectKeepaliveNetwork(lp);
 
-        TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback();
+        TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
         SocketKeepalive ka;
 
         // Attempt to start keepalives with invalid parameters and check for errors.
@@ -4100,6 +4111,22 @@
         ka.stop();
         callback.expectStopped();
 
+        // Check that keepalive could be restarted.
+        ka.start(validKaInterval);
+        callback.expectStarted();
+        ka.stop();
+        callback.expectStopped();
+
+        // Check that keepalive can be restarted without waiting for callback.
+        ka.start(validKaInterval);
+        callback.expectStarted();
+        ka.stop();
+        ka.start(validKaInterval);
+        callback.expectStopped();
+        callback.expectStarted();
+        ka.stop();
+        callback.expectStopped();
+
         // Check that deleting the IP address stops the keepalive.
         LinkProperties bogusLp = new LinkProperties(lp);
         ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback);
@@ -4124,20 +4151,7 @@
         final Network myNetAlias = myNet;
         assertNull(mCm.getNetworkCapabilities(myNetAlias));
         ka.stop();
-
-        // Reconnect.
-        myNet = connectKeepaliveNetwork(lp);
-        mWiFiNetworkAgent.setStartKeepaliveError(SocketKeepalive.SUCCESS);
-
-        // Check things work as expected when the keepalive is stopped and the network disconnects.
-        ka = mCm.createSocketKeepalive(myNet, testSocket, myIPv4, dstIPv4, executor, callback);
-        ka.start(validKaInterval);
-        callback.expectStarted();
-        ka.stop();
-        mWiFiNetworkAgent.disconnect();
-        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
-        waitForIdle();
-        callback.expectStopped();
+        callback.assertNoCallback();
 
         // Reconnect.
         myNet = connectKeepaliveNetwork(lp);
@@ -4152,7 +4166,7 @@
         // The second one gets slot 2.
         mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
         final UdpEncapsulationSocket testSocket2 = mIpSec.openUdpEncapsulationSocket(6789);
-        TestSocketKeepaliveCallback callback2 = new TestSocketKeepaliveCallback();
+        TestSocketKeepaliveCallback callback2 = new TestSocketKeepaliveCallback(executor);
         SocketKeepalive ka2 =
                 mCm.createSocketKeepalive(myNet, testSocket2, myIPv4, dstIPv4, executor, callback2);
         ka2.start(validKaInterval);
@@ -4169,6 +4183,81 @@
 
         mWiFiNetworkAgent.disconnect();
         waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        mWiFiNetworkAgent = null;
+    }
+
+    @Test
+    public void testTcpSocketKeepalives() {
+        runTestWithSerialExecutors(executor -> {
+            try {
+                doTestTcpSocketKeepalivesWithExecutor(executor);
+            } catch (Exception e) {
+                fail(e.getMessage());
+            }
+        });
+    }
+
+    private void doTestTcpSocketKeepalivesWithExecutor(Executor executor) throws Exception {
+        final int srcPortV4 = 12345;
+        final int srcPortV6 = 23456;
+        final InetAddress myIPv4 = InetAddress.getByName("127.0.0.1");
+        final InetAddress myIPv6 = InetAddress.getByName("::1");
+
+        final int validKaInterval = 15;
+        final int invalidKaInterval = 9;
+
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName("wlan12");
+        lp.addLinkAddress(new LinkAddress(myIPv6, 64));
+        lp.addLinkAddress(new LinkAddress(myIPv4, 25));
+        lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
+        lp.addRoute(new RouteInfo(InetAddress.getByName("127.0.0.254")));
+
+        final Network notMyNet = new Network(61234);
+        final Network myNet = connectKeepaliveNetwork(lp);
+
+        final Socket testSocketV4 = new Socket();
+        final Socket testSocketV6 = new Socket();
+
+        TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(executor);
+        SocketKeepalive ka;
+
+        // Attempt to start Tcp keepalives with invalid parameters and check for errors.
+        // Invalid network.
+        ka = mCm.createSocketKeepalive(notMyNet, testSocketV4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_NETWORK);
+
+        // Invalid Socket (socket is not bound with IPv4 address).
+        ka = mCm.createSocketKeepalive(myNet, testSocketV4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
+
+        // Invalid Socket (socket is not bound with IPv6 address).
+        ka = mCm.createSocketKeepalive(myNet, testSocketV6, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
+
+        // Bind the socket address
+        testSocketV4.bind(new InetSocketAddress(myIPv4, srcPortV4));
+        testSocketV6.bind(new InetSocketAddress(myIPv6, srcPortV6));
+
+        // Invalid Socket (socket is bound with IPv4 address).
+        ka = mCm.createSocketKeepalive(myNet, testSocketV4, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
+
+        // Invalid Socket (socket is bound with IPv6 address).
+        ka = mCm.createSocketKeepalive(myNet, testSocketV6, executor, callback);
+        ka.start(validKaInterval);
+        callback.expectError(SocketKeepalive.ERROR_INVALID_SOCKET);
+
+        testSocketV4.close();
+        testSocketV6.close();
+
+        mWiFiNetworkAgent.disconnect();
+        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
+        mWiFiNetworkAgent = null;
     }
 
     @Test
diff --git a/tools/processors/view_inspector/Android.bp b/tools/processors/view_inspector/Android.bp
index 06ff05e..069e61f 100644
--- a/tools/processors/view_inspector/Android.bp
+++ b/tools/processors/view_inspector/Android.bp
@@ -8,6 +8,7 @@
 
     static_libs: [
         "javapoet",
+        "stub-annotations",
     ],
 
     use_tools_jar: true,
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
index 2690ee8..c833e47 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
@@ -16,6 +16,8 @@
 
 package android.processor.view.inspector;
 
+import androidx.annotation.NonNull;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -40,7 +42,7 @@
     private final Elements mElementUtils;
     private final Types mTypeUtils;
 
-    AnnotationUtils(ProcessingEnvironment processingEnv) {
+    AnnotationUtils(@NonNull ProcessingEnvironment processingEnv) {
         mElementUtils = processingEnv.getElementUtils();
         mTypeUtils = processingEnv.getTypeUtils();
     }
@@ -53,7 +55,8 @@
      * @return The mirror of the requested annotation
      * @throws ProcessingException If there is not exactly one of the requested annotation.
      */
-    AnnotationMirror exactlyOneMirror(String qualifiedName, Element element) {
+    @NonNull
+    AnnotationMirror exactlyOneMirror(@NonNull String qualifiedName, @NonNull Element element) {
         final Element targetTypeElment = mElementUtils.getTypeElement(qualifiedName);
         final TypeMirror targetType = targetTypeElment.asType();
         AnnotationMirror result = null;
@@ -89,7 +92,7 @@
      * @param annotationQualifiedName The name of the annotation to check for
      * @return True if the annotation is present, false otherwise
      */
-    boolean hasAnnotation(Element element, String annotationQualifiedName) {
+    boolean hasAnnotation(@NonNull Element element, @NonNull String annotationQualifiedName) {
         final TypeElement namedElement = mElementUtils.getTypeElement(annotationQualifiedName);
 
         if (namedElement != null) {
@@ -118,10 +121,10 @@
      * @return A list containing the requested types
      */
     <T> List<T> typedArrayValuesByName(
-            String propertyName,
-            Class<T> valueClass,
-            Element element,
-            AnnotationMirror annotationMirror) {
+            @NonNull String propertyName,
+            @NonNull Class<T> valueClass,
+            @NonNull Element element,
+            @NonNull AnnotationMirror annotationMirror) {
         return untypedArrayValuesByName(propertyName, element, annotationMirror)
                 .stream()
                 .map(annotationValue -> {
@@ -159,10 +162,11 @@
      * @param annotationMirror An annotation mirror to search for the property
      * @return A list of annotation values, empty list if none found
      */
+    @NonNull
     List<AnnotationValue> untypedArrayValuesByName(
-            String propertyName,
-            Element element,
-            AnnotationMirror annotationMirror) {
+            @NonNull String propertyName,
+            @NonNull Element element,
+            @NonNull AnnotationMirror annotationMirror) {
         return typedValueByName(propertyName, List.class, element, annotationMirror)
                 .map(untypedValues -> {
                     List<AnnotationValue> typedValues = new ArrayList<>(untypedValues.size());
@@ -195,6 +199,7 @@
      * @param <T> The type of the value
      * @return An optional containing the typed value of the named property
      */
+    @NonNull
     <T> Optional<T> typedValueByName(
             String propertyName,
             Class<T> valueClass,
@@ -241,10 +246,11 @@
      * @return An optional containing the untyped value of the named property
      * @see AnnotationValue#getValue()
      */
+    @NonNull
     Optional<Object> untypedValueByName(
-            String propertyName,
-            Element element,
-            AnnotationMirror annotationMirror) {
+            @NonNull String propertyName,
+            @NonNull Element element,
+            @NonNull AnnotationMirror annotationMirror) {
         return valueByName(propertyName, annotationMirror).map(annotationValue -> {
             final Object value = annotationValue.getValue();
 
@@ -269,7 +275,10 @@
      * @param annotationMirror The mirror to search for the property
      * @return The value of the property
      */
-    Optional<AnnotationValue> valueByName(String propertyName, AnnotationMirror annotationMirror) {
+    @NonNull
+    Optional<AnnotationValue> valueByName(
+            @NonNull String propertyName,
+            @NonNull AnnotationMirror annotationMirror) {
         final Map<? extends ExecutableElement, ? extends AnnotationValue> valueMap =
                 annotationMirror.getElementValues();
 
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
index 1ad7ada..147f054 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
@@ -16,6 +16,9 @@
 
 package android.processor.view.inspector;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import com.squareup.javapoet.ClassName;
 
 import java.util.Collection;
@@ -34,27 +37,29 @@
  * testing {@link InspectionCompanionGenerator}.
  */
 public final class InspectableClassModel {
-    private final ClassName mClassName;
-    private final Map<String, Property> mPropertyMap;
-    private Optional<String> mNodeName = Optional.empty();
+    private final @NonNull ClassName mClassName;
+    private final @NonNull Map<String, Property> mPropertyMap;
+    private @NonNull Optional<String> mNodeName = Optional.empty();
 
     /**
      * @param className The name of the modeled class
      */
-    public InspectableClassModel(ClassName className) {
+    public InspectableClassModel(@NonNull ClassName className) {
         mClassName = className;
         mPropertyMap = new HashMap<>();
     }
 
+    @NonNull
     public ClassName getClassName() {
         return mClassName;
     }
 
+    @NonNull
     public Optional<String> getNodeName() {
         return mNodeName;
     }
 
-    public void setNodeName(Optional<String> nodeName) {
+    public void setNodeName(@NonNull Optional<String> nodeName) {
         mNodeName = nodeName;
     }
 
@@ -63,7 +68,7 @@
      *
      * @param property The property to add or replace
      */
-    public void putProperty(Property property) {
+    public void putProperty(@NonNull Property property) {
         mPropertyMap.put(property.getName(), property);
     }
 
@@ -73,7 +78,8 @@
      * @param name The name of the property
      * @return The property or an empty optional
      */
-    public Optional<Property> getProperty(String name) {
+    @NonNull
+    public Optional<Property> getProperty(@NonNull String name) {
         return Optional.ofNullable(mPropertyMap.get(name));
     }
 
@@ -82,6 +88,7 @@
      *
      * @return An un-ordered collection of properties
      */
+    @NonNull
     public Collection<Property> getAllProperties() {
         return mPropertyMap.values();
     }
@@ -90,8 +97,8 @@
      * Represents a way to access a property, either a getter or a field.
      */
     public static final class Accessor {
-        private final String mName;
-        private final Type mType;
+        private final @NonNull String mName;
+        private final @NonNull Type mType;
 
         /**
          * Construct an accessor for a field.
@@ -100,7 +107,8 @@
          * @return The new accessor
          * @see Type#FIELD
          */
-        static Accessor ofField(String name) {
+        @NonNull
+        static Accessor ofField(@NonNull String name) {
             return new Accessor(name, Type.FIELD);
         }
 
@@ -111,19 +119,22 @@
          * @return The new accessor
          * @see Type#GETTER
          */
-        static Accessor ofGetter(String name) {
+        @NonNull
+        static Accessor ofGetter(@NonNull String name) {
             return new Accessor(name, Type.GETTER);
         }
 
-        public Accessor(String name, Type type) {
+        public Accessor(@NonNull String name, @NonNull Type type) {
             mName = Objects.requireNonNull(name, "Accessor name must not be null");
             mType = Objects.requireNonNull(type, "Accessor type must not be null");
         }
 
+        @NonNull
         public String getName() {
             return mName;
         }
 
+        @NonNull
         public Type getType() {
             return mType;
         }
@@ -135,6 +146,7 @@
          *
          * @return A string representing the invocation of this accessor
          */
+        @NonNull
         public String invocation() {
             switch (mType) {
                 case FIELD:
@@ -168,15 +180,15 @@
      * Model an inspectable property
      */
     public static final class Property {
-        private final String mName;
-        private final Accessor mAccessor;
-        private final Type mType;
+        private final @NonNull String mName;
+        private final @NonNull Accessor mAccessor;
+        private final @NonNull Type mType;
         private boolean mAttributeIdInferrableFromR = true;
         private int mAttributeId = 0;
-        private List<IntEnumEntry> mIntEnumEntries;
-        private List<IntFlagEntry> mIntFlagEntries;
+        private @Nullable List<IntEnumEntry> mIntEnumEntries;
+        private @Nullable List<IntFlagEntry> mIntFlagEntries;
 
-        public Property(String name, Accessor accessor, Type type) {
+        public Property(@NonNull String name, @NonNull Accessor accessor, @NonNull Type type) {
             mName = Objects.requireNonNull(name, "Name must not be null");
             mAccessor = Objects.requireNonNull(accessor, "Accessor must not be null");
             mType = Objects.requireNonNull(type, "Type must not be null");
@@ -204,14 +216,17 @@
             mAttributeIdInferrableFromR = attributeIdInferrableFromR;
         }
 
+        @NonNull
         public String getName() {
             return mName;
         }
 
+        @NonNull
         public Accessor getAccessor() {
             return mAccessor;
         }
 
+        @NonNull
         public Type getType() {
             return mType;
         }
@@ -221,6 +236,7 @@
          *
          * @return A list of mapping entries, empty if absent
          */
+        @NonNull
         public List<IntEnumEntry> getIntEnumEntries() {
             if (mIntEnumEntries != null) {
                 return mIntEnumEntries;
@@ -229,7 +245,7 @@
             }
         }
 
-        public void setIntEnumEntries(List<IntEnumEntry> intEnumEntries) {
+        public void setIntEnumEntries(@NonNull List<IntEnumEntry> intEnumEntries) {
             mIntEnumEntries = intEnumEntries;
         }
 
@@ -238,6 +254,7 @@
          *
          * @return A list of mapping entries, empty if absent
          */
+        @NonNull
         public List<IntFlagEntry> getIntFlagEntries() {
             if (mIntFlagEntries != null) {
                 return mIntFlagEntries;
@@ -246,7 +263,7 @@
             }
         }
 
-        public void setIntFlagEntries(List<IntFlagEntry> intFlagEntries) {
+        public void setIntFlagEntries(@NonNull List<IntFlagEntry> intFlagEntries) {
             mIntFlagEntries = intFlagEntries;
         }
 
@@ -321,14 +338,15 @@
      * @see android.view.inspector.IntEnumMapping
      */
     public static final class IntEnumEntry {
-        private final String mName;
+        private final @NonNull String mName;
         private final int mValue;
 
-        public IntEnumEntry(String name, int value) {
+        public IntEnumEntry(int value, @NonNull String name) {
             mName = Objects.requireNonNull(name, "Name must not be null");
             mValue = value;
         }
 
+        @NonNull
         public String getName() {
             return mName;
         }
@@ -344,29 +362,21 @@
      * @see android.view.inspector.IntFlagMapping
      */
     public static final class IntFlagEntry {
-        private final String mName;
+        private final @NonNull String mName;
         private final int mTarget;
         private final int mMask;
 
-        public IntFlagEntry(String name, int target, int mask) {
+        public IntFlagEntry(int mask, int target, @NonNull String name) {
             mName = Objects.requireNonNull(name, "Name must not be null");
             mTarget = target;
             mMask = mask;
         }
 
-        public IntFlagEntry(String name, int target) {
-            this(name, target, target);
+        public IntFlagEntry(int target, String name) {
+            this(target, target, name);
         }
 
-        /**
-         * Determine if this entry has a bitmask.
-         *
-         * @return True if the bitmask and target are different, false otherwise
-         */
-        public boolean hasMask() {
-            return mTarget != mMask;
-        }
-
+        @NonNull
         public String getName() {
             return mName;
         }
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
index 46819b2..64a60fb 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
@@ -16,6 +16,8 @@
 
 package android.processor.view.inspector;
 
+import androidx.annotation.NonNull;
+
 import java.util.Optional;
 
 import javax.annotation.processing.ProcessingEnvironment;
@@ -28,17 +30,17 @@
  * @see android.view.inspector.InspectableNodeName
  */
 public final class InspectableNodeNameProcessor implements ModelProcessor {
-    private final String mQualifiedName;
-    private final ProcessingEnvironment mProcessingEnv;
-    private final AnnotationUtils mAnnotationUtils;
+    private final @NonNull String mQualifiedName;
+    private final @NonNull ProcessingEnvironment mProcessingEnv;
+    private final @NonNull AnnotationUtils mAnnotationUtils;
 
     /**
      * @param annotationQualifiedName The qualified name of the annotation to process
      * @param processingEnv The processing environment from the parent processor
      */
     public InspectableNodeNameProcessor(
-            String annotationQualifiedName,
-            ProcessingEnvironment processingEnv) {
+            @NonNull String annotationQualifiedName,
+            @NonNull ProcessingEnvironment processingEnv) {
         mQualifiedName = annotationQualifiedName;
         mProcessingEnv = processingEnv;
         mAnnotationUtils = new AnnotationUtils(processingEnv);
@@ -54,7 +56,7 @@
      * @param model The model this element should be merged into
      */
     @Override
-    public void process(Element element, InspectableClassModel model) {
+    public void process(@NonNull Element element, @NonNull InspectableClassModel model) {
         try {
             final AnnotationMirror mirror =
                     mAnnotationUtils.exactlyOneMirror(mQualifiedName, element);
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
index 20de90d..2042a68 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
@@ -21,6 +21,8 @@
 import android.processor.view.inspector.InspectableClassModel.IntFlagEntry;
 import android.processor.view.inspector.InspectableClassModel.Property;
 
+import androidx.annotation.NonNull;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
@@ -45,9 +47,9 @@
  * @see android.view.inspector.InspectableProperty
  */
 public final class InspectablePropertyProcessor implements ModelProcessor {
-    private final String mQualifiedName;
-    private final ProcessingEnvironment mProcessingEnv;
-    private final AnnotationUtils mAnnotationUtils;
+    private final @NonNull String mQualifiedName;
+    private final @NonNull ProcessingEnvironment mProcessingEnv;
+    private final @NonNull AnnotationUtils mAnnotationUtils;
 
     /**
      * Regex that matches methods names of the form {@code #getValue()}.
@@ -130,15 +132,15 @@
      * @param processingEnv           The processing environment from the parent processor
      */
     public InspectablePropertyProcessor(
-            String annotationQualifiedName,
-            ProcessingEnvironment processingEnv) {
+            @NonNull String annotationQualifiedName,
+            @NonNull ProcessingEnvironment processingEnv) {
         mQualifiedName = annotationQualifiedName;
         mProcessingEnv = processingEnv;
         mAnnotationUtils = new AnnotationUtils(processingEnv);
     }
 
     @Override
-    public void process(Element element, InspectableClassModel model) {
+    public void process(@NonNull Element element, @NonNull InspectableClassModel model) {
         try {
             final AnnotationMirror annotation =
                     mAnnotationUtils.exactlyOneMirror(mQualifiedName, element);
@@ -169,7 +171,10 @@
      * @return A property for the getter and annotation
      * @throws ProcessingException If the supplied data is invalid and a property cannot be modeled
      */
-    private Property buildProperty(Element accessor, AnnotationMirror annotation) {
+    @NonNull
+    private Property buildProperty(
+            @NonNull Element accessor,
+            @NonNull AnnotationMirror annotation) {
         final Property property;
         final Optional<String> nameFromAnnotation = mAnnotationUtils
                 .typedValueByName("name", String.class, accessor, annotation);
@@ -227,7 +232,7 @@
      * @param element The element to check
      * @throws ProcessingException If the element's modifiers are invalid
      */
-    private void validateModifiers(Element element) {
+    private void validateModifiers(@NonNull Element element) {
         final Set<Modifier> modifiers = element.getModifiers();
 
         if (!modifiers.contains(Modifier.PUBLIC)) {
@@ -256,7 +261,8 @@
      * @return An {@link ExecutableElement} that represents a getter method.
      * @throws ProcessingException if the element isn't a getter
      */
-    private ExecutableElement ensureGetter(Element element) {
+    @NonNull
+    private ExecutableElement ensureGetter(@NonNull Element element) {
         if (element.getKind() != ElementKind.METHOD) {
             throw new ProcessingException(
                     String.format("Expected a method, got a %s", element.getKind()),
@@ -300,10 +306,10 @@
      * @throws ProcessingException If the property type cannot be resolved or is invalid
      * @see android.view.inspector.InspectableProperty#valueType()
      */
+    @NonNull
     private Property.Type determinePropertyType(
-            Element accessor,
-            AnnotationMirror annotation) {
-
+            @NonNull Element accessor,
+            @NonNull AnnotationMirror annotation) {
         final String valueType = mAnnotationUtils
                 .untypedValueByName("valueType", accessor, annotation)
                 .map(Object::toString)
@@ -437,7 +443,8 @@
      * @return The return or field type of the element
      * @throws ProcessingException If the element is not a field or a method
      */
-    private TypeMirror extractReturnOrFieldType(Element element) {
+    @NonNull
+    private TypeMirror extractReturnOrFieldType(@NonNull Element element) {
         switch (element.getKind()) {
             case FIELD:
                 return element.asType();
@@ -460,7 +467,10 @@
      * @return The property type returned by the getter
      * @throws ProcessingException If the return type is not a primitive or an object
      */
-    private Property.Type convertTypeMirrorToPropertyType(TypeMirror typeMirror, Element element) {
+    @NonNull
+    private Property.Type convertTypeMirrorToPropertyType(
+            @NonNull TypeMirror typeMirror,
+            @NonNull Element element) {
         switch (unboxType(typeMirror)) {
             case BOOLEAN:
                 return Property.Type.BOOLEAN;
@@ -503,10 +513,10 @@
      * @throws ProcessingException If the return type is not an int
      */
     private static void requirePackedIntToBeInt(
-            String typeName,
-            Property.Type returnType,
-            Element accessor,
-            AnnotationMirror annotation) {
+            @NonNull String typeName,
+            @NonNull Property.Type returnType,
+            @NonNull Element accessor,
+            @NonNull AnnotationMirror annotation) {
         if (returnType != Property.Type.INT) {
             throw new ProcessingException(
                     String.format(
@@ -528,7 +538,7 @@
      * @param accessor The getter or field to query
      * @return True if the getter has a color annotation, false otherwise
      */
-    private boolean hasColorAnnotation(Element accessor) {
+    private boolean hasColorAnnotation(@NonNull Element accessor) {
         switch (unboxType(extractReturnOrFieldType(accessor))) {
             case INT:
                 for (String name : COLOR_INT_ANNOTATION_NAMES) {
@@ -555,7 +565,7 @@
      * @param accessor The getter or field to query
      * @return True if the accessor is an integer and has a resource ID annotation, false otherwise
      */
-    private boolean hasResourceIdAnnotation(Element accessor) {
+    private boolean hasResourceIdAnnotation(@NonNull Element accessor) {
         if (unboxType(extractReturnOrFieldType(accessor)) == TypeKind.INT) {
             for (String name : RESOURCE_ID_ANNOTATION_NAMES) {
                 if (mAnnotationUtils.hasAnnotation(accessor, name)) {
@@ -581,7 +591,8 @@
      * @param getter An element representing a getter
      * @return A string property name
      */
-    private String inferPropertyNameFromGetter(ExecutableElement getter) {
+    @NonNull
+    private String inferPropertyNameFromGetter(@NonNull ExecutableElement getter) {
         final String name = getter.getSimpleName().toString();
 
         if (GETTER_GET_PREFIX.matcher(name).find()) {
@@ -600,7 +611,6 @@
      * {@link android.view.inspector.InspectableProperty.EnumMap} annotations into
      * {@link IntEnumEntry} objects. Further validation should be handled elsewhere
      *
-     * @see android.view.inspector.IntEnumMapping
      * @see android.view.inspector.InspectableProperty#enumMapping()
      * @param accessor The accessor of the property, used for exceptions
      * @param annotation The {@link android.view.inspector.InspectableProperty} annotation to
@@ -608,9 +618,10 @@
      * @return A list of int enum entries, in the order specified in source
      * @throws ProcessingException if mapping doesn't exist or is invalid
      */
+    @NonNull
     private List<IntEnumEntry> processEnumMapping(
-            Element accessor,
-            AnnotationMirror annotation) {
+            @NonNull Element accessor,
+            @NonNull AnnotationMirror annotation) {
         List<AnnotationMirror> enumAnnotations = mAnnotationUtils.typedArrayValuesByName(
                 "enumMapping", AnnotationMirror.class, accessor, annotation);
         List<IntEnumEntry> enumEntries = new ArrayList<>(enumAnnotations.size());
@@ -623,23 +634,19 @@
         for (AnnotationMirror enumAnnotation : enumAnnotations) {
             final String name = mAnnotationUtils.typedValueByName(
                     "name", String.class, accessor, enumAnnotation)
-                    .orElseThrow(() -> {
-                        throw new ProcessingException(
-                                "Name is required for @EnumMap",
-                                accessor,
-                                enumAnnotation);
-                    });
+                    .orElseThrow(() -> new ProcessingException(
+                            "Name is required for @EnumMap",
+                            accessor,
+                            enumAnnotation));
 
             final int value = mAnnotationUtils.typedValueByName(
                     "value", Integer.class, accessor, enumAnnotation)
-                    .orElseThrow(() -> {
-                        throw new ProcessingException(
-                                "Value is required for @EnumMap",
-                                accessor,
-                                enumAnnotation);
-                    });
+                    .orElseThrow(() -> new ProcessingException(
+                            "Value is required for @EnumMap",
+                            accessor,
+                            enumAnnotation));
 
-            enumEntries.add(new IntEnumEntry(name, value));
+            enumEntries.add(new IntEnumEntry(value, name));
         }
 
         return enumEntries;
@@ -660,9 +667,10 @@
      * @return A list of int flags entries, in the order specified in source
      * @throws ProcessingException if mapping doesn't exist or is invalid
      */
+    @NonNull
     private List<IntFlagEntry> processFlagMapping(
-            Element accessor,
-            AnnotationMirror annotation) {
+            @NonNull Element accessor,
+            @NonNull AnnotationMirror annotation) {
         List<AnnotationMirror> flagAnnotations = mAnnotationUtils.typedArrayValuesByName(
                 "flagMapping", AnnotationMirror.class, accessor, annotation);
         List<IntFlagEntry> flagEntries = new ArrayList<>(flagAnnotations.size());
@@ -675,29 +683,25 @@
         for (AnnotationMirror flagAnnotation : flagAnnotations) {
             final String name = mAnnotationUtils.typedValueByName(
                     "name", String.class, accessor, flagAnnotation)
-                    .orElseThrow(() -> {
-                        throw new ProcessingException(
-                                "Name is required for @FlagMap",
-                                accessor,
-                                flagAnnotation);
-                    });
+                    .orElseThrow(() -> new ProcessingException(
+                            "Name is required for @FlagMap",
+                            accessor,
+                            flagAnnotation));
 
             final int target = mAnnotationUtils.typedValueByName(
                     "target", Integer.class, accessor, flagAnnotation)
-                    .orElseThrow(() -> {
-                        throw new ProcessingException(
-                                "Target is required for @FlagMap",
-                                accessor,
-                                flagAnnotation);
-                    });
+                    .orElseThrow(() -> new ProcessingException(
+                            "Target is required for @FlagMap",
+                            accessor,
+                            flagAnnotation));
 
             final Optional<Integer> mask = mAnnotationUtils.typedValueByName(
                     "mask", Integer.class, accessor, flagAnnotation);
 
             if (mask.isPresent()) {
-                flagEntries.add(new IntFlagEntry(name, target, mask.get()));
+                flagEntries.add(new IntFlagEntry(mask.get(), target, name));
             } else {
-                flagEntries.add(new IntFlagEntry(name, target));
+                flagEntries.add(new IntFlagEntry(target, name));
             }
         }
 
@@ -710,7 +714,7 @@
      * @param type The type mirror to check
      * @return True if the type is a boolean
      */
-    private boolean isBoolean(TypeMirror type) {
+    private boolean isBoolean(@NonNull TypeMirror type) {
         if (type.getKind() == TypeKind.DECLARED) {
             return mProcessingEnv.getTypeUtils().unboxedType(type).getKind() == TypeKind.BOOLEAN;
         } else {
@@ -724,7 +728,8 @@
      * @param typeMirror The type mirror to unbox
      * @return The same type mirror, or an unboxed primitive version
      */
-    private TypeKind unboxType(TypeMirror typeMirror) {
+    @NonNull
+    private TypeKind unboxType(@NonNull TypeMirror typeMirror) {
         final TypeKind typeKind = typeMirror.getKind();
 
         if (typeKind.isPrimitive()) {
@@ -746,7 +751,7 @@
      * @param typeMirror The type mirror to test
      * @return True if it represents a subclass of color, false otherwise
      */
-    private boolean isColorType(TypeMirror typeMirror) {
+    private boolean isColorType(@NonNull TypeMirror typeMirror) {
         final TypeElement colorType = mProcessingEnv
                 .getElementUtils()
                 .getTypeElement("android.graphics.Color");
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
index 6f6c1aa..c428a46 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
@@ -16,11 +16,12 @@
 
 package android.processor.view.inspector;
 
-
 import android.processor.view.inspector.InspectableClassModel.IntEnumEntry;
 import android.processor.view.inspector.InspectableClassModel.IntFlagEntry;
 import android.processor.view.inspector.InspectableClassModel.Property;
 
+import androidx.annotation.NonNull;
+
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.CodeBlock;
 import com.squareup.javapoet.FieldSpec;
@@ -34,9 +35,11 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.NoSuchElementException;
-import java.util.Optional;
+import java.util.stream.Collectors;
 
 import javax.annotation.processing.Filer;
 import javax.lang.model.element.Modifier;
@@ -45,8 +48,8 @@
  * Generates a source file defining a {@link android.view.inspector.InspectionCompanion}.
  */
 public final class InspectionCompanionGenerator {
-    private final Filer mFiler;
-    private final Class mRequestingClass;
+    private final @NonNull Filer mFiler;
+    private final @NonNull Class mRequestingClass;
 
     /**
      * The class name for {@code R.java}.
@@ -72,10 +75,9 @@
             "android.view.inspector", "PropertyReader");
 
     /**
-     * The class name of {@link android.view.inspector.IntEnumMapping}.
+     * The class name of {@link android.util.SparseArray}.
      */
-    private static final ClassName INT_ENUM_MAPPING = ClassName.get(
-            "android.view.inspector", "IntEnumMapping");
+    private static final ClassName SPARSE_ARRAY = ClassName.get("android.util", "SparseArray");
 
     /**
      * The class name of {@link android.view.inspector.IntFlagMapping}.
@@ -84,17 +86,6 @@
             "android.view.inspector", "IntFlagMapping");
 
     /**
-     * The {@code mPropertiesMapped} field.
-     */
-    private static final FieldSpec M_PROPERTIES_MAPPED = FieldSpec
-            .builder(TypeName.BOOLEAN, "mPropertiesMapped", Modifier.PRIVATE)
-            .initializer("false")
-            .addJavadoc(
-                    "Set by {@link #mapProperties($T)} once properties have been mapped.\n",
-                    PROPERTY_MAPPER)
-            .build();
-
-    /**
      * The suffix of the generated class name after the class's binary name.
      */
     private static final String GENERATED_CLASS_SUFFIX = "$InspectionCompanion";
@@ -110,7 +101,7 @@
      * @param filer A filer to write the generated source to
      * @param requestingClass A class object representing the class that invoked the generator
      */
-    public InspectionCompanionGenerator(Filer filer, Class requestingClass) {
+    public InspectionCompanionGenerator(@NonNull Filer filer, @NonNull Class requestingClass) {
         mFiler = filer;
         mRequestingClass = requestingClass;
     }
@@ -121,7 +112,7 @@
      * @param model The model to generated
      * @throws IOException From the Filer
      */
-    public void generate(InspectableClassModel model) throws IOException {
+    public void generate(@NonNull InspectableClassModel model) throws IOException {
         generateFile(model).writeTo(mFiler);
     }
 
@@ -133,7 +124,8 @@
      * @param model The model to generate from
      * @return A generated file of an {@link android.view.inspector.InspectionCompanion}
      */
-    JavaFile generateFile(InspectableClassModel model) {
+    @NonNull
+    JavaFile generateFile(@NonNull InspectableClassModel model) {
         return JavaFile
                 .builder(model.getClassName().packageName(), generateTypeSpec(model))
                 .indent("    ")
@@ -147,8 +139,12 @@
      * @param model The model to generate from
      * @return A TypeSpec of the inspection companion
      */
-    private TypeSpec generateTypeSpec(InspectableClassModel model) {
-        final List<PropertyIdField> propertyIdFields = generatePropertyIdFields(model);
+    @NonNull
+    private TypeSpec generateTypeSpec(@NonNull InspectableClassModel model) {
+        final List<Property> properties = new ArrayList<>(model.getAllProperties());
+        properties.sort(Comparator.comparing(Property::getName));
+
+        final Map<Property, FieldSpec> fields = generateIdFieldSpecs(properties);
 
         TypeSpec.Builder builder = TypeSpec
                 .classBuilder(generateClassName(model))
@@ -158,238 +154,325 @@
                 .addJavadoc("Inspection companion for {@link $T}.\n\n", model.getClassName())
                 .addJavadoc("Generated by {@link $T}\n", getClass())
                 .addJavadoc("on behalf of {@link $T}.\n", mRequestingClass)
-                .addField(M_PROPERTIES_MAPPED);
+                .addField(FieldSpec
+                        .builder(TypeName.BOOLEAN, "mPropertiesMapped", Modifier.PRIVATE)
+                        .initializer("false")
+                        .addJavadoc("Guards against reading properties before mapping them.\n")
+                        .build())
+                .addFields(properties.stream().map(fields::get).collect(Collectors.toList()))
+                .addMethod(generateMapProperties(properties, fields))
+                .addMethod(generateReadProperties(properties, fields, model.getClassName()));
 
-        for (PropertyIdField propertyIdField : propertyIdFields) {
-            builder.addField(propertyIdField.mFieldSpec);
-        }
-
-        builder.addMethod(generateMapProperties(propertyIdFields))
-                .addMethod(generateReadProperties(model, propertyIdFields));
-
-        generateGetNodeName(model).ifPresent(builder::addMethod);
+        model.getNodeName().ifPresent(name -> builder.addMethod(generateGetNodeName(name)));
 
         return builder.build();
     }
 
     /**
-     * Build a list of {@link PropertyIdField}'s for a model.
+     * Map properties to fields to store the mapping IDs in the generated inspection companion.
      *
-     * To insure idempotency of the generated code, this method sorts the list of properties
-     * alphabetically by name.
-     *
-     * A {@link NameAllocator} is used to ensure that the field names are valid Java identifiers,
-     * and it prevents overlaps in names by suffixing them as needed.
-     *
-     * @param model The model to get properties from
-     * @return A list of properties and fields
+     * @param properties A list of property models
+     * @return A map of properties to their {@link FieldSpec}
      */
-    private List<PropertyIdField> generatePropertyIdFields(InspectableClassModel model) {
-        final NameAllocator nameAllocator = new NameAllocator();
-        final List<Property> sortedProperties = new ArrayList<>(model.getAllProperties());
-        final List<PropertyIdField> propertyIdFields = new ArrayList<>(sortedProperties.size());
+    @NonNull
+    private Map<Property, FieldSpec> generateIdFieldSpecs(@NonNull List<Property> properties) {
+        final Map<Property, FieldSpec> fields = new HashMap<>();
+        final NameAllocator fieldNames = new NameAllocator();
+        fieldNames.newName("mPropertiesMapped");
 
-        sortedProperties.sort(Comparator.comparing(Property::getName));
-
-        for (Property property : sortedProperties) {
-            // Format a property to a member field name like "someProperty" -> "mSomePropertyId"
-            final String memberName = String.format(
+        for (Property property : properties) {
+            final String memberName = fieldNames.newName(String.format(
                     "m%s%sId",
                     property.getName().substring(0, 1).toUpperCase(),
-                    property.getName().substring(1));
-            final FieldSpec fieldSpec = FieldSpec
-                    .builder(TypeName.INT, nameAllocator.newName(memberName), Modifier.PRIVATE)
-                    .addJavadoc("Property ID of {@code $L}.\n", property.getName())
-                    .build();
+                    property.getName().substring(1)));
 
-            propertyIdFields.add(new PropertyIdField(fieldSpec, property));
+            fields.put(property, FieldSpec
+                    .builder(TypeName.INT, memberName, Modifier.PRIVATE)
+                    .addJavadoc("Property ID of {@code $L}.\n", property.getName())
+                    .build());
         }
 
-        return propertyIdFields;
+        return fields;
     }
 
     /**
-     * Generate a method definition for
-     * {@link android.view.inspector.InspectionCompanion#getNodeName()}, if needed.
-     *
-     * If {@link InspectableClassModel#getNodeName()} is empty, This method returns an empty
-     * optional, otherwise, it generates a simple method that returns the string value of the
-     * node name.
-     *
-     * @param model The model to generate from
-     * @return The method definition or an empty Optional
-     */
-    private Optional<MethodSpec> generateGetNodeName(InspectableClassModel model) {
-        return model.getNodeName().map(nodeName -> MethodSpec.methodBuilder("getNodeName")
-                .addAnnotation(Override.class)
-                .addModifiers(Modifier.PUBLIC)
-                .returns(String.class)
-                .addStatement("return $S", nodeName)
-                .build());
-    }
-
-    /**
-     * Generate a method definition for
+     * Generates an implementation of
      * {@link android.view.inspector.InspectionCompanion#mapProperties(
      * android.view.inspector.PropertyMapper)}.
      *
-     * @param propertyIdFields A list of properties to map to ID fields
-     * @return The method definition
+     * Example:
+     * <pre>
+     *     @Override
+     *     public void mapProperties(PropertyMapper propertyMapper) {
+     *         mValueId = propertyMapper.mapInt("value", R.attr.value);
+     *         mPropertiesMapped = true;
+     *     }
+     * </pre>
+     *
+     * @param properties A sorted list of property models
+     * @param fields A map of properties to their ID field specs
+     * @return A method definition
      */
-    private MethodSpec generateMapProperties(List<PropertyIdField> propertyIdFields) {
+    @NonNull
+    private MethodSpec generateMapProperties(
+            @NonNull List<Property> properties,
+            @NonNull Map<Property, FieldSpec> fields) {
+        final NameAllocator mappingVariables = new NameAllocator();
+
         final MethodSpec.Builder builder = MethodSpec.methodBuilder("mapProperties")
                 .addAnnotation(Override.class)
                 .addModifiers(Modifier.PUBLIC)
                 .addParameter(PROPERTY_MAPPER, "propertyMapper");
 
-        propertyIdFields.forEach(p -> builder.addStatement(generatePropertyMapperInvocation(p)));
-        builder.addStatement("$N = true", M_PROPERTIES_MAPPED);
+        // Reserve existing names
+        mappingVariables.newName("mPropertiesMapped");
+        mappingVariables.newName("propertyMapper");
+        properties.forEach(p -> mappingVariables.newName(fields.get(p).name));
 
-        return builder.build();
-    }
-
-    /**
-     * Generate a method definition for
-     * {@link android.view.inspector.InspectionCompanion#readProperties(
-     * Object, android.view.inspector.PropertyReader)}.
-     *
-     * @param model The model to generate from
-     * @param propertyIdFields A list of properties and ID fields to read from
-     * @return The method definition
-     */
-    private MethodSpec generateReadProperties(
-            InspectableClassModel model,
-            List<PropertyIdField> propertyIdFields) {
-        final MethodSpec.Builder builder =  MethodSpec.methodBuilder("readProperties")
-                .addAnnotation(Override.class)
-                .addModifiers(Modifier.PUBLIC)
-                .addParameter(model.getClassName(), "node")
-                .addParameter(PROPERTY_READER, "propertyReader")
-                .addCode(generatePropertyMapInitializationCheck());
-
-        for (PropertyIdField propertyIdField : propertyIdFields) {
-            builder.addStatement(
-                    "propertyReader.read$L($N, node.$L)",
-                    methodSuffixForPropertyType(propertyIdField.mProperty.getType()),
-                    propertyIdField.mFieldSpec,
-                    propertyIdField.mProperty.getAccessor().invocation());
-        }
-
-        return builder.build();
-    }
-
-    /**
-     * Generate a statement maps a property with a {@link android.view.inspector.PropertyMapper}.
-     *
-     * @param propertyIdField The property model and ID field to generate from
-     * @return A statement that invokes property mapper method
-     */
-    private CodeBlock generatePropertyMapperInvocation(PropertyIdField propertyIdField) {
-        final CodeBlock.Builder builder = CodeBlock.builder();
-        final Property property = propertyIdField.mProperty;
-        final FieldSpec fieldSpec = propertyIdField.mFieldSpec;
-
-        builder.add(
-                "$N = propertyMapper.map$L($S,$W",
-                fieldSpec,
-                methodSuffixForPropertyType(property.getType()),
-                property.getName());
-
-        if (property.isAttributeIdInferrableFromR()) {
-            builder.add("$T.attr.$L", R_CLASS_NAME, property.getName());
-        } else {
-            if (property.getAttributeId() == ID_NULL) {
-                builder.add("$L", ID_NULL);
-            } else {
-                builder.add("$L", hexLiteral(property.getAttributeId()));
+        for (Property property : properties) {
+            final FieldSpec field = fields.get(property);
+            switch (property.getType()) {
+                case INT_ENUM:
+                    builder.addCode(generateIntEnumPropertyMapperInvocation(
+                            property,
+                            field,
+                            mappingVariables.newName(property.getName() + "EnumMapping")));
+                    break;
+                case INT_FLAG:
+                    builder.addCode(generateIntFlagPropertyMapperInvocation(
+                            property,
+                            field,
+                            mappingVariables.newName(property.getName() + "FlagMapping")));
+                    break;
+                default:
+                    builder.addCode(generateSimplePropertyMapperInvocation(property, field));
             }
         }
 
-        switch (property.getType()) {
-            case INT_ENUM:
-                builder.add(",$W");
-                builder.add(generateIntEnumMappingBuilder(property.getIntEnumEntries()));
-                break;
-            case INT_FLAG:
-                builder.add(",$W");
-                builder.add(generateIntFlagMappingBuilder(property.getIntFlagEntries()));
-                break;
-        }
+        builder.addStatement("mPropertiesMapped = true");
 
-        return builder.add(")").build();
+        return builder.build();
     }
 
     /**
-     * Generate a check that throws
-     * {@link android.view.inspector.InspectionCompanion.UninitializedPropertyMapException}
-     * if the properties haven't been initialized.
+     * Generate a {@link android.view.inspector.PropertyMapper} invocation.
      *
+     * Example:
      * <pre>
-     *     if (!mPropertiesMapped) {
-     *         throw new InspectionCompanion.UninitializedPropertyMapException();
-     *     }
+     *     mValueId = propertyMapper.mapInt("value", R.attr.value);
      * </pre>
      *
-     * @return A codeblock containing the property map initialization check
+     * @param property A property model to map
+     * @param field The property ID field for the property
+     * @return A code block containing a statement
      */
-    private CodeBlock generatePropertyMapInitializationCheck() {
-        return CodeBlock.builder()
-                .beginControlFlow("if (!$N)", M_PROPERTIES_MAPPED)
+    @NonNull
+    private CodeBlock generateSimplePropertyMapperInvocation(
+            @NonNull Property property,
+            @NonNull FieldSpec field) {
+        return CodeBlock
+                .builder()
                 .addStatement(
-                        "throw new $T()",
-                        INSPECTION_COMPANION.nestedClass("UninitializedPropertyMapException"))
-                .endControlFlow()
+                        "$N = propertyMapper.map$L($S, $L)",
+                        field,
+                        methodSuffixForPropertyType(property.getType()),
+                        property.getName(),
+                        generateAttributeId(property))
                 .build();
     }
 
     /**
-     * Generate an invocation of {@link android.view.inspector.IntEnumMapping.Builder}.
+     * Generate a {@link android.view.inspector.PropertyMapper} invocation for an int enum.
      *
+     * Example:
      * <pre>
-     *      new IntEnumMapping.Builder()
-     *          .addValue("ONE", 1)
-     *          .build()
+     *     final SparseArray<String> valueEnumMapping = new SparseArray<>();
+     *     valueEnumMapping.put(1, "ONE");
+     *     valueEnumMapping.put(2, "TWO");
+     *     mValueId = propertyMapper.mapIntEnum("value", R.attr.value, valueEnumMapping::get);
      * </pre>
      *
-     * @return A codeblock containing the an int enum mapping builder
+     * @param property A property model to map
+     * @param field The property ID field for the property
+     * @param variable The name of a local variable to use to store the mapping in
+     * @return A code block containing a series of statements
      */
-    private CodeBlock generateIntEnumMappingBuilder(List<IntEnumEntry> intEnumEntries) {
-        final ArrayList<IntEnumEntry> sortedEntries = new ArrayList<>(intEnumEntries);
-        sortedEntries.sort(Comparator.comparing(IntEnumEntry::getValue));
+    @NonNull
+    private CodeBlock generateIntEnumPropertyMapperInvocation(
+            @NonNull Property property,
+            @NonNull FieldSpec field,
+            @NonNull String variable) {
+        final CodeBlock.Builder builder = CodeBlock.builder();
 
-        final CodeBlock.Builder builder = CodeBlock.builder()
-                .add("new $T()$>", INT_ENUM_MAPPING.nestedClass("Builder"));
+        final List<IntEnumEntry> enumEntries = property.getIntEnumEntries();
+        enumEntries.sort(Comparator.comparing(IntEnumEntry::getValue));
 
-        for (IntEnumEntry entry : sortedEntries) {
-            builder.add("\n.addValue($S, $L)", entry.getName(), entry.getValue());
+        builder.addStatement(
+                "final $1T<$2T> $3N = new $1T<>()",
+                SPARSE_ARRAY,
+                String.class,
+                variable);
+
+        for (IntEnumEntry enumEntry : enumEntries) {
+            builder.addStatement(
+                    "$N.put($L, $S)",
+                    variable,
+                    enumEntry.getValue(),
+                    enumEntry.getName());
         }
 
-        return builder.add("\n.build()$<").build();
+        builder.addStatement(
+                "$N = propertyMapper.mapIntEnum($S, $L, $N::get)",
+                field,
+                property.getName(),
+                generateAttributeId(property),
+                variable);
+
+        return builder.build();
     }
 
-    private CodeBlock generateIntFlagMappingBuilder(List<IntFlagEntry> intFlagEntries) {
-        final ArrayList<IntFlagEntry> sortedEntries = new ArrayList<>(intFlagEntries);
-        sortedEntries.sort(Comparator.comparing(IntFlagEntry::getName));
+    /**
+     * Generate a {@link android.view.inspector.PropertyMapper} invocation for an int flag.
+     *
+     * Example:
+     * <pre>
+     *     final IntFlagMapping valueFlagMapping = new IntFlagMapping();
+     *     valueFlagMapping.add(0x00000003, 0x00000001, "ONE");
+     *     valueFlagMapping.add(0x00000003, 0x00000002, "TWO");
+     *     mValueId = propertyMapper.mapIntFlag("value", R.attr.value, valueFlagMapping::get);
+     * </pre>
+     *
+     * @param property A property model to map
+     * @param field The property ID field for the property
+     * @param variable The name of a local variable to use to store the mapping in
+     * @return A code block containing a series of statements
+     */
+    @NonNull
+    private CodeBlock generateIntFlagPropertyMapperInvocation(
+            @NonNull Property property,
+            @NonNull FieldSpec field,
+            @NonNull String variable) {
+        final CodeBlock.Builder builder = CodeBlock.builder();
 
-        final CodeBlock.Builder builder = CodeBlock.builder()
-                .add("new $T()$>", INT_FLAG_MAPPING.nestedClass("Builder"));
+        final List<IntFlagEntry> flagEntries = property.getIntFlagEntries();
+        flagEntries.sort(Comparator.comparing(IntFlagEntry::getName));
 
-        for (IntFlagEntry entry : sortedEntries) {
-            if (entry.hasMask()) {
-                builder.add(
-                        "\n.addFlag($S, $L, $L)",
-                        entry.getName(),
-                        hexLiteral(entry.getTarget()),
-                        hexLiteral(entry.getMask()));
-            } else {
-                builder.add(
-                        "\n.addFlag($S, $L)",
-                        entry.getName(),
-                        hexLiteral(entry.getTarget()));
-            }
+        builder.addStatement(
+                "final $1T $2N = new $1T()",
+                INT_FLAG_MAPPING,
+                variable);
+
+        for (IntFlagEntry flagEntry : flagEntries) {
+            builder.addStatement(
+                    "$N.add($L, $L, $S)",
+                    variable,
+                    hexLiteral(flagEntry.getMask()),
+                    hexLiteral(flagEntry.getTarget()),
+                    flagEntry.getName());
         }
 
-        return builder.add("\n.build()$<").build();
+        builder.addStatement(
+                "$N = propertyMapper.mapIntFlag($S, $L, $N::get)",
+                field,
+                property.getName(),
+                generateAttributeId(property),
+                variable);
+
+        return builder.build();
+    }
+
+    /**
+     * Generate a literal attribute ID or reference to {@link android.R.attr}.
+     *
+     * Example: {@code R.attr.value} or {@code 0xdecafbad}.
+     *
+     * @param property A property model
+     * @return A code block containing the attribute ID
+     */
+    @NonNull
+    private CodeBlock generateAttributeId(@NonNull Property property) {
+        if (property.isAttributeIdInferrableFromR()) {
+            return CodeBlock.of("$T.attr.$L", R_CLASS_NAME, property.getName());
+        } else {
+            if (property.getAttributeId() == ID_NULL) {
+                return CodeBlock.of("$L", ID_NULL);
+            } else {
+                return CodeBlock.of("$L", hexLiteral(property.getAttributeId()));
+            }
+        }
+    }
+
+    /**
+     * Generate an implementation of
+     * {@link android.view.inspector.InspectionCompanion#readProperties(Object,
+     * android.view.inspector.PropertyReader)}.
+     *
+     * Example:
+     * <pre>
+     *     @Override
+     *     public void readProperties(MyNode node, PropertyReader propertyReader) {
+     *         if (!mPropertiesMapped) {
+     *             throw new InspectionCompanion.UninitializedPropertyMapException();
+     *         }
+     *         propertyReader.readInt(mValueId, node.getValue());
+     *     }
+     * </pre>
+     *
+     * @param properties An ordered list of property models
+     * @param fields A map from properties to their field specs
+     * @param nodeClass The class of the node, used for the parameter type
+     * @return A method definition
+     */
+    @NonNull
+    private MethodSpec generateReadProperties(
+            @NonNull List<Property> properties,
+            @NonNull Map<Property, FieldSpec> fields,
+            @NonNull ClassName nodeClass) {
+        final MethodSpec.Builder builder =  MethodSpec.methodBuilder("readProperties")
+                .addAnnotation(Override.class)
+                .addModifiers(Modifier.PUBLIC)
+                .addParameter(nodeClass, "node")
+                .addParameter(PROPERTY_READER, "propertyReader")
+                .beginControlFlow("if (!mPropertiesMapped)")
+                .addStatement(
+                        "throw new $T()",
+                        INSPECTION_COMPANION.nestedClass("UninitializedPropertyMapException"))
+                .endControlFlow();
+
+        for (Property property : properties) {
+            builder.addStatement(
+                    "propertyReader.read$L($N, node.$L)",
+                    methodSuffixForPropertyType(property.getType()),
+                    fields.get(property),
+                    property.getAccessor().invocation());
+        }
+
+        return builder.build();
+    }
+
+    /**
+     * Generate an implementation of
+     * {@link android.view.inspector.InspectionCompanion#getNodeName()}.
+     *
+     * Example:
+     * <pre>
+     *     @Override
+     *     public String getNodeName() {
+     *         return "nodeName";
+     *     }
+     * </pre>
+     *
+     * @param nodeName The name of this node
+     * @return A method definition that returns the node name
+     */
+    @NonNull
+    private MethodSpec generateGetNodeName(@NonNull String nodeName) {
+        return MethodSpec.methodBuilder("getNodeName")
+                .addAnnotation(Override.class)
+                .addModifiers(Modifier.PUBLIC)
+                .returns(String.class)
+                .addStatement("return $S", nodeName)
+                .build();
     }
 
     /**
@@ -397,14 +480,15 @@
      *
      * The generated class is added to the same package as the source class. If the class in the
      * model is a nested class, the nested class names are joined with {@code "$"}. The suffix
-     * {@code "$$InspectionCompanion"} is always added the the generated name. E.g.: For modeled
+     * {@code "$InspectionCompanion"} is always added to the generated name. E.g.: For modeled
      * class {@code com.example.Outer.Inner}, the generated class name will be
-     * {@code com.example.Outer$Inner$$InspectionCompanion}.
+     * {@code com.example.Outer$Inner$InspectionCompanion}.
      *
      * @param model The model to generate from
      * @return A class name for the generated inspection companion class
      */
-    private static ClassName generateClassName(InspectableClassModel model) {
+    @NonNull
+    private static ClassName generateClassName(@NonNull InspectableClassModel model) {
         final ClassName className = model.getClassName();
 
         return ClassName.get(
@@ -418,7 +502,8 @@
      * @param type The requested property type
      * @return A method suffix
      */
-    private static String methodSuffixForPropertyType(Property.Type type) {
+    @NonNull
+    private static String methodSuffixForPropertyType(@NonNull Property.Type type) {
         switch (type) {
             case BOOLEAN:
                 return "Boolean";
@@ -453,20 +538,14 @@
         }
     }
 
+    /**
+     * Format an int as an 8 digit hex literal
+     *
+     * @param value The value to format
+     * @return A string representation of the hex literal
+     */
+    @NonNull
     private static String hexLiteral(int value) {
         return String.format("0x%08x", value);
     }
-
-    /**
-     * Value class that holds a {@link Property} and a {@link FieldSpec} for that property.
-     */
-    private static final class PropertyIdField {
-        private final FieldSpec mFieldSpec;
-        private final Property mProperty;
-
-        private PropertyIdField(FieldSpec fieldSpec, Property property) {
-            mFieldSpec = fieldSpec;
-            mProperty = property;
-        }
-    }
 }
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
index 6f52260..ab38f4c 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
@@ -16,6 +16,8 @@
 
 package android.processor.view.inspector;
 
+import androidx.annotation.NonNull;
+
 import javax.lang.model.element.Element;
 
 /**
@@ -28,5 +30,5 @@
      * @param element The annotated element to operate on
      * @param model The model this element should be merged into
      */
-    void process(Element element, InspectableClassModel model);
+    void process(@NonNull Element element, @NonNull InspectableClassModel model);
 }
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
index fd142c6..d9ed1fb 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
@@ -18,6 +18,8 @@
 
 import static javax.tools.Diagnostic.Kind.ERROR;
 
+import androidx.annotation.NonNull;
+
 import com.squareup.javapoet.ClassName;
 
 import java.io.IOException;
@@ -63,7 +65,9 @@
     }
 
     @Override
-    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+    public boolean process(
+            @NonNull Set<? extends TypeElement> annotations,
+            @NonNull RoundEnvironment roundEnv) {
         final Map<String, InspectableClassModel> modelMap = new HashMap<>();
 
         for (TypeElement annotation : annotations) {
@@ -109,9 +113,9 @@
      * @param modelMap A map of qualified class names to models
      */
     private void runModelProcessor(
-            Set<? extends Element> elements,
-            ModelProcessor processor,
-            Map<String, InspectableClassModel> modelMap) {
+            @NonNull Set<? extends Element> elements,
+            @NonNull ModelProcessor processor,
+            @NonNull Map<String, InspectableClassModel> modelMap) {
         for (Element element : elements) {
             final Optional<TypeElement> classElement = enclosingClassElement(element);
 
@@ -149,7 +153,7 @@
      * @param typeElement A type element representing the class to check
      * @return f the class contains a class named {@code InspectionCompanion}
      */
-    private static boolean hasNestedInspectionCompanion(TypeElement typeElement) {
+    private static boolean hasNestedInspectionCompanion(@NonNull TypeElement typeElement) {
         for (TypeElement nestedClass : ElementFilter.typesIn(typeElement.getEnclosedElements())) {
             if (nestedClass.getSimpleName().toString().equals("InspectionCompanion")) {
                 return true;
@@ -167,7 +171,8 @@
      * @param element An element to search from
      * @return A TypeElement of the nearest enclosing class or an empty optional
      */
-    private static Optional<TypeElement> enclosingClassElement(Element element) {
+    @NonNull
+    private static Optional<TypeElement> enclosingClassElement(@NonNull Element element) {
         Element cursor = element;
 
         while (cursor != null) {
@@ -186,7 +191,7 @@
      *
      * @param message Message to print
      */
-    private void fail(String message) {
+    private void fail(@NonNull String message) {
         processingEnv.getMessager().printMessage(ERROR, message);
     }
 
@@ -196,7 +201,7 @@
      * @param message Message to print
      * @param element The element that failed
      */
-    private void fail(String message, Element element) {
+    private void fail(@NonNull String message, @NonNull Element element) {
         processingEnv.getMessager().printMessage(ERROR, message, element);
     }
 }
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
index b4c6466..7389c24 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
@@ -18,6 +18,9 @@
 
 import static javax.tools.Diagnostic.Kind.ERROR;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import javax.annotation.processing.Messager;
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.AnnotationValue;
@@ -27,27 +30,30 @@
  * Internal exception used to signal an error processing an annotation.
  */
 final class ProcessingException extends RuntimeException {
-    private final Element mElement;
-    private final AnnotationMirror mAnnotationMirror;
-    private final AnnotationValue mAnnotationValue;
+    private final @Nullable Element mElement;
+    private final @Nullable AnnotationMirror mAnnotationMirror;
+    private final @Nullable AnnotationValue mAnnotationValue;
 
-    ProcessingException(String message) {
+    ProcessingException(@NonNull String message) {
         this(message, null, null, null);
     }
 
-    ProcessingException(String message, Element element) {
+    ProcessingException(@NonNull String message, @NonNull Element element) {
         this(message, element, null, null);
     }
 
-    ProcessingException(String message, Element element, AnnotationMirror annotationMirror) {
+    ProcessingException(
+            @NonNull String message,
+            @NonNull Element element,
+            @NonNull AnnotationMirror annotationMirror) {
         this(message, element, annotationMirror, null);
     }
 
     ProcessingException(
-            String message,
-            Element element,
-            AnnotationMirror annotationMirror,
-            AnnotationValue annotationValue) {
+            @NonNull String message,
+            @Nullable Element element,
+            @Nullable AnnotationMirror annotationMirror,
+            @Nullable AnnotationValue annotationValue) {
         super(message);
         mElement = element;
         mAnnotationMirror = annotationMirror;
@@ -59,7 +65,7 @@
      *
      * @param messager A Messager to print to
      */
-    void print(Messager messager) {
+    void print(@NonNull Messager messager) {
         if (mElement != null) {
             if (mAnnotationMirror != null) {
                 if (mAnnotationValue != null) {
diff --git a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
index 4eed504..3ec620a 100644
--- a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
+++ b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
@@ -118,9 +118,9 @@
                 Property.Type.INT_ENUM);
 
         property.setIntEnumEntries(Arrays.asList(
-                new IntEnumEntry("THREE", 3),
-                new IntEnumEntry("TWO", 2),
-                new IntEnumEntry("ONE", 1)));
+                new IntEnumEntry(3, "THREE"),
+                new IntEnumEntry(2, "TWO"),
+                new IntEnumEntry(1, "ONE")));
 
         mModel.putProperty(property);
 
@@ -136,9 +136,9 @@
 
         property.setAttributeIdInferrableFromR(false);
         property.setIntFlagEntries(Arrays.asList(
-                new IntFlagEntry("TURBO", 0x1, 0x3),
-                new IntFlagEntry("OVERDRIVE", 0x2, 0x3),
-                new IntFlagEntry("WARP", 0x4)
+                new IntFlagEntry(0x3, 0x1, "TURBO"),
+                new IntFlagEntry(0x3, 0x2, "OVERDRIVE"),
+                new IntFlagEntry(0x4, "WARP")
         ));
 
         assertGeneratedFileEquals("IntFlag");
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
index 9a0fe5b..e4a8ba4 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
@@ -14,7 +14,7 @@
  */
 public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
-     * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+     * Guards against reading properties before mapping them.
      */
     private boolean mPropertiesMapped = false;
 
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
index b491de1..fa9dbfd 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
@@ -1,11 +1,12 @@
 package com.android.node;
 
 import android.R;
+import android.util.SparseArray;
 import android.view.inspector.InspectionCompanion;
-import android.view.inspector.IntEnumMapping;
 import android.view.inspector.PropertyMapper;
 import android.view.inspector.PropertyReader;
 import java.lang.Override;
+import java.lang.String;
 
 /**
  * Inspection companion for {@link TestNode}.
@@ -15,7 +16,7 @@
  */
 public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
-     * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+     * Guards against reading properties before mapping them.
      */
     private boolean mPropertiesMapped = false;
 
@@ -26,12 +27,11 @@
 
     @Override
     public void mapProperties(PropertyMapper propertyMapper) {
-        mIntEnumPropertyId = propertyMapper.mapIntEnum("intEnumProperty", R.attr.intEnumProperty,
-                new IntEnumMapping.Builder()
-                    .addValue("ONE", 1)
-                    .addValue("TWO", 2)
-                    .addValue("THREE", 3)
-                    .build());
+        final SparseArray<String> intEnumPropertyEnumMapping = new SparseArray<>();
+        intEnumPropertyEnumMapping.put(1, "ONE");
+        intEnumPropertyEnumMapping.put(2, "TWO");
+        intEnumPropertyEnumMapping.put(3, "THREE");
+        mIntEnumPropertyId = propertyMapper.mapIntEnum("intEnumProperty", R.attr.intEnumProperty, intEnumPropertyEnumMapping::get);
         mPropertiesMapped = true;
     }
 
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
index 7d18058..ed3d8ee 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
@@ -14,7 +14,7 @@
  */
 public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
-     * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+     * Guards against reading properties before mapping them.
      */
     private boolean mPropertiesMapped = false;
 
@@ -25,11 +25,11 @@
 
     @Override
     public void mapProperties(PropertyMapper propertyMapper) {
-        mIntFlagId = propertyMapper.mapIntFlag("intFlag", 0, new IntFlagMapping.Builder()
-                    .addFlag("OVERDRIVE", 0x00000002, 0x00000003)
-                    .addFlag("TURBO", 0x00000001, 0x00000003)
-                    .addFlag("WARP", 0x00000004)
-                    .build());
+        final IntFlagMapping intFlagFlagMapping = new IntFlagMapping();
+        intFlagFlagMapping.add(0x00000003, 0x00000002, "OVERDRIVE");
+        intFlagFlagMapping.add(0x00000003, 0x00000001, "TURBO");
+        intFlagFlagMapping.add(0x00000004, 0x00000004, "WARP");
+        mIntFlagId = propertyMapper.mapIntFlag("intFlag", 0, intFlagFlagMapping::get);
         mPropertiesMapped = true;
     }
 
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
index dc27abb..4514ed9 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
@@ -13,7 +13,7 @@
  */
 public final class Outer$Inner$InspectionCompanion implements InspectionCompanion<Outer.Inner> {
     /**
-     * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+     * Guards against reading properties before mapping them.
      */
     private boolean mPropertiesMapped = false;
 
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
index 738bcd3..563f93df 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
@@ -13,7 +13,7 @@
  */
 public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
-     * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+     * Guards against reading properties before mapping them.
      */
     private boolean mPropertiesMapped = false;
 
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
index 82dd66e..ffa1f0b 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
@@ -14,7 +14,7 @@
  */
 public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
-     * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+     * Guards against reading properties before mapping them.
      */
     private boolean mPropertiesMapped = false;
 
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
index 08ea696..cb85767 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
@@ -14,7 +14,7 @@
  */
 public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
-     * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+     * Guards against reading properties before mapping them.
      */
     private boolean mPropertiesMapped = false;
 
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
index 3bfa78a..731d410 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
@@ -13,7 +13,7 @@
  */
 public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
-     * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+     * Guards against reading properties before mapping them.
      */
     private boolean mPropertiesMapped = false;
 
@@ -24,8 +24,7 @@
 
     @Override
     public void mapProperties(PropertyMapper propertyMapper) {
-        mSuppliedAttributePropertyId = propertyMapper.mapInt("suppliedAttributeProperty",
-                0xdecafbad);
+        mSuppliedAttributePropertyId = propertyMapper.mapInt("suppliedAttributeProperty", 0xdecafbad);
         mPropertiesMapped = true;
     }
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 379819d..47633005 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1171,39 +1171,49 @@
          * This network is disabled because EAP-TLS failure
          */
         public static final int DISABLED_TLS_VERSION_MISMATCH = 8;
+        /**
+         * This network is disabled due to WifiManager.disconnect() call.
+         */
+        public static final int DISABLED_BY_WIFI_MANAGER_DISCONNECT = 9;
+
         // Values above are for temporary disablement; values below are for permanent disablement.
         /**
+         * The starting index for permanent network selection disabled reasons
+         */
+        public static final int NETWORK_SELECTION_DISABLED_PERMANENT_STARTING_INDEX = 10;
+        /**
          * This network is disabled due to absence of user credentials
          */
-        public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 9;
+        public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 10;
         /**
          * This network is permanently disabled because it has no Internet access and user does not
          * want to stay connected.
          */
-        public static final int DISABLED_NO_INTERNET_PERMANENT = 10;
+        public static final int DISABLED_NO_INTERNET_PERMANENT = 11;
         /**
-         * This network is disabled due to WifiManager disable it explicitly
+         * This network is disabled due to WifiManager.disable() call.
          */
-        public static final int DISABLED_BY_WIFI_MANAGER = 11;
+        public static final int DISABLED_BY_WIFI_MANAGER = 12;
         /**
          * This network is disabled due to user switching
          */
-        public static final int DISABLED_DUE_TO_USER_SWITCH = 12;
+        public static final int DISABLED_DUE_TO_USER_SWITCH = 13;
         /**
          * This network is disabled due to wrong password
          */
-        public static final int DISABLED_BY_WRONG_PASSWORD = 13;
+        public static final int DISABLED_BY_WRONG_PASSWORD = 14;
         /**
          * This network is disabled because service is not subscribed
          */
-        public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 14;
+        public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 15;
         /**
          * This Maximum disable reason value
          */
-        public static final int NETWORK_SELECTION_DISABLED_MAX = 15;
+        public static final int NETWORK_SELECTION_DISABLED_MAX = 16;
 
         /**
-         * Quality network selection disable reason String (for debug purpose)
+         * Quality network selection disable reason String (for debug purposes & configuration
+         * storage)
          */
         public static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = {
                 "NETWORK_SELECTION_ENABLE",
@@ -1215,6 +1225,7 @@
                 "NETWORK_SELECTION_DISABLED_NO_INTERNET_TEMPORARY",
                 "NETWORK_SELECTION_DISABLED_WPS_START",
                 "NETWORK_SELECTION_DISABLED_TLS_VERSION",
+                "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER_DISCONNECT",
                 "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS",
                 "NETWORK_SELECTION_DISABLED_NO_INTERNET_PERMANENT",
                 "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER",
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 315f83a..06a99e2 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -65,6 +65,7 @@
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -947,7 +948,8 @@
     /**
      * Directed broadcast intent action indicating that the device has connected to one of the
      * network suggestions provided by the app. This will be sent post connection to a network
-     * which was created with {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired()}
+     * which was created with {@link WifiNetworkSuggestion.Builder#setIsAppInteractionRequired(
+     * boolean)}
      * flag set.
      * <p>
      * Note: The broadcast is sent to the app only if it holds
@@ -1000,8 +1002,9 @@
     /**
      * In this Wi-Fi lock mode, Wi-Fi will not go to power save.
      * This results in operating with low packet latency.
-     * The lock is active  even when the device screen is off or
-     * the acquiring application is running in the background.
+     * The lock is only active when the device is connected to an access point.
+     * The lock is active even when the device screen is off or the acquiring application is
+     * running in the background.
      * This mode will consume more power and hence should be used only
      * when there is a need for this tradeoff.
      * <p>
@@ -1019,6 +1022,7 @@
      * In this Wi-Fi lock mode, Wi-Fi will operate with a priority to achieve low latency.
      * {@link #WIFI_MODE_FULL_LOW_LATENCY} lock has the following limitations:
      * <ol>
+     * <li>The lock is only active when the device is connected to an access point.</li>
      * <li>The lock is only active when the screen is on.</li>
      * <li>The lock is only active when the acquiring app is running in the foreground.</li>
      * </ol>
@@ -1272,7 +1276,10 @@
     })
     @NonNull
     public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
-            List<ScanResult> scanResults) {
+            @Nullable List<ScanResult> scanResults) {
+        if (scanResults == null) {
+            return new HashMap<>();
+        }
         try {
             return mService.getMatchingOsuProviders(scanResults);
         } catch (RemoteException e) {
@@ -4873,14 +4880,14 @@
 
     /**
      * Provide a Wi-Fi usability score information to be recorded (but not acted upon) by the
-     * framework. The Wi-Fi usability score is derived from {@link WifiUsabilityStatsListener}
+     * framework. The Wi-Fi usability score is derived from {@link OnWifiUsabilityStatsListener}
      * where a score is matched to Wi-Fi usability statistics using the sequence number. The score
      * is used to quantify whether Wi-Fi is usable in a future time.
      *
      * @param seqNum Sequence number of the Wi-Fi usability score.
-     * @param score The Wi-Fi usability score.
+     * @param score The Wi-Fi usability score, expected range: [0, 100].
      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second,
-     *                             expected range: [0, 100].
+     *                             expected range: [0, 30].
      *
      * @hide
      */
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
index 8b56b3f..6c2d7ff 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -183,10 +183,12 @@
         /**
          * Specifies whether this represents an Enhanced Open (OWE) network.
          *
+         * @param isEnhancedOpen {@code true} to indicate that the network uses enhanced open,
+         *                       {@code false} otherwise.
          * @return Instance of {@link Builder} to enable chaining of the builder method.
          */
-        public @NonNull Builder setIsEnhancedOpen() {
-            mIsEnhancedOpen = true;
+        public @NonNull Builder setIsEnhancedOpen(boolean isEnhancedOpen) {
+            mIsEnhancedOpen = isEnhancedOpen;
             return this;
         }
 
@@ -261,10 +263,12 @@
          * hidden networks need to be explicitly probed for.</li>
          * <li>If not set, defaults to false (i.e not a hidden network).</li>
          *
+         * @param isHiddenSsid {@code true} to indicate that the network is hidden, {@code false}
+         *                     otherwise.
          * @return Instance of {@link Builder} to enable chaining of the builder method.
          */
-        public @NonNull Builder setIsHiddenSsid() {
-            mIsHiddenSSID = true;
+        public @NonNull Builder setIsHiddenSsid(boolean isHiddenSsid) {
+            mIsHiddenSSID = isHiddenSsid;
             return this;
         }
 
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 3742b83..32a7a47 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -18,6 +18,7 @@
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityThread;
@@ -159,10 +160,12 @@
         /**
          * Specifies whether this represents an Enhanced Open (OWE) network.
          *
+         * @param isEnhancedOpen {@code true} to indicate that the network used enhanced open,
+         *                       {@code false} otherwise.
          * @return Instance of {@link Builder} to enable chaining of the builder method.
          */
-        public @NonNull Builder setIsEnhancedOpen() {
-            mIsEnhancedOpen = true;
+        public @NonNull Builder setIsEnhancedOpen(boolean isEnhancedOpen) {
+            mIsEnhancedOpen = isEnhancedOpen;
             return this;
         }
 
@@ -235,10 +238,12 @@
          * <p>
          * <li>If not set, defaults to false (i.e not a hidden network).</li>
          *
+         * @param isHiddenSsid {@code true} to indicate that the network is hidden, {@code false}
+         *                     otherwise.
          * @return Instance of {@link Builder} to enable chaining of the builder method.
          */
-        public @NonNull Builder setIsHiddenSsid() {
-            mIsHiddenSSID = true;
+        public @NonNull Builder setIsHiddenSsid(boolean isHiddenSsid) {
+            mIsHiddenSSID = isHiddenSsid;
             return this;
         }
 
@@ -253,10 +258,12 @@
          * <p>
          * <li>If not set, defaults to false (i.e no app interaction required).</li>
          *
+         * @param isAppInteractionRequired {@code true} to indicate that app interaction is
+         *                                 required, {@code false} otherwise.
          * @return Instance of {@link Builder} to enable chaining of the builder method.
          */
-        public @NonNull Builder setIsAppInteractionRequired() {
-            mIsAppInteractionRequired = true;
+        public @NonNull Builder setIsAppInteractionRequired(boolean isAppInteractionRequired) {
+            mIsAppInteractionRequired = isAppInteractionRequired;
             return this;
         }
 
@@ -265,10 +272,12 @@
          * <p>
          * <li>If not set, defaults to false (i.e no user interaction required).</li>
          *
+         * @param isUserInteractionRequired {@code true} to indicate that user interaction is
+         *                                  required, {@code false} otherwise.
          * @return Instance of {@link Builder} to enable chaining of the builder method.
          */
-        public @NonNull Builder setIsUserInteractionRequired() {
-            mIsUserInteractionRequired = true;
+        public @NonNull Builder setIsUserInteractionRequired(boolean isUserInteractionRequired) {
+            mIsUserInteractionRequired = isUserInteractionRequired;
             return this;
         }
 
@@ -283,7 +292,7 @@
          * @return Instance of {@link Builder} to enable chaining of the builder method.
          * @throws IllegalArgumentException if the priority value is negative.
          */
-        public @NonNull Builder setPriority(int priority) {
+        public @NonNull Builder setPriority(@IntRange(from = 0) int priority) {
             if (priority < 0) {
                 throw new IllegalArgumentException("Invalid priority value " + priority);
             }
@@ -296,10 +305,12 @@
          * <p>
          * <li>If not set, defaults to false (i.e not metered).</li>
          *
+         * @param isMetered {@code true} to indicate that the network is metered, {@code false}
+         *                  otherwise.
          * @return Instance of {@link Builder} to enable chaining of the builder method.
          */
-        public @NonNull Builder setIsMetered() {
-            mIsMetered = true;
+        public @NonNull Builder setIsMetered(boolean isMetered) {
+            mIsMetered = isMetered;
             return this;
         }
 
diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh
index 2caf8a5..1e0ec37 100755
--- a/wifi/tests/runtests.sh
+++ b/wifi/tests/runtests.sh
@@ -19,7 +19,7 @@
 adb root
 adb wait-for-device
 
-adb install -r -g "$OUT/data/app/FrameworksWifiApiTests/FrameworksWifiApiTests.apk"
+adb install -r -g "$OUT/testcases/FrameworksWifiApiTests/arm64/FrameworksWifiApiTests.apk"
 
 adb shell am instrument --no-hidden-api-checks -w "$@" \
   'android.net.wifi.test/androidx.test.runner.AndroidJUnitRunner'
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
index feac0e5..edb43d8 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSpecifierTest.java
@@ -114,7 +114,7 @@
                 .setSsid(TEST_SSID)
                 .setBssid(MacAddress.fromString(TEST_BSSID))
                 .setWpa2EnterpriseConfig(enterpriseConfig)
-                .setIsHiddenSsid()
+                .setIsHiddenSsid(true)
                 .build();
 
         assertTrue(specifier instanceof WifiNetworkSpecifier);
@@ -278,7 +278,7 @@
         new WifiNetworkSpecifier.Builder()
                 .setBssidPattern(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
                         MacAddress.fromString(TEST_BSSID_OUI_MASK))
-                .setIsHiddenSsid()
+                .setIsHiddenSsid(true)
                 .build();
     }
 
@@ -305,7 +305,7 @@
     public void testWifiNetworkSpecifierBuilderWithSsidMatchPatternForHiddenNetwork() {
         new WifiNetworkSpecifier.Builder()
                 .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_PREFIX))
-                .setIsHiddenSsid()
+                .setIsHiddenSsid(true)
                 .build();
     }
 
@@ -341,14 +341,14 @@
     /**
      * Ensure {@link WifiNetworkSpecifier.Builder#build()} throws an exception
      * when both {@link WifiNetworkSpecifier.Builder#setWpa3Passphrase(String)} and
-     * {@link WifiNetworkSpecifier.Builder#setIsEnhancedOpen()} are invoked.
+     * {@link WifiNetworkSpecifier.Builder#setIsEnhancedOpen(boolean)} are invoked.
      */
     @Test(expected = IllegalStateException.class)
     public void testWifiNetworkSpecifierBuilderWithBothWpa3PasphraseAndEnhancedOpen() {
         new WifiNetworkSpecifier.Builder()
                 .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
                 .setWpa3Passphrase(TEST_PRESHARED_KEY)
-                .setIsEnhancedOpen()
+                .setIsEnhancedOpen(true)
                 .build();
     }
 
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 05ee22c..2b0c773 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -49,7 +49,7 @@
     public void testWifiNetworkSuggestionBuilderForOpenNetworkWithReqAppInteraction() {
         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
                 .setSsid(TEST_SSID)
-                .setIsAppInteractionRequired()
+                .setIsAppInteractionRequired(true)
                 .build();
 
         assertEquals(Process.myUid(), suggestion.suggestorUid);
@@ -74,7 +74,7 @@
         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
                 .setSsid(TEST_SSID)
                 .setWpa2Passphrase(TEST_PRESHARED_KEY)
-                .setIsAppInteractionRequired()
+                .setIsAppInteractionRequired(true)
                 .setPriority(0)
                 .build();
 
@@ -101,8 +101,8 @@
         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
                 .setSsid(TEST_SSID)
                 .setWpa2Passphrase(TEST_PRESHARED_KEY)
-                .setIsUserInteractionRequired()
-                .setIsMetered()
+                .setIsUserInteractionRequired(true)
+                .setIsMetered(true)
                 .build();
 
         assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
@@ -126,7 +126,7 @@
         WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
                 .setSsid(TEST_SSID)
                 .setBssid(MacAddress.fromString(TEST_BSSID))
-                .setIsEnhancedOpen()
+                .setIsEnhancedOpen(true)
                 .build();
 
         assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
@@ -265,7 +265,7 @@
     public void testWifiNetworkSuggestionBuilderWithInvalidPriority() {
         new WifiNetworkSuggestion.Builder()
                 .setSsid(TEST_SSID)
-                .setPriority(-1)
+                .setPriority(-2)
                 .build();
     }
 
@@ -301,14 +301,14 @@
     /**
      * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
      * when both {@link WifiNetworkSuggestion.Builder#setWpa3Passphrase(String)} and
-     * {@link WifiNetworkSuggestion.Builder#setIsEnhancedOpen()} are invoked.
+     * {@link WifiNetworkSuggestion.Builder#setIsEnhancedOpen(boolean)} are invoked.
      */
     @Test(expected = IllegalStateException.class)
     public void testWifiNetworkSuggestionBuilderWithBothWpa3PasphraseAndEnhancedOpen() {
         new WifiNetworkSuggestion.Builder()
                 .setSsid(TEST_SSID)
                 .setWpa3Passphrase(TEST_PRESHARED_KEY)
-                .setIsEnhancedOpen()
+                .setIsEnhancedOpen(true)
                 .build();
     }