Merge "Fix some exception occrued possible code"
diff --git a/apex/permission/apex_manifest.json b/apex/permission/apex_manifest.json
index 7960598..6350d54 100644
--- a/apex/permission/apex_manifest.json
+++ b/apex/permission/apex_manifest.json
@@ -1,4 +1,4 @@
 {
   "name": "com.android.permission",
-  "version": 300000000
+  "version": 309999999
 }
diff --git a/core/api/current.txt b/core/api/current.txt
index 4d944c3..471f4c9 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -165,6 +165,7 @@
     field public static final String USE_BIOMETRIC = "android.permission.USE_BIOMETRIC";
     field @Deprecated public static final String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
     field public static final String USE_FULL_SCREEN_INTENT = "android.permission.USE_FULL_SCREEN_INTENT";
+    field public static final String USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER = "android.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER";
     field public static final String USE_SIP = "android.permission.USE_SIP";
     field public static final String VIBRATE = "android.permission.VIBRATE";
     field public static final String WAKE_LOCK = "android.permission.WAKE_LOCK";
@@ -6215,6 +6216,7 @@
     method public android.app.PictureInPictureParams.Builder setActions(java.util.List<android.app.RemoteAction>);
     method public android.app.PictureInPictureParams.Builder setAspectRatio(android.util.Rational);
     method @NonNull public android.app.PictureInPictureParams.Builder setAutoEnterEnabled(boolean);
+    method @NonNull public android.app.PictureInPictureParams.Builder setSeamlessResizeEnabled(boolean);
     method public android.app.PictureInPictureParams.Builder setSourceRectHint(android.graphics.Rect);
   }
 
@@ -6920,6 +6922,7 @@
     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);
+    method @NonNull public java.util.Set<java.util.Set<java.lang.String>> getKeyPairGrants(@NonNull String);
     method public int getKeyguardDisabledFeatures(@Nullable android.content.ComponentName);
     method public int getLockTaskFeatures(@NonNull android.content.ComponentName);
     method @NonNull public String[] getLockTaskPackages(@NonNull android.content.ComponentName);
@@ -47085,6 +47088,7 @@
     field public static final int APPTYPE_ISIM = 5; // 0x5
     field public static final int APPTYPE_RUIM = 3; // 0x3
     field public static final int APPTYPE_SIM = 1; // 0x1
+    field public static final int APPTYPE_UNKNOWN = 0; // 0x0
     field public static final int APPTYPE_USIM = 2; // 0x2
     field public static final int AUTHTYPE_EAP_AKA = 129; // 0x81
     field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 1d71726..8e440fb1 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -36,6 +36,7 @@
     field public static final String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH";
     field public static final String BIND_EUICC_SERVICE = "android.permission.BIND_EUICC_SERVICE";
     field public static final String BIND_EXTERNAL_STORAGE_SERVICE = "android.permission.BIND_EXTERNAL_STORAGE_SERVICE";
+    field public static final String BIND_GBA_SERVICE = "android.permission.BIND_GBA_SERVICE";
     field public static final String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE";
     field public static final String BIND_KEYGUARD_APPWIDGET = "android.permission.BIND_KEYGUARD_APPWIDGET";
     field public static final String BIND_MUSIC_RECOGNITION_SERVICE = "android.permission.BIND_MUSIC_RECOGNITION_SERVICE";
@@ -210,6 +211,7 @@
     field public static final String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
     field public static final String REVIEW_ACCESSIBILITY_SERVICES = "android.permission.REVIEW_ACCESSIBILITY_SERVICES";
     field public static final String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
+    field public static final String ROTATE_SURFACE_FLINGER = "android.permission.ROTATE_SURFACE_FLINGER";
     field public static final String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
     field public static final String SECURE_ELEMENT_PRIVILEGED_OPERATION = "android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION";
     field public static final String SEND_CATEGORY_CAR_NOTIFICATIONS = "android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS";
@@ -10892,6 +10894,7 @@
   }
 
   public class TelephonyManager {
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void bootstrapAuthenticationRequest(int, @NonNull android.net.Uri, @NonNull android.telephony.gba.UaSecurityProtocolIdentifier, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.BootstrapAuthenticationCallback);
     method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String);
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult changeIccLockPin(@NonNull String, @NonNull String);
     method public int checkCarrierPrivilegesForPackage(String);
@@ -11064,6 +11067,12 @@
     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";
+    field public static final int GBA_FAILURE_REASON_FEATURE_NOT_READY = 2; // 0x2
+    field public static final int GBA_FAILURE_REASON_FEATURE_NOT_SUPPORTED = 1; // 0x1
+    field public static final int GBA_FAILURE_REASON_INCORRECT_NAF_ID = 4; // 0x4
+    field public static final int GBA_FAILURE_REASON_NETWORK_FAILURE = 3; // 0x3
+    field public static final int GBA_FAILURE_REASON_SECURITY_PROTOCOL_NOT_SUPPORTED = 5; // 0x5
+    field public static final int GBA_FAILURE_REASON_UNKNOWN = 0; // 0x0
     field public static final int INVALID_EMERGENCY_NUMBER_DB_VERSION = -1; // 0xffffffff
     field public static final int KEY_TYPE_EPDG = 1; // 0x1
     field public static final int KEY_TYPE_WLAN = 2; // 0x2
@@ -11122,6 +11131,12 @@
     field public static final int THERMAL_MITIGATION_RESULT_UNKNOWN_ERROR = 4; // 0x4
   }
 
+  public static class TelephonyManager.BootstrapAuthenticationCallback {
+    ctor public TelephonyManager.BootstrapAuthenticationCallback();
+    method public void onAuthenticationFailure(int);
+    method public void onKeysAvailable(@NonNull byte[], @NonNull String);
+  }
+
   public static interface TelephonyManager.CallForwardingInfoCallback {
     method public void onCallForwardingInfoAvailable(@NonNull android.telephony.CallForwardingInfo);
     method public void onError(int);
@@ -11564,6 +11579,141 @@
 
 }
 
+package android.telephony.gba {
+
+  public class GbaService extends android.app.Service {
+    ctor public GbaService();
+    method public void onAuthenticationRequest(int, int, int, @NonNull android.net.Uri, @NonNull byte[], boolean);
+    method public final void reportAuthenticationFailure(int, int) throws java.lang.RuntimeException;
+    method public final void reportKeysAvailable(int, @NonNull byte[], @NonNull String) throws java.lang.RuntimeException;
+    field public static final String SERVICE_INTERFACE = "android.telephony.gba.GbaService";
+  }
+
+  public class TlsParams {
+    method public static boolean isTlsCipherSuiteSupported(int);
+    field public static final int GROUP_SECP256R1 = 23; // 0x17
+    field public static final int GROUP_SECP384R1 = 24; // 0x18
+    field public static final int GROUP_X25519 = 29; // 0x1d
+    field public static final int GROUP_X448 = 30; // 0x1e
+    field public static final int PROTOCOL_VERSION_TLS_1_2 = 771; // 0x303
+    field public static final int PROTOCOL_VERSION_TLS_1_3 = 772; // 0x304
+    field public static final int SIG_ECDSA_BRAINPOOLP256R1TLS13_SHA256 = 2074; // 0x81a
+    field public static final int SIG_ECDSA_BRAINPOOLP384R1TLS13_SHA384 = 2075; // 0x81b
+    field public static final int SIG_ECDSA_BRAINPOOLP512R1TLS13_SHA512 = 2076; // 0x81c
+    field public static final int SIG_ECDSA_SECP256R1_SHA256 = 1027; // 0x403
+    field public static final int SIG_ECDSA_SECP384R1_SHA384 = 1283; // 0x503
+    field public static final int SIG_ECDSA_SECP521R1_SHA512 = 1539; // 0x603
+    field public static final int SIG_ECDSA_SHA1 = 515; // 0x203
+    field public static final int SIG_RSA_PKCS1_SHA1 = 513; // 0x201
+    field public static final int SIG_RSA_PKCS1_SHA256 = 1025; // 0x401
+    field public static final int SIG_RSA_PKCS1_SHA256_LEGACY = 1056; // 0x420
+    field public static final int SIG_RSA_PKCS1_SHA384 = 1281; // 0x501
+    field public static final int SIG_RSA_PKCS1_SHA384_LEGACY = 1312; // 0x520
+    field public static final int SIG_RSA_PKCS1_SHA512 = 1537; // 0x601
+    field public static final int SIG_RSA_PKCS1_SHA512_LEGACY = 1568; // 0x620
+    field public static final int SIG_RSA_PSS_RSAE_SHA256 = 2052; // 0x804
+    field public static final int SIG_RSA_PSS_RSAE_SHA384 = 2053; // 0x805
+    field public static final int SIG_RSA_PSS_RSAE_SHA512 = 2054; // 0x806
+    field public static final int TLS_AES_128_CCM_SHA256 = 4868; // 0x1304
+    field public static final int TLS_AES_128_GCM_SHA256 = 4865; // 0x1301
+    field public static final int TLS_AES_256_GCM_SHA384 = 4866; // 0x1302
+    field public static final int TLS_CHACHA20_POLY1305_SHA256 = 4867; // 0x1303
+    field public static final int TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 19; // 0x13
+    field public static final int TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 50; // 0x32
+    field public static final int TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 64; // 0x40
+    field public static final int TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 56; // 0x38
+    field public static final int TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 106; // 0x6a
+    field public static final int TLS_DHE_PSK_WITH_AES_128_CCM = 49318; // 0xc0a6
+    field public static final int TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = 170; // 0xaa
+    field public static final int TLS_DHE_PSK_WITH_AES_256_CCM = 49319; // 0xc0a7
+    field public static final int TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = 171; // 0xab
+    field public static final int TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = 52397; // 0xccad
+    field public static final int TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 22; // 0x16
+    field public static final int TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 51; // 0x33
+    field public static final int TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 103; // 0x67
+    field public static final int TLS_DHE_RSA_WITH_AES_128_CCM = 49310; // 0xc09e
+    field public static final int TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 158; // 0x9e
+    field public static final int TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 57; // 0x39
+    field public static final int TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 107; // 0x6b
+    field public static final int TLS_DHE_RSA_WITH_AES_256_CCM = 49311; // 0xc09f
+    field public static final int TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 159; // 0x9f
+    field public static final int TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 52394; // 0xccaa
+    field public static final int TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA = 27; // 0x1b
+    field public static final int TLS_DH_ANON_WITH_AES_128_CBC_SHA = 52; // 0x34
+    field public static final int TLS_DH_ANON_WITH_AES_128_CBC_SHA256 = 108; // 0x6c
+    field public static final int TLS_DH_ANON_WITH_AES_256_CBC_SHA = 58; // 0x3a
+    field public static final int TLS_DH_ANON_WITH_AES_256_CBC_SHA256 = 109; // 0x6d
+    field public static final int TLS_DH_ANON_WITH_RC4_128_MD5 = 24; // 0x18
+    field public static final int TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 13; // 0xd
+    field public static final int TLS_DH_DSS_WITH_AES_128_CBC_SHA = 48; // 0x30
+    field public static final int TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 62; // 0x3e
+    field public static final int TLS_DH_DSS_WITH_AES_256_CBC_SHA = 54; // 0x36
+    field public static final int TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 104; // 0x68
+    field public static final int TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 16; // 0x10
+    field public static final int TLS_DH_RSA_WITH_AES_128_CBC_SHA = 49; // 0x31
+    field public static final int TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 63; // 0x3f
+    field public static final int TLS_DH_RSA_WITH_AES_256_CBC_SHA = 55; // 0x37
+    field public static final int TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 105; // 0x69
+    field public static final int TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 49195; // 0xc02b
+    field public static final int TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 49196; // 0xc02c
+    field public static final int TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 52393; // 0xcca9
+    field public static final int TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256 = 53253; // 0xd005
+    field public static final int TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 = 53249; // 0xd001
+    field public static final int TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384 = 53250; // 0xd002
+    field public static final int TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = 52396; // 0xccac
+    field public static final int TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 49199; // 0xc02f
+    field public static final int TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 49200; // 0xc030
+    field public static final int TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 52392; // 0xcca8
+    field public static final int TLS_NULL_WITH_NULL_NULL = 0; // 0x0
+    field public static final int TLS_RSA_WITH_3DES_EDE_CBC_SHA = 10; // 0xa
+    field public static final int TLS_RSA_WITH_AES_128_CBC_SHA = 47; // 0x2f
+    field public static final int TLS_RSA_WITH_AES_128_CBC_SHA256 = 60; // 0x3c
+    field public static final int TLS_RSA_WITH_AES_256_CBC_SHA = 53; // 0x35
+    field public static final int TLS_RSA_WITH_AES_256_CBC_SHA256 = 61; // 0x3d
+    field public static final int TLS_RSA_WITH_NULL_MD5 = 1; // 0x1
+    field public static final int TLS_RSA_WITH_NULL_SHA = 2; // 0x2
+    field public static final int TLS_RSA_WITH_NULL_SHA256 = 59; // 0x3b
+    field public static final int TLS_RSA_WITH_RC4_128_MD5 = 4; // 0x4
+    field public static final int TLS_RSA_WITH_RC4_128_SHA = 5; // 0x5
+  }
+
+  public final class UaSecurityProtocolIdentifier implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getOrg();
+    method public int getProtocol();
+    method public int getTlsCipherSuite();
+    method @NonNull public byte[] toByteArray();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.gba.UaSecurityProtocolIdentifier> CREATOR;
+    field public static final int ORG_3GPP = 1; // 0x1
+    field public static final int ORG_3GPP2 = 2; // 0x2
+    field public static final int ORG_GSMA = 4; // 0x4
+    field public static final int ORG_LOCAL = 255; // 0xff
+    field public static final int ORG_NONE = 0; // 0x0
+    field public static final int ORG_OMA = 3; // 0x3
+    field public static final int UA_SECURITY_PROTOCOL_3GPP_GENERATION_TMPI = 256; // 0x100
+    field public static final int UA_SECURITY_PROTOCOL_3GPP_GENERIC_PUSH_LAYER = 5; // 0x5
+    field public static final int UA_SECURITY_PROTOCOL_3GPP_HTTP_BASED_MBMS = 3; // 0x3
+    field public static final int UA_SECURITY_PROTOCOL_3GPP_HTTP_DIGEST_AUTHENTICATION = 2; // 0x2
+    field public static final int UA_SECURITY_PROTOCOL_3GPP_IMS_MEDIA_PLANE = 6; // 0x6
+    field public static final int UA_SECURITY_PROTOCOL_3GPP_MBMS = 1; // 0x1
+    field public static final int UA_SECURITY_PROTOCOL_3GPP_SIP_BASED_MBMS = 4; // 0x4
+    field public static final int UA_SECURITY_PROTOCOL_3GPP_SUBSCRIBER_CERTIFICATE = 0; // 0x0
+    field public static final int UA_SECURITY_PROTOCOL_3GPP_TLS_BROWSER = 131072; // 0x20000
+    field public static final int UA_SECURITY_PROTOCOL_3GPP_TLS_DEFAULT = 65536; // 0x10000
+  }
+
+  public static final class UaSecurityProtocolIdentifier.Builder {
+    ctor public UaSecurityProtocolIdentifier.Builder();
+    ctor public UaSecurityProtocolIdentifier.Builder(@NonNull android.telephony.gba.UaSecurityProtocolIdentifier);
+    method @NonNull public android.telephony.gba.UaSecurityProtocolIdentifier build();
+    method @NonNull public android.telephony.gba.UaSecurityProtocolIdentifier.Builder setOrg(int);
+    method @NonNull public android.telephony.gba.UaSecurityProtocolIdentifier.Builder setProtocol(int);
+    method @NonNull public android.telephony.gba.UaSecurityProtocolIdentifier.Builder setTlsCipherSuite(int);
+  }
+
+}
+
 package android.telephony.ims {
 
   public final class AudioCodecAttributes implements android.os.Parcelable {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index ffb31c9..d2941c3 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -216,6 +216,7 @@
     field public static final String KEY_FG_SERVICE_STATE_SETTLE_TIME = "fg_service_state_settle_time";
     field public static final String KEY_TOP_STATE_SETTLE_TIME = "top_state_settle_time";
     field public static final String OPSTR_MANAGE_ONGOING_CALLS = "android:manage_ongoing_calls";
+    field public static final String OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER = "android:use_icc_auth_with_device_identifier";
     field public static final int OP_COARSE_LOCATION = 0; // 0x0
     field public static final int OP_RECORD_AUDIO = 27; // 0x1b
     field public static final int OP_START_FOREGROUND = 76; // 0x4c
@@ -282,6 +283,7 @@
     method public java.util.List<android.app.RemoteAction> getActions();
     method public float getAspectRatio();
     method public android.graphics.Rect getSourceRectHint();
+    method public boolean isSeamlessResizeEnabled();
   }
 
   public class StatusBarManager {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4dd6a7e..f60f569 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1166,8 +1166,12 @@
     public static final int OP_MANAGE_CREDENTIALS = AppProtoEnums.APP_OP_MANAGE_CREDENTIALS;
 
     /** @hide */
+    public static final int OP_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER =
+            AppProtoEnums.APP_OP_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER;
+
+    /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static final int _NUM_OP = 105;
+    public static final int _NUM_OP = 106;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1525,6 +1529,15 @@
      */
     public static final String OPSTR_MANAGE_CREDENTIALS = "android:manage_credentials";
 
+    /**
+     * Allows to read device identifiers and use ICC based authentication like EAP-AKA.
+     *
+     * @hide
+     */
+    @TestApi
+    public static final String OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER =
+            "android:use_icc_auth_with_device_identifier";
+
     /** {@link #sAppOpsToNote} not initialized yet for this op */
     private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
     /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -1604,6 +1617,7 @@
             OP_INTERACT_ACROSS_PROFILES,
             OP_LOADER_USAGE_STATS,
             OP_MANAGE_ONGOING_CALLS,
+            OP_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
     };
 
     /**
@@ -1720,6 +1734,7 @@
             OP_RECORD_AUDIO_HOTWORD,            // RECORD_AUDIO_HOTWORD
             OP_MANAGE_ONGOING_CALLS,            // MANAGE_ONGOING_CALLS
             OP_MANAGE_CREDENTIALS,              // MANAGE_CREDENTIALS
+            OP_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
     };
 
     /**
@@ -1831,6 +1846,7 @@
             OPSTR_RECORD_AUDIO_HOTWORD,
             OPSTR_MANAGE_ONGOING_CALLS,
             OPSTR_MANAGE_CREDENTIALS,
+            OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
     };
 
     /**
@@ -1943,6 +1959,7 @@
             "RECORD_AUDIO_HOTWORD",
             "MANAGE_ONGOING_CALLS",
             "MANAGE_CREDENTIALS",
+            "USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER",
     };
 
     /**
@@ -2056,6 +2073,7 @@
             null, // no permission for OP_RECORD_AUDIO_HOTWORD
             Manifest.permission.MANAGE_ONGOING_CALLS,
             null, // no permission for OP_MANAGE_CREDENTIALS
+            Manifest.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
     };
 
     /**
@@ -2169,6 +2187,7 @@
             null, // RECORD_AUDIO_HOTWORD
             null, // MANAGE_ONGOING_CALLS
             null, // MANAGE_CREDENTIALS
+            null, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
     };
 
     /**
@@ -2281,6 +2300,7 @@
             null, // RECORD_AUDIO_HOTWORD
             null, // MANAGE_ONGOING_CALLS
             null, // MANAGE_CREDENTIALS
+            null, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
     };
 
     /**
@@ -2392,6 +2412,7 @@
             AppOpsManager.MODE_ALLOWED, // OP_RECORD_AUDIO_HOTWORD
             AppOpsManager.MODE_DEFAULT, // MANAGE_ONGOING_CALLS
             AppOpsManager.MODE_DEFAULT, // MANAGE_CREDENTIALS
+            AppOpsManager.MODE_DEFAULT, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
     };
 
     /**
@@ -2507,6 +2528,7 @@
             false, // RECORD_AUDIO_HOTWORD
             true, // MANAGE_ONGOING_CALLS
             false, // MANAGE_CREDENTIALS
+            true, // USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER
     };
 
     /**
diff --git a/core/java/android/app/PictureInPictureParams.java b/core/java/android/app/PictureInPictureParams.java
index 29c9c67..ea7eab2 100644
--- a/core/java/android/app/PictureInPictureParams.java
+++ b/core/java/android/app/PictureInPictureParams.java
@@ -48,7 +48,9 @@
         @Nullable
         private Rect mSourceRectHint;
 
-        private boolean mAutoEnterEnabled;
+        private Boolean mAutoEnterEnabled;
+
+        private Boolean mSeamlessResizeEnabled;
 
         /**
          * Sets the aspect ratio.  This aspect ratio is defined as the desired width / height, and
@@ -113,7 +115,7 @@
          *
          * If true, {@link Activity#onPictureInPictureRequested()} will never be called.
          *
-         * This property is false by default.
+         * This property is {@code false} by default.
          * @param autoEnterEnabled {@code true} if the system will automatically put the activity
          *                                     in picture-in-picture mode.
          *
@@ -126,6 +128,23 @@
         }
 
         /**
+         * Sets whether the system can seamlessly resize the window while the activity is in
+         * picture-in-picture mode. This should normally be the case for video content and
+         * when it's set to {@code false}, system will perform transitions to overcome the
+         * artifacts due to resize.
+         *
+         * This property is {@code true} by default for backwards compatibility.
+         * @param seamlessResizeEnabled {@code true} if the system can seamlessly resize the window
+         *                                          while activity is in picture-in-picture mode.
+         * @return this builder instance.
+         */
+        @NonNull
+        public Builder setSeamlessResizeEnabled(boolean seamlessResizeEnabled) {
+            mSeamlessResizeEnabled = seamlessResizeEnabled;
+            return this;
+        }
+
+        /**
          * @return an immutable {@link PictureInPictureParams} to be used when entering or updating
          * the activity in picture-in-picture.
          *
@@ -134,7 +153,7 @@
          */
         public PictureInPictureParams build() {
             PictureInPictureParams params = new PictureInPictureParams(mAspectRatio, mUserActions,
-                    mSourceRectHint, mAutoEnterEnabled);
+                    mSourceRectHint, mAutoEnterEnabled, mSeamlessResizeEnabled);
             return params;
         }
     }
@@ -161,8 +180,16 @@
 
     /**
      * Whether the system is allowed to automatically put the activity in picture-in-picture mode.
+     * {@link #isAutoEnterEnabled()} defaults to {@code false} if this is not set.
      */
-    private boolean mAutoEnterEnabled;
+    private Boolean mAutoEnterEnabled;
+
+    /**
+     * Whether system can seamlessly resize the window when activity is in picture-in-picture mode.
+     * {@link #isSeamlessResizeEnabled()} defaults to {@code true} if this is not set for
+     * backwards compatibility.
+     */
+    private Boolean mSeamlessResizeEnabled;
 
     /** {@hide} */
     PictureInPictureParams() {
@@ -183,15 +210,19 @@
         if (in.readInt() != 0) {
             mAutoEnterEnabled = in.readBoolean();
         }
+        if (in.readInt() != 0) {
+            mSeamlessResizeEnabled = in.readBoolean();
+        }
     }
 
     /** {@hide} */
     PictureInPictureParams(Rational aspectRatio, List<RemoteAction> actions,
-            Rect sourceRectHint, boolean autoEnterEnabled) {
+            Rect sourceRectHint, Boolean autoEnterEnabled, Boolean seamlessResizeEnabled) {
         mAspectRatio = aspectRatio;
         mUserActions = actions;
         mSourceRectHint = sourceRectHint;
         mAutoEnterEnabled = autoEnterEnabled;
+        mSeamlessResizeEnabled = seamlessResizeEnabled;
     }
 
     /**
@@ -201,7 +232,7 @@
     public PictureInPictureParams(PictureInPictureParams other) {
         this(other.mAspectRatio, other.mUserActions,
                 other.hasSourceBoundsHint() ? new Rect(other.getSourceRectHint()) : null,
-                other.mAutoEnterEnabled);
+                other.mAutoEnterEnabled, other.mSeamlessResizeEnabled);
     }
 
     /**
@@ -218,7 +249,12 @@
         if (otherArgs.hasSourceBoundsHint()) {
             mSourceRectHint = new Rect(otherArgs.getSourceRectHint());
         }
-        mAutoEnterEnabled = otherArgs.mAutoEnterEnabled;
+        if (otherArgs.mAutoEnterEnabled != null) {
+            mAutoEnterEnabled = otherArgs.mAutoEnterEnabled;
+        }
+        if (otherArgs.mSeamlessResizeEnabled != null) {
+            mSeamlessResizeEnabled = otherArgs.mSeamlessResizeEnabled;
+        }
     }
 
     /**
@@ -295,7 +331,16 @@
      * @hide
      */
     public boolean isAutoEnterEnabled() {
-        return mAutoEnterEnabled;
+        return mAutoEnterEnabled == null ? false : mAutoEnterEnabled;
+    }
+
+    /**
+     * @return whether seamless resize is enabled.
+     * @hide
+     */
+    @TestApi
+    public boolean isSeamlessResizeEnabled() {
+        return mSeamlessResizeEnabled == null ? true : mSeamlessResizeEnabled;
     }
 
     /**
@@ -304,7 +349,7 @@
      */
     public boolean empty() {
         return !hasSourceBoundsHint() && !hasSetActions() && !hasSetAspectRatio()
-                && !mAutoEnterEnabled;
+                && mAutoEnterEnabled != null && mSeamlessResizeEnabled != null;
     }
 
     @Override
@@ -312,7 +357,8 @@
         if (this == o) return true;
         if (!(o instanceof PictureInPictureParams)) return false;
         PictureInPictureParams that = (PictureInPictureParams) o;
-        return mAutoEnterEnabled == that.mAutoEnterEnabled
+        return Objects.equals(mAutoEnterEnabled, that.mAutoEnterEnabled)
+                && Objects.equals(mSeamlessResizeEnabled, that.mSeamlessResizeEnabled)
                 && Objects.equals(mAspectRatio, that.mAspectRatio)
                 && Objects.equals(mUserActions, that.mUserActions)
                 && Objects.equals(mSourceRectHint, that.mSourceRectHint);
@@ -320,7 +366,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mAspectRatio, mUserActions, mSourceRectHint, mAutoEnterEnabled);
+        return Objects.hash(mAspectRatio, mUserActions, mSourceRectHint,
+                mAutoEnterEnabled, mSeamlessResizeEnabled);
     }
 
     @Override
@@ -349,8 +396,18 @@
         } else {
             out.writeInt(0);
         }
-        out.writeInt(1);
-        out.writeBoolean(mAutoEnterEnabled);
+        if (mAutoEnterEnabled != null) {
+            out.writeInt(1);
+            out.writeBoolean(mAutoEnterEnabled);
+        } else {
+            out.writeInt(0);
+        }
+        if (mSeamlessResizeEnabled != null) {
+            out.writeInt(1);
+            out.writeBoolean(mSeamlessResizeEnabled);
+        } else {
+            out.writeInt(0);
+        }
     }
 
     @Override
@@ -360,6 +417,7 @@
                 + " sourceRectHint=" + getSourceRectHint()
                 + " hasSetActions=" + hasSetActions()
                 + " isAutoPipEnabled=" + isAutoEnterEnabled()
+                + " isSeamlessResizeEnabled=" + isSeamlessResizeEnabled()
                 + ")";
     }
 
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4095acc..251252e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -5758,7 +5758,6 @@
         return null;
     }
 
-
     /**
      * Called by a device or profile owner, or delegated certificate chooser (an app that has been
      * delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to grant an application access
@@ -5796,6 +5795,51 @@
 
     /**
      * Called by a device or profile owner, or delegated certificate chooser (an app that has been
+     * delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to query which apps have access
+     * to a given KeyChain key.
+     *
+     * Key are granted on a per-UID basis, so if several apps share the same UID, granting access to
+     * one of them automatically grants it to others. This method returns a set of sets of package
+     * names, where each internal set contains all packages sharing the same UID. Grantee packages
+     * that don't share UID with other packages are represented by singleton sets.
+     *
+     * @param alias The alias of the key to grant access to.
+     * @return package names of apps that have access to a given key, grouped by UIDs
+     *
+     * @throws SecurityException if the caller is not a device owner, a profile owner or
+     *         delegated certificate chooser.
+     * @throws IllegalArgumentException if {@code alias} doesn't correspond to an existing key.
+     *
+     * @see #grantKeyPairToApp(ComponentName, String, String)
+     */
+    public @NonNull Set<Set<String>> getKeyPairGrants(@NonNull String alias) {
+        throwIfParentInstance("getKeyPairGrants");
+        try {
+            // Set of sets is flattened into a null-separated list.
+            final List<String> flattened =
+                    mService.getKeyPairGrants(mContext.getPackageName(), alias);
+            final Set<Set<String>> result = new HashSet<>();
+            Set<String> pkgsForOneUid = new HashSet<>();
+            for (final String pkg : flattened) {
+                if (pkg == null) {
+                    result.add(pkgsForOneUid);
+                    pkgsForOneUid = new HashSet<>();
+                } else {
+                    pkgsForOneUid.add(pkg);
+                }
+            }
+            if (!pkgsForOneUid.isEmpty()) {
+                result.add(pkgsForOneUid);
+            }
+            return result;
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return null;
+    }
+
+    /**
+     * Called by a device or profile owner, or delegated certificate chooser (an app that has been
      * delegated the {@link #DELEGATION_CERT_SELECTION} privilege), to revoke an application's
      * grant to a KeyChain key pair.
      * Calls by the application to {@link android.security.KeyChain#getPrivateKey}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index e21fee2..bcc90f7 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -471,6 +471,7 @@
     boolean startViewCalendarEventInManagedProfile(String packageName, long eventId, long start, long end, boolean allDay, int flags);
 
     boolean setKeyGrantForApp(in ComponentName admin, String callerPackage, String alias, String packageName, boolean hasGrant);
+    List<String> getKeyPairGrants(in String callerPackage, in String alias);
 
     void setUserControlDisabledPackages(in ComponentName admin, in List<String> packages);
 
diff --git a/core/java/android/hardware/hdmi/OWNERS b/core/java/android/hardware/hdmi/OWNERS
index e9557f8..16c15e3 100644
--- a/core/java/android/hardware/hdmi/OWNERS
+++ b/core/java/android/hardware/hdmi/OWNERS
@@ -1,3 +1,6 @@
-# Bug component: 345010
+# Bug component: 826094
 
 include /services/core/java/com/android/server/display/OWNERS
+
+marvinramin@google.com
+nchalko@google.com
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index a0faafa..d84ee2a 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -35,7 +35,6 @@
 import java.net.InetAddress;
 import java.net.SocketException;
 import java.net.UnknownHostException;
-import java.util.Collection;
 import java.util.Locale;
 import java.util.TreeSet;
 
@@ -342,20 +341,6 @@
     }
 
     /**
-     * Create a string array of host addresses from a collection of InetAddresses
-     * @param addrs a Collection of InetAddresses
-     * @return an array of Strings containing their host addresses
-     */
-    public static String[] makeStrings(Collection<InetAddress> addrs) {
-        String[] result = new String[addrs.size()];
-        int i = 0;
-        for (InetAddress addr : addrs) {
-            result[i++] = addr.getHostAddress();
-        }
-        return result;
-    }
-
-    /**
      * Trim leading zeros from IPv4 address strings
      * Our base libraries will interpret that as octel..
      * Must leave non v4 addresses and host names alone.
diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java
index f1d9669..20ccc07 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -205,7 +205,7 @@
                 if (host.equalsIgnoreCase("localhost")) {
                     return true;
                 }
-                if (NetworkUtils.numericToInetAddress(host).isLoopbackAddress()) {
+                if (InetAddresses.parseNumericAddress(host).isLoopbackAddress()) {
                     return true;
                 }
             }
diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl
index 84dd8af..29c9c15 100644
--- a/core/java/android/view/IPinnedStackListener.aidl
+++ b/core/java/android/view/IPinnedStackListener.aidl
@@ -58,19 +58,6 @@
     void onActivityHidden(in ComponentName componentName);
 
     /**
-     * Called when the window manager has detected change on DisplayInfo,  or
-     * when the listener is first registered to allow the listener to synchronized its state with
-     * the controller.
-     */
-    void onDisplayInfoChanged(in DisplayInfo displayInfo);
-
-    /**
-     * Called by the window manager at the beginning of a configuration update cascade
-     * since the metrics from these resources are used for bounds calculations.
-     */
-    void onConfigurationChanged();
-
-    /**
      * Called by the window manager when the aspect ratio is reset.
      */
     void onAspectRatioChanged(float aspectRatio);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index fb6eb97..3f3b202 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -106,7 +106,6 @@
 import com.android.internal.power.MeasuredEnergyStats;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
-import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.XmlUtils;
 
@@ -122,7 +121,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -1080,16 +1078,6 @@
     private long[] mCpuFreqs;
 
     /**
-     * Times spent by the system server process grouped by cluster and CPU speed.
-     */
-    private LongSamplingCounterArray mSystemServerCpuTimesUs;
-
-    /**
-     * Times spent by the system server threads grouped by cluster and CPU speed.
-     */
-    private LongSamplingCounterArray mSystemServerThreadCpuTimesUs;
-
-    /**
      * Times spent by the system server threads handling incoming binder requests.
      */
     private LongSamplingCounterArray mBinderThreadCpuTimesUs;
@@ -10756,6 +10744,14 @@
         }
     }
 
+    /**
+     * Starts tracking CPU time-in-state for threads of the system server process,
+     * keeping a separate account of threads receiving incoming binder calls.
+     */
+    public void startTrackingSystemServerCpuTime() {
+        mSystemServerCpuThreadReader.startTrackingThreadCpuTime();
+    }
+
     public void setCallback(BatteryCallback cb) {
         mCallback = cb;
     }
@@ -11411,8 +11407,6 @@
             mExternalSync.scheduleSync("reset", ExternalStatsSync.UPDATE_ENERGY);
         }
 
-        resetIfNotNull(mSystemServerCpuTimesUs, false, elapsedRealtimeUs);
-        resetIfNotNull(mSystemServerThreadCpuTimesUs, false, elapsedRealtimeUs);
         resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
 
         mLastHistoryStepDetails = null;
@@ -12511,27 +12505,17 @@
             return;
         }
 
