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 {