-        if (mSystemServerCpuTimesUs == null) {
-            mSystemServerCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
-            mSystemServerThreadCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
+        if (mBinderThreadCpuTimesUs == null) {
             mBinderThreadCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
         }
-        mSystemServerCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.processCpuTimesUs);
-        mSystemServerThreadCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.threadCpuTimesUs);
         mBinderThreadCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
 
         if (DEBUG_BINDER_STATS) {
-            Slog.d(TAG, "System server threads per CPU cluster (binder threads/total threads/%)");
-            long totalCpuTimeMs = 0;
-            long totalThreadTimeMs = 0;
+            Slog.d(TAG, "System server threads per CPU cluster (incoming binder threads)");
             long binderThreadTimeMs = 0;
             int cpuIndex = 0;
-            final long[] systemServerCpuTimesUs =
-                    mSystemServerCpuTimesUs.getCountsLocked(0);
-            final long[] systemServerThreadCpuTimesUs =
-                    mSystemServerThreadCpuTimesUs.getCountsLocked(0);
-            final long[] binderThreadCpuTimesUs =
-                    mBinderThreadCpuTimesUs.getCountsLocked(0);
+            final long[] binderThreadCpuTimesUs = mBinderThreadCpuTimesUs.getCountsLocked(
+                    BatteryStats.STATS_SINCE_CHARGED);
             int index = 0;
             int numCpuClusters = mPowerProfile.getNumCpuClusters();
             for (int cluster = 0; cluster < numCpuClusters; cluster++) {
@@ -12542,28 +12526,15 @@
                     if (speed != 0) {
                         sb.append(", ");
                     }
-                    long totalCountMs = systemServerThreadCpuTimesUs[index] / 1000;
                     long binderCountMs = binderThreadCpuTimesUs[index] / 1000;
-                    sb.append(String.format("%d/%d(%.1f%%)",
-                            binderCountMs,
-                            totalCountMs,
-                            totalCountMs != 0 ? (double) binderCountMs * 100 / totalCountMs : 0));
+                    sb.append(TextUtils.formatSimple("%10d", binderCountMs));
 
-                    totalCpuTimeMs += systemServerCpuTimesUs[index] / 1000;
-                    totalThreadTimeMs += totalCountMs;
                     binderThreadTimeMs += binderCountMs;
                     index++;
                 }
                 cpuIndex += mPowerProfile.getNumCoresInCpuCluster(cluster);
                 Slog.d(TAG, sb.toString());
             }
-
-            Slog.d(TAG, "Total system server CPU time (ms): " + totalCpuTimeMs);
-            Slog.d(TAG, "Total system server thread time (ms): " + totalThreadTimeMs);
-            Slog.d(TAG, String.format("Total Binder thread time (ms): %d (%.1f%%)",
-                    binderThreadTimeMs,
-                    binderThreadTimeMs != 0
-                            ? (double) binderThreadTimeMs * 100 / totalThreadTimeMs : 0));
         }
     }
 
@@ -13853,60 +13824,16 @@
     }
 
 
+    /**
+     * Estimates the time spent by the system server handling incoming binder requests.
+     */
     @Override
     public long[] getSystemServiceTimeAtCpuSpeeds() {
-        // Estimates the time spent by the system server handling incoming binder requests.
-        //
-        // The data that we can get from the kernel is this:
-        //   - CPU duration for a (thread - cluster - CPU speed) combination
-        //   - CPU duration for a (UID - cluster - CPU speed) combination
-        //
-        // The configuration we have in the Power Profile is this:
-        //   - Average CPU power for a (cluster - CPU speed) combination.
-        //
-        // The model used by BatteryStats can be illustrated with this example:
-        //
-        // - Let's say the system server has 10 threads.
-        // - These 10 threads spent 1000 ms of CPU time in aggregate
-        // - Of the 10 threads 4 were execute exclusively incoming binder calls.
-        // - These 4 "binder" threads consumed 600 ms of CPU time in aggregate
-        // - The real time spent by the system server process doing all of this is, say, 200 ms.
-        //
-        // We will assume that power consumption is proportional to the time spent by the CPU
-        // across all threads.  This is a crude assumption, but we don't have more detailed data.
-        // Thus,
-        //   binderRealTime = realTime * aggregateBinderThreadTime / aggregateAllThreadTime
-        //
-        // In our example,
-        //   binderRealTime = 200 * 600 / 1000 = 120ms
-        //
-        // We can then multiply this estimated time by the average power to obtain an estimate
-        // of the total power consumed by incoming binder calls for the given cluster/speed
-        // combination.
-
-        if (mSystemServerCpuTimesUs == null) {
+        if (mBinderThreadCpuTimesUs == null) {
             return null;
         }
 
-        final long[] systemServerCpuTimesUs = mSystemServerCpuTimesUs.getCountsLocked(
-                BatteryStats.STATS_SINCE_CHARGED);
-        final long [] systemServerThreadCpuTimesUs = mSystemServerThreadCpuTimesUs.getCountsLocked(
-                BatteryStats.STATS_SINCE_CHARGED);
-        final long[] binderThreadCpuTimesUs = mBinderThreadCpuTimesUs.getCountsLocked(
-                BatteryStats.STATS_SINCE_CHARGED);
-
-        final int size = systemServerCpuTimesUs.length;
-        final long[] results = new long[size];
-
-        for (int i = 0; i < size; i++) {
-            if (systemServerThreadCpuTimesUs[i] == 0) {
-                continue;
-            }
-
-            results[i] = systemServerCpuTimesUs[i] * binderThreadCpuTimesUs[i]
-                    / systemServerThreadCpuTimesUs[i];
-        }
-        return results;
+        return mBinderThreadCpuTimesUs.getCountsLocked(BatteryStats.STATS_SINCE_CHARGED);
     }
 
     /**
@@ -14306,7 +14233,7 @@
         }
 
         updateSystemServiceCallStats();
-        if (mSystemServerThreadCpuTimesUs != null) {
+        if (mBinderThreadCpuTimesUs != null) {
             pw.println("Per UID System server binder time in ms:");
             long[] systemServiceTimeAtCpuSpeeds = getSystemServiceTimeAtCpuSpeeds();
             for (int i = 0; i < size; i++) {
@@ -15872,9 +15799,6 @@
             mUidStats.append(uid, u);
         }
 
-        mSystemServerCpuTimesUs = LongSamplingCounterArray.readFromParcel(in, mOnBatteryTimeBase);
-        mSystemServerThreadCpuTimesUs = LongSamplingCounterArray.readFromParcel(in,
-                mOnBatteryTimeBase);
         mBinderThreadCpuTimesUs = LongSamplingCounterArray.readFromParcel(in, mOnBatteryTimeBase);
     }
 
@@ -16083,8 +16007,6 @@
         } else {
             out.writeInt(0);
         }
-        LongSamplingCounterArray.writeToParcel(out, mSystemServerCpuTimesUs);
-        LongSamplingCounterArray.writeToParcel(out, mSystemServerThreadCpuTimesUs);
         LongSamplingCounterArray.writeToParcel(out, mBinderThreadCpuTimesUs);
     }
 
diff --git a/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
index e6a9623..4d2a08a 100644
--- a/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
@@ -16,23 +16,12 @@
 
 package com.android.internal.os;
 
-import static android.os.Process.PROC_OUT_LONG;
-import static android.os.Process.PROC_SPACE_TERM;
-
 import android.annotation.Nullable;
-import android.os.Process;
-import android.system.Os;
-import android.system.OsConstants;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.IOException;
-import java.nio.file.DirectoryIteratorException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.Arrays;
 
 /**
@@ -45,93 +34,65 @@
     private static final String TAG = "KernelSingleProcCpuThreadRdr";
 
     private static final boolean DEBUG = false;
-    private static final boolean NATIVE_ENABLED = true;
-
-    /**
-     * The name of the file to read CPU statistics from, must be found in {@code
-     * /proc/$PID/task/$TID}
-     */
-    private static final String CPU_STATISTICS_FILENAME = "time_in_state";
-
-    private static final String PROC_STAT_FILENAME = "stat";
-
-    /** Directory under /proc/$PID containing CPU stats files for threads */
-    public static final String THREAD_CPU_STATS_DIRECTORY = "task";
-
-    /** Default mount location of the {@code proc} filesystem */
-    private static final Path DEFAULT_PROC_PATH = Paths.get("/proc");
-
-    /** The initial {@code time_in_state} file for {@link ProcTimeInStateReader} */
-    private static final Path INITIAL_TIME_IN_STATE_PATH = Paths.get("self/time_in_state");
-
-    /** See https://man7.org/linux/man-pages/man5/proc.5.html */
-    private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
-            PROC_SPACE_TERM,
-            PROC_SPACE_TERM,
-            PROC_SPACE_TERM,
-            PROC_SPACE_TERM,
-            PROC_SPACE_TERM,
-            PROC_SPACE_TERM,
-            PROC_SPACE_TERM,
-            PROC_SPACE_TERM,
-            PROC_SPACE_TERM,
-            PROC_SPACE_TERM,
-            PROC_SPACE_TERM,
-            PROC_SPACE_TERM,
-            PROC_SPACE_TERM,
-            PROC_SPACE_TERM | PROC_OUT_LONG,                  // 14: utime
-            PROC_SPACE_TERM | PROC_OUT_LONG,                  // 15: stime
-            // Ignore remaining fields
-    };
-
-    private final long[] mProcessFullStatsData = new long[2];
-
-    private static final int PROCESS_FULL_STAT_UTIME = 0;
-    private static final int PROCESS_FULL_STAT_STIME = 1;
-
-    /** Used to read and parse {@code time_in_state} files */
-    private final ProcTimeInStateReader mProcTimeInStateReader;
 
     private final int mPid;
 
-    /** Where the proc filesystem is mounted */
-    private final Path mProcPath;
+    private final CpuTimeInStateReader mCpuTimeInStateReader;
 
-    // How long a CPU jiffy is in milliseconds.
-    private final long mJiffyMillis;
-
-    // Path: /proc/<pid>/stat
-    private final String mProcessStatFilePath;
-
-    // Path: /proc/<pid>/task
-    private final Path mThreadsDirectoryPath;
+    private int[] mSelectedThreadNativeTids = new int[0];  // Sorted
 
     /**
-     * Count of frequencies read from the {@code time_in_state} file. Read from {@link
-     * #mProcTimeInStateReader#getCpuFrequenciesKhz()}.
+     * Count of frequencies read from the {@code time_in_state} file.
      */
     private int mFrequencyCount;
 
+    private boolean mIsTracking;
+
+    /**
+     * A CPU time-in-state provider for testing.  Imitates the behavior of the corresponding
+     * methods in frameworks/native/libs/cputimeinstate/cputimeinstate.c
+     */
+    @VisibleForTesting
+    public interface CpuTimeInStateReader {
+        /**
+         * Returns the overall number of cluster-frequency combinations.
+         */
+        int getCpuFrequencyCount();
+
+        /**
+         * Returns true to indicate success.
+         *
+         * Called from native.
+         */
+        boolean startTrackingProcessCpuTimes(int tgid);
+
+        /**
+         * Returns true to indicate success.
+         *
+         * Called from native.
+         */
+        boolean startAggregatingTaskCpuTimes(int pid, int aggregationKey);
+
+        /**
+         * Must return an array of strings formatted like this:
+         * "aggKey:t0_0 t0_1...:t1_0 t1_1..."
+         * Times should be provided in nanoseconds.
+         *
+         * Called from native.
+         */
+        String[] getAggregatedTaskCpuFreqTimes(int pid);
+    }
+
     /**
      * Create with a path where `proc` is mounted. Used primarily for testing
      *
      * @param pid      PID of the process whose threads are to be read.
-     * @param procPath where `proc` is mounted (to find, see {@code mount | grep ^proc})
      */
     @VisibleForTesting
-    public KernelSingleProcessCpuThreadReader(
-            int pid,
-            Path procPath) throws IOException {
+    public KernelSingleProcessCpuThreadReader(int pid,
+            @Nullable CpuTimeInStateReader cpuTimeInStateReader) throws IOException {
         mPid = pid;
-        mProcPath = procPath;
-        mProcTimeInStateReader = new ProcTimeInStateReader(
-                mProcPath.resolve(INITIAL_TIME_IN_STATE_PATH));
-        long jiffyHz = Os.sysconf(OsConstants._SC_CLK_TCK);
-        mJiffyMillis = 1000 / jiffyHz;
-        mProcessStatFilePath =
-                mProcPath.resolve(String.valueOf(mPid)).resolve(PROC_STAT_FILENAME).toString();
-        mThreadsDirectoryPath =
-                mProcPath.resolve(String.valueOf(mPid)).resolve(THREAD_CPU_STATS_DIRECTORY);
+        mCpuTimeInStateReader = cpuTimeInStateReader;
     }
 
     /**
@@ -142,7 +103,7 @@
     @Nullable
     public static KernelSingleProcessCpuThreadReader create(int pid) {
         try {
-            return new KernelSingleProcessCpuThreadReader(pid, DEFAULT_PROC_PATH);
+            return new KernelSingleProcessCpuThreadReader(pid, null);
         } catch (IOException e) {
             Slog.e(TAG, "Failed to initialize KernelSingleProcessCpuThreadReader", e);
             return null;
@@ -150,146 +111,98 @@
     }
 
     /**
-     * Get the CPU frequencies that correspond to the times reported in {@link
-     * ProcessCpuUsage#processCpuTimesMillis} etc.
+     * Starts tracking aggregated CPU time-in-state of all threads of the process with the PID
+     * supplied in the constructor.
+     */
+    public void startTrackingThreadCpuTimes() {
+        if (!mIsTracking) {
+            if (!startTrackingProcessCpuTimes(mPid, mCpuTimeInStateReader)) {
+                Slog.e(TAG, "Failed to start tracking process CPU times for " + mPid);
+            }
+            if (mSelectedThreadNativeTids.length > 0) {
+                if (!startAggregatingThreadCpuTimes(mSelectedThreadNativeTids,
+                        mCpuTimeInStateReader)) {
+                    Slog.e(TAG, "Failed to start tracking aggregated thread CPU times for "
+                            + Arrays.toString(mSelectedThreadNativeTids));
+                }
+            }
+            mIsTracking = true;
+        }
+    }
+
+    /**
+     * @param nativeTids an array of native Thread IDs whose CPU times should
+     *                   be aggregated as a group.  This is expected to be a subset
+     *                   of all thread IDs owned by the process.
+     */
+    public void setSelectedThreadIds(int[] nativeTids) {
+        mSelectedThreadNativeTids = nativeTids.clone();
+        if (mIsTracking) {
+            startAggregatingThreadCpuTimes(mSelectedThreadNativeTids, mCpuTimeInStateReader);
+        }
+    }
+
+    /**
+     * Get the CPU frequencies that correspond to the times reported in {@link ProcessCpuUsage}.
      */
     public int getCpuFrequencyCount() {
         if (mFrequencyCount == 0) {
-            mFrequencyCount = mProcTimeInStateReader.getFrequenciesKhz().length;
+            mFrequencyCount = getCpuFrequencyCount(mCpuTimeInStateReader);
         }
         return mFrequencyCount;
     }
 
     /**
-     * Get the total and per-thread CPU usage of the process with the PID specified in the
-     * constructor.
-     *
-     * @param selectedThreadIds a SORTED array of native Thread IDs whose CPU times should
-     *                          be aggregated as a group.  This is expected to be a subset
-     *                          of all thread IDs owned by the process.
+     * Get the total CPU usage of the process with the PID specified in the
+     * constructor. The CPU usage time is aggregated across all threads and may
+     * exceed the time the entire process has been running.
      */
     @Nullable
-    public ProcessCpuUsage getProcessCpuUsage(int[] selectedThreadIds) {
+    public ProcessCpuUsage getProcessCpuUsage() {
         if (DEBUG) {
-            Slog.d(TAG, "Reading CPU thread usages with directory " + mProcPath + " process ID "
-                    + mPid);
+            Slog.d(TAG, "Reading CPU thread usages for PID " + mPid);
         }
 
-        int cpuFrequencyCount = getCpuFrequencyCount();
-        ProcessCpuUsage processCpuUsage = new ProcessCpuUsage(cpuFrequencyCount);
+        ProcessCpuUsage processCpuUsage = new ProcessCpuUsage(getCpuFrequencyCount());
 
-        if (NATIVE_ENABLED) {
-            boolean result = readProcessCpuUsage(mProcPath.toString(), mPid,
-                    selectedThreadIds, processCpuUsage.processCpuTimesMillis,
-                    processCpuUsage.threadCpuTimesMillis,
-                    processCpuUsage.selectedThreadCpuTimesMillis);
-            if (!result) {
-                return null;
-            }
-            return processCpuUsage;
-        }
-
-        if (!isSorted(selectedThreadIds)) {
-            throw new IllegalArgumentException("selectedThreadIds is not sorted: "
-                    + Arrays.toString(selectedThreadIds));
-        }
-
-        if (!Process.readProcFile(mProcessStatFilePath, PROCESS_FULL_STATS_FORMAT, null,
-                mProcessFullStatsData, null)) {
-            Slog.e(TAG, "Failed to read process stat file " + mProcessStatFilePath);
+        boolean result = readProcessCpuUsage(mPid,
+                processCpuUsage.threadCpuTimesMillis,
+                processCpuUsage.selectedThreadCpuTimesMillis,
+                mCpuTimeInStateReader);
+        if (!result) {
             return null;
         }
 
-        long utime = mProcessFullStatsData[PROCESS_FULL_STAT_UTIME];
-        long stime = mProcessFullStatsData[PROCESS_FULL_STAT_STIME];
-
-        long processCpuTimeMillis = (utime + stime) * mJiffyMillis;
-
-        try (DirectoryStream<Path> threadPaths = Files.newDirectoryStream(mThreadsDirectoryPath)) {
-            for (Path threadDirectory : threadPaths) {
-                readThreadCpuUsage(processCpuUsage, selectedThreadIds, threadDirectory);
-            }
-        } catch (IOException | DirectoryIteratorException e) {
-            // Expected when a process finishes
-            return null;
-        }
-
-        // Estimate per cluster per frequency CPU time for the entire process
-        // by distributing the total process CPU time proportionately to how much
-        // CPU time its threads took on those clusters/frequencies.  This algorithm
-        // works more accurately when when we have equally distributed concurrency.
-        // TODO(b/169279846): obtain actual process CPU times from the kernel
-        long totalCpuTimeAllThreads = 0;
-        for (int i = cpuFrequencyCount - 1; i >= 0; i--) {
-            totalCpuTimeAllThreads += processCpuUsage.threadCpuTimesMillis[i];
-        }
-
-        for (int i = cpuFrequencyCount - 1; i >= 0; i--) {
-            processCpuUsage.processCpuTimesMillis[i] =
-                    processCpuTimeMillis * processCpuUsage.threadCpuTimesMillis[i]
-                            / totalCpuTimeAllThreads;
+        if (DEBUG) {
+            Slog.d(TAG, "threadCpuTimesMillis = "
+                    + Arrays.toString(processCpuUsage.threadCpuTimesMillis));
+            Slog.d(TAG, "selectedThreadCpuTimesMillis = "
+                    + Arrays.toString(processCpuUsage.selectedThreadCpuTimesMillis));
         }
 
         return processCpuUsage;
     }
 
-    /**
-     * Reads a thread's CPU usage and aggregates the per-cluster per-frequency CPU times.
-     *
-     * @param threadDirectory the {@code /proc} directory of the thread
-     */
-    private void readThreadCpuUsage(ProcessCpuUsage processCpuUsage, int[] selectedThreadIds,
-            Path threadDirectory) {
-        // Get the thread ID from the directory name
-        final int threadId;
-        try {
-            final String directoryName = threadDirectory.getFileName().toString();
-            threadId = Integer.parseInt(directoryName);
-        } catch (NumberFormatException e) {
-            Slog.w(TAG, "Failed to parse thread ID when iterating over /proc/*/task", e);
-            return;
-        }
-
-        // Get the CPU statistics from the directory
-        final Path threadCpuStatPath = threadDirectory.resolve(CPU_STATISTICS_FILENAME);
-        final long[] cpuUsages = mProcTimeInStateReader.getUsageTimesMillis(threadCpuStatPath);
-        if (cpuUsages == null) {
-            return;
-        }
-
-        final int cpuFrequencyCount = getCpuFrequencyCount();
-        final boolean isSelectedThread = Arrays.binarySearch(selectedThreadIds, threadId) >= 0;
-        for (int i = cpuFrequencyCount - 1; i >= 0; i--) {
-            processCpuUsage.threadCpuTimesMillis[i] += cpuUsages[i];
-            if (isSelectedThread) {
-                processCpuUsage.selectedThreadCpuTimesMillis[i] += cpuUsages[i];
-            }
-        }
-    }
-
     /** CPU usage of a process, all of its threads and a selected subset of its threads */
     public static class ProcessCpuUsage {
-        public long[] processCpuTimesMillis;
         public long[] threadCpuTimesMillis;
         public long[] selectedThreadCpuTimesMillis;
 
         public ProcessCpuUsage(int cpuFrequencyCount) {
-            processCpuTimesMillis = new long[cpuFrequencyCount];
             threadCpuTimesMillis = new long[cpuFrequencyCount];
             selectedThreadCpuTimesMillis = new long[cpuFrequencyCount];
         }
     }
 
-    private static boolean isSorted(int[] array) {
-        for (int i = 0; i < array.length - 1; i++) {
-            if (array[i] > array[i + 1]) {
-                return false;
-            }
-        }
-        return true;
-    }
+    private native int getCpuFrequencyCount(CpuTimeInStateReader reader);
 
-    private native boolean readProcessCpuUsage(String procPath, int pid, int[] selectedThreadIds,
-            long[] processCpuTimesMillis, long[] threadCpuTimesMillis,
-            long[] selectedThreadCpuTimesMillis);
+    private native boolean startTrackingProcessCpuTimes(int pid, CpuTimeInStateReader reader);
+
+    private native boolean startAggregatingThreadCpuTimes(int[] selectedThreadIds,
+            CpuTimeInStateReader reader);
+
+    private native boolean readProcessCpuUsage(int pid,
+            long[] threadCpuTimesMillis,
+            long[] selectedThreadCpuTimesMillis,
+            CpuTimeInStateReader reader);
 }
diff --git a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
index fbbee94..fbad75e 100644
--- a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
+++ b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
@@ -22,8 +22,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Arrays;
 
 /**
  * Reads /proc/UID/task/TID/time_in_state files to obtain statistics on CPU usage
@@ -31,9 +29,7 @@
  */
 public class SystemServerCpuThreadReader {
     private final KernelSingleProcessCpuThreadReader mKernelCpuThreadReader;
-    private int[] mBinderThreadNativeTids = new int[0];  // Sorted
 
-    private long[] mLastProcessCpuTimeUs;
     private long[] mLastThreadCpuTimesUs;
     private long[] mLastBinderThreadCpuTimesUs;
 
@@ -41,8 +37,6 @@
      * Times (in microseconds) spent by the system server UID.
      */
     public static class SystemServiceCpuThreadTimes {
-        // The entire process
-        public long[] processCpuTimesUs;
         // All threads
         public long[] threadCpuTimesUs;
         // Just the threads handling incoming binder calls
@@ -61,8 +55,10 @@
     }
 
     @VisibleForTesting
-    public SystemServerCpuThreadReader(Path procPath, int pid) throws IOException {
-        this(new KernelSingleProcessCpuThreadReader(pid, procPath));
+    public SystemServerCpuThreadReader(int pid,
+            KernelSingleProcessCpuThreadReader.CpuTimeInStateReader cpuTimeInStateReader)
+            throws IOException {
+        this(new KernelSingleProcessCpuThreadReader(pid, cpuTimeInStateReader));
     }
 
     @VisibleForTesting
@@ -70,9 +66,15 @@
         mKernelCpuThreadReader = kernelCpuThreadReader;
     }
 
+    /**
+     * Start tracking CPU time-in-state for the process specified in the constructor.
+     */
+    public void startTrackingThreadCpuTime() {
+        mKernelCpuThreadReader.startTrackingThreadCpuTimes();
+    }
+
     public void setBinderThreadNativeTids(int[] nativeTids) {
-        mBinderThreadNativeTids = nativeTids.clone();
-        Arrays.sort(mBinderThreadNativeTids);
+        mKernelCpuThreadReader.setSelectedThreadIds(nativeTids);
     }
 
     /**
@@ -81,33 +83,27 @@
     @Nullable
     public SystemServiceCpuThreadTimes readDelta() {
         final int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequencyCount();
-        if (mLastProcessCpuTimeUs == null) {
-            mLastProcessCpuTimeUs = new long[numCpuFrequencies];
+        if (mLastThreadCpuTimesUs == null) {
             mLastThreadCpuTimesUs = new long[numCpuFrequencies];
             mLastBinderThreadCpuTimesUs = new long[numCpuFrequencies];
 
-            mDeltaCpuThreadTimes.processCpuTimesUs = new long[numCpuFrequencies];
             mDeltaCpuThreadTimes.threadCpuTimesUs = new long[numCpuFrequencies];
             mDeltaCpuThreadTimes.binderThreadCpuTimesUs = new long[numCpuFrequencies];
         }
 
         final KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
-                mKernelCpuThreadReader.getProcessCpuUsage(mBinderThreadNativeTids);
+                mKernelCpuThreadReader.getProcessCpuUsage();
         if (processCpuUsage == null) {
             return null;
         }
 
         for (int i = numCpuFrequencies - 1; i >= 0; i--) {
-            long processCpuTimesUs = processCpuUsage.processCpuTimesMillis[i] * 1000;
             long threadCpuTimesUs = processCpuUsage.threadCpuTimesMillis[i] * 1000;
             long binderThreadCpuTimesUs = processCpuUsage.selectedThreadCpuTimesMillis[i] * 1000;
-            mDeltaCpuThreadTimes.processCpuTimesUs[i] =
-                    Math.max(0, processCpuTimesUs - mLastProcessCpuTimeUs[i]);
             mDeltaCpuThreadTimes.threadCpuTimesUs[i] =
                     Math.max(0, threadCpuTimesUs - mLastThreadCpuTimesUs[i]);
             mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] =
                     Math.max(0, binderThreadCpuTimesUs - mLastBinderThreadCpuTimesUs[i]);
-            mLastProcessCpuTimeUs[i] = processCpuTimesUs;
             mLastThreadCpuTimesUs[i] = threadCpuTimesUs;
             mLastBinderThreadCpuTimesUs[i] = binderThreadCpuTimesUs;
         }
diff --git a/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp b/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp
index 52bed6b..dfae684 100644
--- a/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp
+++ b/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp
@@ -26,239 +26,230 @@
 #include <android_runtime/Log.h>
 
 #include <nativehelper/ScopedPrimitiveArray.h>
-#include <nativehelper/ScopedUtfChars.h>
 
 namespace android {
 
+static constexpr uint16_t DEFAULT_THREAD_AGGREGATION_KEY = 0;
+static constexpr uint16_t SELECTED_THREAD_AGGREGATION_KEY = 1;
+
+static constexpr uint64_t NSEC_PER_MSEC = 1000000;
+
 // Number of milliseconds in a jiffy - the unit of time measurement for processes and threads
 static const uint32_t gJiffyMillis = (uint32_t)(1000 / sysconf(_SC_CLK_TCK));
 
-// Given a PID, returns a vector of all TIDs for the process' tasks. Thread IDs are
-// file names in the /proc/<pid>/task directory.
-static bool getThreadIds(const std::string &procPath, const pid_t pid,
-                         std::vector<pid_t> &outThreadIds) {
-    std::string taskPath = android::base::StringPrintf("%s/%u/task", procPath.c_str(), pid);
+// Abstract class for readers of CPU time-in-state. There are two implementations of
+// this class: BpfCpuTimeInStateReader and MockCpuTimeInStateReader.  The former is used
+// by the production code. The latter is used by unit tests to provide mock
+// CPU time-in-state data via a Java implementation.
+class ICpuTimeInStateReader {
+public:
+    virtual ~ICpuTimeInStateReader() {}
 
-    struct dirent **dirlist;
-    int threadCount = scandir(taskPath.c_str(), &dirlist, NULL, NULL);
-    if (threadCount == -1) {
-        ALOGE("Cannot read directory %s", taskPath.c_str());
-        return false;
-    }
+    // Returns the overall number of cluser-frequency combinations
+    virtual size_t getCpuFrequencyCount();
 
-    outThreadIds.reserve(threadCount);
+    // Marks the CPU time-in-state tracking for threads of the specified TGID
+    virtual bool startTrackingProcessCpuTimes(pid_t) = 0;
 
-    for (int i = 0; i < threadCount; i++) {
-        pid_t tid;
-        if (android::base::ParseInt<pid_t>(dirlist[i]->d_name, &tid)) {
-            outThreadIds.push_back(tid);
+    // Marks the thread specified by its PID for CPU time-in-state tracking.
+    virtual bool startAggregatingTaskCpuTimes(pid_t, uint16_t) = 0;
+
+    // Retrieves the accumulated time-in-state data, which is organized as a map
+    // from aggregation keys to vectors of vectors using the format:
+    // { aggKey0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
+    //   aggKey1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
+    // where ti_j_k is the ns tid i spent running on the jth cluster at the cluster's kth lowest
+    // freq.
+    virtual std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
+    getAggregatedTaskCpuFreqTimes(pid_t, const std::vector<uint16_t> &);
+};
+
+// ICpuTimeInStateReader that uses eBPF to provide a map of aggregated CPU time-in-state values.
+// See cputtimeinstate.h/.cpp
+class BpfCpuTimeInStateReader : public ICpuTimeInStateReader {
+public:
+    size_t getCpuFrequencyCount() {
+        std::optional<std::vector<std::vector<uint32_t>>> cpuFreqs = android::bpf::getCpuFreqs();
+        if (!cpuFreqs) {
+            ALOGE("Cannot obtain CPU frequency count");
+            return 0;
         }
-        free(dirlist[i]);
-    }
-    free(dirlist);
 
-    return true;
+        size_t freqCount = 0;
+        for (auto cluster : *cpuFreqs) {
+            freqCount += cluster.size();
+        }
+
+        return freqCount;
+    }
+
+    bool startTrackingProcessCpuTimes(pid_t tgid) {
+        return android::bpf::startTrackingProcessCpuTimes(tgid);
+    }
+
+    bool startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey) {
+        return android::bpf::startAggregatingTaskCpuTimes(pid, aggregationKey);
+    }
+
+    std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
+    getAggregatedTaskCpuFreqTimes(pid_t pid, const std::vector<uint16_t> &aggregationKeys) {
+        return android::bpf::getAggregatedTaskCpuFreqTimes(pid, aggregationKeys);
+    }
+};
+
+// ICpuTimeInStateReader that uses JNI to provide a map of aggregated CPU time-in-state
+// values.
+// This version of CpuTimeInStateReader is used exclusively for providing mock data in tests.
+class MockCpuTimeInStateReader : public ICpuTimeInStateReader {
+private:
+    JNIEnv *mEnv;
+    jobject mCpuTimeInStateReader;
+
+public:
+    MockCpuTimeInStateReader(JNIEnv *env, jobject cpuTimeInStateReader)
+          : mEnv(env), mCpuTimeInStateReader(cpuTimeInStateReader) {}
+
+    size_t getCpuFrequencyCount();
+
+    bool startTrackingProcessCpuTimes(pid_t tgid);
+
+    bool startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey);
+
+    std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
+    getAggregatedTaskCpuFreqTimes(pid_t tgid, const std::vector<uint16_t> &aggregationKeys);
+};
+
+static ICpuTimeInStateReader *getCpuTimeInStateReader(JNIEnv *env,
+                                                      jobject cpuTimeInStateReaderObject) {
+    if (cpuTimeInStateReaderObject) {
+        return new MockCpuTimeInStateReader(env, cpuTimeInStateReaderObject);
+    } else {
+        return new BpfCpuTimeInStateReader();
+    }
 }
 
-// Reads contents of a time_in_state file and returns times as a vector of times per frequency
-// A time_in_state file contains pairs of frequency - time (in jiffies):
-//
-//    cpu0
-//    300000 30
-//    403200 0
-//    cpu4
-//    710400 10
-//    825600 20
-//    940800 30
-//
-static bool getThreadTimeInState(const std::string &procPath, const pid_t pid, const pid_t tid,
-                                 const size_t frequencyCount,
-                                 std::vector<uint64_t> &outThreadTimeInState) {
-    std::string timeInStateFilePath =
-            android::base::StringPrintf("%s/%u/task/%u/time_in_state", procPath.c_str(), pid, tid);
-    std::string data;
+static jint getCpuFrequencyCount(JNIEnv *env, jclass, jobject cpuTimeInStateReaderObject) {
+    std::unique_ptr<ICpuTimeInStateReader> cpuTimeInStateReader(
+            getCpuTimeInStateReader(env, cpuTimeInStateReaderObject));
+    return cpuTimeInStateReader->getCpuFrequencyCount();
+}
 
-    if (!android::base::ReadFileToString(timeInStateFilePath, &data)) {
-        ALOGE("Cannot read file: %s", timeInStateFilePath.c_str());
-        return false;
-    }
+static jboolean startTrackingProcessCpuTimes(JNIEnv *env, jclass, jint tgid,
+                                             jobject cpuTimeInStateReaderObject) {
+    std::unique_ptr<ICpuTimeInStateReader> cpuTimeInStateReader(
+            getCpuTimeInStateReader(env, cpuTimeInStateReaderObject));
+    return cpuTimeInStateReader->startTrackingProcessCpuTimes(tgid);
+}
 
-    auto lines = android::base::Split(data, "\n");
-    size_t index = 0;
-    for (const auto &line : lines) {
-        if (line.empty()) {
-            continue;
-        }
+static jboolean startAggregatingThreadCpuTimes(JNIEnv *env, jclass, jintArray selectedThreadIdArray,
+                                               jobject cpuTimeInStateReaderObject) {
+    ScopedIntArrayRO selectedThreadIds(env, selectedThreadIdArray);
+    std::unique_ptr<ICpuTimeInStateReader> cpuTimeInStateReader(
+            getCpuTimeInStateReader(env, cpuTimeInStateReaderObject));
 
-        auto numbers = android::base::Split(line, " ");
-        if (numbers.size() != 2) {
-            continue;
-        }
-        uint64_t timeInState;
-        if (!android::base::ParseUint<uint64_t>(numbers[1], &timeInState)) {
-            ALOGE("Invalid time_in_state file format: %s", timeInStateFilePath.c_str());
+    for (int i = 0; i < selectedThreadIds.size(); i++) {
+        if (!cpuTimeInStateReader->startAggregatingTaskCpuTimes(selectedThreadIds[i],
+                                                                SELECTED_THREAD_AGGREGATION_KEY)) {
             return false;
         }
-        if (index < frequencyCount) {
-            outThreadTimeInState[index] = timeInState;
-        }
-        index++;
     }
+    return true;
+}
 
+// Converts time-in-state data from a vector of vectors to a flat array.
+// Also converts from nanoseconds to milliseconds.
+static bool flattenTimeInStateData(ScopedLongArrayRW &cpuTimesMillis,
+                                   const std::vector<std::vector<uint64_t>> &data) {
+    size_t frequencyCount = cpuTimesMillis.size();
+    size_t index = 0;
+    for (const auto &cluster : data) {
+        for (const uint64_t &timeNanos : cluster) {
+            if (index < frequencyCount) {
+                cpuTimesMillis[index] = timeNanos / NSEC_PER_MSEC;
+            }
+            index++;
+        }
+    }
     if (index != frequencyCount) {
-        ALOGE("Incorrect number of frequencies %u in %s. Expected %u",
-              (uint32_t)outThreadTimeInState.size(), timeInStateFilePath.c_str(),
-              (uint32_t)frequencyCount);
+        ALOGE("CPU time-in-state reader returned data for %zu frequencies; expected: %zu", index,
+              frequencyCount);
         return false;
     }
 
     return true;
 }
 
-static int pidCompare(const void *a, const void *b) {
-    return (*(pid_t *)a - *(pid_t *)b);
-}
-
-static inline bool isSelectedThread(const pid_t tid, const pid_t *selectedThreadIds,
-                                    const size_t selectedThreadCount) {
-    return bsearch(&tid, selectedThreadIds, selectedThreadCount, sizeof(pid_t), pidCompare) != NULL;
-}
-
-// Reads all /proc/<pid>/task/*/time_in_state files and aggregates per-frequency
+// Reads all CPU time-in-state data accumulated by BPF and aggregates per-frequency
 // time in state data for all threads.  Also, separately aggregates time in state for
 // selected threads whose TIDs are passes as selectedThreadIds.
-static void aggregateThreadCpuTimes(const std::string &procPath, const pid_t pid,
-                                    const std::vector<pid_t> &threadIds,
-                                    const size_t frequencyCount, const pid_t *selectedThreadIds,
-                                    const size_t selectedThreadCount,
-                                    uint64_t *threadCpuTimesMillis,
-                                    uint64_t *selectedThreadCpuTimesMillis) {
-    for (size_t j = 0; j < frequencyCount; j++) {
-        threadCpuTimesMillis[j] = 0;
-        selectedThreadCpuTimesMillis[j] = 0;
-    }
-
-    for (size_t i = 0; i < threadIds.size(); i++) {
-        pid_t tid = threadIds[i];
-        std::vector<uint64_t> timeInState(frequencyCount);
-        if (!getThreadTimeInState(procPath, pid, tid, frequencyCount, timeInState)) {
-            continue;
-        }
-
-        bool selectedThread = isSelectedThread(tid, selectedThreadIds, selectedThreadCount);
-        for (size_t j = 0; j < frequencyCount; j++) {
-            threadCpuTimesMillis[j] += timeInState[j];
-            if (selectedThread) {
-                selectedThreadCpuTimesMillis[j] += timeInState[j];
-            }
-        }
-    }
-    for (size_t i = 0; i < frequencyCount; i++) {
-        threadCpuTimesMillis[i] *= gJiffyMillis;
-        selectedThreadCpuTimesMillis[i] *= gJiffyMillis;
-    }
-}
-
-// Reads process utime and stime from the /proc/<pid>/stat file.
-// Format of this file is described in https://man7.org/linux/man-pages/man5/proc.5.html.
-static bool getProcessCpuTime(const std::string &procPath, const pid_t pid,
-                              uint64_t &outTimeMillis) {
-    std::string statFilePath = android::base::StringPrintf("%s/%u/stat", procPath.c_str(), pid);
-    std::string data;
-    if (!android::base::ReadFileToString(statFilePath, &data)) {
-        return false;
-    }
-
-    auto fields = android::base::Split(data, " ");
-    uint64_t utime, stime;
-
-    // Field 14 (counting from 1) is utime - process time in user space, in jiffies
-    // Field 15 (counting from 1) is stime - process time in system space, in jiffies
-    if (fields.size() < 15 || !android::base::ParseUint(fields[13], &utime) ||
-        !android::base::ParseUint(fields[14], &stime)) {
-        ALOGE("Invalid file format %s", statFilePath.c_str());
-        return false;
-    }
-
-    outTimeMillis = (utime + stime) * gJiffyMillis;
-    return true;
-}
-
-// Estimates per cluster per frequency CPU time for the entire process
-// by distributing the total process CPU time proportionately to how much
-// CPU time its threads took on those clusters/frequencies.  This algorithm
-// works more accurately when when we have equally distributed concurrency.
-// TODO(b/169279846): obtain actual process CPU times from the kernel
-static void estimateProcessTimeInState(const uint64_t processCpuTimeMillis,
-                                       const uint64_t *threadCpuTimesMillis,
-                                       const size_t frequencyCount,
-                                       uint64_t *processCpuTimesMillis) {
-    uint64_t totalCpuTimeAllThreads = 0;
-    for (size_t i = 0; i < frequencyCount; i++) {
-        totalCpuTimeAllThreads += threadCpuTimesMillis[i];
-    }
-
-    if (totalCpuTimeAllThreads != 0) {
-        for (size_t i = 0; i < frequencyCount; i++) {
-            processCpuTimesMillis[i] =
-                    processCpuTimeMillis * threadCpuTimesMillis[i] / totalCpuTimeAllThreads;
-        }
-    } else {
-        for (size_t i = 0; i < frequencyCount; i++) {
-            processCpuTimesMillis[i] = 0;
-        }
-    }
-}
-
-static jboolean readProcessCpuUsage(JNIEnv *env, jclass, jstring procPath, jint pid,
-                                    jintArray selectedThreadIdArray,
-                                    jlongArray processCpuTimesMillisArray,
+static jboolean readProcessCpuUsage(JNIEnv *env, jclass, jint pid,
                                     jlongArray threadCpuTimesMillisArray,
-                                    jlongArray selectedThreadCpuTimesMillisArray) {
-    ScopedUtfChars procPathChars(env, procPath);
-    ScopedIntArrayRO selectedThreadIds(env, selectedThreadIdArray);
-    ScopedLongArrayRW processCpuTimesMillis(env, processCpuTimesMillisArray);
+                                    jlongArray selectedThreadCpuTimesMillisArray,
+                                    jobject cpuTimeInStateReaderObject) {
     ScopedLongArrayRW threadCpuTimesMillis(env, threadCpuTimesMillisArray);
     ScopedLongArrayRW selectedThreadCpuTimesMillis(env, selectedThreadCpuTimesMillisArray);
+    std::unique_ptr<ICpuTimeInStateReader> cpuTimeInStateReader(
+            getCpuTimeInStateReader(env, cpuTimeInStateReaderObject));
 
-    std::string procPathStr(procPathChars.c_str());
-
-    // Get all thread IDs for the process.
-    std::vector<pid_t> threadIds;
-    if (!getThreadIds(procPathStr, pid, threadIds)) {
-        ALOGE("Could not obtain thread IDs from: %s", procPathStr.c_str());
-        return false;
-    }
-
-    size_t frequencyCount = processCpuTimesMillis.size();
+    const size_t frequencyCount = cpuTimeInStateReader->getCpuFrequencyCount();
 
     if (threadCpuTimesMillis.size() != frequencyCount) {
-        ALOGE("Invalid array length: threadCpuTimesMillis");
+        ALOGE("Invalid threadCpuTimesMillis array length: %zu frequencies; expected: %zu",
+              threadCpuTimesMillis.size(), frequencyCount);
         return false;
     }
+
     if (selectedThreadCpuTimesMillis.size() != frequencyCount) {
-        ALOGE("Invalid array length: selectedThreadCpuTimesMillisArray");
+        ALOGE("Invalid selectedThreadCpuTimesMillis array length: %zu frequencies; expected: %zu",
+              selectedThreadCpuTimesMillis.size(), frequencyCount);
         return false;
     }
 
-    aggregateThreadCpuTimes(procPathStr, pid, threadIds, frequencyCount, selectedThreadIds.get(),
-                            selectedThreadIds.size(),
-                            reinterpret_cast<uint64_t *>(threadCpuTimesMillis.get()),
-                            reinterpret_cast<uint64_t *>(selectedThreadCpuTimesMillis.get()));
-
-    uint64_t processCpuTime;
-    bool ret = getProcessCpuTime(procPathStr, pid, processCpuTime);
-    if (ret) {
-        estimateProcessTimeInState(processCpuTime,
-                                   reinterpret_cast<uint64_t *>(threadCpuTimesMillis.get()),
-                                   frequencyCount,
-                                   reinterpret_cast<uint64_t *>(processCpuTimesMillis.get()));
+    for (size_t i = 0; i < frequencyCount; i++) {
+        threadCpuTimesMillis[i] = 0;
+        selectedThreadCpuTimesMillis[i] = 0;
     }
-    return ret;
+
+    std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>> data =
+            cpuTimeInStateReader->getAggregatedTaskCpuFreqTimes(pid,
+                                                                {DEFAULT_THREAD_AGGREGATION_KEY,
+                                                                 SELECTED_THREAD_AGGREGATION_KEY});
+    if (!data) {
+        ALOGE("Cannot read thread CPU times for PID %d", pid);
+        return false;
+    }
+
+    if (!flattenTimeInStateData(threadCpuTimesMillis, (*data)[DEFAULT_THREAD_AGGREGATION_KEY])) {
+        return false;
+    }
+
+    if (!flattenTimeInStateData(selectedThreadCpuTimesMillis,
+                                (*data)[SELECTED_THREAD_AGGREGATION_KEY])) {
+        return false;
+    }
+
+    // threadCpuTimesMillis returns CPU times for _all_ threads, including the selected ones
+    for (size_t i = 0; i < frequencyCount; i++) {
+        threadCpuTimesMillis[i] += selectedThreadCpuTimesMillis[i];
+    }
+
+    return true;
 }
 
 static const JNINativeMethod g_single_methods[] = {
-        {"readProcessCpuUsage", "(Ljava/lang/String;I[I[J[J[J)Z", (void *)readProcessCpuUsage},
+        {"getCpuFrequencyCount",
+         "(Lcom/android/internal/os/KernelSingleProcessCpuThreadReader$CpuTimeInStateReader;)I",
+         (void *)getCpuFrequencyCount},
+        {"startTrackingProcessCpuTimes",
+         "(ILcom/android/internal/os/KernelSingleProcessCpuThreadReader$CpuTimeInStateReader;)Z",
+         (void *)startTrackingProcessCpuTimes},
+        {"startAggregatingThreadCpuTimes",
+         "([ILcom/android/internal/os/KernelSingleProcessCpuThreadReader$CpuTimeInStateReader;)Z",
+         (void *)startAggregatingThreadCpuTimes},
+        {"readProcessCpuUsage",
+         "(I[J[J"
+         "Lcom/android/internal/os/KernelSingleProcessCpuThreadReader$CpuTimeInStateReader;)Z",
+         (void *)readProcessCpuUsage},
 };
 
 int register_com_android_internal_os_KernelSingleProcessCpuThreadReader(JNIEnv *env) {
@@ -266,4 +257,77 @@
                                 g_single_methods, NELEM(g_single_methods));
 }
 
+size_t MockCpuTimeInStateReader::getCpuFrequencyCount() {
+    jclass cls = mEnv->GetObjectClass(mCpuTimeInStateReader);
+    jmethodID mid = mEnv->GetMethodID(cls, "getCpuFrequencyCount", "()I");
+    if (mid == 0) {
+        ALOGE("Couldn't find the method getCpuFrequencyCount");
+        return false;
+    }
+    return (size_t)mEnv->CallIntMethod(mCpuTimeInStateReader, mid);
+}
+
+bool MockCpuTimeInStateReader::startTrackingProcessCpuTimes(pid_t tgid) {
+    jclass cls = mEnv->GetObjectClass(mCpuTimeInStateReader);
+    jmethodID mid = mEnv->GetMethodID(cls, "startTrackingProcessCpuTimes", "(I)Z");
+    if (mid == 0) {
+        ALOGE("Couldn't find the method startTrackingProcessCpuTimes");
+        return false;
+    }
+    return mEnv->CallBooleanMethod(mCpuTimeInStateReader, mid, tgid);
+}
+
+bool MockCpuTimeInStateReader::startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey) {
+    jclass cls = mEnv->GetObjectClass(mCpuTimeInStateReader);
+    jmethodID mid = mEnv->GetMethodID(cls, "startAggregatingTaskCpuTimes", "(II)Z");
+    if (mid == 0) {
+        ALOGE("Couldn't find the method startAggregatingTaskCpuTimes");
+        return false;
+    }
+    return mEnv->CallBooleanMethod(mCpuTimeInStateReader, mid, pid, aggregationKey);
+}
+
+std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
+MockCpuTimeInStateReader::getAggregatedTaskCpuFreqTimes(
+        pid_t pid, const std::vector<uint16_t> &aggregationKeys) {
+    jclass cls = mEnv->GetObjectClass(mCpuTimeInStateReader);
+    jmethodID mid =
+            mEnv->GetMethodID(cls, "getAggregatedTaskCpuFreqTimes", "(I)[Ljava/lang/String;");
+    if (mid == 0) {
+        ALOGE("Couldn't find the method getAggregatedTaskCpuFreqTimes");
+        return {};
+    }
+
+    std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>> map;
+
+    jobjectArray stringArray =
+            (jobjectArray)mEnv->CallObjectMethod(mCpuTimeInStateReader, mid, pid);
+    int size = mEnv->GetArrayLength(stringArray);
+    for (int i = 0; i < size; i++) {
+        ScopedUtfChars line(mEnv, (jstring)mEnv->GetObjectArrayElement(stringArray, i));
+        uint16_t aggregationKey;
+        std::vector<std::vector<uint64_t>> times;
+
+        // Each string is formatted like this: "aggKey:t0_0 t0_1...:t1_0 t1_1..."
+        auto fields = android::base::Split(line.c_str(), ":");
+        android::base::ParseUint(fields[0], &aggregationKey);
+
+        for (int j = 1; j < fields.size(); j++) {
+            auto numbers = android::base::Split(fields[j], " ");
+
+            std::vector<uint64_t> chunk;
+            for (int k = 0; k < numbers.size(); k++) {
+                uint64_t time;
+                android::base::ParseUint(numbers[k], &time);
+                chunk.emplace_back(time);
+            }
+            times.emplace_back(chunk);
+        }
+
+        map.emplace(aggregationKey, times);
+    }
+
+    return map;
+}
+
 } // namespace android
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1250eb7..7cd497e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2212,6 +2212,13 @@
     <permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows to read device identifiers and use ICC based authentication like EAP-AKA.
+         Often required in authentication to access the carrier's server and manage services
+         of the subscriber.
+         <p>Protection level: signature|appop -->
+    <permission android:name="android.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER"
+        android:protectionLevel="signature|appop" />
+
     <!-- @SystemApi Allows read access to emergency number information for ongoing calls or SMS
          sessions.
          @hide Used internally. -->
@@ -2379,6 +2386,15 @@
     <permission android:name="android.permission.READ_CARRIER_APP_INFO"
         android:protectionLevel="signature" />
 
+    <!-- Must be required by an GbaService to ensure that only the
+         system can bind to it.
+         <p>Protection level: signature
+         @SystemApi
+         @hide
+    -->
+    <permission android:name="android.permission.BIND_GBA_SERVICE"
+        android:protectionLevel="signature" />
+
     <!-- ================================== -->
     <!-- Permissions for sdcard interaction -->
     <!-- ================================== -->
@@ -3953,6 +3969,14 @@
     <permission android:name="android.permission.ACCESS_SURFACE_FLINGER"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows an application to rotate a surface by arbitrary degree.
+         This is a sub-feature of ACCESS_SURFACE_FLINGER and can be granted in a more concrete way.
+         <p>Not for use by third-party applications.
+         @hide
+    -->
+    <permission android:name="android.permission.ROTATE_SURFACE_FLINGER"
+        android:protectionLevel="signature|recents" />
+
     <!-- Allows an application to take screen shots and more generally
          get access to the frame buffer data.
          <p>Not for use by third-party applications.
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
index b5720a2..2de800b 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
@@ -19,122 +19,87 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.os.FileUtils;
-
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.File;
 import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class KernelSingleProcessCpuThreadReaderTest {
 
-    private File mProcDirectory;
-
-    @Before
-    public void setUp() {
-        Context context = InstrumentationRegistry.getContext();
-        mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        FileUtils.deleteContents(mProcDirectory);
-    }
-
     @Test
     public void getProcessCpuUsage() throws IOException {
-        setupDirectory(42,
-                new int[] {42, 1, 2, 3},
-                new int[] {1000, 2000},
-                // Units are 10ms aka 10000Us
-                new int[][] {{100, 200}, {0, 200}, {100, 300}, {0, 600}},
-                new int[] {4500, 500});
+        // Units are nanoseconds
+        MockCpuTimeInStateReader mockReader = new MockCpuTimeInStateReader(4, new String[] {
+                "0:1000000000 2000000000 3000000000:4000000000",
+                "1:100000000 200000000 300000000:400000000",
+        });
 
         KernelSingleProcessCpuThreadReader reader = new KernelSingleProcessCpuThreadReader(42,
-                mProcDirectory.toPath());
+                mockReader);
+        reader.setSelectedThreadIds(new int[] {2, 3});
+        reader.startTrackingThreadCpuTimes();
         KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
-                reader.getProcessCpuUsage(new int[] {2, 3});
-        assertThat(processCpuUsage.threadCpuTimesMillis).isEqualTo(new long[] {2000, 13000});
-        assertThat(processCpuUsage.selectedThreadCpuTimesMillis).isEqualTo(new long[] {1000, 9000});
-        assertThat(processCpuUsage.processCpuTimesMillis).isEqualTo(new long[] {6666, 43333});
+                reader.getProcessCpuUsage();
+        assertThat(mockReader.mTrackedTgid).isEqualTo(42);
+        // The strings are formatted as <TID TGID AGG_KEY>, where AGG_KEY is 1 for binder
+        // threads and 0 for all other threads.
+        assertThat(mockReader.mTrackedTasks).containsExactly(
+                "2 1",
+                "3 1");
+        assertThat(processCpuUsage.threadCpuTimesMillis).isEqualTo(
+                new long[] {1100, 2200, 3300, 4400});
+        assertThat(processCpuUsage.selectedThreadCpuTimesMillis).isEqualTo(
+                new long[] {100, 200, 300, 400});
     }
 
     @Test
     public void getCpuFrequencyCount() throws IOException {
-        setupDirectory(13,
-                new int[] {13},
-                new int[] {1000, 2000, 3000},
-                new int[][] {{100, 200, 300}},
-                new int[] {14, 15});
+        MockCpuTimeInStateReader mockReader = new MockCpuTimeInStateReader(3, new String[0]);
 
         KernelSingleProcessCpuThreadReader reader = new KernelSingleProcessCpuThreadReader(13,
-                mProcDirectory.toPath());
+                mockReader);
         int cpuFrequencyCount = reader.getCpuFrequencyCount();
         assertThat(cpuFrequencyCount).isEqualTo(3);
     }
 
-    private void setupDirectory(int pid, int[] threadIds, int[] cpuFrequencies,
-            int[][] threadCpuTimes, int[] processCpuTimes)
-            throws IOException {
+    public static class MockCpuTimeInStateReader implements
+            KernelSingleProcessCpuThreadReader.CpuTimeInStateReader {
+        private final int mCpuFrequencyCount;
+        private final String[] mAggregatedTaskCpuFreqTimes;
+        public int mTrackedTgid;
+        public List<String> mTrackedTasks = new ArrayList<>();
 
-        assertTrue(mProcDirectory.toPath().resolve("self").toFile().mkdirs());
-
-        try (OutputStream timeInStateStream =
-                     Files.newOutputStream(
-                             mProcDirectory.toPath().resolve("self").resolve("time_in_state"))) {
-            for (int i = 0; i < cpuFrequencies.length; i++) {
-                final String line = cpuFrequencies[i] + " 0\n";
-                timeInStateStream.write(line.getBytes());
-            }
+        public MockCpuTimeInStateReader(int cpuFrequencyCount,
+                String[] aggregatedTaskCpuFreqTimes) {
+            mCpuFrequencyCount = cpuFrequencyCount;
+            mAggregatedTaskCpuFreqTimes = aggregatedTaskCpuFreqTimes;
         }
 
-        Path processPath = mProcDirectory.toPath().resolve(String.valueOf(pid));
-
-        // Make /proc/$PID
-        assertTrue(processPath.toFile().mkdirs());
-
-        // Write /proc/$PID/stat. Only the fields 14-17 matter.
-        try (OutputStream timeInStateStream = Files.newOutputStream(processPath.resolve("stat"))) {
-            timeInStateStream.write(
-                    (pid + " (test) S 4 5 6 7 8 9 10 11 12 13 "
-                            + processCpuTimes[0] + " "
-                            + processCpuTimes[1] + " "
-                            + "16 17 18 19 20 ...").getBytes());
+        @Override
+        public int getCpuFrequencyCount() {
+            return mCpuFrequencyCount;
         }
 
-        // Make /proc/$PID/task
-        final Path selfThreadsPath = processPath.resolve("task");
-        assertTrue(selfThreadsPath.toFile().mkdirs());
+        @Override
+        public boolean startTrackingProcessCpuTimes(int tgid) {
+            mTrackedTgid = tgid;
+            return true;
+        }
 
-        // Make thread directories
-        for (int i = 0; i < threadIds.length; i++) {
-            // Make /proc/$PID/task/$TID
-            final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
-            assertTrue(threadPath.toFile().mkdirs());
+        public boolean startAggregatingTaskCpuTimes(int pid, int aggregationKey) {
+            mTrackedTasks.add(pid + " " + aggregationKey);
+            return true;
+        }
 
-            // Make /proc/$PID/task/$TID/time_in_state
-            try (OutputStream timeInStateStream =
-                         Files.newOutputStream(threadPath.resolve("time_in_state"))) {
-                for (int j = 0; j < cpuFrequencies.length; j++) {
-                    final String line = cpuFrequencies[j] + " " + threadCpuTimes[i][j] + "\n";
-                    timeInStateStream.write(line.getBytes());
-                }
-            }
+        public String[] getAggregatedTaskCpuFreqTimes(int pid) {
+            return mAggregatedTaskCpuFreqTimes;
         }
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
index 121c637..d116d4d 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
@@ -16,146 +16,86 @@
 
 package com.android.internal.os;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
 
-import android.content.Context;
-import android.os.FileUtils;
-
-import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.File;
 import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class SystemServerCpuThreadReaderTest {
-    private File mProcDirectory;
-
-    @Before
-    public void setUp() {
-        Context context = InstrumentationRegistry.getContext();
-        mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        FileUtils.deleteContents(mProcDirectory);
-    }
 
     @Test
-    public void testReaderDelta_firstTime() throws IOException {
+    public void testReadDelta() throws IOException {
         int pid = 42;
-        setupDirectory(
-                pid,
-                new int[] {42, 1, 2, 3},
-                new int[] {1000, 2000},
-                // Units are 10ms aka 10000Us
-                new int[][] {{100, 200}, {0, 200}, {0, 300}, {0, 400}},
-                new int[] {1400, 1500});
 
-        SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
-                mProcDirectory.toPath(), pid);
-        reader.setBinderThreadNativeTids(new int[] {1, 3});
-        SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
-                reader.readDelta();
-        assertArrayEquals(new long[] {100 * 10000, 1100 * 10000},
-                systemServiceCpuThreadTimes.threadCpuTimesUs);
-        assertArrayEquals(new long[] {0, 600 * 10000},
-                systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
-    }
+        MockCpuTimeInStateReader mockReader = new MockCpuTimeInStateReader(4);
+        // Units are nanoseconds
+        mockReader.setAggregatedTaskCpuFreqTimes(new String[] {
+                "0:1000000000 2000000000 3000000000:4000000000",
+                "1:100000000 200000000 300000000:400000000",
+        });
 
-    @Test
-    public void testReaderDelta_nextTime() throws IOException {
-        int pid = 42;
-        setupDirectory(
-                pid,
-                new int[] {42, 1, 2, 3},
-                new int[] {1000, 2000},
-                new int[][] {{100, 200}, {0, 200}, {0, 300}, {0, 400}},
-                new int[] {1400, 1500});
-
-        SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
-                mProcDirectory.toPath(), pid);
+        SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(pid, mockReader);
         reader.setBinderThreadNativeTids(new int[] {1, 3});
 
-        // First time, populate "last" snapshot
-        reader.readDelta();
-
-        FileUtils.deleteContents(mProcDirectory);
-        setupDirectory(
-                pid,
-                new int[] {42, 1, 2, 3},
-                new int[] {1000, 2000},
-                new int[][] {{500, 600}, {700, 800}, {900, 1000}, {1100, 1200}},
-                new int[] {2400, 2500});
-
-        // Second time, get the actual delta
+        // The first invocation of readDelta populates the "last" snapshot
         SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
                 reader.readDelta();
 
-        assertArrayEquals(new long[] {3100 * 10000, 2500 * 10000},
-                systemServiceCpuThreadTimes.threadCpuTimesUs);
-        assertArrayEquals(new long[] {1800 * 10000, 1400 * 10000},
-                systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
+        assertThat(systemServiceCpuThreadTimes.threadCpuTimesUs)
+                .isEqualTo(new long[] {1100000, 2200000, 3300000, 4400000});
+        assertThat(systemServiceCpuThreadTimes.binderThreadCpuTimesUs)
+                .isEqualTo(new long[] {100000, 200000, 300000, 400000});
+
+        mockReader.setAggregatedTaskCpuFreqTimes(new String[] {
+                "0:1010000000 2020000000 3030000000:4040000000",
+                "1:101000000 202000000 303000000:404000000",
+        });
+
+        // The second invocation gets the actual delta
+        systemServiceCpuThreadTimes = reader.readDelta();
+
+        assertThat(systemServiceCpuThreadTimes.threadCpuTimesUs)
+                .isEqualTo(new long[] {11000, 22000, 33000, 44000});
+        assertThat(systemServiceCpuThreadTimes.binderThreadCpuTimesUs)
+                .isEqualTo(new long[] {1000, 2000, 3000, 4000});
     }
 
-    private void setupDirectory(int pid, int[] threadIds, int[] cpuFrequencies, int[][] cpuTimes,
-            int[] processCpuTimes)
-            throws IOException {
+    public static class MockCpuTimeInStateReader implements
+            KernelSingleProcessCpuThreadReader.CpuTimeInStateReader {
+        private final int mCpuFrequencyCount;
+        private String[] mAggregatedTaskCpuFreqTimes;
 
-        assertTrue(mProcDirectory.toPath().resolve("self").toFile().mkdirs());
-
-        try (OutputStream timeInStateStream =
-                     Files.newOutputStream(
-                             mProcDirectory.toPath().resolve("self").resolve("time_in_state"))) {
-            for (int i = 0; i < cpuFrequencies.length; i++) {
-                final String line = cpuFrequencies[i] + " 0\n";
-                timeInStateStream.write(line.getBytes());
-            }
+        MockCpuTimeInStateReader(int frequencyCount) {
+            mCpuFrequencyCount = frequencyCount;
         }
 
-        Path processPath = mProcDirectory.toPath().resolve(String.valueOf(pid));
-        // Make /proc/$PID
-        assertTrue(processPath.toFile().mkdirs());
-
-        // Write /proc/$PID/stat. Only the fields 14-17 matter.
-        try (OutputStream timeInStateStream = Files.newOutputStream(processPath.resolve("stat"))) {
-            timeInStateStream.write(
-                    (pid + " (test) S 4 5 6 7 8 9 10 11 12 13 "
-                            + processCpuTimes[0] + " "
-                            + processCpuTimes[1] + " "
-                            + "16 17 18 19 20 ...").getBytes());
+        @Override
+        public int getCpuFrequencyCount() {
+            return mCpuFrequencyCount;
         }
 
-        // Make /proc/$PID/task
-        final Path selfThreadsPath = processPath.resolve("task");
-        assertTrue(selfThreadsPath.toFile().mkdirs());
+        @Override
+        public boolean startTrackingProcessCpuTimes(int tgid) {
+            return true;
+        }
 
-        // Make thread directories
-        for (int i = 0; i < threadIds.length; i++) {
-            // Make /proc/$PID/task/$TID
-            final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
-            assertTrue(threadPath.toFile().mkdirs());
+        public boolean startAggregatingTaskCpuTimes(int pid, int aggregationKey) {
+            return true;
+        }
 
-            // Make /proc/$PID/task/$TID/time_in_state
-            try (OutputStream timeInStateStream =
-                         Files.newOutputStream(threadPath.resolve("time_in_state"))) {
-                for (int j = 0; j < cpuFrequencies.length; j++) {
-                    final String line = cpuFrequencies[j] + " " + cpuTimes[i][j] + "\n";
-                    timeInStateStream.write(line.getBytes());
-                }
-            }
+        public void setAggregatedTaskCpuFreqTimes(String[] mAggregatedTaskCpuFreqTimes) {
+            this.mAggregatedTaskCpuFreqTimes = mAggregatedTaskCpuFreqTimes;
+        }
+
+        public String[] getAggregatedTaskCpuFreqTimes(int pid) {
+            return mAggregatedTaskCpuFreqTimes;
         }
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index dbb36fb..c8e8585 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -66,7 +66,6 @@
     public void testCalculateApp() {
         // Test Power Profile has two CPU clusters with 3 and 4 speeds, thus 7 freq times total
         mMockSystemServerCpuThreadReader.setCpuTimes(
-                new long[] {10000, 15000, 20000, 25000, 30000, 35000, 40000},
                 new long[] {30000, 40000, 50000, 60000, 70000, 80000, 90000},
                 new long[] {20000, 30000, 40000, 50000, 60000, 70000, 80000});
 
@@ -146,9 +145,7 @@
             super(null);
         }
 
-        public void setCpuTimes(long[] processCpuTimesUs, long[] threadCpuTimesUs,
-                long[] binderThreadCpuTimesUs) {
-            mThreadTimes.processCpuTimesUs = processCpuTimesUs;
+        public void setCpuTimes(long[] threadCpuTimesUs, long[] binderThreadCpuTimesUs) {
             mThreadTimes.threadCpuTimesUs = threadCpuTimesUs;
             mThreadTimes.binderThreadCpuTimesUs = binderThreadCpuTimesUs;
         }
diff --git a/data/etc/car/OWNERS b/data/etc/car/OWNERS
new file mode 100644
index 0000000..09e257c
--- /dev/null
+++ b/data/etc/car/OWNERS
@@ -0,0 +1 @@
+include platform/packages/services/Car:/OWNERS
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index add52fa..a9d4094 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -49,6 +49,7 @@
         in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias, int uid);
     boolean removeKeyPair(String alias);
     boolean containsKeyPair(String alias);
+    int[] getGrants(String alias);
 
     // APIs used by Settings
     boolean deleteCaCertificate(String alias);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 625c0a7..a89c8bb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -54,7 +54,6 @@
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.splitscreen.SplitScreen;
 
-import java.util.Objects;
 import java.util.Optional;
 
 /**
@@ -108,16 +107,22 @@
         DragLayout dragLayout = new DragLayout(context, mSplitScreen);
         rootView.addView(dragLayout,
                 new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-        wm.addView(rootView, layoutParams);
-
-        mDisplayDropTargets.put(displayId,
-                new PerDisplay(displayId, context, wm, rootView, dragLayout));
+        try {
+            wm.addView(rootView, layoutParams);
+            mDisplayDropTargets.put(displayId,
+                    new PerDisplay(displayId, context, wm, rootView, dragLayout));
+        } catch (WindowManager.InvalidDisplayException e) {
+            Slog.w(TAG, "Unable to add view for display id: " + displayId);
+        }
     }
 
     @Override
     public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Display changed: %d", displayId);
         final PerDisplay pd = mDisplayDropTargets.get(displayId);
+        if (pd == null) {
+            return;
+        }
         pd.rootView.requestApplyInsets();
     }
 
@@ -125,6 +130,9 @@
     public void onDisplayRemoved(int displayId) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Display removed: %d", displayId);
         final PerDisplay pd = mDisplayDropTargets.get(displayId);
+        if (pd == null) {
+            return;
+        }
         pd.wm.removeViewImmediate(pd.rootView);
         mDisplayDropTargets.remove(displayId);
     }
@@ -139,6 +147,10 @@
         final PerDisplay pd = mDisplayDropTargets.get(displayId);
         final ClipDescription description = event.getClipDescription();
 
+        if (pd == null) {
+            return false;
+        }
+
         if (event.getAction() == ACTION_DRAG_STARTED) {
             final boolean hasValidClipData = event.getClipData().getItemCount() > 0
                     && (description.hasMimeType(MIMETYPE_APPLICATION_ACTIVITY)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
index 5593268..d59aec2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PinnedStackListenerForwarder.java
@@ -20,7 +20,6 @@
 import android.content.ComponentName;
 import android.content.pm.ParceledListSlice;
 import android.os.RemoteException;
-import android.view.DisplayInfo;
 import android.view.IPinnedStackListener;
 import android.view.WindowManagerGlobal;
 
@@ -85,18 +84,6 @@
         }
     }
 
-    private void onDisplayInfoChanged(DisplayInfo displayInfo) {
-        for (PinnedStackListener listener : mListeners) {
-            listener.onDisplayInfoChanged(displayInfo);
-        }
-    }
-
-    private void onConfigurationChanged() {
-        for (PinnedStackListener listener : mListeners) {
-            listener.onConfigurationChanged();
-        }
-    }
-
     private void onAspectRatioChanged(float aspectRatio) {
         for (PinnedStackListener listener : mListeners) {
             listener.onAspectRatioChanged(aspectRatio);
@@ -134,20 +121,6 @@
         }
 
         @Override
-        public void onDisplayInfoChanged(DisplayInfo displayInfo) {
-            mShellMainExecutor.execute(() -> {
-                PinnedStackListenerForwarder.this.onDisplayInfoChanged(displayInfo);
-            });
-        }
-
-        @Override
-        public void onConfigurationChanged() {
-            mShellMainExecutor.execute(() -> {
-                PinnedStackListenerForwarder.this.onConfigurationChanged();
-            });
-        }
-
-        @Override
         public void onAspectRatioChanged(float aspectRatio) {
             mShellMainExecutor.execute(() -> {
                 PinnedStackListenerForwarder.this.onAspectRatioChanged(aspectRatio);
@@ -168,10 +141,6 @@
 
         public void onActivityHidden(ComponentName componentName) {}
 
-        public void onDisplayInfoChanged(DisplayInfo displayInfo) {}
-
-        public void onConfigurationChanged() {}
-
         public void onAspectRatioChanged(float aspectRatio) {}
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index da9ce0a..1f07542 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -20,6 +20,7 @@
 import android.app.PictureInPictureParams;
 import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 
 import com.android.wm.shell.common.annotations.ExternalThread;
@@ -82,6 +83,12 @@
     }
 
     /**
+     * Called when configuration is changed.
+     */
+    default void onConfigurationChanged(Configuration newConfig) {
+    }
+
+    /**
      * Called when display size or font size of settings changed
      */
     default void onDensityOrFontScaleChanged() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index 1bb5eda..22d8ed5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -102,9 +102,7 @@
         return mSnapAlgorithm;
     }
 
-    /**
-     * Responds to IPinnedStackListener on configuration change.
-     */
+    /** Responds to configuration change. */
     public void onConfigurationChanged(Context context) {
         reloadResources(context);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 167b9f9..9081783 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -502,7 +502,6 @@
 
         mPipMenuController.attach(leash);
 
-
         if (mShouldIgnoreEnteringPipTransition) {
             final Rect destinationBounds = mPipBoundsState.getBounds();
             // animation is finished in the Launcher and here we directly apply the final touch.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 3234ef6..46fff85 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -33,6 +33,7 @@
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ParceledListSlice;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -104,6 +105,9 @@
             // Skip if we aren't in PIP or haven't actually entered PIP yet. We still need to update
             // the display layout in the bounds handler in this case.
             onDisplayRotationChangedNotInPip(mContext, toRotation);
+            // do not forget to update the movement bounds as well.
+            updateMovementBounds(mPipBoundsState.getNormalBounds(), true /* fromRotation */,
+                    false /* fromImeAdjustment */, false /* fromShelfAdjustment */, t);
             return;
         }
         // If there is an animation running (ie. from a shelf offset), then ensure that we calculate
@@ -136,7 +140,7 @@
         }
     };
 
-    private DisplayController.OnDisplaysChangedListener mFixedRotationListener =
+    private final DisplayController.OnDisplaysChangedListener mFixedRotationListener =
             new DisplayController.OnDisplaysChangedListener() {
                 @Override
                 public void onFixedRotationStarted(int displayId, int newRotation) {
@@ -188,18 +192,6 @@
         }
 
         @Override
-        public void onDisplayInfoChanged(DisplayInfo displayInfo) {
-            mPipBoundsState.setDisplayInfo(displayInfo);
-        }
-
-        @Override
-        public void onConfigurationChanged() {
-            mPipBoundsAlgorithm.onConfigurationChanged(mContext);
-            mTouchHandler.onConfigurationChanged();
-            mPipBoundsState.onConfigurationChanged();
-        }
-
-        @Override
         public void onAspectRatioChanged(float aspectRatio) {
             // TODO(b/169373982): Remove this callback as it is redundant with PipTaskOrg params
             // change.
@@ -334,6 +326,15 @@
     }
 
     @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        mMainExecutor.execute(() -> {
+            mPipBoundsAlgorithm.onConfigurationChanged(mContext);
+            mTouchHandler.onConfigurationChanged();
+            mPipBoundsState.onConfigurationChanged();
+        });
+    }
+
+    @Override
     public void onDensityOrFontScaleChanged() {
         mMainExecutor.execute(() -> {
             mPipTaskOrganizer.onDensityOrFontScaleChanged(mContext);
@@ -532,7 +533,7 @@
      *
      * @return {@code true} if internal {@link DisplayInfo} is rotated, {@code false} otherwise.
      */
-    public boolean onDisplayRotationChanged(Context context, Rect outBounds, Rect oldBounds,
+    private boolean onDisplayRotationChanged(Context context, Rect outBounds, Rect oldBounds,
             Rect outInsetBounds,
             int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) {
         // Bail early if the event is not sent to current {@link #mDisplayInfo}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index 88a1168..2f5219c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -93,6 +93,7 @@
 
     private int mDelta;
     private float mTouchSlop;
+
     private boolean mAllowGesture;
     private boolean mIsAttached;
     private boolean mIsEnabled;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 9281f58..33439a4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -86,7 +86,7 @@
     private boolean mEnableStash = true;
 
     // The reference inset bounds, used to determine the dismiss fraction
-    private Rect mInsetBounds = new Rect();
+    private final Rect mInsetBounds = new Rect();
     private int mExpandedShortestEdgeSize;
 
     // Used to workaround an issue where the WM rotation happens before we are notified, allowing
@@ -94,7 +94,8 @@
     private int mDeferResizeToNormalBoundsUntilRotation = -1;
     private int mDisplayRotation;
 
-    private Handler mHandler = new Handler();
+    private final Handler mHandler = new Handler();
+    private final PipAccessibilityInteractionConnection mConnection;
 
     // Behaviour states
     private int mMenuState = MENU_STATE_NONE;
@@ -108,7 +109,6 @@
     private float mSavedSnapFraction = -1f;
     private boolean mSendingHoverAccessibilityEvents;
     private boolean mMovementWithinDismiss;
-    private PipAccessibilityInteractionConnection mConnection;
 
     // Touch state
     private final PipTouchState mTouchState;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
index 763370b..0955056 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
@@ -37,7 +37,6 @@
 import android.content.pm.ParceledListSlice;
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.os.Debug;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -56,8 +55,6 @@
 import com.android.wm.shell.pip.PipMediaController;
 import com.android.wm.shell.pip.PipTaskOrganizer;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Objects;
 
 /**
@@ -87,42 +84,21 @@
     private static final int TASK_ID_NO_PIP = -1;
     private static final int INVALID_RESOURCE_TYPE = -1;
 
-    public static final int SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH = 0x1;
-
-    /**
-     * PIPed activity is playing a media and it can be paused.
-     */
-    static final int PLAYBACK_STATE_PLAYING = 0;
-    /**
-     * PIPed activity has a paused media and it can be played.
-     */
-    static final int PLAYBACK_STATE_PAUSED = 1;
-    /**
-     * Users are unable to control PIPed activity's media playback.
-     */
-    static final int PLAYBACK_STATE_UNAVAILABLE = 2;
-
-    private static final int CLOSE_PIP_WHEN_MEDIA_SESSION_GONE_TIMEOUT_MS = 3000;
-
-    private int mSuspendPipResizingReason;
-
     private final Context mContext;
     private final PipBoundsState mPipBoundsState;
     private final PipBoundsAlgorithm mPipBoundsAlgorithm;
     private final PipTaskOrganizer mPipTaskOrganizer;
     private final PipMediaController mPipMediaController;
     private final TvPipMenuController mTvPipMenuController;
+    private final PipNotification mPipNotification;
 
     private IActivityTaskManager mActivityTaskManager;
     private int mState = STATE_NO_PIP;
-    private int mResumeResizePinnedStackRunnableState = STATE_NO_PIP;
     private final Handler mHandler = new Handler();
-    private List<Listener> mListeners = new ArrayList<>();
     private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
     private int mPipTaskId = TASK_ID_NO_PIP;
     private int mPinnedStackId = INVALID_STACK_ID;
     private String[] mLastPackagesResourceGranted;
-    private PipNotification mPipNotification;
     private ParceledListSlice<RemoteAction> mCustomActions;
     private WindowManagerShellWrapper mWindowManagerShellWrapper;
     private int mResizeAnimationDuration;
@@ -135,9 +111,7 @@
     private boolean mImeVisible;
     private int mImeHeightAdjustment;
 
-    private final Runnable mResizePinnedStackRunnable =
-            () -> resizePinnedStack(mResumeResizePinnedStackRunnableState);
-    private final Runnable mClosePipRunnable = () -> closePip();
+    private final Runnable mClosePipRunnable = this::closePip;
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -237,8 +211,6 @@
         mPipTaskOrganizer.registerPipTransitionCallback(this);
         mActivityTaskManager = ActivityTaskManager.getService();
 
-        addListener(mPipNotification);
-
         final IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(ACTION_CLOSE);
         intentFilter.addAction(ACTION_MENU);
@@ -297,6 +269,7 @@
     /**
      * Updates the PIP per configuration changed.
      */
+    @Override
     public void onConfigurationChanged(Configuration newConfig) {
         loadConfigurationsAndApply(newConfig);
         mPipNotification.onConfigurationChanged(mContext);
@@ -340,9 +313,8 @@
                 mPinnedStackId = INVALID_STACK_ID;
             }
         }
-        for (int i = mListeners.size() - 1; i >= 0; --i) {
-            mListeners.get(i).onPipActivityClosed();
-        }
+        mPipNotification.dismiss();
+        mTvPipMenuController.hideMenu();
         mHandler.removeCallbacks(mClosePipRunnable);
     }
 
@@ -353,9 +325,9 @@
         if (DEBUG) Log.d(TAG, "movePipToFullscreen(), current state=" + getStateDescription());
 
         mPipTaskId = TASK_ID_NO_PIP;
-        for (int i = mListeners.size() - 1; i >= 0; --i) {
-            mListeners.get(i).onMoveToFullscreen();
-        }
+        mTvPipMenuController.hideMenu();
+        mPipNotification.dismiss();
+
         resizePinnedStack(STATE_NO_PIP);
     }
 
@@ -379,9 +351,7 @@
         // Set state to STATE_PIP so we show it when the pinned stack animation ends.
         mState = STATE_PIP;
         mPipMediaController.onActivityPinned();
-        for (int i = mListeners.size() - 1; i >= 0; i--) {
-            mListeners.get(i).onPipEntered(packageName);
-        }
+        mPipNotification.show(packageName);
     }
 
     private void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
@@ -428,61 +398,17 @@
     }
 
     /**
-     * Suspends resizing operation on the Pip until {@link #resumePipResizing} is called
-     *
-     * @param reason The reason for suspending resizing operations on the Pip.
-     */
-    public void suspendPipResizing(int reason) {
-        if (DEBUG) {
-            Log.d(TAG,
-                    "suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
-        }
-        mSuspendPipResizingReason |= reason;
-    }
-
-    /**
-     * Resumes resizing operation on the Pip that was previously suspended.
-     *
-     * @param reason The reason resizing operations on the Pip was suspended.
-     */
-    public void resumePipResizing(int reason) {
-        if ((mSuspendPipResizingReason & reason) == 0) {
-            return;
-        }
-        if (DEBUG) {
-            Log.d(TAG,
-                    "resumePipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
-        }
-        mSuspendPipResizingReason &= ~reason;
-        mHandler.post(mResizePinnedStackRunnable);
-    }
-
-    /**
      * Resize the Pip to the appropriate size for the input state.
      *
      * @param state In Pip state also used to determine the new size for the Pip.
      */
     public void resizePinnedStack(int state) {
-
         if (DEBUG) {
             Log.d(TAG, "resizePinnedStack() state=" + stateToName(state) + ", current state="
                     + getStateDescription(), new Exception());
         }
-
-        boolean wasStateNoPip = (mState == STATE_NO_PIP);
-        for (int i = mListeners.size() - 1; i >= 0; --i) {
-            mListeners.get(i).onPipResizeAboutToStart();
-        }
-        if (mSuspendPipResizingReason != 0) {
-            mResumeResizePinnedStackRunnableState = state;
-            if (DEBUG) {
-                Log.d(TAG, "resizePinnedStack() deferring"
-                        + " mSuspendPipResizingReason=" + mSuspendPipResizingReason
-                        + " mResumeResizePinnedStackRunnableState="
-                        + stateToName(mResumeResizePinnedStackRunnableState));
-            }
-            return;
-        }
+        final boolean wasStateNoPip = (mState == STATE_NO_PIP);
+        mTvPipMenuController.hideMenu();
         mState = state;
         final Rect newBounds;
         switch (mState) {
@@ -510,45 +436,20 @@
     }
 
     /**
-     * @return the current state, or the pending state if the state change was previously suspended.
+     * @return the current state.
      */
     private int getState() {
-        if (mSuspendPipResizingReason != 0) {
-            return mResumeResizePinnedStackRunnableState;
-        }
         return mState;
     }
 
-    /**
-     * Shows PIP menu UI by launching {@link PipMenuActivity}. It also locates the pinned
-     * stack to the centered PIP bound {@link R.config_centeredPictureInPictureBounds}.
-     */
     private void showPipMenu() {
         if (DEBUG) Log.d(TAG, "showPipMenu(), current state=" + getStateDescription());
 
         mState = STATE_PIP_MENU;
-        for (int i = mListeners.size() - 1; i >= 0; --i) {
-            mListeners.get(i).onShowPipMenu();
-        }
-
         mTvPipMenuController.showMenu();
     }
 
     /**
-     * Adds a {@link Listener} to PipController.
-     */
-    void addListener(Listener listener) {
-        mListeners.add(listener);
-    }
-
-    /**
-     * Removes a {@link Listener} from PipController.
-     */
-    void removeListener(Listener listener) {
-        mListeners.remove(listener);
-    }
-
-    /**
      * Returns {@code true} if PIP is shown.
      */
     public boolean isPipShown() {
@@ -619,33 +520,8 @@
         }
     }
 
-    /**
-     * A listener interface to receive notification on changes in PIP.
-     */
-    public interface Listener {
-        /**
-         * Invoked when an activity is pinned and PIP manager is set corresponding information.
-         * Classes must use this instead of {@link android.app.ITaskStackListener.onActivityPinned}
-         * because there's no guarantee for the PIP manager be return relavent information
-         * correctly. (e.g. {@link Pip.isPipShown}).
-         */
-        void onPipEntered(String packageName);
-        /** Invoked when a PIPed activity is closed. */
-        void onPipActivityClosed();
-        /** Invoked when the PIP menu gets shown. */
-        void onShowPipMenu();
-        /** Invoked when the PIPed activity is about to return back to the fullscreen. */
-        void onMoveToFullscreen();
-        /** Invoked when we are above to start resizing the Pip. */
-        void onPipResizeAboutToStart();
-    }
-
     private String getStateDescription() {
-        if (mSuspendPipResizingReason == 0) {
-            return stateToName(mState);
-        }
-        return stateToName(mResumeResizePinnedStackRunnableState) + " (while " + stateToName(mState)
-                + " is suspended)";
+        return stateToName(mState);
     }
 
     private static String stateToName(int state) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java
index 689c3ed..83cb7ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java
@@ -16,6 +16,9 @@
 
 package com.android.wm.shell.pip.tv;
 
+import static android.view.KeyEvent.ACTION_UP;
+import static android.view.KeyEvent.KEYCODE_BACK;
+
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.annotation.Nullable;
@@ -36,25 +39,22 @@
 /**
  * The Menu View that shows controls of the PiP. Always fullscreen.
  */
-public class PipMenuView extends FrameLayout implements PipController.Listener {
+public class PipMenuView extends FrameLayout {
     private static final String TAG = "PipMenuView";
     private static final boolean DEBUG = PipController.DEBUG;
 
-    private final PipController mPipController;
     private final Animator mFadeInAnimation;
     private final Animator mFadeOutAnimation;
     private final PipControlsViewController mPipControlsViewController;
-    private boolean mRestorePipSizeWhenClose;
+    @Nullable
+    private OnBackPressListener mOnBackPressListener;
 
     public PipMenuView(Context context, PipController pipController) {
         super(context, null, 0);
-        mPipController = pipController;
-
         inflate(context, R.layout.tv_pip_menu, this);
 
         mPipControlsViewController = new PipControlsViewController(
-                findViewById(R.id.pip_controls), mPipController);
-        mRestorePipSizeWhenClose = true;
+                findViewById(R.id.pip_controls), pipController);
         mFadeInAnimation = AnimatorInflater.loadAnimator(
                 mContext, R.anim.tv_pip_menu_fade_in_animation);
         mFadeInAnimation.setTarget(mPipControlsViewController.getView());
@@ -63,16 +63,6 @@
         mFadeOutAnimation.setTarget(mPipControlsViewController.getView());
     }
 
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
-                && event.getAction() == KeyEvent.ACTION_UP) {
-            restorePipAndFinish();
-            return true;
-        }
-        return super.dispatchKeyEvent(event);
-    }
-
     @Nullable
     SurfaceControl getWindowSurfaceControl() {
         final ViewRootImpl root = getViewRootImpl();
@@ -87,53 +77,39 @@
     }
 
     void showMenu() {
-        mPipController.addListener(this);
         mFadeInAnimation.start();
         setAlpha(1.0f);
-        try {
-            WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
-                    getViewRootImpl().getInputToken(), true /* grantFocus */);
-        } catch (Exception e) {
-            Log.e(TAG, "Unable to update focus as menu appears", e);
-        }
+        grantWindowFocus(true);
     }
 
     void hideMenu() {
-        mPipController.removeListener(this);
-        mPipController.resumePipResizing(
-                PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
         mFadeOutAnimation.start();
         setAlpha(0.0f);
+        grantWindowFocus(false);
+    }
+
+    private void grantWindowFocus(boolean grantFocus) {
         try {
             WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
-                    getViewRootImpl().getInputToken(), false /* grantFocus */);
+                    getViewRootImpl().getInputToken(), grantFocus);
         } catch (Exception e) {
             Log.e(TAG, "Unable to update focus as menu disappears", e);
         }
     }
 
-    private void restorePipAndFinish() {
-        if (DEBUG) Log.d(TAG, "restorePipAndFinish()");
+    void setOnBackPressListener(OnBackPressListener onBackPressListener) {
+        mOnBackPressListener = onBackPressListener;
+    }
 
-        if (mRestorePipSizeWhenClose) {
-            if (DEBUG) Log.d(TAG, "   > restoring to the default position");
-
-            // When PIP menu activity is closed, restore to the default position.
-            mPipController.resizePinnedStack(PipController.STATE_PIP);
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (event.getKeyCode() == KEYCODE_BACK && event.getAction() == ACTION_UP
+                && mOnBackPressListener != null) {
+            mOnBackPressListener.onBackPress();
+            return true;
+        } else {
+            return super.dispatchKeyEvent(event);
         }
-        hideMenu();
-    }
-
-    @Override
-    public void onPipEntered(String packageName) {
-        if (DEBUG) Log.d(TAG, "onPipEntered(), packageName=" + packageName);
-    }
-
-    @Override
-    public void onPipActivityClosed() {
-        if (DEBUG) Log.d(TAG, "onPipActivityClosed()");
-
-        hideMenu();
     }
 
     void setAppActions(ParceledListSlice<RemoteAction> actions) {
@@ -144,27 +120,7 @@
                 hasCustomActions ? actions.getList() : Collections.emptyList());
     }
 
-    @Override
-    public void onShowPipMenu() {
-        if (DEBUG) Log.d(TAG, "onShowPipMenu()");
-    }
-
-    @Override
-    public void onMoveToFullscreen() {
-        if (DEBUG) Log.d(TAG, "onMoveToFullscreen()");
-
-        // Moving PIP to fullscreen is implemented by resizing PINNED_STACK with null bounds.
-        // This conflicts with restoring PIP position, so disable it.
-        mRestorePipSizeWhenClose = false;
-        hideMenu();
-    }
-
-    @Override
-    public void onPipResizeAboutToStart() {
-        if (DEBUG) Log.d(TAG, "onPipResizeAboutToStart()");
-
-        hideMenu();
-        mPipController.suspendPipResizing(
-                PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
+    interface OnBackPressListener {
+        void onBackPress();
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
index d56a888..4e0ab66 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java
@@ -39,7 +39,7 @@
  * <p>Once it's created, it will manage the PIP notification UI by itself except for handling
  * configuration changes.
  */
-public class PipNotification implements PipController.Listener {
+public class PipNotification {
     private static final boolean DEBUG = PipController.DEBUG;
     private static final String TAG = "PipNotification";
 
@@ -79,38 +79,21 @@
         onConfigurationChanged(context);
     }
 
-    @Override
-    public void onPipEntered(String packageName) {
+    void show(String packageName) {
         mPackageName = packageName;
-        notifyPipNotification();
+        update();
     }
 
-    @Override
-    public void onPipActivityClosed() {
-        dismissPipNotification();
+    void dismiss() {
+        mNotificationManager.cancel(NOTIFICATION_TAG, SystemMessage.NOTE_TV_PIP);
+        mNotified = false;
         mPackageName = null;
     }
 
-    @Override
-    public void onShowPipMenu() {
-        // no-op.
-    }
-
-    @Override
-    public void onMoveToFullscreen() {
-        dismissPipNotification();
-        mPackageName = null;
-    }
-
-    @Override
-    public void onPipResizeAboutToStart() {
-        // no-op.
-    }
-
     private void onMediaMetadataChanged(MediaMetadata metadata) {
         if (updateMediaControllerMetadata(metadata) && mNotified) {
             // update notification
-            notifyPipNotification();
+            update();
         }
     }
 
@@ -123,11 +106,11 @@
         mDefaultIconResId = R.drawable.pip_icon;
         if (mNotified) {
             // update notification
-            notifyPipNotification();
+            update();
         }
     }
 
-    private void notifyPipNotification() {
+    private void update() {
         mNotified = true;
         mNotificationBuilder
                 .setShowWhen(true)
@@ -144,11 +127,6 @@
                 mNotificationBuilder.build());
     }
 
-    private void dismissPipNotification() {
-        mNotified = false;
-        mNotificationManager.cancel(NOTIFICATION_TAG, SystemMessage.NOTE_TV_PIP);
-    }
-
     private boolean updateMediaControllerMetadata(MediaMetadata metadata) {
         String title = null;
         Bitmap art = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 91aef67..5d0d761 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -21,6 +21,7 @@
 import android.app.RemoteAction;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
+import android.util.Log;
 import android.view.SurfaceControl;
 
 import com.android.wm.shell.common.SystemWindows;
@@ -31,6 +32,8 @@
  * Manages the visibility of the PiP Menu as user interacts with PiP.
  */
 public class TvPipMenuController implements PipMenuController {
+    private static final String TAG = "TvPipMenuController";
+    private static final boolean DEBUG = PipController.DEBUG;
 
     private final Context mContext;
     private final SystemWindows mSystemWindows;
@@ -52,6 +55,8 @@
 
     @Override
     public void showMenu() {
+        if (DEBUG) Log.d(TAG, "showMenu()");
+
         if (mMenuView != null) {
             mSystemWindows.updateViewLayout(mMenuView, getPipMenuLayoutParams(MENU_WINDOW_TITLE,
                     mPipBoundsState.getDisplayBounds().width(),
@@ -68,27 +73,62 @@
         }
     }
 
-    @Override
-    public void attach(SurfaceControl leash) {
-        if (mMenuView == null) {
-            mMenuView = new PipMenuView(mContext, mPipController);
-            mSystemWindows.addView(mMenuView,
-                    getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
-                    0, SHELL_ROOT_LAYER_PIP);
-            mLeash = leash;
+    void hideMenu() {
+        if (DEBUG) Log.d(TAG, "hideMenu()");
+
+        if (isMenuVisible()) {
+            mMenuView.hideMenu();
+            mPipController.resizePinnedStack(PipController.STATE_PIP);
         }
     }
 
     @Override
+    public void attach(SurfaceControl leash) {
+        mLeash = leash;
+        attachPipMenuView();
+    }
+
+    @Override
     public void detach() {
+        hideMenu();
+        detachPipMenuView();
+        mLeash = null;
+    }
+
+    private void attachPipMenuView() {
+        if (DEBUG) Log.d(TAG, "attachPipMenuView()");
+
+        if (mMenuView != null) {
+            detachPipMenuView();
+        }
+
+        mMenuView = new PipMenuView(mContext, mPipController);
+        mMenuView.setOnBackPressListener(this::hideMenu);
+        mSystemWindows.addView(mMenuView,
+                getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
+                0, SHELL_ROOT_LAYER_PIP);
+    }
+
+    private void detachPipMenuView() {
+        if (DEBUG) Log.d(TAG, "detachPipMenuView()");
+
+        if (mMenuView == null) {
+            return;
+        }
+
         mSystemWindows.removeView(mMenuView);
         mMenuView = null;
-        mLeash = null;
     }
 
     @Override
     public void setAppActions(ParceledListSlice<RemoteAction> appActions) {
-        mMenuView.setAppActions(appActions);
+        if (DEBUG) Log.d(TAG, "setAppActions(), actions=" + appActions);
+
+        if (mMenuView != null) {
+            mMenuView.setAppActions(appActions);
+        } else {
+            Log.w(TAG, "Cannot set remote actions, there is no View");
+        }
     }
 
     @Override
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index 738246d..ee7d15a 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -159,7 +159,7 @@
         // GPU start time is approximated to the moment before swapBuffer is invoked.
         // We could add an EGLSyncKHR fence at the beginning of the frame, but that is an overhead.
         int64_t endTime = get(FrameInfoIndex::GpuCompleted);
-        return endTime > 0 ? endTime - get(FrameInfoIndex::SwapBuffers) : 0;
+        return endTime > 0 ? endTime - get(FrameInfoIndex::SwapBuffers) : -1;
     }
 
     inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 4578883..c67d90a 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -2881,7 +2881,12 @@
      * @return true if any music tracks are active.
      */
     public boolean isMusicActive() {
-        return AudioSystem.isStreamActive(STREAM_MUSIC, 0);
+        final IAudioService service = getService();
+        try {
+            return service.isMusicActive();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 5c012be..2ac5b50 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -334,4 +334,6 @@
     oneway void setStreamVolumeForUid(int streamType, int direction, int flags,
             in String packageName, int uid, int pid, in UserHandle userHandle,
             int targetSdkVersion);
+
+    boolean isMusicActive();
 }
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index a17ff82..babc1d5 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -19,7 +19,7 @@
 import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED;
 
 import android.compat.annotation.UnsupportedAppUsage;
-import android.net.NetworkUtils;
+import android.net.InetAddresses;
 import android.os.IBinder;
 import android.os.StrictMode;
 import android.util.Log;
@@ -214,7 +214,7 @@
             if (host.equalsIgnoreCase("localhost")) {
                 return true;
             }
-            if (NetworkUtils.numericToInetAddress(host).isLoopbackAddress()) {
+            if (InetAddresses.parseNumericAddress(host).isLoopbackAddress()) {
                 return true;
             }
         } catch (IllegalArgumentException iex) {
diff --git a/mime/java-res/android.mime.types b/mime/java-res/android.mime.types
index e5273a9..92365d1 100644
--- a/mime/java-res/android.mime.types
+++ b/mime/java-res/android.mime.types
@@ -63,6 +63,7 @@
 ?application/x-android-drm-fl fl
 ?application/x-flac flac
 ?application/x-font pcf
+?application/x-mobipocket-ebook prc mobi
 ?application/x-mpegurl m3u m3u8
 ?application/x-pem-file pem
 ?application/x-pkcs12 p12 pfx
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
index 1403631..99d2ff7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
@@ -113,12 +113,13 @@
     private void addEmergencyNumberToTelephony() {
         final int subId = SubscriptionManager.getDefaultSubscriptionId();
         EmergencyNumber emergencyNumber = mock(EmergencyNumber.class);
+        when(emergencyNumber.isInEmergencyServiceCategories(EMERGENCY_SERVICE_CATEGORY_POLICE))
+                .thenReturn(true);
         Map<Integer, List<EmergencyNumber>> numbers = new ArrayMap<>();
         List<EmergencyNumber> numbersForSubId = new ArrayList<>();
         numbersForSubId.add(emergencyNumber);
         numbers.put(subId, numbersForSubId);
-        when(mTelephonyManager.getEmergencyNumberList(
-                EMERGENCY_SERVICE_CATEGORY_POLICE)).thenReturn(numbers);
+        when(mTelephonyManager.getEmergencyNumberList()).thenReturn(numbers);
         when(emergencyNumber.getNumber()).thenReturn(TELEPHONY_EMERGENCY_NUMBER);
     }
 }
diff --git a/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml b/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml
index 55116c6..9f66581 100644
--- a/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml
+++ b/packages/SystemUI/res/drawable/ic_open_in_new_fullscreen.xml
@@ -19,8 +19,8 @@
         <shape android:shape="rectangle">
             <solid android:color="@color/magnification_switch_button_color" />
             <size
-                android:width="40dp"
-                android:height="40dp" />
+                android:width="48dp"
+                android:height="48dp" />
         </shape>
     </item>
 
diff --git a/packages/SystemUI/res/drawable/ic_open_in_new_window.xml b/packages/SystemUI/res/drawable/ic_open_in_new_window.xml
index 5f571cf..659b020 100644
--- a/packages/SystemUI/res/drawable/ic_open_in_new_window.xml
+++ b/packages/SystemUI/res/drawable/ic_open_in_new_window.xml
@@ -19,8 +19,8 @@
         <shape android:shape="rectangle">
             <solid android:color="@color/magnification_switch_button_color" />
             <size
-                android:width="40dp"
-                android:height="40dp" />
+                android:width="48dp"
+                android:height="48dp" />
         </shape>
     </item>
 
diff --git a/packages/SystemUI/res/drawable/people_space_content_background.xml b/packages/SystemUI/res/drawable/people_space_content_background.xml
new file mode 100644
index 0000000..53108409
--- /dev/null
+++ b/packages/SystemUI/res/drawable/people_space_content_background.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" >
+    <solid android:color="?android:attr/colorControlHighlight" />
+    <corners android:radius="@dimen/people_space_widget_radius" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/people_space_round_tile_view_card.xml b/packages/SystemUI/res/drawable/people_space_round_tile_view_card.xml
new file mode 100644
index 0000000..59af775
--- /dev/null
+++ b/packages/SystemUI/res/drawable/people_space_round_tile_view_card.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="?android:attr/colorBackground" />
+    <corners android:radius="@dimen/people_space_widget_round_radius" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/people_space_rounded_border.xml b/packages/SystemUI/res/drawable/people_space_rounded_border.xml
new file mode 100644
index 0000000..9956bc2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/people_space_rounded_border.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="?android:attr/colorBackground" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/people_space_tile_view_card.xml b/packages/SystemUI/res/drawable/people_space_tile_view_card.xml
index 4772ae7..8fd4388 100644
--- a/packages/SystemUI/res/drawable/people_space_tile_view_card.xml
+++ b/packages/SystemUI/res/drawable/people_space_tile_view_card.xml
@@ -14,6 +14,6 @@
   ~ limitations under the License.
   -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@android:color/white" />
+    <solid android:color="?android:attr/colorBackground" />
     <corners android:radius="@dimen/people_space_widget_radius" />
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/people_space_widget_background.xml b/packages/SystemUI/res/drawable/people_space_widget_background.xml
index b929359..fa45718 100644
--- a/packages/SystemUI/res/drawable/people_space_widget_background.xml
+++ b/packages/SystemUI/res/drawable/people_space_widget_background.xml
@@ -18,7 +18,7 @@
     android:shape="rectangle" >
     <solid
         android:color="?android:attr/colorControlNormal" />
-    <corners android:radius="@dimen/people_space_widget_radius" />
+    <corners android:radius="@dimen/people_space_widget_background_padding" />
     <padding
         android:left="@dimen/people_space_widget_background_padding"
         android:top="@dimen/people_space_widget_background_padding"
diff --git a/packages/SystemUI/res/layout/feedback_info.xml b/packages/SystemUI/res/layout/feedback_info.xml
index 7047c1b..753f56a 100644
--- a/packages/SystemUI/res/layout/feedback_info.xml
+++ b/packages/SystemUI/res/layout/feedback_info.xml
@@ -109,24 +109,4 @@
             style="@style/TextAppearance.NotificationInfo.Button"/>
     </LinearLayout>
 
-    <!-- Done button -->
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/notification_guts_button_spacing"
-        android:layout_marginBottom="@dimen/notification_guts_button_spacing"
-        android:gravity="end"
-        android:orientation="horizontal">
-
-        <TextView
-            android:id="@+id/ok"
-            android:text="@string/feedback_ok"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:background="@drawable/ripple_drawable"
-            android:minWidth="48dp"
-            android:layout_marginStart="8dp"
-            android:layout_marginEnd="-8dp"
-            style="@style/TextAppearance.NotificationInfo.Button"/>
-    </LinearLayout>
 </com.android.systemui.statusbar.notification.row.FeedbackInfo>
diff --git a/packages/SystemUI/res/layout/people_space_large_avatar_tile.xml b/packages/SystemUI/res/layout/people_space_large_avatar_tile.xml
new file mode 100644
index 0000000..e9f3424
--- /dev/null
+++ b/packages/SystemUI/res/layout/people_space_large_avatar_tile.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <LinearLayout
+        android:background="@drawable/people_space_round_tile_view_card"
+        android:id="@+id/item"
+        android:paddingVertical="6dp"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <LinearLayout
+            android:orientation="horizontal"
+            android:gravity="center_vertical"
+            android:paddingStart="12dp"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+                <ImageView
+                    android:id="@+id/person_icon"
+                    android:layout_width="60dp"
+                    android:layout_height="60dp" />
+
+                <LinearLayout
+                    android:background="@drawable/people_space_rounded_border"
+                    android:layout_marginStart="-12dp"
+                    android:layout_marginTop="28dp"
+                    android:layout_marginBottom="14dp"
+                    android:layout_width="16dp"
+                    android:layout_height="16dp">
+
+                    <ImageView
+                        android:id="@+id/package_icon"
+                        android:layout_width="12dp"
+                        android:layout_marginStart="2dp"
+                        android:layout_marginEnd="2dp"
+                        android:layout_marginBottom="2dp"
+                        android:layout_marginTop="2dp"
+                        android:layout_height="12dp" />
+                </LinearLayout>
+
+            <LinearLayout
+                android:orientation="vertical"
+                android:paddingStart="8dp"
+                android:paddingEnd="12dp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+
+                <TextView
+                    android:id="@+id/name"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                    android:textColor="?android:attr/textColorPrimary"
+                    android:textSize="16sp"
+                    android:maxLines="1"
+                    android:ellipsize="end"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" />
+
+                <TextView
+                    android:id="@+id/status"
+                    android:textColor="?android:attr/textColorSecondary"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                    android:paddingVertical="3dp"
+                    android:textSize="12sp"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:maxLines="3"
+                    android:ellipsize="end" />
+            </LinearLayout>
+        </LinearLayout>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml b/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml
new file mode 100644
index 0000000..f474830
--- /dev/null
+++ b/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <LinearLayout
+        android:background="@drawable/people_space_tile_view_card"
+        android:id="@+id/item"
+        android:orientation="vertical"
+        android:paddingTop="6dp"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <LinearLayout
+            android:orientation="horizontal"
+            android:paddingHorizontal="12dp"
+            android:paddingBottom="4dp"
+            android:gravity="top"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <ImageView
+                android:id="@+id/person_icon"
+                android:layout_width="34dp"
+                android:layout_height="34dp" />
+
+            <LinearLayout
+                android:background="@drawable/people_space_rounded_border"
+                android:layout_marginStart="-5dp"
+                android:layout_marginTop="18dp"
+                android:layout_width="8dp"
+                android:layout_height="8dp">
+
+                <ImageView
+                    android:id="@+id/package_icon"
+                    android:layout_width="6dp"
+                    android:layout_marginEnd="1dp"
+                    android:layout_marginStart="1dp"
+                    android:layout_marginBottom="1dp"
+                    android:layout_marginTop="1dp"
+                    android:layout_height="6dp" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:orientation="vertical"
+                android:paddingStart="6dp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+
+                <TextView
+                    android:id="@+id/name"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                    android:textColor="?android:attr/textColorPrimary"
+                    android:textSize="14sp"
+                    android:maxLines="1"
+                    android:ellipsize="end"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" />
+
+                <TextView
+                    android:id="@+id/time"
+                    android:textColor="?android:attr/textColorSecondary"
+                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                    android:textSize="10sp"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:maxLines="1"
+                    android:ellipsize="end" />
+            </LinearLayout>
+        </LinearLayout>
+        <TextView
+            android:id="@+id/content"
+            android:paddingVertical="3dp"
+            android:paddingHorizontal="12dp"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+            android:background="@drawable/people_space_content_background"
+            android:textSize="14sp"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:maxLines="2"
+            android:ellipsize="end" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/people_space_widget_item.xml b/packages/SystemUI/res/layout/people_space_widget_item.xml
index 95de6d6..170386f 100644
--- a/packages/SystemUI/res/layout/people_space_widget_item.xml
+++ b/packages/SystemUI/res/layout/people_space_widget_item.xml
@@ -16,6 +16,7 @@
   -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
+    android:padding="4dp"
     android:layout_height="wrap_content"
     android:orientation="vertical">
     <LinearLayout
@@ -31,24 +32,37 @@
         <LinearLayout
             android:orientation="horizontal"
             android:gravity="center_vertical"
+            android:paddingStart="12dp"
             android:layout_width="match_parent"
             android:layout_height="wrap_content">
 
             <ImageView
                 android:id="@+id/person_icon"
-                android:layout_width="42dp"
-                android:layout_height="42dp" />
+                android:layout_width="60dp"
+                android:layout_height="60dp" />
 
-            <ImageView
-                android:id="@+id/package_icon"
-                android:gravity="bottom|end"
-                android:layout_width="14dp"
-                android:layout_marginStart="-8dp"
-                android:layout_height="14dp" />
+            <LinearLayout
+                android:background="@drawable/people_space_rounded_border"
+                android:layout_marginStart="-12dp"
+                android:layout_marginTop="28dp"
+                android:layout_marginBottom="14dp"
+                android:layout_width="16dp"
+                android:layout_height="16dp">
+
+                <ImageView
+                    android:id="@+id/package_icon"
+                    android:layout_width="12dp"
+                    android:layout_marginStart="2dp"
+                    android:layout_marginEnd="2dp"
+                    android:layout_marginBottom="2dp"
+                    android:layout_marginTop="2dp"
+                    android:layout_height="12dp" />
+            </LinearLayout>
 
             <LinearLayout
                 android:orientation="vertical"
-                android:paddingStart="4dp"
+                android:paddingStart="8dp"
+                android:paddingEnd="12dp"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content">
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 57e1d43..a960133 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1194,8 +1194,8 @@
     <dimen name="magnification_frame_move_long">25dp</dimen>
     <dimen name="magnification_drag_view_size">38dp</dimen>
     <dimen name="magnification_controls_size">90dp</dimen>
-    <dimen name="magnification_switch_button_size">32dp</dimen>
-    <dimen name="magnification_switch_button_padding">8dp</dimen>
+    <dimen name="magnification_switch_button_size">60dp</dimen>
+    <dimen name="magnification_switch_button_padding">12dp</dimen>
     <dimen name="magnifier_left_right_controls_width">35dp</dimen>
     <dimen name="magnifier_left_right_controls_height">45dp</dimen>
     <dimen name="magnifier_up_down_controls_width">45dp</dimen>
@@ -1303,6 +1303,7 @@
     <dimen name="media_output_dialog_icon_corner_radius">16dp</dimen>
     <dimen name="media_output_dialog_title_anim_y_delta">12.5dp</dimen>
 
-    <dimen name="people_space_widget_radius">10dp</dimen>
+    <dimen name="people_space_widget_radius">24dp</dimen>
+    <dimen name="people_space_widget_round_radius">100dp</dimen>
     <dimen name="people_space_widget_background_padding">6dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 0697c5c..6c0635a 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -489,7 +489,6 @@
 
     <style name="TextAppearance.NotificationInfo">
         <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
-        <item name="android:textColor">@color/notification_primary_text_color</item>
     </style>
 
     <style name="TextAppearance.NotificationInfo.Secondary">
@@ -498,7 +497,6 @@
     </style>
 
     <style name="TextAppearance.NotificationInfo.Title">
-        <item name="android:textColor">@color/notification_primary_text_color</item>
         <item name="android:textStyle">bold</item>
     </style>
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index e40185c..267debc 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -23,6 +23,7 @@
 import android.content.pm.ActivityInfo;
 import android.graphics.PixelFormat;
 import android.graphics.PointF;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -41,6 +42,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.R;
 
+import java.util.Collections;
+
 /**
  * Shows/hides a {@link android.widget.ImageView} on the screen and changes the values of
  * {@link Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE} when the UI is toggled.
@@ -52,7 +55,7 @@
     @VisibleForTesting
     static final long FADING_ANIMATION_DURATION_MS = 300;
     @VisibleForTesting
-    static final int DEFAULT_FADE_OUT_ANIMATION_DELAY_MS = 3000;
+    static final int DEFAULT_FADE_OUT_ANIMATION_DELAY_MS = 5000;
     private int mUiTimeout;
     private final Runnable mFadeInAnimationTask;
     private final Runnable mFadeOutAnimationTask;
@@ -85,7 +88,6 @@
         mImageView = imageView;
         mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
         applyResourcesValues();
-        mImageView.setImageResource(getIconResId(mMagnificationMode));
         mImageView.setOnTouchListener(this::onTouch);
         mImageView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
             @Override
@@ -138,6 +140,7 @@
         final int padding = mContext.getResources().getDimensionPixelSize(
                 R.dimen.magnification_switch_button_padding);
         mImageView.setPadding(padding, padding, padding, padding);
+        mImageView.setImageResource(getIconResId(mMagnificationMode));
     }
 
     private boolean onTouch(View v, MotionEvent event) {
@@ -205,6 +208,8 @@
         }
         if (!mIsVisible) {
             mWindowManager.addView(mImageView, mParams);
+            // Exclude magnification switch button from system gesture area.
+            setSystemGestureExclusion();
             mIsVisible = true;
             mImageView.postOnAnimation(mFadeInAnimationTask);
             mUiTimeout = mAccessibilityManager.getRecommendedTimeoutMillis(
@@ -224,7 +229,11 @@
     void onConfigurationChanged(int configDiff) {
         if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) {
             applyResourcesValues();
-            mImageView.setImageResource(getIconResId(mMagnificationMode));
+            if (mIsVisible) {
+                mWindowManager.updateViewLayout(mImageView, mParams);
+                // Exclude magnification switch button from system gesture area.
+                setSystemGestureExclusion();
+            }
             return;
         }
         if ((configDiff & ActivityInfo.CONFIG_LOCALE) != 0) {
@@ -261,7 +270,6 @@
         ImageView imageView = new ImageView(context);
         imageView.setClickable(true);
         imageView.setFocusable(true);
-        imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
         imageView.setAlpha(0f);
         return imageView;
     }
@@ -288,4 +296,13 @@
     private static String getAccessibilityWindowTitle(Context context) {
         return context.getString(com.android.internal.R.string.android_system_label);
     }
+
+    private void setSystemGestureExclusion() {
+        mImageView.post(() -> {
+            mImageView.setSystemGestureExclusionRects(
+                    Collections.singletonList(
+                            new Rect(0, 0, mImageView.getWidth(), mImageView.getHeight())));
+        });
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 451bd42..eb86128 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -37,6 +37,7 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.core.graphics.drawable.IconCompat;
 
+import com.android.internal.logging.UiEventLogger;
 import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.Utils;
 import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -84,11 +85,14 @@
     @VisibleForTesting
     LocalMediaManager mLocalMediaManager;
 
+    private MediaOutputMetricLogger mMetricLogger;
+    private UiEventLogger mUiEventLogger;
+
     @Inject
     public MediaOutputController(@NonNull Context context, String packageName,
             boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager
             lbm, ShadeController shadeController, ActivityStarter starter,
-            NotificationEntryManager notificationEntryManager) {
+            NotificationEntryManager notificationEntryManager, UiEventLogger uiEventLogger) {
         mContext = context;
         mPackageName = packageName;
         mMediaSessionManager = mediaSessionManager;
@@ -98,6 +102,8 @@
         mNotificationEntryManager = notificationEntryManager;
         InfoMediaManager imm = new InfoMediaManager(mContext, packageName, null, lbm);
         mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName);
+        mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
+        mUiEventLogger = uiEventLogger;
     }
 
     void start(@NonNull Callback cb) {
@@ -151,6 +157,7 @@
     public void onSelectedDeviceStateChanged(MediaDevice device,
             @LocalMediaManager.MediaDeviceState int state) {
         mCallback.onRouteChanged();
+        mMetricLogger.logOutputSuccess(device.toString(), mMediaDevices);
     }
 
     @Override
@@ -161,6 +168,7 @@
     @Override
     public void onRequestFailed(int reason) {
         mCallback.onRouteChanged();
+        mMetricLogger.logOutputFailure(mMediaDevices, reason);
     }
 
     CharSequence getHeaderTitle() {
@@ -311,6 +319,8 @@
     }
 
     void connectDevice(MediaDevice device) {
+        mMetricLogger.updateOutputEndPoints(getCurrentConnectedMediaDevice(), device);
+
         ThreadUtils.postOnBackgroundThread(() -> {
             mLocalMediaManager.connectDevice(device);
         });
@@ -439,7 +449,7 @@
 
     void launchMediaOutputDialog() {
         mCallback.dismissDialog();
-        new MediaOutputDialog(mContext, mAboveStatusbar, this);
+        new MediaOutputDialog(mContext, mAboveStatusbar, this, mUiEventLogger);
     }
 
     void launchMediaOutputGroupDialog() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index a892a12..53029bd0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -23,6 +23,9 @@
 
 import androidx.core.graphics.drawable.IconCompat;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 
@@ -31,10 +34,12 @@
  */
 @SysUISingleton
 public class MediaOutputDialog extends MediaOutputBaseDialog {
+    final UiEventLogger mUiEventLogger;
 
     MediaOutputDialog(Context context, boolean aboveStatusbar, MediaOutputController
-            mediaOutputController) {
+            mediaOutputController, UiEventLogger uiEventLogger) {
         super(context, mediaOutputController);
+        mUiEventLogger = uiEventLogger;
         mAdapter = new MediaOutputAdapter(mMediaOutputController);
         if (!aboveStatusbar) {
             getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
@@ -45,6 +50,7 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        mUiEventLogger.log(MediaOutputEvent.MEDIA_OUTPUT_DIALOG_SHOW);
     }
 
     @Override
@@ -78,4 +84,21 @@
         return mMediaOutputController.isActiveRemoteDevice(
                 mMediaOutputController.getCurrentConnectedMediaDevice()) ? View.VISIBLE : View.GONE;
     }
+
+    @VisibleForTesting
+    public enum MediaOutputEvent implements UiEventLogger.UiEventEnum {
+        @UiEvent(doc = "The MediaOutput dialog became visible on the screen.")
+        MEDIA_OUTPUT_DIALOG_SHOW(655);
+
+        private final int mId;
+
+        MediaOutputEvent(int id) {
+            mId = id;
+        }
+
+        @Override
+        public int getId() {
+            return mId;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
index 7d1a7ce..0f340a5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.media.session.MediaSessionManager
+import com.android.internal.logging.UiEventLogger
 import com.android.settingslib.bluetooth.LocalBluetoothManager
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.statusbar.notification.NotificationEntryManager
@@ -33,7 +34,8 @@
     private val lbm: LocalBluetoothManager?,
     private val shadeController: ShadeController,
     private val starter: ActivityStarter,
-    private val notificationEntryManager: NotificationEntryManager
+    private val notificationEntryManager: NotificationEntryManager,
+    private val uiEventLogger: UiEventLogger
 ) {
     companion object {
         var mediaOutputDialog: MediaOutputDialog? = null
@@ -43,8 +45,10 @@
     fun create(packageName: String, aboveStatusBar: Boolean) {
         mediaOutputDialog?.dismiss()
         mediaOutputDialog = MediaOutputController(context, packageName, aboveStatusBar,
-                mediaSessionManager, lbm, shadeController, starter, notificationEntryManager).run {
-            MediaOutputDialog(context, aboveStatusBar, this) }
+                mediaSessionManager, lbm, shadeController, starter, notificationEntryManager,
+                uiEventLogger).run {
+            MediaOutputDialog(context, aboveStatusBar, this, uiEventLogger)
+        }
     }
 
     /** dismiss [MediaOutputDialog] if exist. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
new file mode 100644
index 0000000..ac0295e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2020 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.media.dialog;
+
+import static android.media.MediaRoute2ProviderService.REASON_INVALID_COMMAND;
+import static android.media.MediaRoute2ProviderService.REASON_NETWORK_ERROR;
+import static android.media.MediaRoute2ProviderService.REASON_REJECTED;
+import static android.media.MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE;
+import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.util.Log;
+
+import com.android.settingslib.media.MediaDevice;
+import com.android.systemui.shared.system.SysUiStatsLog;
+
+import java.util.List;
+
+/**
+ * Metric logger for media output features
+ */
+public class MediaOutputMetricLogger {
+
+    private static final String TAG = "MediaOutputMetricLogger";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final Context mContext;
+    private final String mPackageName;
+    private MediaDevice mSourceDevice, mTargetDevice;
+    private int mWiredDeviceCount;
+    private int mConnectedBluetoothDeviceCount;
+    private int mRemoteDeviceCount;
+    private int mAppliedDeviceCountWithinRemoteGroup;
+
+    public MediaOutputMetricLogger(Context context, String packageName) {
+        mContext = context;
+        mPackageName = packageName;
+    }
+
+    /**
+     * Update the endpoints of a content switching operation.
+     * This method should be called before a switching operation, so the metric logger can track
+     * source and target devices.
+     * @param source the current connected media device
+     * @param target the target media device for content switching to
+     */
+    public void updateOutputEndPoints(MediaDevice source, MediaDevice target) {
+        mSourceDevice = source;
+        mTargetDevice = target;
+
+        if (DEBUG) {
+            Log.d(TAG, "updateOutputEndPoints -"
+                    + " source:" + mSourceDevice.toString()
+                    + " target:" + mTargetDevice.toString());
+        }
+    }
+
+    /**
+     * Do the metric logging of content switching success.
+     * @param selectedDeviceType string representation of the target media device
+     * @param deviceList media device list for device count updating
+     */
+    public void logOutputSuccess(String selectedDeviceType, List<MediaDevice> deviceList) {
+        if (DEBUG) {
+            Log.d(TAG, "logOutputSuccess - selected device: " + selectedDeviceType);
+        }
+
+        updateLoggingDeviceCount(deviceList);
+
+        SysUiStatsLog.write(
+                SysUiStatsLog.MEDIAOUTPUT_OP_SWITCH_REPORTED,
+                getLoggingDeviceType(mSourceDevice, true),
+                getLoggingDeviceType(mTargetDevice, false),
+                SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__RESULT__OK,
+                SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__NO_ERROR,
+                getLoggingPackageName(),
+                mWiredDeviceCount,
+                mConnectedBluetoothDeviceCount,
+                mRemoteDeviceCount,
+                mAppliedDeviceCountWithinRemoteGroup);
+    }
+
+    /**
+     * Do the metric logging of content switching failure.
+     * @param deviceList media device list for device count updating
+     * @param reason the reason of content switching failure
+     */
+    public void logOutputFailure(List<MediaDevice> deviceList, int reason) {
+        if (DEBUG) {
+            Log.e(TAG, "logRequestFailed - " + reason);
+        }
+
+        updateLoggingDeviceCount(deviceList);
+
+        SysUiStatsLog.write(
+                SysUiStatsLog.MEDIAOUTPUT_OP_SWITCH_REPORTED,
+                getLoggingDeviceType(mSourceDevice, true),
+                getLoggingDeviceType(mTargetDevice, false),
+                SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__RESULT__ERROR,
+                getLoggingSwitchOpSubResult(reason),
+                getLoggingPackageName(),
+                mWiredDeviceCount,
+                mConnectedBluetoothDeviceCount,
+                mRemoteDeviceCount,
+                mAppliedDeviceCountWithinRemoteGroup);
+    }
+
+    private void updateLoggingDeviceCount(List<MediaDevice> deviceList) {
+        mWiredDeviceCount = mConnectedBluetoothDeviceCount = mRemoteDeviceCount = 0;
+        mAppliedDeviceCountWithinRemoteGroup = 0;
+
+        for (MediaDevice mediaDevice : deviceList) {
+            if (mediaDevice.isConnected()) {
+                switch (mediaDevice.getDeviceType()) {
+                    case MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE:
+                    case MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE:
+                        mWiredDeviceCount++;
+                        break;
+                    case MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE:
+                        mConnectedBluetoothDeviceCount++;
+                        break;
+                    case MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE:
+                    case MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE:
+                        mRemoteDeviceCount++;
+                        break;
+                    default:
+                }
+            }
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "connected devices:" + " wired: " + mWiredDeviceCount
+                    + " bluetooth: " + mConnectedBluetoothDeviceCount
+                    + " remote: " + mRemoteDeviceCount);
+        }
+    }
+
+    private int getLoggingDeviceType(MediaDevice device, boolean isSourceDevice) {
+        switch (device.getDeviceType()) {
+            case MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE:
+                return isSourceDevice
+                        ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__BUILTIN_SPEAKER
+                        : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__BUILTIN_SPEAKER;
+            case MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE:
+                return isSourceDevice
+                        ? SysUiStatsLog
+                        .MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__WIRED_3POINT5_MM_AUDIO
+                        : SysUiStatsLog
+                                .MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__WIRED_3POINT5_MM_AUDIO;
+            case MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE:
+                return isSourceDevice
+                        ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__USB_C_AUDIO
+                        : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__USB_C_AUDIO;
+            case MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE:
+                return isSourceDevice
+                        ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__BLUETOOTH
+                        : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__BLUETOOTH;
+            case MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE:
+                return isSourceDevice
+                        ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__REMOTE_SINGLE
+                        : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__REMOTE_SINGLE;
+            case MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE:
+                return isSourceDevice
+                        ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__REMOTE_GROUP
+                        : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__REMOTE_GROUP;
+            default:
+                return isSourceDevice
+                        ? SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SOURCE__UNKNOWN_TYPE
+                        : SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__TARGET__UNKNOWN_TYPE;
+        }
+    }
+
+    private int getLoggingSwitchOpSubResult(int reason) {
+        switch (reason) {
+            case REASON_REJECTED:
+                return SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__REJECTED;
+            case REASON_NETWORK_ERROR:
+                return SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__NETWORK_ERROR;
+            case REASON_ROUTE_NOT_AVAILABLE:
+                return SysUiStatsLog
+                        .MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__ROUTE_NOT_AVAILABLE;
+            case REASON_INVALID_COMMAND:
+                return SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__INVALID_COMMAND;
+            case REASON_UNKNOWN_ERROR:
+            default:
+                return SysUiStatsLog.MEDIA_OUTPUT_OP_SWITCH_REPORTED__SUBRESULT__UNKNOWN_ERROR;
+        }
+    }
+
+    private String getLoggingPackageName() {
+        if (mPackageName != null && !mPackageName.isEmpty()) {
+            try {
+                final ApplicationInfo applicationInfo = mContext.getPackageManager()
+                        .getApplicationInfo(mPackageName, /* default flag */ 0);
+                if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
+                        || (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+                    return mPackageName;
+                }
+            } catch (Exception ex) {
+                Log.e(TAG, mPackageName + " is invalid.");
+            }
+        }
+
+        return "";
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index 5f3ceb1..dddd39b 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -111,8 +111,6 @@
                             context, notificationManager,
                             mPeopleManager, mLauncherApps);
             for (int appWidgetId : appWidgetIds) {
-                RemoteViews views = new RemoteViews(context.getPackageName(),
-                        R.layout.people_space_widget_item);
                 String shortcutId = sp.getString(String.valueOf(appWidgetId), null);
                 if (DEBUG) {
                     Log.d(TAG, "Set widget: " + appWidgetId + " with shortcut ID: " + shortcutId);
@@ -127,6 +125,8 @@
                     continue;
                 }
                 PeopleSpaceTile tile = entry.get().getValue();
+                RemoteViews views = new RemoteViews(context.getPackageName(),
+                        getLayout(tile));
 
                 String status = PeopleSpaceUtils.getLastInteractionString(context,
                         entry.get().getKey());
@@ -158,6 +158,12 @@
         }
     }
 
+    /** Returns the layout ID for the {@code tile}. */
+    private static int getLayout(PeopleSpaceTile tile) {
+        return tile.getNotification() == null ? R.layout.people_space_large_avatar_tile :
+                R.layout.people_space_small_avatar_tile;
+    }
+
     /** Returns a list sorted by ascending last interaction time from {@code stream}. */
     private static List<Map.Entry<Long, PeopleSpaceTile>> getSortedTiles(
             IPeopleManager peopleManager, Stream<PeopleSpaceTile> stream) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
index 4c78e62..149ee8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FeedbackInfo.java
@@ -19,7 +19,6 @@
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.service.notification.NotificationListenerService.Ranking.RANKING_DEMOTED;
 import static android.service.notification.NotificationListenerService.Ranking.RANKING_PROMOTED;
-import static android.service.notification.NotificationListenerService.Ranking.RANKING_UNCHANGED;
 
 import android.annotation.SuppressLint;
 import android.app.Notification;
@@ -43,6 +42,7 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.notification.AssistantFeedbackController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -64,6 +64,9 @@
     private NotificationEntryManager mNotificationEntryManager;
     private IStatusBarService mStatusBarService;
     private AssistantFeedbackController mFeedbackController;
+    private NotificationGutsManager mNotificationGutsManager;
+    private NotificationMenuRowPlugin mMenuRowPlugin;
+    private ExpandableNotificationRow mExpandableNotificationRow;
 
     public FeedbackInfo(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -73,19 +76,21 @@
             final PackageManager pm,
             final StatusBarNotification sbn,
             final NotificationEntry entry,
+            final ExpandableNotificationRow row,
             final AssistantFeedbackController controller) {
         mPkg = sbn.getPackageName();
         mPm = pm;
         mEntry = entry;
+        mExpandableNotificationRow = row;
         mRanking = entry.getRanking();
         mFeedbackController = controller;
         mAppName = mPkg;
         mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
         mStatusBarService = Dependency.get(IStatusBarService.class);
+        mNotificationGutsManager = Dependency.get(NotificationGutsManager.class);
 
         bindHeader();
         bindPrompt();
-        bindButton();
     }
 
     private void bindHeader() {
@@ -161,27 +166,24 @@
         return sb.toString();
     }
 
-    private void bindButton() {
-        TextView ok = findViewById(R.id.ok);
-        ok.setOnClickListener(this::closeControls);
-    }
-
     private void positiveFeedback(View v) {
+        mGutsContainer.closeControls(v, false);
         handleFeedback(true);
     }
 
     private void negativeFeedback(View v) {
+        mMenuRowPlugin = mExpandableNotificationRow.getProvider();
+        NotificationMenuRowPlugin.MenuItem menuItem = null;
+        if (mMenuRowPlugin != null) {
+            menuItem = mMenuRowPlugin.getLongpressMenuItem(mContext);
+        }
+
+        mGutsContainer.closeControls(v, false);
+        mNotificationGutsManager.openGuts(mExpandableNotificationRow, 0, 0, menuItem);
         handleFeedback(false);
     }
 
     private void handleFeedback(boolean positive) {
-        TextView prompt = findViewById(R.id.prompt);
-        prompt.setText(mContext.getString(R.string.feedback_response));
-        TextView yes = findViewById(R.id.yes);
-        yes.setVisibility(View.GONE);
-        TextView no = findViewById(R.id.no);
-        no.setVisibility(View.GONE);
-
         Bundle feedback = new Bundle();
         feedback.putBoolean(FEEDBACK_KEY, positive);
         sendFeedbackToAssistant(feedback);
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 d2cfb29..c4f0098 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
@@ -324,7 +324,7 @@
                 userHandle.getIdentifier());
 
         if (mAssistantFeedbackController.showFeedbackIndicator(row.getEntry())) {
-            feedbackInfo.bindGuts(pmUser, sbn, row.getEntry(), mAssistantFeedbackController);
+            feedbackInfo.bindGuts(pmUser, sbn, row.getEntry(), row, mAssistantFeedbackController);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
index 4c9c2f9..414d620 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
@@ -47,6 +47,10 @@
     public void onContentUpdated(ExpandableNotificationRow row) {
         super.onContentUpdated(row);
 
+        // Custom views will most likely use just white or black as their text color.
+        // We need to scan through and replace these colors by Material NEXT colors.
+        ensureThemeOnChildren();
+
         // Let's invert the notification colors when we're in night mode and
         // the notification background isn't colorized.
         if (needsInversion(mBackgroundColor, mView)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
index 49a8d56..7964845 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
@@ -43,6 +43,11 @@
         if (childIndex != null && childIndex != -1) {
             mWrappedView = container.getChildAt(childIndex);
         }
+
+        // Custom views will most likely use just white or black as their text color.
+        // We need to scan through and replace these colors by Material NEXT colors.
+        ensureThemeOnChildren();
+
         if (needsInversion(resolveBackgroundColor(), mWrappedView)) {
             invertViewLuminosity(mWrappedView);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 416c5af..2d706a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -29,11 +29,13 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.view.ContextThemeWrapper;
 import android.view.NotificationHeaderView;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
 import com.android.internal.util.ContrastColorUtil;
@@ -55,6 +57,9 @@
     private final Rect mTmpRect = new Rect();
 
     protected int mBackgroundColor = 0;
+    private int mLightTextColor;
+    private int mDarkTextColor;
+    private int mDefaultTextColor;
 
     public static NotificationViewWrapper wrap(Context ctx, View v, ExpandableNotificationRow row) {
         if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
@@ -110,6 +115,15 @@
             mBackgroundColor = backgroundColor;
             mView.setBackground(new ColorDrawable(Color.TRANSPARENT));
         }
+        mLightTextColor = mView.getContext().getColor(
+                com.android.internal.R.color.notification_primary_text_color_light);
+        mDarkTextColor = mView.getContext().getColor(
+                R.color.notification_primary_text_color_dark);
+
+        Context themedContext = new ContextThemeWrapper(mView.getContext(),
+                R.style.Theme_DeviceDefault_DayNight);
+        mDefaultTextColor = Utils.getColorAttr(themedContext, R.attr.textColorPrimary)
+                .getDefaultColor();
     }
 
     protected boolean needsInversion(int defaultBackgroundColor, View view) {
@@ -187,6 +201,42 @@
         return false;
     }
 
+    protected void ensureThemeOnChildren() {
+        if (mView == null) {
+            return;
+        }
+
+        // Notifications with custom backgrounds should not be adjusted
+        if (mBackgroundColor != Color.TRANSPARENT
+                || getBackgroundColor(mView) != Color.TRANSPARENT) {
+            return;
+        }
+
+        // Now let's check if there's unprotected text somewhere, and apply the theme if we find it.
+        if (!(mView instanceof ViewGroup)) {
+            return;
+        }
+        processChildrenTextColor((ViewGroup) mView);
+    }
+
+    private void processChildrenTextColor(ViewGroup viewGroup) {
+        if (viewGroup == null) {
+            return;
+        }
+
+        for (int i = 0; i < viewGroup.getChildCount(); i++) {
+            View child = viewGroup.getChildAt(i);
+            if (child instanceof TextView) {
+                int foreground = ((TextView) child).getCurrentTextColor();
+                if (foreground == mLightTextColor || foreground == mDarkTextColor) {
+                    ((TextView) child).setTextColor(mDefaultTextColor);
+                }
+            } else if (child instanceof ViewGroup) {
+                processChildrenTextColor((ViewGroup) child);
+            }
+        }
+    }
+
     protected int getBackgroundColor(View view) {
         if (view == null) {
             return Color.TRANSPARENT;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt
index 92e5b78..27e40e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt
@@ -56,7 +56,8 @@
 
             val intent = Intent(Intent.ACTION_VIEW,
                     Uri.parse(context.getString(R.string.config_batteryStateUnknownUrl)))
-            val pi = PendingIntent.getActivity(context, 0, intent, 0)
+            val pi = PendingIntent.getActivity(context, 0, intent,
+                    PendingIntent.FLAG_IMMUTABLE)
 
             val builder = Notification.Builder(context, channel.id)
                     .setAutoCancel(false)
@@ -87,4 +88,4 @@
 
 private const val TAG = "BatteryStateNotifier"
 private const val ID = 666
-private const val DELAY_MILLIS: Long = 4 * 60 * 60 * 1000
\ No newline at end of file
+private const val DELAY_MILLIS: Long = 4 * 60 * 60 * 1000
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index a879a1e..2a18f3c5 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -168,6 +168,11 @@
 
         mConfigurationController.addCallback(new ConfigurationController.ConfigurationListener() {
             @Override
+            public void onConfigChanged(Configuration newConfig) {
+                pip.onConfigurationChanged(newConfig);
+            }
+
+            @Override
             public void onDensityOrFontScaleChanged() {
                 pip.onDensityOrFontScaleChanged();
             }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index 1115043..0451d45 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -143,6 +143,13 @@
     }
 
     @Test
+    public void showButton_excludeSystemGestureArea() {
+        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+
+        verify(mSpyImageView).setSystemGestureExclusionRects(any(List.class));
+    }
+
+    @Test
     public void showMagnificationButton_setA11yTimeout_postDelayedAnimationWithA11yTimeout() {
         final int a11yTimeout = 12345;
         when(mAccessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenReturn(
@@ -178,14 +185,17 @@
     }
 
     @Test
-    public void onConfigurationChanged_buttonIsShowing_setImageResource() {
+    public void onConfigurationChanged_buttonIsShowing_updateResourcesAndLayout() {
         mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
         resetAndStubMockImageViewAndAnimator();
 
         mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
 
+        verify(mSpyImageView).setPadding(anyInt(), anyInt(), anyInt(), anyInt());
         verify(mSpyImageView).setImageResource(
                 getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN));
+        verify(mWindowManager).updateViewLayout(eq(mSpyImageView), any());
+        verify(mSpyImageView).setSystemGestureExclusionRects(any(List.class));
     }
 
     @Test
@@ -368,6 +378,11 @@
     private void resetAndStubMockImageViewAndAnimator() {
         resetAndStubMockAnimator();
         Mockito.reset(mSpyImageView);
+        doAnswer(invocation -> {
+            final Runnable runnable = invocation.getArgument(0);
+            runnable.run();
+            return null;
+        }).when(mSpyImageView).post(any(Runnable.class));
         doReturn(mViewPropertyAnimator).when(mSpyImageView).animate();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index c897d8a..fd5d996 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -35,6 +35,7 @@
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.UiEventLogger;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
@@ -61,6 +62,7 @@
     private ActivityStarter mStarter = mock(ActivityStarter.class);
     private NotificationEntryManager mNotificationEntryManager =
             mock(NotificationEntryManager.class);
+    private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
 
     private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl;
     private MediaOutputController mMediaOutputController;
@@ -73,7 +75,7 @@
     public void setUp() {
         mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager);
+                mNotificationEntryManager, mUiEventLogger);
         mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext,
                 mMediaOutputController);
         mMediaOutputBaseDialogImpl.onCreate(new Bundle());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index 0d352c1..d1a617b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -42,6 +42,7 @@
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.UiEventLogger;
 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.media.LocalMediaManager;
@@ -89,6 +90,7 @@
     private ActivityStarter mStarter = mock(ActivityStarter.class);
     private NotificationEntryManager mNotificationEntryManager =
             mock(NotificationEntryManager.class);
+    private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
 
     private Context mSpyContext;
     private MediaOutputController mMediaOutputController;
@@ -111,7 +113,7 @@
 
         mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager);
+                mNotificationEntryManager, mUiEventLogger);
         mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
         mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
         MediaDescription.Builder builder = new MediaDescription.Builder();
@@ -155,7 +157,7 @@
     public void start_withoutPackageName_verifyMediaControllerInit() {
         mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager);
+                mNotificationEntryManager, mUiEventLogger);
 
         mMediaOutputController.start(mCb);
 
@@ -176,7 +178,7 @@
     public void stop_withoutPackageName_verifyMediaControllerDeinit() {
         mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager);
+                mNotificationEntryManager, mUiEventLogger);
 
         mMediaOutputController.start(mCb);
 
@@ -200,8 +202,10 @@
 
     @Test
     public void onSelectedDeviceStateChanged_verifyCallback() {
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice2);
         mMediaOutputController.start(mCb);
         reset(mCb);
+        mMediaOutputController.connectDevice(mMediaDevice1);
 
         mMediaOutputController.onSelectedDeviceStateChanged(mMediaDevice1,
                 LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
@@ -221,8 +225,10 @@
 
     @Test
     public void onRequestFailed_verifyCallback() {
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice1);
         mMediaOutputController.start(mCb);
         reset(mCb);
+        mMediaOutputController.connectDevice(mMediaDevice2);
 
         mMediaOutputController.onRequestFailed(0 /* reason */);
 
@@ -268,6 +274,8 @@
 
     @Test
     public void connectDevice_verifyConnect() {
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice2);
+
         mMediaOutputController.connectDevice(mMediaDevice1);
 
         // Wait for background thread execution
@@ -441,7 +449,7 @@
     public void getNotificationLargeIcon_withoutPackageName_returnsNull() {
         mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager);
+                mNotificationEntryManager, mUiEventLogger);
 
         assertThat(mMediaOutputController.getNotificationIcon()).isNull();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index c1e7db1..86f6bde 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -19,6 +19,8 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.media.MediaRoute2Info;
@@ -29,6 +31,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.UiEventLogger;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
@@ -53,26 +56,28 @@
     private static final String TEST_PACKAGE = "test_package";
 
     // Mock
-    private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
-    private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
-    private ShadeController mShadeController = mock(ShadeController.class);
-    private ActivityStarter mStarter = mock(ActivityStarter.class);
-    private LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class);
-    private MediaDevice mMediaDevice = mock(MediaDevice.class);
-    private NotificationEntryManager mNotificationEntryManager =
+    private final MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
+    private final LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
+    private final ShadeController mShadeController = mock(ShadeController.class);
+    private final ActivityStarter mStarter = mock(ActivityStarter.class);
+    private final LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class);
+    private final MediaDevice mMediaDevice = mock(MediaDevice.class);
+    private final NotificationEntryManager mNotificationEntryManager =
             mock(NotificationEntryManager.class);
+    private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
 
     private MediaOutputDialog mMediaOutputDialog;
     private MediaOutputController mMediaOutputController;
-    private List<String> mFeatures = new ArrayList<>();
+    private final List<String> mFeatures = new ArrayList<>();
 
     @Before
     public void setUp() {
         mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager);
+                mNotificationEntryManager, mUiEventLogger);
         mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
-        mMediaOutputDialog = new MediaOutputDialog(mContext, false, mMediaOutputController);
+        mMediaOutputDialog = new MediaOutputDialog(mContext, false,
+                mMediaOutputController, mUiEventLogger);
 
         when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice);
         when(mMediaDevice.getFeatures()).thenReturn(mFeatures);
@@ -112,4 +117,16 @@
         assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.GONE);
     }
 
+    @Test
+    // Check the visibility metric logging by creating a new MediaOutput dialog,
+    // and verify if the calling times increases.
+    public void onCreate_ShouldLogVisibility() {
+        MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false,
+                mMediaOutputController, mUiEventLogger);
+
+        testDialog.dismissDialog();
+
+        verify(mUiEventLogger, times(2))
+                .log(MediaOutputDialog.MediaOutputEvent.MEDIA_OUTPUT_DIALOG_SHOW);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
index 5813350..c296ff5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
@@ -28,6 +28,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.UiEventLogger;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
@@ -62,6 +63,7 @@
     private MediaDevice mMediaDevice1 = mock(MediaDevice.class);
     private NotificationEntryManager mNotificationEntryManager =
             mock(NotificationEntryManager.class);
+    private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
 
     private MediaOutputGroupDialog mMediaOutputGroupDialog;
     private MediaOutputController mMediaOutputController;
@@ -71,7 +73,7 @@
     public void setUp() {
         mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager);
+                mNotificationEntryManager, mUiEventLogger);
         mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
         mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false,
                 mMediaOutputController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
index 738ce53..9d87579 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
@@ -28,7 +28,6 @@
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.eq;
@@ -56,6 +55,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.notification.AssistantFeedbackController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -65,8 +65,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-
-import java.util.concurrent.CountDownLatch;
+import org.mockito.MockitoAnnotations;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -78,18 +77,24 @@
     private FeedbackInfo mFeedbackInfo;
     private final PackageManager mMockPackageManager = mock(PackageManager.class);
     private final NotificationGuts mGutsParent = mock(NotificationGuts.class);
+    private final ExpandableNotificationRow mMockNotificationRow =
+            mock(ExpandableNotificationRow.class);
     private StatusBarNotification mSbn;
 
     @Mock
     private NotificationEntryManager mNotificationEntryManager;
     @Mock
     private IStatusBarService mStatusBarService;
+    @Mock
+    private NotificationGutsManager mNotificationGutsManager;
 
     @Before
     public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
 
         mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
         mDependency.injectTestDependency(IStatusBarService.class, mStatusBarService);
+        mDependency.injectTestDependency(NotificationGutsManager.class, mNotificationGutsManager);
 
         // Inflate the layout
         final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
@@ -108,13 +113,14 @@
 
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
                 new Notification(), UserHandle.CURRENT, null, 0);
+
     }
 
     @Test
     public void testBindNotification_SetsTextApplicationName() {
         when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(),
-                mock(AssistantFeedbackController.class));
+                mMockNotificationRow, mock(AssistantFeedbackController.class));
         final TextView textView = mFeedbackInfo.findViewById(R.id.pkg_name);
         assertTrue(textView.getText().toString().contains("App Name"));
     }
@@ -125,27 +131,16 @@
         when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class)))
                 .thenReturn(iconDrawable);
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(),
-                mock(AssistantFeedbackController.class));
+                mMockNotificationRow, mock(AssistantFeedbackController.class));
         final ImageView iconView = mFeedbackInfo.findViewById(R.id.pkg_icon);
         assertEquals(iconDrawable, iconView.getDrawable());
     }
 
     @Test
-    public void testOk() {
-        final CountDownLatch latch = new CountDownLatch(1);
-        mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(),
-                mock(AssistantFeedbackController.class));
-
-        final View okButton = mFeedbackInfo.findViewById(R.id.ok);
-        okButton.performClick();
-        assertEquals(1, latch.getCount());
-        verify(mGutsParent, times(1)).closeControls(any(), anyBoolean());
-    }
-
-    @Test
     public void testPrompt_silenced() {
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(IMPORTANCE_DEFAULT,
-                IMPORTANCE_LOW, RANKING_UNCHANGED), mock(AssistantFeedbackController.class));
+                IMPORTANCE_LOW, RANKING_UNCHANGED), mMockNotificationRow,
+                mock(AssistantFeedbackController.class));
         TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
         assertEquals("This notification was silenced by the system. Was this correct?",
                 prompt.getText());
@@ -154,7 +149,8 @@
     @Test
     public void testPrompt_promoted_importance() {
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(IMPORTANCE_DEFAULT,
-                IMPORTANCE_HIGH, RANKING_UNCHANGED), mock(AssistantFeedbackController.class));
+                IMPORTANCE_HIGH, RANKING_UNCHANGED), mMockNotificationRow,
+                mock(AssistantFeedbackController.class));
         TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
         assertEquals("This notification was promoted by the system. Was this correct?",
                 prompt.getText());
@@ -163,7 +159,8 @@
     @Test
     public void testPrompt_promoted_ranking() {
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(IMPORTANCE_DEFAULT,
-                IMPORTANCE_DEFAULT, RANKING_PROMOTED), mock(AssistantFeedbackController.class));
+                IMPORTANCE_DEFAULT, RANKING_PROMOTED), mMockNotificationRow,
+                mock(AssistantFeedbackController.class));
         TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
         assertEquals("This notification was promoted by the system. Was this correct?",
                 prompt.getText());
@@ -172,7 +169,8 @@
     @Test
     public void testPrompt_demoted_importance() {
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(IMPORTANCE_LOW,
-                IMPORTANCE_MIN, RANKING_UNCHANGED), mock(AssistantFeedbackController.class));
+                IMPORTANCE_MIN, RANKING_UNCHANGED), mMockNotificationRow,
+                mock(AssistantFeedbackController.class));
         TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
         assertEquals("This notification was demoted by the system. Was this correct?",
                 prompt.getText());
@@ -181,12 +179,43 @@
     @Test
     public void testPrompt_demoted_ranking() {
         mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(IMPORTANCE_DEFAULT,
-                IMPORTANCE_DEFAULT, RANKING_DEMOTED), mock(AssistantFeedbackController.class));
+                IMPORTANCE_DEFAULT, RANKING_DEMOTED), mMockNotificationRow,
+                mock(AssistantFeedbackController.class));
         TextView prompt = mFeedbackInfo.findViewById(R.id.prompt);
         assertEquals("This notification was demoted by the system. Was this correct?",
                 prompt.getText());
     }
 
+    @Test
+    public void testPositiveFeedback() {
+        mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+                mock(AssistantFeedbackController.class));
+
+        final View yes = mFeedbackInfo.findViewById(R.id.yes);
+        yes.performClick();
+        verify(mGutsParent, times(1)).closeControls(yes, false);
+    }
+
+    @Test
+    public void testNegativeFeedback() {
+        when(mNotificationGutsManager.openGuts(
+                any(View.class),
+                anyInt(),
+                anyInt(),
+                any(NotificationMenuRowPlugin.MenuItem.class)))
+                .thenReturn(true);
+
+        mFeedbackInfo.bindGuts(mMockPackageManager, mSbn, getEntry(), mMockNotificationRow,
+                mock(AssistantFeedbackController.class));
+
+        final View no = mFeedbackInfo.findViewById(R.id.no);
+        no.performClick();
+        verify(mGutsParent, times(1)).closeControls(no, false);
+        verify(mNotificationGutsManager, times(1)).openGuts(
+                eq(mMockNotificationRow), eq(0), eq(0),
+                any());
+    }
+
     private NotificationEntry getEntry(int oldImportance, int newImportance,
             int rankingAdjustment) {
         NotificationChannel channel = new NotificationChannel("id", "name", oldImportance);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index d08b2b7..2101ea1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -81,12 +81,15 @@
         View mockContracted = mock(NotificationHeaderView.class);
         when(mockContracted.findViewById(com.android.internal.R.id.feedback))
                 .thenReturn(mockContracted);
+        when(mockContracted.getContext()).thenReturn(mContext);
         View mockExpanded = mock(NotificationHeaderView.class);
         when(mockExpanded.findViewById(com.android.internal.R.id.feedback))
                 .thenReturn(mockExpanded);
+        when(mockExpanded.getContext()).thenReturn(mContext);
         View mockHeadsUp = mock(NotificationHeaderView.class);
         when(mockHeadsUp.findViewById(com.android.internal.R.id.feedback))
                 .thenReturn(mockHeadsUp);
+        when(mockHeadsUp.getContext()).thenReturn(mContext);
 
         mView.setContractedChild(mockContracted);
         mView.setExpandedChild(mockExpanded);
@@ -107,18 +110,21 @@
         when(mockContracted.animate()).thenReturn(mock(ViewPropertyAnimator.class));
         when(mockContracted.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
                 mockContractedEB);
+        when(mockContracted.getContext()).thenReturn(mContext);
 
         View mockExpandedEB = mock(NotificationExpandButton.class);
         View mockExpanded = mock(NotificationHeaderView.class);
         when(mockExpanded.animate()).thenReturn(mock(ViewPropertyAnimator.class));
         when(mockExpanded.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
                 mockExpandedEB);
+        when(mockExpanded.getContext()).thenReturn(mContext);
 
         View mockHeadsUpEB = mock(NotificationExpandButton.class);
         View mockHeadsUp = mock(NotificationHeaderView.class);
         when(mockHeadsUp.animate()).thenReturn(mock(ViewPropertyAnimator.class));
         when(mockHeadsUp.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
                 mockHeadsUpEB);
+        when(mockHeadsUp.getContext()).thenReturn(mContext);
 
         // Set up all 3 child forms
         mView.setContractedChild(mockContracted);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
index 085bd90..93a9e59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification.row.wrapper;
 
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.testing.AndroidTestingRunner;
@@ -49,6 +50,7 @@
     public void setup() throws Exception {
         allowTestableLooperAsMainThread();
         mView = mock(View.class);
+        when(mView.getContext()).thenReturn(mContext);
         NotificationTestHelper helper = new NotificationTestHelper(
                 mContext,
                 mDependency,
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index b2f0c83..f648c3e 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -31,6 +31,7 @@
 import android.content.pm.PackageManager;
 import android.net.IIpSecService;
 import android.net.INetd;
+import android.net.InetAddresses;
 import android.net.IpSecAlgorithm;
 import android.net.IpSecConfig;
 import android.net.IpSecManager;
@@ -41,7 +42,6 @@
 import android.net.IpSecUdpEncapResponse;
 import android.net.LinkAddress;
 import android.net.Network;
-import android.net.NetworkUtils;
 import android.net.TrafficStats;
 import android.net.util.NetdService;
 import android.os.Binder;
@@ -1083,7 +1083,7 @@
             throw new IllegalArgumentException("Unspecified address");
         }
 
-        InetAddress checkAddr = NetworkUtils.numericToInetAddress(inetAddress);
+        InetAddress checkAddr = InetAddresses.parseNumericAddress(inetAddress);
 
         if (checkAddr.isAnyLocalAddress()) {
             throw new IllegalArgumentException("Inappropriate wildcard address: " + inetAddress);
@@ -1467,7 +1467,7 @@
 
     private int getFamily(String inetAddress) {
         int family = AF_UNSPEC;
-        InetAddress checkAddress = NetworkUtils.numericToInetAddress(inetAddress);
+        InetAddress checkAddress = InetAddresses.parseNumericAddress(inetAddress);
         if (checkAddress instanceof Inet4Address) {
             family = AF_INET;
         } else if (checkAddress instanceof Inet6Address) {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 821a967..5e86f85 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -58,7 +58,6 @@
 import android.net.NetworkPolicyManager;
 import android.net.NetworkStack;
 import android.net.NetworkStats;
-import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.TetherStatsParcel;
 import android.net.UidRange;
@@ -803,7 +802,7 @@
         InterfaceConfiguration cfg = new InterfaceConfiguration();
         cfg.setHardwareAddress(p.hwAddr);
 
-        final InetAddress addr = NetworkUtils.numericToInetAddress(p.ipv4Addr);
+        final InetAddress addr = InetAddresses.parseNumericAddress(p.ipv4Addr);
         cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength));
         for (String flag : p.flags) {
             cfg.setFlag(flag);
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 48cbd54..fcf07f8 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -19,6 +19,7 @@
 per-file *Storage* = file:/core/java/android/os/storage/OWNERS
 per-file *TimeUpdate* = file:/core/java/android/app/timezone/OWNERS
 per-file ConnectivityService.java = file:/services/core/java/com/android/server/net/OWNERS
+per-file GestureLauncherService.java = file:platform/packages/apps/EmergencyInfo:/OWNERS
 per-file IpSecService.java = file:/services/core/java/com/android/server/net/OWNERS
 per-file MmsServiceBroker.java = file:/telephony/OWNERS
 per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWNERS
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index dbd27af4..c95bfd03 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -108,7 +108,6 @@
 import android.os.storage.StorageVolume;
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
-import android.provider.DeviceConfig;
 import android.provider.DocumentsContract;
 import android.provider.Downloads;
 import android.provider.MediaStore;
@@ -206,27 +205,6 @@
     private static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
             "persist.sys.vold_app_data_isolation_enabled";
 
-    // TODO(b/169327180): Will be fetched from the server, but for now, we emulate this in
-    // the system_server since it can write to DeviceConfig and MediaProvider can read it
-    private static final String PROP_TRANSCODE_ENABLED = "transcode_enabled";
-    private static final String PROP_TRANSCODE_DEFAULT = "transcode_default";
-    private static final String PROP_TRANSCODE_COMPAT_MANIFEST = "transcode_compat_manifest";
-    private static final boolean TRANSCODE_ENABLED_VALUE = false;
-    // Determines the default behavior of apps when transcode is enabled, AKA, Option A/Option B.
-    // If true, transcode by default (Option B). If false, don't transcode by default (Option A)
-    // For dogfood, we go with Option B
-    private static final boolean TRANSCODE_DEFAULT_VALUE = true;
-    // Format is <package_name>,<media_capability_bit_mask>,...
-    // media_capability_bit_mask is defined in MediaProvider/../TranscodeHelper.java:
-    // FLAG_HEVC = 1 << 0;
-    // FLAG_SLOW_MOTION = 1 << 1;
-    // FLAG_HDR_10 = 1 << 2;
-    // FLAG_HDR_10_PLUS = 1 << 3;
-    // FLAG_HDR_HLG = 1 << 4;
-    // FLAG_HDR_DOLBY_VISION = 1 << 5;
-    private static final String TRANSCODE_COMPAT_MANIFEST_VALUE =
-            "com.google.android.apps.photos,1";
-
     // How long we wait to reset storage, if we failed to call onMount on the
     // external storage service.
     public static final int FAILED_MOUNT_RESET_TIMEOUT_SECONDS = 10;
@@ -901,18 +879,6 @@
                     com.android.internal.R.bool.config_zramWriteback)) {
             ZramWriteback.scheduleZramWriteback(mContext);
         }
-
-        // TODO(b/169327180): Remove after setting up server-side DeviceConfig flags
-        // Set DeviceConfig values for transcoding that will be read by MediaProvider
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
-                PROP_TRANSCODE_ENABLED, String.valueOf(TRANSCODE_ENABLED_VALUE),
-                false /* makeDefault */);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
-                PROP_TRANSCODE_DEFAULT, String.valueOf(TRANSCODE_DEFAULT_VALUE),
-                false /* makeDefault */);
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
-                PROP_TRANSCODE_COMPAT_MANIFEST, TRANSCODE_COMPAT_MANIFEST_VALUE,
-                false /* makeDefault */);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0f9e9ee..18cc9a0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17225,8 +17225,6 @@
                     throw new SecurityException("Shell can delegate permissions only "
                             + "to one instrumentation at a time");
                 }
-                delegate.setPermissions(permissions);
-                return;
             }
 
             final int instrCount = mActiveInstrumentation.size();
@@ -17269,7 +17267,8 @@
 
     private class ShellDelegate implements CheckOpsDelegate {
         private final int mTargetUid;
-        private @Nullable String[] mPermissions;
+        @Nullable
+        private final String[] mPermissions;
 
         ShellDelegate(int targetUid, @Nullable String[] permissions) {
             mTargetUid = targetUid;
@@ -17280,11 +17279,6 @@
             return mTargetUid;
         }
 
-        void setPermissions(@Nullable String[] permissions) {
-            mPermissions = permissions;
-            PackageManager.invalidatePackageInfoCache();
-        }
-
         @Override
         public int checkOperation(int code, int uid, String packageName, boolean raw,
                 QuadFunction<Integer, Integer, String, Boolean, Integer> superImpl) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 3b6f0ac..422ae68 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -261,6 +261,8 @@
         mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
         mStats.setPowerProfileLocked(new PowerProfile(context));
+        mStats.startTrackingSystemServerCpuTime();
+
         mBatteryUsageStatsProvider = new BatteryUsageStatsProvider(context, mStats);
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index af00731..6bc927a 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2108,6 +2108,12 @@
         return getDevicesForAttributesInt(attributes);
     }
 
+    /** @see AudioManager#isMusicActive() */
+    public boolean isMusicActive() {
+        // no permission required
+        return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0);
+    }
+
     protected @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesInt(
             @NonNull AudioAttributes attributes) {
         Objects.requireNonNull(attributes);
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 1f0fb5e..712ef76 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -34,7 +34,6 @@
 import android.net.IDnsResolver;
 import android.net.LinkProperties;
 import android.net.Network;
-import android.net.NetworkUtils;
 import android.net.ResolverOptionsParcel;
 import android.net.ResolverParamsParcel;
 import android.net.Uri;
@@ -50,6 +49,7 @@
 
 import java.net.InetAddress;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -364,12 +364,11 @@
         paramsParcel.successThreshold = mSuccessThreshold;
         paramsParcel.minSamples = mMinSamples;
         paramsParcel.maxSamples = mMaxSamples;
-        paramsParcel.servers =
-                NetworkUtils.makeStrings(lp.getDnsServers());
+        paramsParcel.servers = makeStrings(lp.getDnsServers());
         paramsParcel.domains = getDomainStrings(lp.getDomains());
         paramsParcel.tlsName = strictMode ? privateDnsCfg.hostname : "";
         paramsParcel.tlsServers =
-                strictMode ? NetworkUtils.makeStrings(
+                strictMode ? makeStrings(
                         Arrays.stream(privateDnsCfg.ips)
                               .filter((ip) -> lp.isReachable(ip))
                               .collect(Collectors.toList()))
@@ -460,6 +459,21 @@
         return Settings.Global.getInt(mContentResolver, which, dflt);
     }
 
+    /**
+     * Create a string array of host addresses from a collection of InetAddresses
+     *
+     * @param addrs a Collection of InetAddresses
+     * @return an array of Strings containing their host addresses
+     */
+    private String[] makeStrings(Collection<InetAddress> addrs) {
+        String[] result = new String[addrs.size()];
+        int i = 0;
+        for (InetAddress addr : addrs) {
+            result[i++] = addr.getHostAddress();
+        }
+        return result;
+    }
+
     private static String getPrivateDnsMode(ContentResolver cr) {
         String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
         if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE);
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 8625a6f..96cbfde 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -40,11 +40,11 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.net.ISocketKeepaliveCallback;
+import android.net.InetAddresses;
 import android.net.InvalidPacketException;
 import android.net.KeepalivePacketData;
 import android.net.NattKeepalivePacketData;
 import android.net.NetworkAgent;
-import android.net.NetworkUtils;
 import android.net.SocketKeepalive.InvalidSocketException;
 import android.net.TcpKeepalivePacketData;
 import android.net.util.KeepaliveUtils;
@@ -625,8 +625,8 @@
 
         InetAddress srcAddress, dstAddress;
         try {
-            srcAddress = NetworkUtils.numericToInetAddress(srcAddrString);
-            dstAddress = NetworkUtils.numericToInetAddress(dstAddrString);
+            srcAddress = InetAddresses.parseNumericAddress(srcAddrString);
+            dstAddress = InetAddresses.parseNumericAddress(dstAddrString);
         } catch (IllegalArgumentException e) {
             notifyErrorCallback(cb, ERROR_INVALID_IP_ADDRESS);
             return;
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 49c16ad..a7be657 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -20,10 +20,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.net.InetAddresses;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
-import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.TrafficStats;
 import android.net.shared.PrivateDnsConfig;
@@ -97,8 +97,8 @@
 public class NetworkDiagnostics {
     private static final String TAG = "NetworkDiagnostics";
 
-    private static final InetAddress TEST_DNS4 = NetworkUtils.numericToInetAddress("8.8.8.8");
-    private static final InetAddress TEST_DNS6 = NetworkUtils.numericToInetAddress(
+    private static final InetAddress TEST_DNS4 = InetAddresses.parseNumericAddress("8.8.8.8");
+    private static final InetAddress TEST_DNS6 = InetAddresses.parseNumericAddress(
             "2001:4860:4860::8888");
 
     // For brevity elsewhere.
diff --git a/services/core/java/com/android/server/location/gnss/GnssPowerStats.java b/services/core/java/com/android/server/location/gnss/GnssPowerStats.java
index 70ab3c6..b924d1f 100644
--- a/services/core/java/com/android/server/location/gnss/GnssPowerStats.java
+++ b/services/core/java/com/android/server/location/gnss/GnssPowerStats.java
@@ -16,8 +16,8 @@
 
 package com.android.server.location.gnss;
 
-import static android.hardware.gnss.IGnss.ELAPSED_REALTIME_HAS_TIMESTAMP_NS;
-import static android.hardware.gnss.IGnss.ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS;
+import static android.hardware.gnss.ElapsedRealtime.HAS_TIMESTAMP_NS;
+import static android.hardware.gnss.ElapsedRealtime.HAS_TIME_UNCERTAINTY_NS;
 
 import com.android.internal.util.Preconditions;
 
@@ -57,12 +57,12 @@
 
     /** Returns true if {@link #getElapsedRealtimeNanos()} is available. */
     public boolean hasElapsedRealtimeNanos() {
-        return (mElapsedRealtimeFlags & ELAPSED_REALTIME_HAS_TIMESTAMP_NS) != 0;
+        return (mElapsedRealtimeFlags & HAS_TIMESTAMP_NS) != 0;
     }
 
     /** Returns true if {@link #getElapsedRealtimeUncertaintyNanos()} is available. */
     public boolean hasElapsedRealtimeUncertaintyNanos() {
-        return (mElapsedRealtimeFlags & ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS) != 0;
+        return (mElapsedRealtimeFlags & HAS_TIME_UNCERTAINTY_NS) != 0;
     }
 
     /**
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index f0bf5c0..9c5abd4 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -16,11 +16,11 @@
 
 package com.android.server.net;
 
+import android.net.InetAddresses;
 import android.net.IpConfiguration;
 import android.net.IpConfiguration.IpAssignment;
 import android.net.IpConfiguration.ProxySettings;
 import android.net.LinkAddress;
-import android.net.NetworkUtils;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
 import android.net.StaticIpConfiguration;
@@ -284,8 +284,10 @@
                         } else if (key.equals(IP_ASSIGNMENT_KEY)) {
                             ipAssignment = IpAssignment.valueOf(in.readUTF());
                         } else if (key.equals(LINK_ADDRESS_KEY)) {
-                            LinkAddress linkAddr = new LinkAddress(
-                                    NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt());
+                            LinkAddress linkAddr =
+                                    new LinkAddress(
+                                            InetAddresses.parseNumericAddress(in.readUTF()),
+                                            in.readInt());
                             if (linkAddr.getAddress() instanceof Inet4Address &&
                                     staticIpConfiguration.ipAddress == null) {
                                 staticIpConfiguration.ipAddress = linkAddr;
@@ -297,7 +299,7 @@
                             InetAddress gateway = null;
                             if (version == 1) {
                                 // only supported default gateways - leave the dest/prefix empty
-                                gateway = NetworkUtils.numericToInetAddress(in.readUTF());
+                                gateway = InetAddresses.parseNumericAddress(in.readUTF());
                                 if (staticIpConfiguration.gateway == null) {
                                     staticIpConfiguration.gateway = gateway;
                                 } else {
@@ -305,12 +307,13 @@
                                 }
                             } else {
                                 if (in.readInt() == 1) {
-                                    dest = new LinkAddress(
-                                            NetworkUtils.numericToInetAddress(in.readUTF()),
-                                            in.readInt());
+                                    dest =
+                                            new LinkAddress(
+                                                    InetAddresses.parseNumericAddress(in.readUTF()),
+                                                    in.readInt());
                                 }
                                 if (in.readInt() == 1) {
-                                    gateway = NetworkUtils.numericToInetAddress(in.readUTF());
+                                    gateway = InetAddresses.parseNumericAddress(in.readUTF());
                                 }
                                 RouteInfo route = new RouteInfo(dest, gateway);
                                 if (route.isIPv4Default() &&
@@ -322,7 +325,7 @@
                             }
                         } else if (key.equals(DNS_KEY)) {
                             staticIpConfiguration.dnsServers.add(
-                                    NetworkUtils.numericToInetAddress(in.readUTF()));
+                                    InetAddresses.parseNumericAddress(in.readUTF()));
                         } else if (key.equals(PROXY_SETTINGS_KEY)) {
                             proxySettings = ProxySettings.valueOf(in.readUTF());
                         } else if (key.equals(PROXY_HOST_KEY)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 318b229..2f6756d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -27,7 +27,6 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.role.IRoleManager;
 import android.app.role.RoleManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -80,7 +79,6 @@
 import android.os.ParcelFileDescriptor.AutoCloseInputStream;
 import android.os.PersistableBundle;
 import android.os.Process;
-import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
@@ -106,6 +104,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
+import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 import com.android.server.pm.PackageManagerShellCommandDataLoader.Metadata;
@@ -2971,12 +2970,10 @@
         final int translatedUserId =
                 translateUserId(userId, UserHandle.USER_NULL, "runSetHomeActivity");
         final CompletableFuture<Boolean> future = new CompletableFuture<>();
-        final RemoteCallback callback = new RemoteCallback(res -> future.complete(res != null));
         try {
-            IRoleManager roleManager = android.app.role.IRoleManager.Stub.asInterface(
-                    ServiceManager.getServiceOrThrow(Context.ROLE_SERVICE));
-            roleManager.addRoleHolderAsUser(RoleManager.ROLE_HOME, pkgName,
-                    0, translatedUserId, callback);
+            RoleManager roleManager = mContext.getSystemService(RoleManager.class);
+            roleManager.addRoleHolderAsUser(RoleManager.ROLE_HOME, pkgName, 0,
+                    UserHandle.of(translatedUserId), FgThread.getExecutor(), future::complete);
             boolean success = future.get();
             if (success) {
                 pw.println("Success");
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index 68d038b..16f5069 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -113,11 +113,6 @@
     private boolean mIsInteractive;
 
     /**
-     * Read-only list of plugins. No need for synchronization.
-     */
-    private final Plugin[] mPlugins;
-
-    /**
      * Package name that will receive an explicit manifest broadcast for
      * {@link PowerManager#ACTION_POWER_SAVE_MODE_CHANGED}. It's {@code null} if it hasn't been
      * retrieved yet.
@@ -172,15 +167,6 @@
         }
     }
 
-    /**
-     * Plugin interface. All methods are guaranteed to be called on the same (handler) thread.
-     */
-    public interface Plugin {
-        void onSystemReady(BatterySaverController caller);
-
-        void onBatterySaverChanged(BatterySaverController caller);
-    }
-
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -194,6 +180,7 @@
                         updateBatterySavingStats();
                         return; // No need to send it if not enabled.
                     }
+                    // We currently evaluate state only for CPU frequency changes.
                     // Don't send the broadcast, because we never did so in this case.
                     mHandler.postStateChanged(/*sendBroadcast=*/ false,
                             REASON_INTERACTIVE_CHANGED);
@@ -224,9 +211,6 @@
         mFileUpdater = new FileUpdater(context);
         mBatterySavingStats = batterySavingStats;
 
-        // TODO(79580230): remove plugin code and maybe screen on/off listeners?
-        // Initialize plugins.
-        mPlugins = new Plugin[0];
         PowerManager.invalidatePowerSaveModeCaches();
     }
 
@@ -300,12 +284,6 @@
                             msg.arg1 == ARG_SEND_BROADCAST,
                             msg.arg2);
                     break;
-
-                case MSG_SYSTEM_READY:
-                    for (Plugin p : mPlugins) {
-                        p.onSystemReady(BatterySaverController.this);
-                    }
-                    break;
             }
         }
     }
@@ -479,10 +457,6 @@
             mFileUpdater.writeFiles(fileValues);
         }
 
-        for (Plugin p : mPlugins) {
-            p.onBatterySaverChanged(this);
-        }
-
         if (sendBroadcast) {
 
             if (DEBUG) {
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index eb15c80..caa275d 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -34,7 +34,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
@@ -754,18 +753,6 @@
 
             dumpOutputStream.flush();
         }
-
-        private int getUidForPackage(String packageName) {
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                return getContext().getPackageManager().getApplicationInfo(packageName,
-                        PackageManager.MATCH_ANY_USER).uid;
-            } catch (NameNotFoundException nnfe) {
-                return -1;
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
     }
 
     private class Internal extends RoleManagerInternal {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 8298dfd..5fed940 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4708,8 +4708,11 @@
                             .setContentTitle(text)
                             .setContentText(
                                     mContext.getText(R.string.heavy_weight_notification_detail))
+                            // TODO(b/175194709) Please replace FLAG_MUTABLE_UNAUDITED below
+                            // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
                             .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0,
-                                    intent, PendingIntent.FLAG_CANCEL_CURRENT, null,
+                                    intent, PendingIntent.FLAG_CANCEL_CURRENT
+                                    | PendingIntent.FLAG_MUTABLE_UNAUDITED, null,
                                     new UserHandle(userId)))
                             .build();
             try {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e88f8e3..0678a5e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2298,10 +2298,6 @@
                             .setSubtype(getConfiguration().orientation)
                             .addTaggedData(MetricsEvent.FIELD_DISPLAY_ID, getDisplayId()));
         }
-
-        if (mPinnedStackControllerLocked != null) {
-            mPinnedStackControllerLocked.onDisplayInfoChanged(getDisplayInfo());
-        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index fd42b24..8fe2481 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -127,7 +127,6 @@
         try {
             listener.asBinder().linkToDeath(mPinnedStackListenerDeathHandler, 0);
             mPinnedStackListener = listener;
-            notifyDisplayInfoChanged(mDisplayInfo);
             notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
             notifyMovementBoundsChanged(false /* fromImeAdjustment */);
             notifyActionsChanged(mActions);
@@ -171,23 +170,6 @@
         }
     }
 
-    private void setDisplayInfo(DisplayInfo displayInfo) {
-        mDisplayInfo.copyFrom(displayInfo);
-        notifyDisplayInfoChanged(mDisplayInfo);
-    }
-
-    /**
-     * In the case where the display rotation is changed but there is no stack, we can't depend on
-     * onTaskStackBoundsChanged() to be called.  But we still should update our known display info
-     * with the new state so that we can update SystemUI.
-     */
-    void onDisplayInfoChanged(DisplayInfo displayInfo) {
-        synchronized (mService.mGlobalLock) {
-            setDisplayInfo(displayInfo);
-            notifyMovementBoundsChanged(false /* fromImeAdjustment */);
-        }
-    }
-
     /**
      * Sets the Ime state and height.
      */
@@ -288,18 +270,6 @@
         }
     }
 
-    /**
-     * Notifies listeners that the PIP animation is about to happen.
-     */
-    private void notifyDisplayInfoChanged(DisplayInfo displayInfo) {
-        if (mPinnedStackListener == null) return;
-        try {
-            mPinnedStackListener.onDisplayInfoChanged(displayInfo);
-        } catch (RemoteException e) {
-            Slog.e(TAG_WM, "Error delivering DisplayInfo changed event.", e);
-        }
-    }
-
     void dump(String prefix, PrintWriter pw) {
         pw.println(prefix + "PinnedStackController");
         pw.println(prefix + "  mIsImeShowing=" + mIsImeShowing);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 616a789..b2f3062 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -369,7 +369,8 @@
         SurfaceControl[] excludeLayers;
         final WindowState imeWindow = task.getDisplayContent().mInputMethodWindow;
         // Exclude IME window snapshot when IME isn't proper to attach to app.
-        if (imeWindow != null && !task.getDisplayContent().isImeAttachedToApp()) {
+        if (imeWindow != null && imeWindow.getSurfaceControl() != null
+                && !task.getDisplayContent().isImeAttachedToApp()) {
             excludeLayers = new SurfaceControl[1];
             excludeLayers[0] = imeWindow.getSurfaceControl();
         } else {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index ce61d50..22976c30 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -22,6 +22,8 @@
 
 import com.android.server.SystemService;
 
+import java.util.List;
+
 /**
  * Defines the required interface for IDevicePolicyManager implemenation.
  *
@@ -101,4 +103,9 @@
     public boolean canProfileOwnerResetPasswordWhenLocked(int userId) {
         return false;
     }
+
+    public List<String> getKeyPairGrants(String callerPackage, String alias) {
+        // STOPSHIP: implement delegation code in ArcDevicePolicyManagerWrapperService & nuke this.
+        return null;
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c7dbf95..6d2cb9c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5192,6 +5192,44 @@
         return false;
     }
 
+    @Override
+    public List<String> getKeyPairGrants(String callerPackage, String alias) {
+        final CallerIdentity caller = getCallerIdentity(callerPackage);
+        Preconditions.checkCallAuthorization(canManageCertificates(caller));
+
+        return mInjector.binderWithCleanCallingIdentity(() -> {
+            try (KeyChainConnection keyChainConnection =
+                         KeyChain.bindAsUser(mContext, caller.getUserHandle())) {
+                final List<String> result = new ArrayList<>();
+                final int[] granteeUids = keyChainConnection.getService().getGrants(alias);
+                final PackageManager pm = mInjector.getPackageManager(caller.getUserId());
+
+                // TODO: Return Set<Set<String>> when AIDL supports it: b/136048684
+                // Public API returns a set of sets, where each internal set contains all package
+                // names corresponding to the same UID. For now a set of sets is marshalled as a
+                // null-separated list.
+                for (final int uid : granteeUids) {
+                    final String[] packages = pm.getPackagesForUid(uid);
+                    if (packages == null) {
+                        Slog.wtf(LOG_TAG, "No packages found for uid " + uid);
+                        continue;
+                    }
+                    if (!result.isEmpty()) {
+                        result.add(null);
+                    }
+                    result.addAll(Arrays.asList(packages));
+                }
+                return result;
+            } catch (RemoteException e) {
+                Log.e(LOG_TAG, "Querying keypair grants", e);
+            } catch (InterruptedException e) {
+                Log.w(LOG_TAG, "Interrupted while querying keypair grants", e);
+                Thread.currentThread().interrupt();
+            }
+            return Collections.emptyList();
+        });
+    }
+
     /**
      * Enforce one the following conditions are met:
      * (1) The device has a Device Owner, and one of the following holds:
@@ -6118,8 +6156,8 @@
 
         int userId = admin != null ? admin.getUserHandle().getIdentifier()
                 : caller.getUserId();
-        Slog.i(LOG_TAG, "wipeDataWithReason(" + wipeReasonForUser + "): admin=" + admin + ", user="
-                + userId);
+        Slog.i(LOG_TAG, String.format("wipeDataWithReason(%s): admin=%s, user=%d",
+                wipeReasonForUser, admin, userId));
         if (calledByProfileOwnerOnOrgOwnedDevice) {
             // When wipeData is called on the parent instance, it implies wiping the entire device.
             if (calledOnParentInstance) {
diff --git a/services/tests/servicestests/src/com/android/server/OWNERS b/services/tests/servicestests/src/com/android/server/OWNERS
index 6153db3..2463fc6 100644
--- a/services/tests/servicestests/src/com/android/server/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/OWNERS
@@ -4,3 +4,4 @@
 per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
 per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS
 per-file *Vibrator* = file:/services/core/java/com/android/server/vibrator/OWNERS
+per-file GestureLauncherServiceTest.java = file:platform/packages/apps/EmergencyInfo:/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java
index 7767a28..9d300a6 100644
--- a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java
@@ -20,11 +20,11 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
 
+import android.net.InetAddresses;
 import android.net.IpConfiguration;
 import android.net.IpConfiguration.IpAssignment;
 import android.net.IpConfiguration.ProxySettings;
 import android.net.LinkAddress;
-import android.net.NetworkUtils;
 import android.net.ProxyInfo;
 import android.net.StaticIpConfiguration;
 import android.util.ArrayMap;
@@ -79,8 +79,8 @@
 
         StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
         staticIpConfiguration.ipAddress = new LinkAddress(IP_ADDR_1);
-        staticIpConfiguration.dnsServers.add(NetworkUtils.numericToInetAddress(DNS_IP_ADDR_1));
-        staticIpConfiguration.dnsServers.add(NetworkUtils.numericToInetAddress(DNS_IP_ADDR_2));
+        staticIpConfiguration.dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_1));
+        staticIpConfiguration.dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_2));
 
         ProxyInfo proxyInfo = new ProxyInfo("10.10.10.10", 88, "host1,host2");
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 0bb2867..ec65085 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -30,6 +30,8 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
 import android.app.WindowConfiguration;
@@ -183,6 +185,24 @@
         }
     }
 
+    @UseTestDisplay(addWindows = {W_ACTIVITY, W_INPUT_METHOD})
+    @Test
+    public void testCreateTaskSnapshotWithExcludingIme() {
+        Task task = mAppWindow.mActivityRecord.getTask();
+        spyOn(task);
+        spyOn(mDisplayContent);
+        when(task.getDisplayContent().isImeAttachedToApp()).thenReturn(false);
+        // Intentionally set the SurfaceControl of input method window as null.
+        mDisplayContent.mInputMethodWindow.setSurfaceControl(null);
+        // Verify no NPE happens when calling createTaskSnapshot.
+        try {
+            mWm.mTaskSnapshotController.createTaskSnapshot(mAppWindow.mActivityRecord.getTask(),
+                    1f /* scaleFraction */, PixelFormat.UNKNOWN, null /* outTaskSize */);
+        } catch (NullPointerException e) {
+            fail("There should be no exception when calling createTaskSnapshot");
+        }
+    }
+
     @UseTestDisplay(addWindows = W_ACTIVITY)
     @Test
     public void testPrepareTaskSnapshot() {
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 0c46394..4bb7cc4 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -244,7 +244,9 @@
      * <ul>
      *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
      *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
-     *       access check, or the calling package has carrier privileges on any active subscription.
+     *       access check, or the calling package has carrier privileges on any active
+     *       subscription, or the calling package has the {@link
+     *       Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} appop permission.
      *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
      *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission
      *       or carrier privileges of any active subscription.
@@ -256,6 +258,10 @@
      */
     public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, int subId,
             String callingPackage, @Nullable String callingFeatureId, String message) {
+        if (checkCallingOrSelfUseIccAuthWithDeviceIdentifier(context, callingPackage,
+                callingFeatureId, message)) {
+            return true;
+        }
         return checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
                 context, subId, callingPackage, callingFeatureId, message, true);
     }
@@ -267,7 +273,9 @@
      * <ul>
      *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
      *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
-     *       access check, or the calling package has carrier privileges on specified subscription.
+     *       access check, or the calling package has carrier privileges on specified subscription,
+     *       or the calling package has the {@link
+     *       Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} appop permission.
      *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
      *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
      *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
@@ -278,6 +286,10 @@
      */
     public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
             String callingPackage, @Nullable String callingFeatureId, String message) {
+        if (checkCallingOrSelfUseIccAuthWithDeviceIdentifier(context, callingPackage,
+                callingFeatureId, message)) {
+            return true;
+        }
         return checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
                 context, subId, callingPackage, callingFeatureId, message, false);
     }
@@ -385,6 +397,26 @@
     }
 
     /**
+     * Check whether the caller (or self, if not processing an IPC) has {@link
+     * Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} AppOp permission.
+     *
+     * <p>With the permission, the caller can access device/subscriber identifiers and use ICC
+     * authentication like EAP-AKA.
+     */
+    public static boolean checkCallingOrSelfUseIccAuthWithDeviceIdentifier(Context context,
+            String callingPackage, String callingFeatureId, String message) {
+        // Cannot perform appop check if the calling package is null
+        if (callingPackage == null) {
+            return false;
+        }
+        int callingUid = Binder.getCallingUid();
+        AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        int opMode = appOps.noteOpNoThrow(AppOpsManager.OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER,
+                callingUid, callingPackage, callingFeatureId, message);
+        return opMode == AppOpsManager.MODE_ALLOWED;
+    }
+
+    /**
      * Check whether the app with the given pid/uid can read the call log.
      * @return {@code true} if the specified app has the read call log permission and AppOpp granted
      *      to it, {@code false} otherwise.
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index f900c38..99f2e5e 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -624,6 +624,20 @@
     public @interface UiccAppType{}
 
     /**
+     * UICC SIM Application Types including UNKNOWN
+     */
+    @IntDef(prefix = { "APPTYPE_" }, value = {
+            TelephonyManager.APPTYPE_UNKNOWN,
+            TelephonyManager.APPTYPE_SIM,
+            TelephonyManager.APPTYPE_USIM,
+            TelephonyManager.APPTYPE_RUIM,
+            TelephonyManager.APPTYPE_CSIM,
+            TelephonyManager.APPTYPE_ISIM
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface UiccAppTypeExt{}
+
+    /**
      * Override network type
      */
     @Retention(RetentionPolicy.SOURCE)
diff --git a/telephony/java/android/telephony/IBootstrapAuthenticationCallback.aidl b/telephony/java/android/telephony/IBootstrapAuthenticationCallback.aidl
new file mode 100644
index 0000000..d39ad0e
--- /dev/null
+++ b/telephony/java/android/telephony/IBootstrapAuthenticationCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 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.telephony;
+
+/**
+ * Callback to handle the response of bootstrapAuthenticationRequest
+ * @hide
+ */
+oneway interface IBootstrapAuthenticationCallback
+{
+    void onKeysAvailable(int token, in byte[] gbaKey, String btId);
+    void onAuthenticationFailure(int token, int reason);
+}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ef09962..b48df71 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -80,12 +80,14 @@
 import android.telephony.Annotation.SimActivationState;
 import android.telephony.Annotation.ThermalMitigationResult;
 import android.telephony.Annotation.UiccAppType;
+import android.telephony.Annotation.UiccAppTypeExt;
 import android.telephony.CallForwardingInfo.CallForwardingReason;
 import android.telephony.VisualVoicemailService.VisualVoicemailTask;
 import android.telephony.data.ApnSetting;
 import android.telephony.data.ApnSetting.MvnoType;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
+import android.telephony.gba.UaSecurityProtocolIdentifier;
 import android.telephony.ims.ImsMmTelManager;
 import android.telephony.ims.aidl.IImsConfig;
 import android.telephony.ims.aidl.IImsRegistration;
@@ -2009,6 +2011,8 @@
      *     active subscription.
      *     <li>If the calling app is the default SMS role holder (see {@link
      *     RoleManager#isRoleHeld(String)}).
+     *     <li>If the calling app has been granted the
+     *      {@link Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} permission.
      * </ul>
      *
      * <p>If the calling app does not meet one of these requirements then this method will behave
@@ -4019,6 +4023,8 @@
      *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *     <li>If the calling app is the default SMS role holder (see {@link
      *     RoleManager#isRoleHeld(String)}).
+     *     <li>If the calling app has been granted the
+     *     {@link Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} permission.
      * </ul>
      *
      * <p>If the calling app does not meet one of these requirements then this method will behave
@@ -4043,33 +4049,8 @@
      * for a subscription.
      * Return null if it is unavailable.
      *
-     * <p>Starting with API level 29, persistent device identifiers are guarded behind additional
-     * restrictions, and apps are recommended to use resettable identifiers (see <a
-     * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This
-     * method can be invoked if one of the following requirements is met:
-     * <ul>
-     *     <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this
-     *     is a privileged permission that can only be granted to apps preloaded on the device.
-     *     <li>If the calling app is the device or profile owner and has been granted the
-     *     {@link Manifest.permission#READ_PHONE_STATE} permission. The profile owner is an app that
-     *     owns a managed profile on the device; for more details see <a
-     *     href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
-     *     Profile owner access is deprecated and will be removed in a future release.
-     *     <li>If the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
-     *     <li>If the calling app is the default SMS role holder (see {@link
-     *     RoleManager#isRoleHeld(String)}).
-     * </ul>
-     *
-     * <p>If the calling app does not meet one of these requirements then this method will behave
-     * as follows:
-     *
-     * <ul>
-     *     <li>If the calling app's target SDK is API level 28 or lower and the app has the
-     *     READ_PHONE_STATE permission then null is returned.</li>
-     *     <li>If the calling app's target SDK is API level 28 or lower and the app does not have
-     *     the READ_PHONE_STATE permission, or if the calling app is targeting API level 29 or
-     *     higher, then a SecurityException is thrown.</li>
-     * </ul>
+     * See {@link #getSubscriberId()} for details on the required permissions and behavior
+     * when the caller does not hold sufficient permissions.
      *
      * @param subId whose subscriber id is returned
      * @hide
@@ -7153,6 +7134,8 @@
         }
     }
 
+    /** UICC application type is unknown or not specified */
+    public static final int APPTYPE_UNKNOWN = PhoneConstants.APPTYPE_UNKNOWN;
     /** UICC application type is SIM */
     public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM;
     /** UICC application type is USIM */
@@ -7175,8 +7158,13 @@
      * Returns the response of authentication for the default subscription.
      * Returns null if the authentication hasn't been successful
      *
-     * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE or that the calling
-     * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     * <p>Requires one of the following permissions:
+     * <ul>
+     *     <li>READ_PRIVILEGED_PHONE_STATE
+     *     <li>the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     *     <li>the calling app has been granted the
+     *     {@link Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER} permission.
+     * </ul>
      *
      * @param appType the icc application type, like {@link #APPTYPE_USIM}
      * @param authType the authentication type, {@link #AUTHTYPE_EAP_AKA} or
@@ -7201,7 +7189,8 @@
      * Returns the response of USIM Authentication for specified subId.
      * Returns null if the authentication hasn't been successful
      *
-     * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+     * <p>See {@link #getIccAuthentication(int, int, String)} for details on the required
+     * permissions.
      *
      * @param subId subscription ID used for authentication
      * @param appType the icc application type, like {@link #APPTYPE_USIM}
@@ -7224,7 +7213,8 @@
             IPhoneSubInfo info = getSubscriberInfoService();
             if (info == null)
                 return null;
-            return info.getIccSimChallengeResponse(subId, appType, authType, data);
+            return info.getIccSimChallengeResponse(subId, appType, authType, data,
+                    getOpPackageName(), getAttributionTag());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
@@ -14511,4 +14501,173 @@
             throw new IllegalStateException("telephony service is null.");
         }
     }
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"GBA_FAILURE_REASON_"}, value = {
+            GBA_FAILURE_REASON_UNKNOWN,
+            GBA_FAILURE_REASON_FEATURE_NOT_SUPPORTED,
+            GBA_FAILURE_REASON_FEATURE_NOT_READY,
+            GBA_FAILURE_REASON_NETWORK_FAILURE,
+            GBA_FAILURE_REASON_INCORRECT_NAF_ID,
+            GBA_FAILURE_REASON_SECURITY_PROTOCOL_NOT_SUPPORTED})
+    public @interface AuthenticationFailureReason {}
+
+    /**
+     * GBA Authentication has failed for an unknown reason.
+     *
+     * <p>The caller should retry a message that failed with this response.
+     * @hide
+     */
+    @SystemApi
+    public static final int GBA_FAILURE_REASON_UNKNOWN = 0;
+
+    /**
+     * GBA Authentication is not supported by the carrier, SIM or android.
+     *
+     * <p>Application should use other authentication mechanisms if possible.
+     * @hide
+     */
+    @SystemApi
+    public static final int GBA_FAILURE_REASON_FEATURE_NOT_SUPPORTED = 1;
+
+    /**
+     * GBA Authentication service is not ready for use.
+     *
+     * <p>Application could try again at a later time.
+     * @hide
+     */
+    @SystemApi
+    public static final int GBA_FAILURE_REASON_FEATURE_NOT_READY = 2;
+
+    /**
+     * GBA Authentication has been failed by the network.
+     * @hide
+     */
+    @SystemApi
+    public static final int GBA_FAILURE_REASON_NETWORK_FAILURE = 3;
+
+    /**
+     * GBA Authentication has failed due to incorrect NAF URL.
+     * @hide
+     */
+    @SystemApi
+    public static final int GBA_FAILURE_REASON_INCORRECT_NAF_ID = 4;
+
+    /**
+     * GBA Authentication has failed due to unsupported security protocol
+     * @hide
+     */
+    @SystemApi
+    public static final int GBA_FAILURE_REASON_SECURITY_PROTOCOL_NOT_SUPPORTED = 5;
+
+    /**
+     * The callback associated with a {@link #bootstrapAuthenticationRequest()}.
+     * @hide
+     */
+    @SystemApi
+    public static class BootstrapAuthenticationCallback {
+
+        /**
+         * Invoked when the previously requested GBA keys are available (@see
+         * bootstrapAuthenticationRequest()).
+         * @param gbaKey Ks_NAF/Ks_ext_NAF Response
+         * @param transactionId Bootstrapping Transaction Identifier
+         */
+        public void onKeysAvailable(@NonNull byte[] gbaKey, @NonNull String transactionId) {}
+
+        /**
+         * @param reason The reason for the authentication failure.
+         */
+        public void onAuthenticationFailure(@AuthenticationFailureReason int reason) {}
+    }
+
+    /**
+     * Used to get the Generic Bootstrapping Architecture authentication keys
+     * KsNAF/Ks_ext_NAF for a particular NAF as defined in 3GPP spec TS 33.220 for
+     * the specified sub id.
+     *
+     * <p>Application must be prepared to wait for receiving the Gba keys through the
+     * registered callback and not invoke the API on the main application thread.
+     * Application also must call the api to get the fresh key every time instead
+     * of caching the key.
+     *
+     * Following steps may be invoked on the API call depending on the state of the
+     * underlying GBA implementation:
+     * <ol>
+     *     <li>Resolve and bind to a Gba implementation.</li>
+     *     <li>Run bootstrapping if no valid keys are available or bootstrapping is forced.</li>
+     *     <li>Generate the ks_NAF/ ks_Ext_NAF to be returned via the callback.</li>
+     * </ol>
+     *
+     * <p> Requires Permission: MODIFY_PHONE_STATE or that the calling app has carrier
+     * privileges (see {@link #hasCarrierPrivileges}).
+     * @param appType icc application type, like {@link #APPTYPE_USIM} or {@link
+     * #APPTYPE_ISIM} or {@link#APPTYPE_UNKNOWN}
+     * @param nafId Network Application Function(NAF) fully qualified domain name and
+     * the selected GBA mode. It shall contain two parts delimited by "@" sign. The first
+     * part is the constant string "3GPP-bootstrapping" (GBA_ME),
+     * "3GPP-bootstrapping-uicc" (GBA_ U), or "3GPP-bootstrapping-digest" (GBA_Digest),
+     * and the latter part shall be the FQDN of the NAF (e.g.
+     * "3GPP-bootstrapping@naf1.operator.com" or "3GPP-bootstrapping-uicc@naf1.operator.com",
+     * or "3GPP-bootstrapping-digest@naf1.operator.com").
+     * @param securityProtocol Security protocol identifier between UE and NAF.  See
+     * 3GPP TS 33.220 Annex H. Application can use
+     * {@link UaSecurityProtocolIdentifier#createDefaultUaSpId},
+     * {@link UaSecurityProtocolIdentifier#create3GppUaSpId},
+     * to create the ua security protocol identifier as needed
+     * @param forceBootStrapping true=force bootstrapping, false=do not force
+     * bootstrapping. Bootstrapping shouldn't be forced unless the application sees
+     * authentication errors from the server.
+     * @param e The {@link Executor} that will be used to call the Gba callback.
+     * @param callback A callback called on the supplied {@link Executor} that will
+     * contain the GBA Ks_NAF/Ks_ext_NAF when available. If the NAF keys are
+     * available and valid at the time of call and bootstrapping is not requested,
+     * then the callback shall be invoked with the available keys.
+     * @hide
+     */
+    @SystemApi
+    @WorkerThread
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public void bootstrapAuthenticationRequest(
+            @UiccAppTypeExt int appType, @NonNull Uri nafId,
+            @NonNull UaSecurityProtocolIdentifier securityProtocol,
+            boolean forceBootStrapping, @NonNull Executor e,
+            @NonNull BootstrapAuthenticationCallback callback) {
+        try {
+            ITelephony service = getITelephony();
+            if (service == null) {
+                e.execute(() -> callback.onAuthenticationFailure(
+                        GBA_FAILURE_REASON_FEATURE_NOT_READY));
+                return;
+            }
+            service.bootstrapAuthenticationRequest(
+                    getSubId(), appType, nafId, securityProtocol, forceBootStrapping,
+                    new IBootstrapAuthenticationCallback.Stub() {
+                        @Override
+                        public void onKeysAvailable(int token, byte[] gbaKey,
+                                String transactionId) {
+                            final long identity = Binder.clearCallingIdentity();
+                            try {
+                                e.execute(() -> callback.onKeysAvailable(gbaKey, transactionId));
+                            } finally {
+                                Binder.restoreCallingIdentity(identity);
+                            }
+                        }
+
+                        @Override
+                        public void onAuthenticationFailure(int token, int reason) {
+                            final long identity = Binder.clearCallingIdentity();
+                            try {
+                                e.execute(() -> callback.onAuthenticationFailure(reason));
+                            } finally {
+                                Binder.restoreCallingIdentity(identity);
+                            }
+                        }
+                    });
+        } catch (RemoteException exception) {
+            Log.e(TAG, "Error calling ITelephony#bootstrapAuthenticationRequest", exception);
+            e.execute(() -> callback.onAuthenticationFailure(GBA_FAILURE_REASON_FEATURE_NOT_READY));
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/gba/GbaAuthRequest.aidl b/telephony/java/android/telephony/gba/GbaAuthRequest.aidl
new file mode 100644
index 0000000..ba243a2
--- /dev/null
+++ b/telephony/java/android/telephony/gba/GbaAuthRequest.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2020 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.telephony.gba;
+
+parcelable GbaAuthRequest;
diff --git a/telephony/java/android/telephony/gba/GbaAuthRequest.java b/telephony/java/android/telephony/gba/GbaAuthRequest.java
new file mode 100644
index 0000000..5366e9a
--- /dev/null
+++ b/telephony/java/android/telephony/gba/GbaAuthRequest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2020 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.telephony.gba;
+
+import android.annotation.NonNull;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.IBootstrapAuthenticationCallback;
+
+import com.android.internal.telephony.uicc.IccUtils;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * GBA authentication request
+ * {@hide}
+ */
+public final class GbaAuthRequest implements Parcelable {
+    private int mToken;
+    private int mSubId;
+    private int mAppType;
+    private Uri mNafUrl;
+    private byte[] mSecurityProtocol;
+    private boolean mForceBootStrapping;
+    private IBootstrapAuthenticationCallback mCallback;
+
+    private static AtomicInteger sUniqueToken = new AtomicInteger(0);
+
+    public GbaAuthRequest(int subId, int appType, Uri nafUrl, byte[] securityProtocol,
+            boolean forceBootStrapping, IBootstrapAuthenticationCallback callback) {
+        this(nextUniqueToken(), subId, appType, nafUrl,
+                securityProtocol, forceBootStrapping, callback);
+    }
+
+    public GbaAuthRequest(GbaAuthRequest request) {
+        this(request.mToken, request.mSubId, request.mAppType, request.mNafUrl,
+                request.mSecurityProtocol, request.mForceBootStrapping, request.mCallback);
+    }
+
+    public GbaAuthRequest(int token, int subId, int appType, Uri nafUrl, byte[] securityProtocol,
+            boolean forceBootStrapping, IBootstrapAuthenticationCallback callback) {
+        mToken = token;
+        mSubId = subId;
+        mAppType = appType;
+        mNafUrl = nafUrl;
+        mSecurityProtocol = securityProtocol;
+        mCallback = callback;
+        mForceBootStrapping = forceBootStrapping;
+    }
+
+    public int getToken() {
+        return mToken;
+    }
+
+    public int getSubId() {
+        return mSubId;
+    }
+
+    public int getAppType() {
+        return mAppType;
+    }
+
+    public Uri getNafUrl() {
+        return mNafUrl;
+    }
+
+    public byte[] getSecurityProtocol() {
+        return mSecurityProtocol;
+    }
+
+    public boolean isForceBootStrapping() {
+        return mForceBootStrapping;
+    }
+
+    public void setCallback(IBootstrapAuthenticationCallback cb) {
+        mCallback = cb;
+    }
+
+    public IBootstrapAuthenticationCallback getCallback() {
+        return mCallback;
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeInt(mToken);
+        out.writeInt(mSubId);
+        out.writeInt(mAppType);
+        out.writeParcelable(mNafUrl, 0);
+        out.writeInt(mSecurityProtocol.length);
+        out.writeByteArray(mSecurityProtocol);
+        out.writeBoolean(mForceBootStrapping);
+        out.writeStrongInterface(mCallback);
+    }
+
+    /**
+     * {@link Parcelable.Creator}
+     *
+     */
+    public static final @android.annotation.NonNull Parcelable.Creator<
+            GbaAuthRequest> CREATOR = new Creator<GbaAuthRequest>() {
+                @Override
+                public GbaAuthRequest createFromParcel(Parcel in) {
+                    int token = in.readInt();
+                    int subId = in.readInt();
+                    int appType = in.readInt();
+                    Uri nafUrl = in.readParcelable(GbaAuthRequest.class.getClassLoader());
+                    int len = in.readInt();
+                    byte[] protocol = new byte[len];
+                    in.readByteArray(protocol);
+                    boolean forceBootStrapping = in.readBoolean();
+                    IBootstrapAuthenticationCallback callback =
+                            IBootstrapAuthenticationCallback.Stub
+                            .asInterface(in.readStrongBinder());
+                    return new GbaAuthRequest(token, subId, appType, nafUrl, protocol,
+                            forceBootStrapping, callback);
+                }
+
+                @Override
+                public GbaAuthRequest[] newArray(int size) {
+                    return new GbaAuthRequest[size];
+                }
+            };
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    private static int nextUniqueToken() {
+        return sUniqueToken.getAndIncrement() << 16 | (0xFFFF & (int) System.currentTimeMillis());
+    }
+
+    @Override
+    public String toString() {
+        String str = "Token: " +  mToken + "SubId:" + mSubId + ", AppType:"
+                + mAppType + ", NafUrl:" + mNafUrl + ", SecurityProtocol:"
+                + IccUtils.bytesToHexString(mSecurityProtocol)
+                + ", ForceBootStrapping:" + mForceBootStrapping
+                + ", CallBack:" + mCallback;
+        return str;
+    }
+}
diff --git a/telephony/java/android/telephony/gba/GbaService.java b/telephony/java/android/telephony/gba/GbaService.java
new file mode 100644
index 0000000..3962aff
--- /dev/null
+++ b/telephony/java/android/telephony/gba/GbaService.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2020 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.telephony.gba;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telephony.Annotation.UiccAppTypeExt;
+import android.telephony.IBootstrapAuthenticationCallback;
+import android.telephony.TelephonyManager;
+import android.telephony.TelephonyManager.AuthenticationFailureReason;
+import android.util.Log;
+import android.util.SparseArray;
+
+/**
+  * Base class for GBA Service. Any implementation which wants to provide
+  * GBA service must extend this class.
+  *
+  * <p>Note that the application to implement the service must declare to use
+  * the permission {@link android.Manifest.permission#BIND_GBA_SERVICE},
+  * and filter the intent of {@link #SERVICE_INTERFACE}.
+  * The manifest of the service must follow the format below:
+  *
+  * <p>...
+  * <service
+  *     android:name=".EgGbaService"
+  *     android:directBootAware="true"
+  *     android:permission="android.permission.BIND_GBA_SERVICE" >
+  *     ...
+  *     <intent-filter>
+  *         <action android:name="android.telephony.gba.GbaService"/>
+  *     </intent-filter>
+  * </service>
+  * ...
+  *
+  * <p>The service should also be file-based encryption (FBE) aware.
+  * {@hide}
+  */
+@SystemApi
+public class GbaService extends Service  {
+    private static final boolean DBG = Build.IS_DEBUGGABLE;
+    private static final String TAG = "GbaService";
+
+    /**
+    * The intent must be defined as an intent-filter in the
+    * AndroidManifest of the GbaService.
+    */
+    public static final String SERVICE_INTERFACE = "android.telephony.gba.GbaService";
+
+    private static final int EVENT_GBA_AUTH_REQUEST = 1;
+
+    private final HandlerThread mHandlerThread;
+    private final GbaServiceHandler mHandler;
+
+    private final SparseArray<IBootstrapAuthenticationCallback> mCallbacks = new SparseArray<>();
+    private final IGbaServiceWrapper mBinder = new IGbaServiceWrapper();
+
+    /**
+     * Default constructor.
+     */
+    public GbaService() {
+        mHandlerThread = new HandlerThread(TAG);
+        mHandlerThread.start();
+
+        mHandler = new GbaServiceHandler(mHandlerThread.getLooper());
+        Log.d(TAG, "GBA service created");
+    }
+
+    private class GbaServiceHandler extends Handler {
+
+        GbaServiceHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case EVENT_GBA_AUTH_REQUEST:
+                    GbaAuthRequest req = (GbaAuthRequest) msg.obj;
+                    synchronized (mCallbacks) {
+                        mCallbacks.put(req.getToken(), req.getCallback());
+                    }
+                    onAuthenticationRequest(req.getSubId(), req.getToken(), req.getAppType(),
+                            req.getNafUrl(), req.getSecurityProtocol(), req.isForceBootStrapping());
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Called by the platform when a GBA authentication request is received from
+     * {@link TelephonyManager#bootstrapAuthenticationRequest} to get the KsNAF for
+     * a particular NAF.
+     *
+     * @param subscriptionId the ICC card to be used for the bootstrapping authentication.
+     * @param token the identification of the authentication request.
+     * @param appType icc application type, like {@link #APPTYPE_USIM} or {@link
+     * #APPTYPE_ISIM} or {@link#APPTYPE_UNKNOWN}
+     * @param nafUrl Network Application Function(NAF) fully qualified domain name and
+     * the selected GBA mode. It shall contain two parts delimited by "@" sign. The first
+     * part is the constant string "3GPP-bootstrapping" (GBA_ME),
+     * "3GPP-bootstrapping-uicc" (GBA_ U), or "3GPP-bootstrapping-digest" (GBA_Digest),
+     * and the latter part shall be the FQDN of the NAF (e.g.
+     * "3GPP-bootstrapping@naf1.operator.com" or "3GPP-bootstrapping-uicc@naf1.operator.com",
+     * or "3GPP-bootstrapping-digest@naf1.operator.com").
+     * @param securityProtocol Security protocol identifier between UE and NAF.  See
+     * 3GPP TS 33.220 Annex H. Application can use
+     * {@link UaSecurityProtocolIdentifier#createDefaultUaSpId},
+     * {@link UaSecurityProtocolIdentifier#create3GppUaSpId},
+     * to create the ua security protocol identifier as needed
+     * @param forceBootStrapping true=force bootstrapping, false=do not force
+     * bootstrapping. Bootstrapping shouldn't be forced unless the application sees
+     * authentication errors from the server.
+     * Response is returned via {@link TelephonyManager#BootstrapAuthenticationCallback}
+     * along with the token to identify the request.
+     *
+     * <p>Note that this is not called in the main thread.
+     */
+    public void onAuthenticationRequest(int subscriptionId, int token, @UiccAppTypeExt int appType,
+            @NonNull Uri nafUrl, @NonNull byte[] securityProtocol, boolean forceBootStrapping) {
+        //Default implementation should be overridden by vendor Gba Service. Vendor Gba Service
+        //should handle the gba bootstrap authentication request, and call reportKeysAvailable or
+        //reportAuthenticationFailure to notify the caller accordingly.
+        reportAuthenticationFailure(
+                token, TelephonyManager.GBA_FAILURE_REASON_FEATURE_NOT_SUPPORTED);
+    }
+
+    /**
+     * Called by {@link GbaService} when the previously requested GBA keys are available
+     * (@see onAuthenticationRequest())
+     *
+     * @param token unique identifier of the request.
+     * @param gbaKey KsNaf Response.
+     * @param transactionId Bootstrapping Transaction ID.
+     * @throws RuntimeException when there is remote failure of callback.
+     */
+    public final void reportKeysAvailable(int token, @NonNull byte[] gbaKey,
+            @NonNull String transactionId) throws RuntimeException {
+        IBootstrapAuthenticationCallback cb = null;
+        synchronized (mCallbacks) {
+            cb = mCallbacks.get(token);
+            mCallbacks.remove(token);
+        }
+        if (cb != null) {
+            try {
+                cb.onKeysAvailable(token, gbaKey, transactionId);
+            } catch (RemoteException exception) {
+                throw exception.rethrowAsRuntimeException();
+            }
+        }
+    }
+
+    /**
+     * Invoked when the previously requested GBA key authentication failed
+     * (@see onAuthenticationRequest())
+     *
+     * @param token unique identifier of the request.
+     * @param reason The reason for the authentication failure.
+     * @throws RuntimeException when there is remote failure of callback.
+     */
+    public final void reportAuthenticationFailure(int token,
+            @AuthenticationFailureReason int reason) throws RuntimeException {
+        IBootstrapAuthenticationCallback cb = null;
+        synchronized (mCallbacks) {
+            cb = mCallbacks.get(token);
+            mCallbacks.remove(token);
+        }
+        if (cb != null) {
+            try {
+                cb.onAuthenticationFailure(token, reason);
+            } catch (RemoteException exception) {
+                throw exception.rethrowAsRuntimeException();
+            }
+        }
+    }
+
+    /** @hide */
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
+            Log.d(TAG, "GbaService Bound.");
+            return mBinder;
+        }
+        return null;
+    }
+
+    /** @hide */
+    @Override
+    public void onDestroy() {
+        mHandlerThread.quit();
+        super.onDestroy();
+    }
+
+    private class IGbaServiceWrapper extends IGbaService.Stub {
+        @Override
+        public void authenticationRequest(GbaAuthRequest request) {
+            if (DBG) Log.d(TAG, "receive request: " + request);
+            mHandler.obtainMessage(EVENT_GBA_AUTH_REQUEST, request).sendToTarget();
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/gba/IGbaService.aidl b/telephony/java/android/telephony/gba/IGbaService.aidl
new file mode 100644
index 0000000..b7ba5a4
--- /dev/null
+++ b/telephony/java/android/telephony/gba/IGbaService.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 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.telephony.gba;
+
+import android.net.Uri;
+import android.telephony.gba.GbaAuthRequest;
+
+/**
+ * @hide
+ */
+interface IGbaService
+{
+    oneway void authenticationRequest(in GbaAuthRequest request);
+}
diff --git a/telephony/java/android/telephony/gba/TlsParams.java b/telephony/java/android/telephony/gba/TlsParams.java
new file mode 100644
index 0000000..922f4bb
--- /dev/null
+++ b/telephony/java/android/telephony/gba/TlsParams.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2020 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.telephony.gba;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+
+/**
+ * Defines the TLS parameters for GBA as per IANA and TS 33.210, which are used
+ * by some UA security protocol identifiers defined in 3GPP TS 33.220 Annex H,
+ * and 3GPP TS 33.222.
+ *
+ * @hide
+ */
+@SystemApi
+public class TlsParams {
+
+    private TlsParams() {}
+
+    /**
+     * TLS protocol version supported by GBA
+     */
+    public static final int PROTOCOL_VERSION_TLS_1_2 = 0x0303;
+    public static final int PROTOCOL_VERSION_TLS_1_3 = 0x0304;
+
+    /**
+     * TLS cipher suites are used to create {@link UaSecurityProtocolIdentifier}
+     * by {@link UaSecurityProtocolIdentifier#create3GppUaSpId}
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+        prefix = {"TLS_"},
+        value = {
+            TLS_NULL_WITH_NULL_NULL,
+            TLS_RSA_WITH_NULL_MD5,
+            TLS_RSA_WITH_NULL_SHA,
+            TLS_RSA_WITH_RC4_128_MD5,
+            TLS_RSA_WITH_RC4_128_SHA,
+            TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+            TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA,
+            TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA,
+            TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+            TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+            TLS_DH_ANON_WITH_RC4_128_MD5,
+            TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA,
+            TLS_RSA_WITH_AES_128_CBC_SHA,
+            TLS_DH_DSS_WITH_AES_128_CBC_SHA,
+            TLS_DH_RSA_WITH_AES_128_CBC_SHA,
+            TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+            TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+            TLS_DH_ANON_WITH_AES_128_CBC_SHA,
+            TLS_RSA_WITH_AES_256_CBC_SHA,
+            TLS_DH_DSS_WITH_AES_256_CBC_SHA,
+            TLS_DH_RSA_WITH_AES_256_CBC_SHA,
+            TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+            TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+            TLS_DH_ANON_WITH_AES_256_CBC_SHA,
+            TLS_RSA_WITH_NULL_SHA256,
+            TLS_RSA_WITH_AES_128_CBC_SHA256,
+            TLS_RSA_WITH_AES_256_CBC_SHA256,
+            TLS_DH_DSS_WITH_AES_128_CBC_SHA256,
+            TLS_DH_RSA_WITH_AES_128_CBC_SHA256,
+            TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
+            TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+            TLS_DH_DSS_WITH_AES_256_CBC_SHA256,
+            TLS_DH_RSA_WITH_AES_256_CBC_SHA256,
+            TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+            TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+            TLS_DH_ANON_WITH_AES_128_CBC_SHA256,
+            TLS_DH_ANON_WITH_AES_256_CBC_SHA256,
+            TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+            TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+            TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
+            TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
+            TLS_AES_128_GCM_SHA256,
+            TLS_AES_256_GCM_SHA384,
+            TLS_CHACHA20_POLY1305_SHA256,
+            TLS_AES_128_CCM_SHA256,
+            TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+            TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+            TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+            TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+            TLS_DHE_RSA_WITH_AES_128_CCM,
+            TLS_DHE_RSA_WITH_AES_256_CCM,
+            TLS_DHE_PSK_WITH_AES_128_CCM,
+            TLS_DHE_PSK_WITH_AES_256_CCM,
+            TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+            TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+            TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+            TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+            TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+            TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+            TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384,
+            TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256
+        })
+    public @interface TlsCipherSuite {}
+
+    // Cipher suites for TLS v1.2 per RFC5246
+    public static final int TLS_NULL_WITH_NULL_NULL = 0x0000;
+    public static final int TLS_RSA_WITH_NULL_MD5 = 0x0001;
+    public static final int TLS_RSA_WITH_NULL_SHA = 0x0002;
+    public static final int TLS_RSA_WITH_RC4_128_MD5 = 0x0004;
+    public static final int TLS_RSA_WITH_RC4_128_SHA = 0x0005;
+    public static final int TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A;
+    public static final int TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D;
+    public static final int TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010;
+    public static final int TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013;
+    public static final int TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016;
+    public static final int TLS_DH_ANON_WITH_RC4_128_MD5 = 0x0018;
+    public static final int TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA = 0x001B;
+    public static final int TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F;
+    public static final int TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x0030;
+    public static final int TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x0031;
+    public static final int TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032;
+    public static final int TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033;
+    public static final int TLS_DH_ANON_WITH_AES_128_CBC_SHA = 0x0034;
+    public static final int TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035;
+    public static final int TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x0036;
+    public static final int TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x0037;
+    public static final int TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038;
+    public static final int TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039;
+    public static final int TLS_DH_ANON_WITH_AES_256_CBC_SHA = 0x003A;
+    public static final int TLS_RSA_WITH_NULL_SHA256 = 0x003B;
+    public static final int TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C;
+    public static final int TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D;
+    public static final int TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x003E;
+    public static final int TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x003F;
+    public static final int TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040;
+    public static final int TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067;
+    public static final int TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x0068;
+    public static final int TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x0069;
+    public static final int TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A;
+    public static final int TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B;
+    public static final int TLS_DH_ANON_WITH_AES_128_CBC_SHA256 = 0x006C;
+    public static final int TLS_DH_ANON_WITH_AES_256_CBC_SHA256 = 0x006D;
+
+    // Cipher suites for TLS v1.3 per RFC8446 and recommended by IANA
+    public static final int TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E;
+    public static final int TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F;
+    public static final int TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = 0x00AA;
+    public static final int TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = 0x00AB;
+    public static final int TLS_AES_128_GCM_SHA256 = 0x1301;
+    public static final int TLS_AES_256_GCM_SHA384 = 0x1302;
+    public static final int TLS_CHACHA20_POLY1305_SHA256 = 0x1303;
+    public static final int TLS_AES_128_CCM_SHA256 = 0x1304;
+    public static final int TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B;
+    public static final int TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C;
+    public static final int TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F;
+    public static final int TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030;
+    public static final int TLS_DHE_RSA_WITH_AES_128_CCM = 0xC09E;
+    public static final int TLS_DHE_RSA_WITH_AES_256_CCM = 0xC09F;
+    public static final int TLS_DHE_PSK_WITH_AES_128_CCM = 0xC0A6;
+    public static final int TLS_DHE_PSK_WITH_AES_256_CCM = 0xC0A7;
+    public static final int TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8;
+    public static final int TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9;
+    public static final int TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAA;
+    public static final int TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAC;
+    public static final int TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAD;
+    public static final int TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 = 0xD001;
+    public static final int TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384 = 0xD002;
+    public static final int TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256 = 0xD005;
+
+    private static final int[] CS_EXPECTED = {
+        TLS_NULL_WITH_NULL_NULL,
+        TLS_RSA_WITH_NULL_MD5,
+        TLS_RSA_WITH_NULL_SHA,
+        TLS_RSA_WITH_RC4_128_MD5,
+        TLS_RSA_WITH_RC4_128_SHA,
+        TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+        TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA,
+        TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA,
+        TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+        TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
+        TLS_DH_ANON_WITH_RC4_128_MD5,
+        TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA,
+        TLS_RSA_WITH_AES_128_CBC_SHA,
+        TLS_DH_DSS_WITH_AES_128_CBC_SHA,
+        TLS_DH_RSA_WITH_AES_128_CBC_SHA,
+        TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+        TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+        TLS_DH_ANON_WITH_AES_128_CBC_SHA,
+        TLS_RSA_WITH_AES_256_CBC_SHA,
+        TLS_DH_DSS_WITH_AES_256_CBC_SHA,
+        TLS_DH_RSA_WITH_AES_256_CBC_SHA,
+        TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+        TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+        TLS_DH_ANON_WITH_AES_256_CBC_SHA,
+        TLS_RSA_WITH_NULL_SHA256,
+        TLS_RSA_WITH_AES_128_CBC_SHA256,
+        TLS_RSA_WITH_AES_256_CBC_SHA256,
+        TLS_DH_DSS_WITH_AES_128_CBC_SHA256,
+        TLS_DH_RSA_WITH_AES_128_CBC_SHA256,
+        TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
+        TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+        TLS_DH_DSS_WITH_AES_256_CBC_SHA256,
+        TLS_DH_RSA_WITH_AES_256_CBC_SHA256,
+        TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+        TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+        TLS_DH_ANON_WITH_AES_128_CBC_SHA256,
+        TLS_DH_ANON_WITH_AES_256_CBC_SHA256,
+        TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+        TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+        TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
+        TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
+        TLS_AES_128_GCM_SHA256,
+        TLS_AES_256_GCM_SHA384,
+        TLS_CHACHA20_POLY1305_SHA256,
+        TLS_AES_128_CCM_SHA256,
+        TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+        TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+        TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+        TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+        TLS_DHE_RSA_WITH_AES_128_CCM,
+        TLS_DHE_RSA_WITH_AES_256_CCM,
+        TLS_DHE_PSK_WITH_AES_128_CCM,
+        TLS_DHE_PSK_WITH_AES_256_CCM,
+        TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+        TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+        TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+        TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+        TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
+        TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+        TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384,
+        TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256
+    };
+
+    /**
+     * TLS supported groups required by TS 33.210
+     */
+    public static final int GROUP_SECP256R1 = 23;
+    public static final int GROUP_SECP384R1 = 24;
+    public static final int GROUP_X25519 = 29;
+    public static final int GROUP_X448 = 30;
+
+    /**
+     * Signature algorithms shall be supported as per TS 33.210
+     */
+    public static final int SIG_RSA_PKCS1_SHA1 = 0X0201;
+    public static final int SIG_ECDSA_SHA1 = 0X0203;
+    public static final int SIG_RSA_PKCS1_SHA256 = 0X0401;
+    public static final int SIG_ECDSA_SECP256R1_SHA256 = 0X0403;
+    public static final int SIG_RSA_PKCS1_SHA256_LEGACY = 0X0420;
+    public static final int SIG_RSA_PKCS1_SHA384 = 0X0501;
+    public static final int SIG_ECDSA_SECP384R1_SHA384 = 0X0503;
+    public static final int SIG_RSA_PKCS1_SHA384_LEGACY = 0X0520;
+    public static final int SIG_RSA_PKCS1_SHA512 = 0X0601;
+    public static final int SIG_ECDSA_SECP521R1_SHA512 = 0X0603;
+    public static final int SIG_RSA_PKCS1_SHA512_LEGACY = 0X0620;
+    public static final int SIG_RSA_PSS_RSAE_SHA256 = 0X0804;
+    public static final int SIG_RSA_PSS_RSAE_SHA384 = 0X0805;
+    public static final int SIG_RSA_PSS_RSAE_SHA512 = 0X0806;
+    public static final int SIG_ECDSA_BRAINPOOLP256R1TLS13_SHA256 = 0X081A;
+    public static final int SIG_ECDSA_BRAINPOOLP384R1TLS13_SHA384 = 0X081B;
+    public static final int SIG_ECDSA_BRAINPOOLP512R1TLS13_SHA512 = 0X081C;
+
+    /**
+     * Returns whether the TLS cipher suite id is supported
+     */
+    public static boolean isTlsCipherSuiteSupported(int csId) {
+        return Arrays.binarySearch(CS_EXPECTED, csId) >= 0;
+    }
+}
diff --git a/telephony/java/android/telephony/gba/UaSecurityProtocolIdentifier.aidl b/telephony/java/android/telephony/gba/UaSecurityProtocolIdentifier.aidl
new file mode 100644
index 0000000..a71e860
--- /dev/null
+++ b/telephony/java/android/telephony/gba/UaSecurityProtocolIdentifier.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2020 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.telephony.gba;
+
+parcelable UaSecurityProtocolIdentifier;
diff --git a/telephony/java/android/telephony/gba/UaSecurityProtocolIdentifier.java b/telephony/java/android/telephony/gba/UaSecurityProtocolIdentifier.java
new file mode 100644
index 0000000..c141875
--- /dev/null
+++ b/telephony/java/android/telephony/gba/UaSecurityProtocolIdentifier.java
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2020 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.telephony.gba;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.gba.TlsParams.TlsCipherSuite;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+/**
+ * Description of ua security protocol identifier defined in 3GPP TS 33.220 H.2
+ * @hide
+ */
+@SystemApi
+public final class UaSecurityProtocolIdentifier implements Parcelable {
+
+    /**
+     * Organization code defined in 3GPP TS 33.220 H.3
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"ORG_"}, value = {
+        ORG_NONE,
+        ORG_3GPP,
+        ORG_3GPP2,
+        ORG_OMA,
+        ORG_GSMA,
+        ORG_LOCAL})
+    public @interface OrganizationCode {}
+
+    /**
+     * Organization octet value for default ua security protocol
+     */
+    public static final int ORG_NONE  = 0;
+    /**
+     * Organization octet value for 3GPP ua security protocol
+     */
+    public static final int ORG_3GPP  = 0x01;
+    /**
+     * Organization octet value for 3GPP2 ua security protocol
+     */
+    public static final int ORG_3GPP2 = 0x02;
+    /**
+     * Organization octet value for OMA ua security protocol
+     */
+    public static final int ORG_OMA   = 0x03;
+    /**
+     * Organization octet value for GSMA ua security protocol
+     */
+    public static final int ORG_GSMA  = 0x04;
+    /**
+     * Internal organization octet value for local/experimental protocols
+     */
+    public static final int ORG_LOCAL = 0xFF;
+
+    /**
+     * 3GPP UA Security Protocol ID defined in 3GPP TS 33.220 H.3
+     *
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"UA_SECURITY_PROTOCOL_3GPP_"}, value = {
+        UA_SECURITY_PROTOCOL_3GPP_SUBSCRIBER_CERTIFICATE,
+        UA_SECURITY_PROTOCOL_3GPP_MBMS,
+        UA_SECURITY_PROTOCOL_3GPP_HTTP_DIGEST_AUTHENTICATION,
+        UA_SECURITY_PROTOCOL_3GPP_HTTP_BASED_MBMS,
+        UA_SECURITY_PROTOCOL_3GPP_SIP_BASED_MBMS,
+        UA_SECURITY_PROTOCOL_3GPP_GENERIC_PUSH_LAYER,
+        UA_SECURITY_PROTOCOL_3GPP_IMS_MEDIA_PLANE,
+        UA_SECURITY_PROTOCOL_3GPP_GENERATION_TMPI,
+        UA_SECURITY_PROTOCOL_3GPP_TLS_DEFAULT,
+        UA_SECURITY_PROTOCOL_3GPP_TLS_BROWSER})
+    public @interface UaSecurityProtocol3gpp {}
+
+    /**
+     * Security protocol param according to TS 33.221 as described in TS
+     * 33.220 Annex H. Mapped to byte stream "0x01,0x00,0x00,0x00,0x00".
+     */
+    public static final int UA_SECURITY_PROTOCOL_3GPP_SUBSCRIBER_CERTIFICATE = 0;
+
+    /**
+     * Security protocol param according to TS 33.246 for Multimedia
+     * broadcast/Multimedia services (MBMS) as described in TS
+     * 33.220 Annex H. Mapped to byte stream "0x01,0x00,0x00,0x00,0x01".
+     */
+    public static final int UA_SECURITY_PROTOCOL_3GPP_MBMS = 1;
+
+    /**
+     * Security protocol param based on HTTP digest authentication
+     * according to TS 24.109 as described in TS 33.220 Annex H. Mapped to
+     * byte stream "0x01,0x00,0x00,0x00,0x02".
+     */
+    public static final int UA_SECURITY_PROTOCOL_3GPP_HTTP_DIGEST_AUTHENTICATION = 2;
+
+    /**
+     * Security protocol param used with HTTP-based security procedures for
+     * Multimedia broadcast/Multimedia services (MBMS) user services
+     * according to TS 26.237 as described in TS 33.220 Annex H.
+     * Mapped to byte stream "0x01,0x00,0x00,0x00,0x03".
+     */
+    public static final int UA_SECURITY_PROTOCOL_3GPP_HTTP_BASED_MBMS = 3;
+
+    /**
+     * Security protocol param used with SIP-based security procedures for
+     * Multimedia broadcast/Multimedia services (MBMS) user services
+     * according to TS 26.237 as described in TS 33.220 Annex H.
+     * Mapped to byte stream "0x01,0x00,0x00,0x00,0x04".
+     */
+    public static final int UA_SECURITY_PROTOCOL_3GPP_SIP_BASED_MBMS = 4;
+
+    /**
+     * Security protocol param used with Generic Push Layer according to TS
+     * 33.224  as described in TS 33.220 Annex H. Mapped to byte stream
+     * "0x01,0x00,0x00,0x00,0x05".
+     */
+    public static final int UA_SECURITY_PROTOCOL_3GPP_GENERIC_PUSH_LAYER = 5;
+
+    /**
+     * Security protocol param used for IMS UE to KMS http based message
+     * exchanges according to "IMS media plane security", TS 33.328   as
+     * described in TS 33.220 Annex H. Mapped to byte stream
+     * "0x01,0x00,0x00,0x00,0x06".
+     */
+    public static final int UA_SECURITY_PROTOCOL_3GPP_IMS_MEDIA_PLANE = 6;
+
+    /**
+     * Security protocol param used for Generation of Temporary IP
+     * Multimedia Private Identity (TMPI) according to TS 33.220 Annex B.4
+     * Mapped to byte stream "0x01,0x00,0x00,0x01,0x00".
+     */
+    public static final int UA_SECURITY_PROTOCOL_3GPP_GENERATION_TMPI = 0x0100;
+
+    /**
+     * Security protocol param used for Shared key-based UE authentication with
+     * certificate-based NAF authentication, according to TS 33.222 section 5.3,
+     * or Shared key-based mutual authentication between UE and NAF, according to
+     * TS 33.222 section 5.4. Mapped to byte stream "0x01,0x00,0x01,yy,zz".
+     * "yy, zz" is the TLS CipherSuite code.
+     */
+    public static final int UA_SECURITY_PROTOCOL_3GPP_TLS_DEFAULT = 0x010000;
+
+    /**
+     * Security protocol param used for Shared key-based UE authentication with
+     * certificate-based NAF authentication, according to TS 33.222 Annex D.
+     * Mapped to byte stream "0x01,0x00,0x02,yy,zz".
+     * "yy, zz" is the TLS CipherSuite code.
+     */
+    public static final int UA_SECURITY_PROTOCOL_3GPP_TLS_BROWSER = 0x020000;
+
+    private static final int PROTOCOL_SIZE = 5;
+    private static final int[] sUaSp3gppIds = new int[] {
+            UA_SECURITY_PROTOCOL_3GPP_SUBSCRIBER_CERTIFICATE,
+            UA_SECURITY_PROTOCOL_3GPP_MBMS,
+            UA_SECURITY_PROTOCOL_3GPP_HTTP_DIGEST_AUTHENTICATION,
+            UA_SECURITY_PROTOCOL_3GPP_HTTP_BASED_MBMS,
+            UA_SECURITY_PROTOCOL_3GPP_SIP_BASED_MBMS,
+            UA_SECURITY_PROTOCOL_3GPP_GENERIC_PUSH_LAYER,
+            UA_SECURITY_PROTOCOL_3GPP_IMS_MEDIA_PLANE,
+            UA_SECURITY_PROTOCOL_3GPP_GENERATION_TMPI,
+            UA_SECURITY_PROTOCOL_3GPP_TLS_DEFAULT,
+            UA_SECURITY_PROTOCOL_3GPP_TLS_BROWSER};
+
+    private int mOrg;
+    private int mProtocol;
+    private int mTlsCipherSuite;
+
+    private UaSecurityProtocolIdentifier() {}
+
+    private UaSecurityProtocolIdentifier(UaSecurityProtocolIdentifier sp) {
+        mOrg = sp.mOrg;
+        mProtocol = sp.mProtocol;
+        mTlsCipherSuite = sp.mTlsCipherSuite;
+    }
+
+    /**
+     * Returns the byte array representing the ua security protocol
+     */
+    @NonNull
+    public byte[] toByteArray() {
+        byte[] data = new byte[PROTOCOL_SIZE];
+        ByteBuffer buf = ByteBuffer.wrap(data);
+        buf.put((byte) mOrg);
+        buf.putInt(mProtocol | mTlsCipherSuite);
+        return data;
+    }
+
+    /**
+     * Returns the organization code
+     */
+    public @OrganizationCode int getOrg() {
+        return mOrg;
+    }
+
+    /**
+     * Returns the security procotol id
+     *
+     * <p>Note that only 3GPP UA Security Protocols are supported for now
+     */
+    public @UaSecurityProtocol3gpp int getProtocol() {
+        return mProtocol;
+    }
+
+    /**
+     * Returns the TLS cipher suite
+     */
+    public @TlsCipherSuite int getTlsCipherSuite() {
+        return mTlsCipherSuite;
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        out.writeInt(mOrg);
+        out.writeInt(mProtocol);
+        out.writeInt(mTlsCipherSuite);
+    }
+
+    /**
+     * {@link Parcelable.Creator}
+     *
+     */
+    public static final @NonNull Parcelable.Creator<
+            UaSecurityProtocolIdentifier> CREATOR = new Creator<UaSecurityProtocolIdentifier>() {
+                @Nullable
+                @Override
+                public UaSecurityProtocolIdentifier createFromParcel(Parcel in) {
+                    int org = in.readInt();
+                    int protocol = in.readInt();
+                    int cs = in.readInt();
+                    if (org < 0 || protocol < 0 || cs < 0) {
+                        return null;
+                    }
+                    Builder builder = new Builder();
+                    try {
+                        if (org > 0) {
+                            builder.setOrg(org);
+                        }
+                        if (protocol > 0) {
+                            builder.setProtocol(protocol);
+                        }
+                        if (cs > 0) {
+                            builder.setTlsCipherSuite(cs);
+                        }
+                    } catch (IllegalArgumentException e) {
+                        return null;
+                    }
+                    return builder.build();
+                }
+
+                @NonNull
+                @Override
+                public UaSecurityProtocolIdentifier[] newArray(int size) {
+                    return new UaSecurityProtocolIdentifier[size];
+                }
+            };
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return "UaSecurityProtocolIdentifier[" + mOrg + " , " + (mProtocol | mTlsCipherSuite) + "]";
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof UaSecurityProtocolIdentifier)) {
+            return false;
+        }
+
+        UaSecurityProtocolIdentifier other = (UaSecurityProtocolIdentifier) obj;
+
+        return mOrg == other.mOrg && mProtocol == other.mProtocol
+                && mTlsCipherSuite == other.mTlsCipherSuite;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mOrg, mProtocol, mTlsCipherSuite);
+    }
+
+    private boolean isTlsSupported() {
+        //TODO May update to support non 3gpp protocol in the future
+        if (mOrg == ORG_3GPP && (mProtocol == UA_SECURITY_PROTOCOL_3GPP_TLS_DEFAULT
+                    || mProtocol == UA_SECURITY_PROTOCOL_3GPP_TLS_BROWSER)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Builder class for UaSecurityProtocolIdentifier
+     */
+    public static final class Builder {
+        private final UaSecurityProtocolIdentifier mSp;
+
+        /**
+         * Creates a Builder with default UaSecurityProtocolIdentifier, a.k.a 0x00 00 00 00 00
+         */
+        public Builder() {
+            mSp = new UaSecurityProtocolIdentifier();
+        }
+
+        /**
+         * Creates a Builder from a UaSecurityProtocolIdentifier
+         */
+        public Builder(@NonNull final UaSecurityProtocolIdentifier sp) {
+            Objects.requireNonNull(sp);
+            mSp = new UaSecurityProtocolIdentifier(sp);
+        }
+
+        /**
+         * Sets the organization code
+         *
+         * @param orgCode the organization code with the following value
+         * <ol>
+         * <li>{@link #ORG_NONE} </li>
+         * <li>{@link #ORG_3GPP} </li>
+         * <li>{@link #ORG_3GPP2} </li>
+         * <li>{@link #ORG_OMA} </li>
+         * <li>{@link #ORG_GSMA} </li>
+         * <li>{@link #ORG_LOCAL} </li>
+         * </ol>
+         * @throws IllegalArgumentException if it is not one of the value above.
+         *
+         * <p>Note that this method will reset the security protocol and TLS cipher suite
+         * if they have been set.
+         */
+        @NonNull
+        public Builder setOrg(@OrganizationCode int orgCode) {
+            if (orgCode < ORG_NONE || orgCode > ORG_LOCAL) {
+                throw new IllegalArgumentException("illegal organization code");
+            }
+            mSp.mOrg = orgCode;
+            mSp.mProtocol = 0;
+            mSp.mTlsCipherSuite = 0;
+            return this;
+        }
+
+        /**
+         * Sets the UA security protocol for 3GPP
+         *
+         * @param protocol only 3GPP ua security protocol ID is supported for now, which
+         * is one of the following value
+         * <ol>
+         * <li>{@link #UA_SECURITY_PROTOCOL_3GPP_SUBSCRIBER_CERTIFICATE} </li>
+         * <li>{@link #UA_SECURITY_PROTOCOL_3GPP_MBMS} </li>
+         * <li>{@link #UA_SECURITY_PROTOCOL_3GPP_HTTP_DIGEST_AUTHENTICATION} </li>
+         * <li>{@link #UA_SECURITY_PROTOCOL_3GPP_HTTP_BASED_MBMS} </li>
+         * <li>{@link #UA_SECURITY_PROTOCOL_3GPP_SIP_BASED_MBMS} </li>
+         * <li>{@link #UA_SECURITY_PROTOCOL_3GPP_GENERIC_PUSH_LAYER} </li>
+         * <li>{@link #UA_SECURITY_PROTOCOL_3GPP_IMS_MEDIA_PLANE} </li>
+         * <li>{@link #UA_SECURITY_PROTOCOL_3GPP_GENERATION_TMPI} </li>
+         * <li>{@link #UA_SECURITY_PROTOCOL_3GPP_TLS_DEFAULT} </li>
+         * <li>{@link #UA_SECURITY_PROTOCOL_3GPP_TLS_BROWSER} </li>
+         * </ol>
+         * @throws IllegalArgumentException if the protocol is not one of the value above.
+         *
+         * <p>Note that this method will reset TLS cipher suite if it has been set.
+         */
+        @NonNull
+        public Builder setProtocol(@UaSecurityProtocol3gpp int protocol) {
+            //TODO May update to support non 3gpp protocol in the future
+            if (protocol < UA_SECURITY_PROTOCOL_3GPP_SUBSCRIBER_CERTIFICATE
+                    || (protocol > UA_SECURITY_PROTOCOL_3GPP_IMS_MEDIA_PLANE
+                    && protocol != UA_SECURITY_PROTOCOL_3GPP_GENERATION_TMPI
+                    && protocol != UA_SECURITY_PROTOCOL_3GPP_TLS_DEFAULT
+                    && protocol != UA_SECURITY_PROTOCOL_3GPP_TLS_BROWSER)
+                    || mSp.mOrg != ORG_3GPP) {
+                throw new IllegalArgumentException("illegal protocol code");
+            }
+            mSp.mProtocol = protocol;
+            mSp.mTlsCipherSuite = 0;
+            return this;
+        }
+
+        /**
+         * Sets the UA security protocol for 3GPP
+         *
+         * @param cs TLS cipher suite value defined by {@link TlsParams#TlsCipherSuite}
+         * @throws IllegalArgumentException if it is not a 3GPP ua security protocol,
+         * the protocol does not support TLS, or does not support the cipher suite.
+         */
+        @NonNull
+        public Builder setTlsCipherSuite(@TlsCipherSuite int cs) {
+            if (!mSp.isTlsSupported()) {
+                throw new IllegalArgumentException("The protocol does not support TLS");
+            }
+            if (!TlsParams.isTlsCipherSuiteSupported(cs)) {
+                throw new IllegalArgumentException("TLS cipher suite is not supported");
+            }
+            mSp.mTlsCipherSuite = cs;
+            return this;
+        }
+
+        /**
+         * Builds the instance of UaSecurityProtocolIdentifier
+         *
+         * @return the built instance of UaSecurityProtocolIdentifier
+         */
+        @NonNull
+        public UaSecurityProtocolIdentifier build() {
+            return new UaSecurityProtocolIdentifier(mSp);
+        }
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index 09f9b42..ce2017b 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -216,5 +216,6 @@
      * @param data authentication challenge data
      * @return challenge response
      */
-    String getIccSimChallengeResponse(int subId, int appType, int authType, String data);
+    String getIccSimChallengeResponse(int subId, int appType, int authType, String data,
+            String callingPackage, String callingFeatureId);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 1af3ea1..2da45ca 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -37,6 +37,8 @@
 import android.telephony.CellInfo;
 import android.telephony.ClientRequestStats;
 import android.telephony.ThermalMitigationRequest;
+import android.telephony.gba.UaSecurityProtocolIdentifier;
+import android.telephony.IBootstrapAuthenticationCallback;
 import android.telephony.IccOpenLogicalChannelResponse;
 import android.telephony.ICellInfoCallback;
 import android.telephony.ModemActivityInfo;
@@ -2282,4 +2284,31 @@
      */
     int sendThermalMitigationRequest(int subId,
             in ThermalMitigationRequest thermalMitigationRequest);
+
+    /**
+     * get the Generic Bootstrapping Architecture authentication keys
+     */
+    void bootstrapAuthenticationRequest(int subId, int appType, in Uri nafUrl,
+            in UaSecurityProtocolIdentifier securityProtocol,
+            boolean forceBootStrapping, IBootstrapAuthenticationCallback callback);
+
+    /**
+     * Set the GbaService Package Name that Telephony will bind to.
+     */
+    boolean setBoundGbaServiceOverride(int subId, String packageName);
+
+    /**
+     * Return the package name of the currently bound GbaService.
+     */
+    String getBoundGbaService(int subId);
+
+    /**
+     * Set the release time for telephony to unbind GbaService.
+     */
+    boolean setGbaReleaseTimeOverride(int subId, int interval);
+
+    /**
+     * Return the release time for telephony to unbind GbaService.
+     */
+    int getGbaReleaseTime(int subId);
 }
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
index 60308e3..1eaf30c 100644
--- a/tests/net/common/java/android/net/LinkAddressTest.java
+++ b/tests/net/common/java/android/net/LinkAddressTest.java
@@ -68,8 +68,8 @@
 
     private static final String V4 = "192.0.2.1";
     private static final String V6 = "2001:db8::1";
-    private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4);
-    private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6);
+    private static final InetAddress V4_ADDRESS = InetAddresses.parseNumericAddress(V4);
+    private static final InetAddress V6_ADDRESS = InetAddresses.parseNumericAddress(V6);
 
     @Test
     public void testConstants() {
@@ -131,10 +131,10 @@
             ipv6Loopback = new LinkAddress(addrs.get(0));
         }
 
-        assertEquals(NetworkUtils.numericToInetAddress("127.0.0.1"), ipv4Loopback.getAddress());
+        assertEquals(InetAddresses.parseNumericAddress("127.0.0.1"), ipv4Loopback.getAddress());
         assertEquals(8, ipv4Loopback.getPrefixLength());
 
-        assertEquals(NetworkUtils.numericToInetAddress("::1"), ipv6Loopback.getAddress());
+        assertEquals(InetAddresses.parseNumericAddress("::1"), ipv6Loopback.getAddress());
         assertEquals(128, ipv6Loopback.getPrefixLength());
 
         // Null addresses are rejected.
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 059e054..b6f91c4 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -181,7 +181,6 @@
 import android.net.NetworkStackClient;
 import android.net.NetworkState;
 import android.net.NetworkTestResultParcelable;
-import android.net.NetworkUtils;
 import android.net.ProxyInfo;
 import android.net.ResolverParamsParcel;
 import android.net.RouteInfo;
@@ -4860,7 +4859,7 @@
         lp.setInterfaceName(WIFI_IFNAME);
         LinkAddress myIpv4Address = new LinkAddress("192.168.12.3/24");
         RouteInfo myIpv4DefaultRoute = new RouteInfo((IpPrefix) null,
-                NetworkUtils.numericToInetAddress("192.168.12.1"), lp.getInterfaceName());
+                InetAddresses.parseNumericAddress("192.168.12.1"), lp.getInterfaceName());
         lp.addLinkAddress(myIpv4Address);
         lp.addRoute(myIpv4DefaultRoute);
 
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 529d03c..799bcc8 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -34,6 +34,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.net.INetd;
+import android.net.InetAddresses;
 import android.net.IpSecAlgorithm;
 import android.net.IpSecConfig;
 import android.net.IpSecManager;
@@ -44,7 +45,6 @@
 import android.net.IpSecUdpEncapResponse;
 import android.net.LinkAddress;
 import android.net.Network;
-import android.net.NetworkUtils;
 import android.os.Binder;
 import android.os.INetworkManagementService;
 import android.os.ParcelFileDescriptor;
@@ -272,7 +272,7 @@
 
         IpSecSpiResponse spi =
                 mIpSecService.allocateSecurityParameterIndex(
-                        NetworkUtils.numericToInetAddress(remoteAddress).getHostAddress(),
+                        InetAddresses.parseNumericAddress(remoteAddress).getHostAddress(),
                         IpSecManager.INVALID_SECURITY_PARAMETER_INDEX,
                         new Binder());
         return spi.resourceId;
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index 226d1a3..1bb9ebc 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -538,15 +538,6 @@
         if (!SdkLevel.isAtLeastS()) {
             throw new UnsupportedOperationException();
         }
-        return getChannelsInternal();
-    }
-
-    /**
-     * Internal version bypassing SdkLevel checks
-     * TODO(b/173791707): find a better way to allow Wifi to call its own new S APIs.
-     * @hide
-     */
-    public @NonNull SparseIntArray getChannelsInternal() {
         return mChannels.clone();
     }
 
@@ -945,6 +936,9 @@
          */
         @NonNull
         public Builder setBands(@NonNull int[] bands) {
+            if (!SdkLevel.isAtLeastS()) {
+                throw new UnsupportedOperationException();
+            }
             if (bands.length == 0 || bands.length > 2) {
                 throw new IllegalArgumentException("Unsupported number of bands("
                         + bands.length + ") configured");
@@ -1036,6 +1030,9 @@
          */
         @NonNull
         public Builder setChannels(@NonNull SparseIntArray channels) {
+            if (!SdkLevel.isAtLeastS()) {
+                throw new UnsupportedOperationException();
+            }
             if (channels.size() == 0 || channels.size() > 2) {
                 throw new IllegalArgumentException("Unsupported number of channels("
                         + channels.size() + ") configured");
diff --git a/wifi/java/android/net/wifi/SoftApInfo.java b/wifi/java/android/net/wifi/SoftApInfo.java
index 55c2f17..9a16fac 100644
--- a/wifi/java/android/net/wifi/SoftApInfo.java
+++ b/wifi/java/android/net/wifi/SoftApInfo.java
@@ -183,15 +183,6 @@
         if (!SdkLevel.isAtLeastS()) {
             throw new UnsupportedOperationException();
         }
-        return getWifiStandardInternal();
-    }
-
-    /**
-     * Internal version bypassing SdkLevel checks
-     * TODO(b/173791707): find a better way to allow Wifi to call its own new S APIs.
-     * @hide
-     */
-    public @WifiAnnotations.WifiStandard int getWifiStandardInternal() {
         return mWifiStandard;
     }
 
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index ad0fdd3..bcfdf7d 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -20,6 +20,7 @@
 
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import android.net.MacAddress;
 import android.os.Parcel;
@@ -371,6 +372,7 @@
 
     @Test
     public void testDualBands() {
+        assumeTrue(SdkLevel.isAtLeastS());
         int[] dual_bands = new int[2];
         dual_bands[0] = SoftApConfiguration.BAND_2GHZ;
         dual_bands[1] = SoftApConfiguration.BAND_5GHZ;
@@ -384,6 +386,7 @@
 
     @Test
     public void testDualChannels() {
+        assumeTrue(SdkLevel.isAtLeastS());
         int[] expected_dual_bands = new int[2];
         expected_dual_bands[0] = SoftApConfiguration.BAND_2GHZ;
         expected_dual_bands[1] = SoftApConfiguration.BAND_5GHZ;
@@ -417,6 +420,7 @@
 
     @Test
     public void testInvalidBandWhenSetBands() {
+        assumeTrue(SdkLevel.isAtLeastS());
         boolean isIllegalArgumentExceptionHappened = false;
         int[] dual_bands = new int[2];
         dual_bands[0] = SoftApConfiguration.BAND_2GHZ;
@@ -457,6 +461,7 @@
 
     @Test
     public void testInvalidConfigWhenSetChannels() {
+        assumeTrue(SdkLevel.isAtLeastS());
         boolean isIllegalArgumentExceptionHappened = false;
         SparseIntArray invalid_channels = new SparseIntArray();
         try {