summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp12
-rw-r--r--api/current.txt326
-rw-r--r--api/lint-baseline.txt8
-rw-r--r--api/module-lib-current.txt22
-rwxr-xr-xapi/system-current.txt210
-rw-r--r--api/system-removed.txt12
-rw-r--r--api/test-current.txt281
-rw-r--r--core/java/android/app/AppOpsManager.java36
-rw-r--r--core/java/android/app/SystemServiceRegistry.java13
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java3
-rw-r--r--core/java/android/bluetooth/BluetoothPan.java22
-rw-r--r--core/java/android/bluetooth/BluetoothProfile.java6
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/content/Intent.java13
-rw-r--r--core/java/android/debug/AdbManager.java37
-rw-r--r--core/java/android/debug/IAdbManager.aidl11
-rw-r--r--core/java/android/hardware/biometrics/BiometricPrompt.java13
-rw-r--r--core/java/android/hardware/biometrics/CryptoObject.java24
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java13
-rw-r--r--core/java/android/net/CaptivePortalData.aidl19
-rw-r--r--core/java/android/net/CaptivePortalData.java281
-rw-r--r--core/java/android/net/ConnectivityDiagnosticsManager.aidl21
-rw-r--r--core/java/android/net/ConnectivityDiagnosticsManager.java281
-rw-r--r--core/java/android/net/ConnectivityManager.java17
-rw-r--r--core/java/android/net/IConnectivityManager.aidl7
-rw-r--r--core/java/android/net/LinkProperties.java169
-rw-r--r--core/java/android/net/NetworkAgent.java217
-rw-r--r--core/java/android/net/NetworkAgentConfig.aidl (renamed from core/java/android/net/NetworkMisc.aidl)2
-rw-r--r--core/java/android/net/NetworkAgentConfig.java230
-rw-r--r--core/java/android/net/NetworkCapabilities.java1
-rw-r--r--core/java/android/net/NetworkFactory.java7
-rw-r--r--core/java/android/net/NetworkMisc.java133
-rw-r--r--core/java/android/net/NetworkRequest.java13
-rw-r--r--core/java/android/net/StringNetworkSpecifier.java13
-rw-r--r--core/java/android/net/Uri.aidl2
-rw-r--r--core/java/android/nfc/Tag.java10
-rw-r--r--core/java/android/nfc/tech/BasicTagTechnology.java5
-rw-r--r--core/java/android/os/AppZygote.java4
-rw-r--r--core/java/android/se/omapi/ISecureElementReader.aidl6
-rw-r--r--core/java/android/se/omapi/Reader.java23
-rw-r--r--core/java/android/se/omapi/SEService.java79
-rw-r--r--core/java/android/telephony/PhoneStateListener.java24
-rw-r--r--core/java/android/timezone/CountryTimeZones.java1
-rw-r--r--core/java/android/timezone/TelephonyLookup.java9
-rw-r--r--core/java/android/timezone/TelephonyNetworkFinder.java2
-rw-r--r--core/java/android/timezone/TimeZoneFinder.java29
-rw-r--r--core/java/android/timezone/TzDataSetVersion.java154
-rw-r--r--core/java/android/timezone/ZoneInfoDb.java66
-rw-r--r--core/java/android/util/TimeUtils.java2
-rw-r--r--core/java/android/util/proto/ProtoOutputStream.java316
-rw-r--r--core/java/android/util/proto/ProtoStream.java322
-rw-r--r--core/java/android/util/proto/ProtoUtils.java4
-rw-r--r--core/java/android/util/proto/package.html4
-rw-r--r--core/jni/android_os_Debug.cpp3
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp35
-rw-r--r--core/res/res/values/strings.xml4
-rw-r--r--core/res/res/values/symbols.xml3
-rw-r--r--core/tests/overlaytests/host/Android.bp30
-rw-r--r--core/tests/overlaytests/host/Android.mk17
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--identity/MODULE_LICENSE_APACHE20
-rw-r--r--identity/NOTICE190
-rw-r--r--identity/OWNERS3
-rw-r--r--identity/java/android/security/identity/AccessControlProfile.java131
-rw-r--r--identity/java/android/security/identity/AccessControlProfileId.java42
-rw-r--r--identity/java/android/security/identity/AlreadyPersonalizedException.java43
-rw-r--r--identity/java/android/security/identity/CipherSuiteNotSupportedException.java43
-rw-r--r--identity/java/android/security/identity/CredstoreIdentityCredential.java424
-rw-r--r--identity/java/android/security/identity/CredstoreIdentityCredentialStore.java162
-rw-r--r--identity/java/android/security/identity/CredstoreResultData.java162
-rw-r--r--identity/java/android/security/identity/CredstoreWritableIdentityCredential.java168
-rw-r--r--identity/java/android/security/identity/DocTypeNotSupportedException.java43
-rw-r--r--identity/java/android/security/identity/EphemeralPublicKeyNotFoundException.java44
-rw-r--r--identity/java/android/security/identity/IdentityCredential.java309
-rw-r--r--identity/java/android/security/identity/IdentityCredentialException.java44
-rw-r--r--identity/java/android/security/identity/IdentityCredentialStore.java186
-rw-r--r--identity/java/android/security/identity/InvalidReaderSignatureException.java46
-rw-r--r--identity/java/android/security/identity/InvalidRequestMessageException.java46
-rw-r--r--identity/java/android/security/identity/MessageDecryptionException.java44
-rw-r--r--identity/java/android/security/identity/NoAuthenticationKeyAvailableException.java46
-rw-r--r--identity/java/android/security/identity/PersonalizationData.java157
-rw-r--r--identity/java/android/security/identity/ResultData.java224
-rw-r--r--identity/java/android/security/identity/SessionTranscriptMismatchException.java44
-rw-r--r--identity/java/android/security/identity/UnknownAuthenticationKeyException.java43
-rw-r--r--identity/java/android/security/identity/Util.java140
-rw-r--r--identity/java/android/security/identity/WritableIdentityCredential.java116
-rw-r--r--media/java/android/media/tv/TvTrackInfo.java14
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java56
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java2
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java2
-rw-r--r--services/core/java/com/android/server/BluetoothAirplaneModeListener.java258
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java131
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java349
-rw-r--r--services/core/java/com/android/server/NetworkTimeUpdateService.java270
-rw-r--r--services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java288
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java30
-rw-r--r--services/core/java/com/android/server/TestNetworkService.java4
-rw-r--r--services/core/java/com/android/server/adb/AdbService.java25
-rw-r--r--services/core/java/com/android/server/connectivity/Nat464Xlat.java3
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java33
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java12
-rw-r--r--services/core/java/com/android/server/lights/OWNERS3
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java11
-rw-r--r--services/core/java/com/android/server/policy/GlobalKeyManager.java2
-rw-r--r--services/java/com/android/server/SystemServer.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java125
-rw-r--r--telecomm/java/android/telecom/Call.java11
-rw-r--r--telecomm/java/android/telecom/Conference.java105
-rw-r--r--telecomm/java/android/telecom/Connection.java15
-rw-r--r--telecomm/java/android/telecom/ConnectionRequest.java71
-rw-r--r--telecomm/java/android/telecom/ConnectionService.java387
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapter.java13
-rw-r--r--telecomm/java/android/telecom/ConnectionServiceAdapterServant.java28
-rw-r--r--telecomm/java/android/telecom/ParcelableConference.java48
-rw-r--r--telecomm/java/android/telecom/PhoneAccount.java15
-rw-r--r--telecomm/java/android/telecom/RemoteConnectionService.java8
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java75
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionService.aidl14
-rw-r--r--telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl6
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl11
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java10
-rw-r--r--telephony/java/android/telephony/ImsManager.java37
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java15
-rw-r--r--telephony/java/android/telephony/SmsManager.java52
-rw-r--r--telephony/java/android/telephony/SmsMessage.java122
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java21
-rw-r--r--telephony/java/android/telephony/ims/ImsCallProfile.java15
-rw-r--r--telephony/java/android/telephony/ims/ImsCallSession.java59
-rw-r--r--telephony/java/android/telephony/ims/ImsCallSessionListener.java64
-rw-r--r--telephony/java/android/telephony/ims/ImsException.java12
-rw-r--r--telephony/java/android/telephony/ims/ImsMmTelManager.java264
-rw-r--r--telephony/java/android/telephony/ims/ProvisioningManager.java507
-rw-r--r--telephony/java/android/telephony/ims/RegistrationManager.java20
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl6
-rw-r--r--telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java13
-rw-r--r--telephony/java/android/telephony/ims/feature/ImsFeature.java24
-rw-r--r--telephony/java/android/telephony/ims/feature/MmTelFeature.java108
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsUtImplBase.java17
-rw-r--r--telephony/java/com/android/ims/ImsConfig.java336
-rw-r--r--telephony/java/com/android/ims/ImsUtInterface.java6
-rw-r--r--telephony/java/com/android/ims/internal/IImsUt.aidl6
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyIntents.java2
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/SmsMessage.java165
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java38
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsMessage.java274
-rw-r--r--tests/net/common/java/android/net/LinkPropertiesTest.java41
-rw-r--r--tests/net/integration/util/com/android/server/NetworkAgentWrapper.java14
-rw-r--r--tests/net/java/android/net/CaptivePortalDataTest.kt72
-rw-r--r--tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java196
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java111
-rw-r--r--tests/net/java/com/android/server/connectivity/LingerMonitorTest.java4
-rw-r--r--tests/net/java/com/android/server/connectivity/Nat464XlatTest.java14
157 files changed, 9810 insertions, 1814 deletions
diff --git a/Android.bp b/Android.bp
index f57acfa4ab60..3046b20c7096 100644
--- a/Android.bp
+++ b/Android.bp
@@ -53,6 +53,7 @@ filegroup {
"core/java/android/view/DisplayAdjustments.java",
],
path: "core/java",
+ visibility: ["//frameworks/base/test-mock"],
}
filegroup {
@@ -73,6 +74,14 @@ filegroup {
}
filegroup {
+ name: "framework-identity-sources",
+ srcs: [
+ "identity/java/**/*.java",
+ ],
+ path: "identity/java",
+}
+
+filegroup {
name: "framework-keystore-sources",
srcs: [
"keystore/java/**/*.java",
@@ -216,6 +225,7 @@ filegroup {
":framework-drm-sources",
":framework-graphics-sources",
":framework-keystore-sources",
+ ":framework-identity-sources",
":framework-location-sources",
":framework-lowpan-sources",
":framework-media-sources",
@@ -238,6 +248,7 @@ filegroup {
":platform-compat-native-aidl",
// AIDL sources from external directories
+ ":credstore_aidl",
":dumpstate_aidl",
":framework_native_aidl",
":gatekeeper_aidl",
@@ -289,6 +300,7 @@ java_defaults {
"core/java",
"drm/java",
"graphics/java",
+ "identity/java",
"keystore/java",
"location/java",
"lowpan/java",
diff --git a/api/current.txt b/api/current.txt
index 02ef7c164f93..7ebca90212d9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9824,6 +9824,7 @@ package android.content {
field public static final String CARRIER_CONFIG_SERVICE = "carrier_config";
field public static final String CLIPBOARD_SERVICE = "clipboard";
field public static final String COMPANION_DEVICE_SERVICE = "companiondevice";
+ field public static final String CONNECTIVITY_DIAGNOSTICS_SERVICE = "connectivity_diagnostics";
field public static final String CONNECTIVITY_SERVICE = "connectivity";
field public static final String CONSUMER_IR_SERVICE = "consumer_ir";
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
@@ -16637,7 +16638,9 @@ package android.hardware.biometrics {
ctor public BiometricPrompt.CryptoObject(@NonNull java.security.Signature);
ctor public BiometricPrompt.CryptoObject(@NonNull javax.crypto.Cipher);
ctor public BiometricPrompt.CryptoObject(@NonNull javax.crypto.Mac);
+ ctor public BiometricPrompt.CryptoObject(@NonNull android.security.identity.IdentityCredential);
method public javax.crypto.Cipher getCipher();
+ method @Nullable public android.security.identity.IdentityCredential getIdentityCredential();
method public javax.crypto.Mac getMac();
method public java.security.Signature getSignature();
}
@@ -17575,7 +17578,9 @@ package android.hardware.fingerprint {
ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull java.security.Signature);
ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher);
ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac);
+ ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull android.security.identity.IdentityCredential);
method @Deprecated public javax.crypto.Cipher getCipher();
+ method @Deprecated @Nullable public android.security.identity.IdentityCredential getIdentityCredential();
method @Deprecated public javax.crypto.Mac getMac();
method @Deprecated public java.security.Signature getSignature();
}
@@ -18287,6 +18292,7 @@ package android.icu.lang {
field public static final int CHEROKEE_SUPPLEMENT_ID = 255; // 0xff
field public static final android.icu.lang.UCharacter.UnicodeBlock CHESS_SYMBOLS;
field public static final int CHESS_SYMBOLS_ID = 281; // 0x119
+ field public static final android.icu.lang.UCharacter.UnicodeBlock CHORASMIAN;
field public static final int CHORASMIAN_ID = 301; // 0x12d
field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_COMPATIBILITY;
field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_COMPATIBILITY_FORMS;
@@ -18315,6 +18321,7 @@ package android.icu.lang {
field public static final int CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E_ID = 256; // 0x100
field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F;
field public static final int CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F_ID = 274; // 0x112
+ field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G;
field public static final int CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G_ID = 302; // 0x12e
field public static final int CJK_UNIFIED_IDEOGRAPHS_ID = 71; // 0x47
field public static final android.icu.lang.UCharacter.UnicodeBlock COMBINING_DIACRITICAL_MARKS;
@@ -18365,6 +18372,7 @@ package android.icu.lang {
field public static final int DEVANAGARI_ID = 15; // 0xf
field public static final android.icu.lang.UCharacter.UnicodeBlock DINGBATS;
field public static final int DINGBATS_ID = 56; // 0x38
+ field public static final android.icu.lang.UCharacter.UnicodeBlock DIVES_AKURU;
field public static final int DIVES_AKURU_ID = 303; // 0x12f
field public static final android.icu.lang.UCharacter.UnicodeBlock DOGRA;
field public static final int DOGRA_ID = 282; // 0x11a
@@ -22537,6 +22545,7 @@ package android.icu.util {
field public static final android.icu.util.VersionInfo UNICODE_11_0;
field public static final android.icu.util.VersionInfo UNICODE_12_0;
field public static final android.icu.util.VersionInfo UNICODE_12_1;
+ field public static final android.icu.util.VersionInfo UNICODE_13_0;
field public static final android.icu.util.VersionInfo UNICODE_1_0;
field public static final android.icu.util.VersionInfo UNICODE_1_0_1;
field public static final android.icu.util.VersionInfo UNICODE_1_1_0;
@@ -28683,8 +28692,6 @@ package android.net {
public class ConnectivityDiagnosticsManager {
method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
- field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
- field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
}
public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
@@ -28694,21 +28701,29 @@ package android.net {
method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean);
}
- public static class ConnectivityDiagnosticsManager.ConnectivityReport {
+ public static final class ConnectivityDiagnosticsManager.ConnectivityReport implements android.os.Parcelable {
ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
- field @NonNull public final android.os.PersistableBundle additionalInfo;
- field @NonNull public final android.net.LinkProperties linkProperties;
- field @NonNull public final android.net.Network network;
- field @NonNull public final android.net.NetworkCapabilities networkCapabilities;
- field public final long reportTimestamp;
+ method public int describeContents();
+ method @NonNull public android.os.PersistableBundle getAdditionalInfo();
+ method @NonNull public android.net.LinkProperties getLinkProperties();
+ method @NonNull public android.net.Network getNetwork();
+ method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
+ method public long getReportTimestamp();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.ConnectivityReport> CREATOR;
}
- public static class ConnectivityDiagnosticsManager.DataStallReport {
+ public static final class ConnectivityDiagnosticsManager.DataStallReport implements android.os.Parcelable {
ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.os.PersistableBundle);
- field public final int detectionMethod;
- field @NonNull public final android.net.Network network;
- field public final long reportTimestamp;
- field @NonNull public final android.os.PersistableBundle stallDetails;
+ method public int describeContents();
+ method public int getDetectionMethod();
+ method @NonNull public android.net.Network getNetwork();
+ method public long getReportTimestamp();
+ method @NonNull public android.os.PersistableBundle getStallDetails();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.DataStallReport> CREATOR;
+ field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
+ field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
}
public class ConnectivityManager {
@@ -40921,6 +40936,7 @@ package android.se.omapi {
public final class SEService {
ctor public SEService(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, @NonNull android.se.omapi.SEService.OnConnectedListener);
method @NonNull public android.se.omapi.Reader[] getReaders();
+ method @NonNull public android.se.omapi.Reader getUiccReader(int);
method @NonNull public String getVersion();
method public boolean isConnected();
method public void shutdown();
@@ -41058,6 +41074,138 @@ package android.security {
}
+package android.security.identity {
+
+ public class AccessControlProfile {
+ }
+
+ public static final class AccessControlProfile.Builder {
+ ctor public AccessControlProfile.Builder(@NonNull android.security.identity.AccessControlProfileId);
+ method @NonNull public android.security.identity.AccessControlProfile build();
+ method @NonNull public android.security.identity.AccessControlProfile.Builder setReaderCertificate(@NonNull java.security.cert.X509Certificate);
+ method @NonNull public android.security.identity.AccessControlProfile.Builder setUserAuthenticationRequired(boolean);
+ method @NonNull public android.security.identity.AccessControlProfile.Builder setUserAuthenticationTimeout(long);
+ }
+
+ public class AccessControlProfileId {
+ ctor public AccessControlProfileId(int);
+ method public int getId();
+ }
+
+ public class AlreadyPersonalizedException extends android.security.identity.IdentityCredentialException {
+ ctor public AlreadyPersonalizedException(@NonNull String);
+ ctor public AlreadyPersonalizedException(@NonNull String, @NonNull Throwable);
+ }
+
+ public class CipherSuiteNotSupportedException extends android.security.identity.IdentityCredentialException {
+ ctor public CipherSuiteNotSupportedException(@NonNull String);
+ ctor public CipherSuiteNotSupportedException(@NonNull String, @NonNull Throwable);
+ }
+
+ public class DocTypeNotSupportedException extends android.security.identity.IdentityCredentialException {
+ ctor public DocTypeNotSupportedException(@NonNull String);
+ ctor public DocTypeNotSupportedException(@NonNull String, @NonNull Throwable);
+ }
+
+ public class EphemeralPublicKeyNotFoundException extends android.security.identity.IdentityCredentialException {
+ ctor public EphemeralPublicKeyNotFoundException(@NonNull String);
+ ctor public EphemeralPublicKeyNotFoundException(@NonNull String, @NonNull Throwable);
+ }
+
+ public abstract class IdentityCredential {
+ method @NonNull public abstract java.security.KeyPair createEphemeralKeyPair();
+ method @NonNull public abstract byte[] decryptMessageFromReader(@NonNull byte[]) throws android.security.identity.MessageDecryptionException;
+ method @NonNull public abstract byte[] encryptMessageToReader(@NonNull byte[]);
+ method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getAuthKeysNeedingCertification();
+ method @NonNull public abstract int[] getAuthenticationDataUsageCount();
+ method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getCredentialKeyCertificateChain();
+ method @NonNull public abstract android.security.identity.ResultData getEntries(@Nullable byte[], @NonNull java.util.Map<java.lang.String,java.util.Collection<java.lang.String>>, @Nullable byte[], @Nullable byte[]) throws android.security.identity.EphemeralPublicKeyNotFoundException, android.security.identity.InvalidReaderSignatureException, android.security.identity.InvalidRequestMessageException, android.security.identity.NoAuthenticationKeyAvailableException, android.security.identity.SessionTranscriptMismatchException;
+ method public abstract void setAllowUsingExhaustedKeys(boolean);
+ method public abstract void setAvailableAuthenticationKeys(int, int);
+ method public abstract void setReaderEphemeralPublicKey(@NonNull java.security.PublicKey) throws java.security.InvalidKeyException;
+ method public abstract void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException;
+ }
+
+ public class IdentityCredentialException extends java.lang.Exception {
+ ctor public IdentityCredentialException(@NonNull String);
+ ctor public IdentityCredentialException(@NonNull String, @NonNull Throwable);
+ }
+
+ public abstract class IdentityCredentialStore {
+ method @NonNull public abstract android.security.identity.WritableIdentityCredential createCredential(@NonNull String, @NonNull String) throws android.security.identity.AlreadyPersonalizedException, android.security.identity.DocTypeNotSupportedException;
+ method @Nullable public abstract byte[] deleteCredentialByName(@NonNull String);
+ method @Nullable public abstract android.security.identity.IdentityCredential getCredentialByName(@NonNull String, int) throws android.security.identity.CipherSuiteNotSupportedException;
+ method @Nullable public static android.security.identity.IdentityCredentialStore getDirectAccessInstance(@NonNull android.content.Context);
+ method @Nullable public static android.security.identity.IdentityCredentialStore getInstance(@NonNull android.content.Context);
+ method @NonNull public abstract String[] getSupportedDocTypes();
+ field public static final int CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 = 1; // 0x1
+ }
+
+ public class InvalidReaderSignatureException extends android.security.identity.IdentityCredentialException {
+ ctor public InvalidReaderSignatureException(@NonNull String);
+ ctor public InvalidReaderSignatureException(@NonNull String, @NonNull Throwable);
+ }
+
+ public class InvalidRequestMessageException extends android.security.identity.IdentityCredentialException {
+ ctor public InvalidRequestMessageException(@NonNull String);
+ ctor public InvalidRequestMessageException(@NonNull String, @NonNull Throwable);
+ }
+
+ public class MessageDecryptionException extends android.security.identity.IdentityCredentialException {
+ ctor public MessageDecryptionException(@NonNull String);
+ ctor public MessageDecryptionException(@NonNull String, @NonNull Throwable);
+ }
+
+ public class NoAuthenticationKeyAvailableException extends android.security.identity.IdentityCredentialException {
+ ctor public NoAuthenticationKeyAvailableException(@NonNull String);
+ ctor public NoAuthenticationKeyAvailableException(@NonNull String, @NonNull Throwable);
+ }
+
+ public class PersonalizationData {
+ }
+
+ public static final class PersonalizationData.Builder {
+ ctor public PersonalizationData.Builder();
+ method @NonNull public android.security.identity.PersonalizationData.Builder addAccessControlProfile(@NonNull android.security.identity.AccessControlProfile);
+ method @NonNull public android.security.identity.PersonalizationData build();
+ method @NonNull public android.security.identity.PersonalizationData.Builder setEntry(@NonNull String, @NonNull String, @NonNull java.util.Collection<android.security.identity.AccessControlProfileId>, @NonNull byte[]);
+ }
+
+ public abstract class ResultData {
+ method @NonNull public abstract byte[] getAuthenticatedData();
+ method @Nullable public abstract byte[] getEntry(@NonNull String, @NonNull String);
+ method @Nullable public abstract java.util.Collection<java.lang.String> getEntryNames(@NonNull String);
+ method @Nullable public abstract byte[] getMessageAuthenticationCode();
+ method @NonNull public abstract java.util.Collection<java.lang.String> getNamespaceNames();
+ method @Nullable public abstract java.util.Collection<java.lang.String> getRetrievedEntryNames(@NonNull String);
+ method @NonNull public abstract byte[] getStaticAuthenticationData();
+ method public abstract int getStatus(@NonNull String, @NonNull String);
+ field public static final int STATUS_NOT_IN_REQUEST_MESSAGE = 3; // 0x3
+ field public static final int STATUS_NOT_REQUESTED = 2; // 0x2
+ field public static final int STATUS_NO_ACCESS_CONTROL_PROFILES = 6; // 0x6
+ field public static final int STATUS_NO_SUCH_ENTRY = 1; // 0x1
+ field public static final int STATUS_OK = 0; // 0x0
+ field public static final int STATUS_READER_AUTHENTICATION_FAILED = 5; // 0x5
+ field public static final int STATUS_USER_AUTHENTICATION_FAILED = 4; // 0x4
+ }
+
+ public class SessionTranscriptMismatchException extends android.security.identity.IdentityCredentialException {
+ ctor public SessionTranscriptMismatchException(@NonNull String);
+ ctor public SessionTranscriptMismatchException(@NonNull String, @NonNull Throwable);
+ }
+
+ public class UnknownAuthenticationKeyException extends android.security.identity.IdentityCredentialException {
+ ctor public UnknownAuthenticationKeyException(@NonNull String);
+ ctor public UnknownAuthenticationKeyException(@NonNull String, @NonNull Throwable);
+ }
+
+ public abstract class WritableIdentityCredential {
+ method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getCredentialKeyCertificateChain(@NonNull byte[]);
+ method @NonNull public abstract byte[] personalize(@NonNull android.security.identity.PersonalizationData);
+ }
+
+}
+
package android.security.keystore {
public class KeyExpiredException extends java.security.InvalidKeyException {
@@ -43467,6 +43615,7 @@ package android.telecom {
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+ field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 8192; // 0x2000
field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 2048; // 0x800
field public static final int PROPERTY_RTT = 1024; // 0x400
@@ -43544,6 +43693,7 @@ package android.telecom {
public abstract class Conference extends android.telecom.Conferenceable {
ctor public Conference(android.telecom.PhoneAccountHandle);
method public final boolean addConnection(android.telecom.Connection);
+ method @NonNull public static android.telecom.Conference createFailedConference(@NonNull android.telecom.DisconnectCause, @NonNull android.telecom.PhoneAccountHandle);
method public final void destroy();
method public final android.telecom.CallAudioState getCallAudioState();
method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
@@ -43558,6 +43708,8 @@ package android.telecom {
method public final android.telecom.StatusHints getStatusHints();
method public android.telecom.Connection.VideoProvider getVideoProvider();
method public int getVideoState();
+ method public final boolean isRingbackRequested();
+ method public void onAnswer(int);
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onConnectionAdded(android.telecom.Connection);
method public void onDisconnect();
@@ -43566,6 +43718,7 @@ package android.telecom {
method public void onMerge(android.telecom.Connection);
method public void onMerge();
method public void onPlayDtmfTone(char);
+ method public void onReject();
method public void onSeparate(android.telecom.Connection);
method public void onStopDtmfTone();
method public void onSwap();
@@ -43585,6 +43738,8 @@ package android.telecom {
method public final void setDisconnected(android.telecom.DisconnectCause);
method public final void setExtras(@Nullable android.os.Bundle);
method public final void setOnHold();
+ method public final void setRingbackRequested(boolean);
+ method public final void setRinging();
method public final void setStatusHints(android.telecom.StatusHints);
method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
method public final void setVideoState(android.telecom.Connection, int);
@@ -43742,6 +43897,7 @@ package android.telecom {
field public static final int PROPERTY_ASSISTED_DIALING_USED = 512; // 0x200
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
field public static final int PROPERTY_HIGH_DEF_AUDIO = 4; // 0x4
+ field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 4096; // 0x1000
field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int PROPERTY_IS_RTT = 256; // 0x100
field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 1024; // 0x400
@@ -43814,8 +43970,10 @@ package android.telecom {
method public android.telecom.PhoneAccountHandle getAccountHandle();
method public android.net.Uri getAddress();
method public android.os.Bundle getExtras();
+ method @Nullable public java.util.List<android.net.Uri> getParticipants();
method public android.telecom.Connection.RttTextStream getRttTextStream();
method public int getVideoState();
+ method public boolean isAdhocConferenceCall();
method public boolean isRequestingRtt();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telecom.ConnectionRequest> CREATOR;
@@ -43835,9 +43993,13 @@ package android.telecom {
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public void onConnectionServiceFocusGained();
method public void onConnectionServiceFocusLost();
+ method @Nullable public android.telecom.Conference onCreateIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method public void onCreateIncomingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method @Nullable public android.telecom.Conference onCreateOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method public void onCreateOutgoingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
@@ -43952,6 +44114,7 @@ package android.telecom {
method public boolean supportsUriScheme(String);
method public android.telecom.PhoneAccount.Builder toBuilder();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int CAPABILITY_ADHOC_CONFERENCE_CALLING = 16384; // 0x4000
field public static final int CAPABILITY_CALL_PROVIDER = 2; // 0x2
field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
@@ -44147,6 +44310,7 @@ package android.telecom {
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
+ method public void addNewIncomingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent();
method @Deprecated @RequiresPermission(android.Manifest.permission.ANSWER_PHONE_CALLS) public boolean endCall();
@@ -44174,6 +44338,7 @@ package android.telecom {
method public void registerPhoneAccount(android.telecom.PhoneAccount);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void showInCallScreen(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger();
+ method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void startConference(@NonNull java.util.List<android.net.Uri>, @NonNull android.os.Bundle);
method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
field public static final String ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER";
field public static final String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
@@ -44652,6 +44817,7 @@ package android.telephony {
field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
field public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
+ field public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL = "support_adhoc_conference_calls_bool";
field public static final String KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL = "support_clir_network_default_bool";
field public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool";
@@ -45182,7 +45348,7 @@ package android.telephony {
field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_IMS_CALL_DISCONNECT_CAUSES = 134217728; // 0x8000000
field public static final int LISTEN_MESSAGE_WAITING_INDICATOR = 4; // 0x4
field public static final int LISTEN_NONE = 0; // 0x0
- field @RequiresPermission("android.permission.MODIFY_PHONE_STATE") public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
+ field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 4096; // 0x1000
field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int LISTEN_REGISTRATION_FAILURE = 1073741824; // 0x40000000
field public static final int LISTEN_SERVICE_STATE = 1; // 0x1
field @Deprecated public static final int LISTEN_SIGNAL_STRENGTH = 2; // 0x2
@@ -45609,6 +45775,7 @@ package android.telephony {
method public String getNetworkCountryIso();
method public String getNetworkOperator();
method public String getNetworkOperatorName();
+ method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getNetworkSelectionMode();
method public String getNetworkSpecifier();
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getNetworkType();
method @Deprecated public int getPhoneCount();
@@ -45741,6 +45908,9 @@ package android.telephony {
field public static final int MULTISIM_ALLOWED = 0; // 0x0
field public static final int MULTISIM_NOT_SUPPORTED_BY_CARRIER = 2; // 0x2
field public static final int MULTISIM_NOT_SUPPORTED_BY_HARDWARE = 1; // 0x1
+ field public static final int NETWORK_SELECTION_MODE_AUTO = 1; // 0x1
+ field public static final int NETWORK_SELECTION_MODE_MANUAL = 2; // 0x2
+ field public static final int NETWORK_SELECTION_MODE_UNKNOWN = 0; // 0x0
field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
field public static final int NETWORK_TYPE_EDGE = 2; // 0x2
@@ -46152,6 +46322,37 @@ package android.telephony.gsm {
package android.telephony.ims {
+ public final class ImsException extends java.lang.Exception {
+ method public int getCode();
+ field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1
+ field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0
+ field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2
+ }
+
+ public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
+ method @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getVoWiFiModeSetting();
+ method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isAdvancedCallingSettingEnabled();
+ method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isTtyOverVolteEnabled();
+ method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiRoamingSettingEnabled();
+ method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiSettingEnabled();
+ method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVtSettingEnabled();
+ method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
+ method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback);
+ field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1
+ field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0
+ field public static final int WIFI_MODE_WIFI_PREFERRED = 2; // 0x2
+ }
+
+ public static class ImsMmTelManager.CapabilityCallback {
+ ctor public ImsMmTelManager.CapabilityCallback();
+ method public void onCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities);
+ }
+
public final class ImsReasonInfo implements android.os.Parcelable {
ctor public ImsReasonInfo(int, int, @Nullable String);
method public int describeContents();
@@ -46335,6 +46536,38 @@ package android.telephony.ims {
field public static final int EXTRA_CODE_CALL_RETRY_SILENT_REDIAL = 2; // 0x2
}
+ public interface RegistrationManager {
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
+ field public static final int REGISTRATION_STATE_NOT_REGISTERED = 0; // 0x0
+ field public static final int REGISTRATION_STATE_REGISTERED = 2; // 0x2
+ field public static final int REGISTRATION_STATE_REGISTERING = 1; // 0x1
+ }
+
+ public static class RegistrationManager.RegistrationCallback {
+ ctor public RegistrationManager.RegistrationCallback();
+ method public void onRegistered(int);
+ method public void onRegistering(int);
+ method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo);
+ method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo);
+ }
+
+}
+
+package android.telephony.ims.feature {
+
+ public class MmTelFeature {
+ }
+
+ public static class MmTelFeature.MmTelCapabilities {
+ field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8
+ field public static final int CAPABILITY_TYPE_UT = 4; // 0x4
+ field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2
+ field public static final int CAPABILITY_TYPE_VOICE = 1; // 0x1
+ }
+
}
package android.telephony.mbms {
@@ -49360,6 +49593,71 @@ package android.util {
}
+package android.util.proto {
+
+ public final class ProtoOutputStream {
+ ctor public ProtoOutputStream();
+ ctor public ProtoOutputStream(int);
+ ctor public ProtoOutputStream(@NonNull java.io.OutputStream);
+ method public static int checkFieldId(long, long);
+ method public void dump(@NonNull String);
+ method public void end(long);
+ method public void flush();
+ method @NonNull public byte[] getBytes();
+ method @Nullable public static String getFieldCountString(long);
+ method @NonNull public static String getFieldIdString(long);
+ method @Nullable public static String getFieldTypeString(long);
+ method public int getRawSize();
+ method @Nullable public static String getWireTypeString(int);
+ method public static long makeFieldId(int, long);
+ method public static long makeToken(int, boolean, int, int, int);
+ method public long start(long);
+ method @NonNull public static String token2String(long);
+ method public void write(long, double);
+ method public void write(long, float);
+ method public void write(long, int);
+ method public void write(long, long);
+ method public void write(long, boolean);
+ method public void write(long, @Nullable String);
+ method public void write(long, @Nullable byte[]);
+ method public void writeTag(int, int);
+ field public static final long FIELD_COUNT_MASK = 16492674416640L; // 0xf0000000000L
+ field public static final long FIELD_COUNT_PACKED = 5497558138880L; // 0x50000000000L
+ field public static final long FIELD_COUNT_REPEATED = 2199023255552L; // 0x20000000000L
+ field public static final int FIELD_COUNT_SHIFT = 40; // 0x28
+ field public static final long FIELD_COUNT_SINGLE = 1099511627776L; // 0x10000000000L
+ field public static final long FIELD_COUNT_UNKNOWN = 0L; // 0x0L
+ field public static final int FIELD_ID_SHIFT = 3; // 0x3
+ field public static final long FIELD_TYPE_BOOL = 34359738368L; // 0x800000000L
+ field public static final long FIELD_TYPE_BYTES = 51539607552L; // 0xc00000000L
+ field public static final long FIELD_TYPE_DOUBLE = 4294967296L; // 0x100000000L
+ field public static final long FIELD_TYPE_ENUM = 60129542144L; // 0xe00000000L
+ field public static final long FIELD_TYPE_FIXED32 = 30064771072L; // 0x700000000L
+ field public static final long FIELD_TYPE_FIXED64 = 25769803776L; // 0x600000000L
+ field public static final long FIELD_TYPE_FLOAT = 8589934592L; // 0x200000000L
+ field public static final long FIELD_TYPE_INT32 = 21474836480L; // 0x500000000L
+ field public static final long FIELD_TYPE_INT64 = 12884901888L; // 0x300000000L
+ field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L
+ field public static final long FIELD_TYPE_MESSAGE = 47244640256L; // 0xb00000000L
+ field public static final long FIELD_TYPE_SFIXED32 = 64424509440L; // 0xf00000000L
+ field public static final long FIELD_TYPE_SFIXED64 = 68719476736L; // 0x1000000000L
+ field public static final int FIELD_TYPE_SHIFT = 32; // 0x20
+ field public static final long FIELD_TYPE_SINT32 = 73014444032L; // 0x1100000000L
+ field public static final long FIELD_TYPE_SINT64 = 77309411328L; // 0x1200000000L
+ field public static final long FIELD_TYPE_STRING = 38654705664L; // 0x900000000L
+ field public static final long FIELD_TYPE_UINT32 = 55834574848L; // 0xd00000000L
+ field public static final long FIELD_TYPE_UINT64 = 17179869184L; // 0x400000000L
+ field public static final int WIRE_TYPE_END_GROUP = 4; // 0x4
+ field public static final int WIRE_TYPE_FIXED32 = 5; // 0x5
+ field public static final int WIRE_TYPE_FIXED64 = 1; // 0x1
+ field public static final int WIRE_TYPE_LENGTH_DELIMITED = 2; // 0x2
+ field public static final int WIRE_TYPE_MASK = 7; // 0x7
+ field public static final int WIRE_TYPE_START_GROUP = 3; // 0x3
+ field public static final int WIRE_TYPE_VARINT = 0; // 0x0
+ }
+
+}
+
package android.view {
public abstract class AbsSavedState implements android.os.Parcelable {
diff --git a/api/lint-baseline.txt b/api/lint-baseline.txt
index 07106babeb76..5c31f41e2e3c 100644
--- a/api/lint-baseline.txt
+++ b/api/lint-baseline.txt
@@ -485,6 +485,12 @@ HiddenSuperclass: android.util.StatsLog:
+MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#CHORASMIAN:
+ Missing nullability on field `CHORASMIAN` in class `class android.icu.lang.UCharacter.UnicodeBlock`
+MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G:
+ Missing nullability on field `CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G` in class `class android.icu.lang.UCharacter.UnicodeBlock`
+MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#DIVES_AKURU:
+ Missing nullability on field `DIVES_AKURU` in class `class android.icu.lang.UCharacter.UnicodeBlock`
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS:
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#ELYMAIC:
@@ -529,6 +535,8 @@ MissingNullability: android.icu.util.VersionInfo#UNICODE_12_0:
MissingNullability: android.icu.util.VersionInfo#UNICODE_12_1:
+MissingNullability: android.icu.util.VersionInfo#UNICODE_13_0:
+ Missing nullability on field `UNICODE_13_0` in class `class android.icu.util.VersionInfo`
RequiresPermission: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler):
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index c8253a0b9e88..c657e0049670 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -118,9 +118,31 @@ package android.timezone {
}
public final class TimeZoneFinder {
+ method @Nullable public String getIanaVersion();
method @NonNull public static android.timezone.TimeZoneFinder getInstance();
method @Nullable public android.timezone.CountryTimeZones lookupCountryTimeZones(@NonNull String);
}
+ public final class TzDataSetVersion {
+ method public static int currentFormatMajorVersion();
+ method public static int currentFormatMinorVersion();
+ method public int getFormatMajorVersion();
+ method public int getFormatMinorVersion();
+ method public int getRevision();
+ method @NonNull public String getRulesVersion();
+ method public static boolean isCompatibleWithThisDevice(android.timezone.TzDataSetVersion);
+ method @NonNull public static android.timezone.TzDataSetVersion read() throws java.io.IOException, android.timezone.TzDataSetVersion.TzDataSetException;
+ }
+
+ public static class TzDataSetVersion.TzDataSetException extends java.lang.Exception {
+ ctor public TzDataSetVersion.TzDataSetException(String);
+ ctor public TzDataSetVersion.TzDataSetException(String, Throwable);
+ }
+
+ public final class ZoneInfoDb {
+ method @NonNull public static android.timezone.ZoneInfoDb getInstance();
+ method @NonNull public String getVersion();
+ }
+
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 98701fd5c599..0e42ac1011a1 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1440,12 +1440,13 @@ package android.bluetooth {
field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
}
- public final class BluetoothPan implements android.bluetooth.BluetoothProfile {
- method protected void finalize();
+ public final class BluetoothPan implements java.lang.AutoCloseable android.bluetooth.BluetoothProfile {
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public void close();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) protected void finalize();
method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
- method public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice);
- method public boolean isTetheringOn();
- method public void setBluetoothTethering(boolean);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isTetheringOn();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public void setBluetoothTethering(boolean);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
@@ -1463,10 +1464,14 @@ package android.bluetooth {
}
public interface BluetoothProfile {
+ field public static final int A2DP_SINK = 11; // 0xb
+ field public static final int AVRCP_CONTROLLER = 12; // 0xc
field public static final int CONNECTION_POLICY_ALLOWED = 100; // 0x64
field public static final int CONNECTION_POLICY_FORBIDDEN = 0; // 0x0
field public static final int CONNECTION_POLICY_UNKNOWN = -1; // 0xffffffff
+ field public static final int HEADSET_CLIENT = 16; // 0x10
field public static final int PAN = 5; // 0x5
+ field public static final int PBAP_CLIENT = 17; // 0x11
field @Deprecated public static final int PRIORITY_OFF = 0; // 0x0
field @Deprecated public static final int PRIORITY_ON = 100; // 0x64
}
@@ -1653,6 +1658,7 @@ package android.content {
field public static final String EXTRA_PERMISSION_GROUP_NAME = "android.intent.extra.PERMISSION_GROUP_NAME";
field public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
field public static final String EXTRA_REASON = "android.intent.extra.REASON";
+ field @Deprecated public static final String EXTRA_REBROADCAST_ON_UNLOCK = "rebroadcastOnUnlock";
field public static final String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
field public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
@@ -2087,6 +2093,15 @@ package android.content.rollback {
}
+package android.debug {
+
+ public class AdbManager {
+ method @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) public boolean isAdbWifiQrSupported();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) public boolean isAdbWifiSupported();
+ }
+
+}
+
package android.hardware {
public final class Sensor {
@@ -4293,6 +4308,32 @@ package android.net {
field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2
}
+ public final class CaptivePortalData implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getByteLimit();
+ method public long getExpiryTimeMillis();
+ method public long getRefreshTimeMillis();
+ method @Nullable public android.net.Uri getUserPortalUrl();
+ method @Nullable public android.net.Uri getVenueInfoUrl();
+ method public boolean isCaptive();
+ method public boolean isSessionExtendable();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR;
+ }
+
+ public static class CaptivePortalData.Builder {
+ ctor public CaptivePortalData.Builder();
+ ctor public CaptivePortalData.Builder(@Nullable android.net.CaptivePortalData);
+ method @NonNull public android.net.CaptivePortalData build();
+ method @NonNull public android.net.CaptivePortalData.Builder setBytesRemaining(long);
+ method @NonNull public android.net.CaptivePortalData.Builder setCaptive(boolean);
+ method @NonNull public android.net.CaptivePortalData.Builder setExpiryTime(long);
+ method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long);
+ method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
+ method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
+ method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
+ }
+
public class ConnectivityManager {
method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
@@ -4424,6 +4465,8 @@ package android.net {
method @NonNull public java.util.List<java.lang.String> getAllInterfaceNames();
method @NonNull public java.util.List<android.net.LinkAddress> getAllLinkAddresses();
method @NonNull public java.util.List<android.net.RouteInfo> getAllRoutes();
+ method @Nullable public android.net.Uri getCaptivePortalApiUrl();
+ method @Nullable public android.net.CaptivePortalData getCaptivePortalData();
method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
method @Nullable public String getTcpBufferSizes();
method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
@@ -4437,9 +4480,12 @@ package android.net {
method public boolean isIpv6Provisioned();
method public boolean isProvisioned();
method public boolean isReachable(@NonNull java.net.InetAddress);
+ method @NonNull public android.net.LinkProperties makeSensitiveFieldsParcelingCopy();
method public boolean removeDnsServer(@NonNull java.net.InetAddress);
method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
method public boolean removeRoute(@NonNull android.net.RouteInfo);
+ method public void setCaptivePortalApiUrl(@Nullable android.net.Uri);
+ method public void setCaptivePortalData(@Nullable android.net.CaptivePortalData);
method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
method public void setPrivateDnsServerName(@Nullable String);
method public void setTcpBufferSizes(@Nullable String);
@@ -4468,8 +4514,26 @@ package android.net {
field public final int netId;
}
+ public final class NetworkAgentConfig implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public String getSubscriberId();
+ method public boolean isNat64DetectionEnabled();
+ method public boolean isProvisioningNotificationEnabled();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR;
+ }
+
+ public static class NetworkAgentConfig.Builder {
+ ctor public NetworkAgentConfig.Builder();
+ method @NonNull public android.net.NetworkAgentConfig build();
+ method @NonNull public android.net.NetworkAgentConfig.Builder disableNat64Detection();
+ method @NonNull public android.net.NetworkAgentConfig.Builder disableProvisioningNotification();
+ method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
+ }
+
public final class NetworkCapabilities implements android.os.Parcelable {
method public boolean deduceRestrictedCapability();
+ method @Nullable public String getSSID();
method @NonNull public int[] getTransportTypes();
method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
method @NonNull public android.net.NetworkCapabilities setSSID(@Nullable String);
@@ -4506,6 +4570,10 @@ package android.net {
method public abstract void onRequestScores(android.net.NetworkKey[]);
}
+ public class NetworkRequest implements android.os.Parcelable {
+ method public boolean satisfiedBy(@Nullable android.net.NetworkCapabilities);
+ }
+
public static class NetworkRequest.Builder {
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
}
@@ -7024,6 +7092,14 @@ package android.provider {
}
+package android.se.omapi {
+
+ public final class Reader {
+ method @RequiresPermission(android.Manifest.permission.SECURE_ELEMENT_PRIVILEGED) public boolean reset();
+ }
+
+}
+
package android.security.keystore {
public abstract class AttestationUtils {
@@ -8825,7 +8901,7 @@ package android.telephony {
method public void onRadioPowerStateChanged(int);
method public void onSrvccStateChanged(int);
method public void onVoiceActivationStateChanged(int);
- field public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
+ field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000
field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000
field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000
field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_PRECISE_CALL_STATE = 2048; // 0x800
@@ -9106,6 +9182,7 @@ package android.telephony {
}
public final class SmsManager {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_MESSAGES_ON_ICC) public boolean copyMessageToIcc(@Nullable byte[], @NonNull byte[], int);
method @RequiresPermission(android.Manifest.permission.ACCESS_MESSAGES_ON_ICC) public boolean deleteMessageFromIcc(int);
method public boolean disableCellBroadcastRange(int, int, int);
method public boolean enableCellBroadcastRange(int, int, int);
@@ -9117,6 +9194,7 @@ package android.telephony {
public class SmsMessage {
method @Nullable public static android.telephony.SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[], boolean);
+ method @Nullable public static android.telephony.SmsMessage.SubmitPdu getSmsPdu(int, int, @Nullable String, @NonNull String, @NonNull String, long);
method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static byte[] getSubmitPduEncodedMessage(boolean, @NonNull String, @NonNull String, int, int, int, int, int, int);
}
@@ -9781,7 +9859,8 @@ package android.telephony.ims {
field public static final int DIALSTRING_USSD = 2; // 0x2
field public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
field public static final String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS = "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS";
- field public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
+ field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telephony.ims.extra.CALL_NETWORK_TYPE";
+ field @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
field public static final String EXTRA_CHILD_NUMBER = "ChildNum";
field public static final String EXTRA_CNA = "cna";
field public static final String EXTRA_CNAP = "cnap";
@@ -9813,8 +9892,8 @@ package android.telephony.ims {
method public void callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
method public void callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
method public void callSessionConferenceStateUpdated(android.telephony.ims.ImsConferenceState);
- method public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo);
- method public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo);
+ method @Deprecated public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo);
+ method @Deprecated public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo);
method public void callSessionHeld(android.telephony.ims.ImsCallProfile);
method public void callSessionHoldFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionHoldReceived(android.telephony.ims.ImsCallProfile);
@@ -9822,7 +9901,7 @@ package android.telephony.ims {
method public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionInviteParticipantsRequestDelivered();
method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo);
- method public void callSessionMayHandover(int, int);
+ method @Deprecated public void callSessionMayHandover(int, int);
method public void callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase);
method public void callSessionMergeFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
@@ -9844,6 +9923,9 @@ package android.telephony.ims {
method public void callSessionUpdateReceived(android.telephony.ims.ImsCallProfile);
method public void callSessionUpdated(android.telephony.ims.ImsCallProfile);
method public void callSessionUssdMessageReceived(int, String);
+ method public void onHandover(int, int, @Nullable android.telephony.ims.ImsReasonInfo);
+ method public void onHandoverFailed(int, int, @NonNull android.telephony.ims.ImsReasonInfo);
+ method public void onMayHandover(int, int);
}
public final class ImsConferenceState implements android.os.Parcelable {
@@ -9875,10 +9957,6 @@ package android.telephony.ims {
ctor public ImsException(@Nullable String);
ctor public ImsException(@Nullable String, int);
ctor public ImsException(@Nullable String, int, @Nullable Throwable);
- method public int getCode();
- field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1
- field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0
- field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2
}
public final class ImsExternalCallState implements android.os.Parcelable {
@@ -9901,26 +9979,19 @@ package android.telephony.ims {
method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int);
method @NonNull public android.telephony.ims.ImsRcsManager getImsRcsManager(int);
field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION";
+ field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR";
+ field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
+ field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE";
}
public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
- method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiModeSetting();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAdvancedCallingSettingEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException;
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTtyOverVolteEnabled();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiRoamingSettingEnabled();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiSettingEnabled();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVtSettingEnabled();
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException;
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(int);
@@ -9930,16 +10001,6 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean);
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback);
- field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1
- field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0
- field public static final int WIFI_MODE_WIFI_PREFERRED = 2; // 0x2
- }
-
- public static class ImsMmTelManager.CapabilityCallback {
- ctor public ImsMmTelManager.CapabilityCallback();
- method public void onCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities);
}
@Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback {
@@ -10203,7 +10264,27 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
+ field public static final int KEY_1X_EPDG_TIMER_SEC = 64; // 0x40
+ field public static final int KEY_1X_THRESHOLD = 59; // 0x3b
+ field public static final int KEY_AMR_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 50; // 0x32
+ field public static final int KEY_AMR_CODEC_MODE_SET_VALUES = 0; // 0x0
+ field public static final int KEY_AMR_DEFAULT_ENCODING_MODE = 53; // 0x35
+ field public static final int KEY_AMR_OCTET_ALIGNED_PAYLOAD_TYPE = 49; // 0x31
+ field public static final int KEY_AMR_WB_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 48; // 0x30
+ field public static final int KEY_AMR_WB_CODEC_MODE_SET_VALUES = 1; // 0x1
+ field public static final int KEY_AMR_WB_OCTET_ALIGNED_PAYLOAD_TYPE = 47; // 0x2f
+ field public static final int KEY_DTMF_NB_PAYLOAD_TYPE = 52; // 0x34
+ field public static final int KEY_DTMF_WB_PAYLOAD_TYPE = 51; // 0x33
field public static final int KEY_EAB_PROVISIONING_STATUS = 25; // 0x19
+ field public static final int KEY_ENABLE_SILENT_REDIAL = 6; // 0x6
+ field public static final int KEY_LOCAL_BREAKOUT_PCSCF_ADDRESS = 31; // 0x1f
+ field public static final int KEY_LTE_EPDG_TIMER_SEC = 62; // 0x3e
+ field public static final int KEY_LTE_THRESHOLD_1 = 56; // 0x38
+ field public static final int KEY_LTE_THRESHOLD_2 = 57; // 0x39
+ field public static final int KEY_LTE_THRESHOLD_3 = 58; // 0x3a
+ field public static final int KEY_MINIMUM_SIP_SESSION_EXPIRATION_TIMER_SEC = 3; // 0x3
+ field public static final int KEY_MOBILE_DATA_ENABLED = 29; // 0x1d
+ field public static final int KEY_MULTIENDPOINT_ENABLED = 65; // 0x41
field public static final int KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC = 19; // 0x13
field public static final int KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC = 18; // 0x12
field public static final int KEY_RCS_CAPABILITIES_POLL_INTERVAL_SEC = 20; // 0x14
@@ -10213,16 +10294,52 @@ package android.telephony.ims {
field public static final int KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS = 21; // 0x15
field public static final int KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC = 16; // 0x10
field public static final int KEY_RCS_PUBLISH_TIMER_SEC = 15; // 0xf
+ field public static final int KEY_REGISTRATION_DOMAIN_NAME = 12; // 0xc
+ field public static final int KEY_REGISTRATION_RETRY_BASE_TIME_SEC = 33; // 0x21
+ field public static final int KEY_REGISTRATION_RETRY_MAX_TIME_SEC = 34; // 0x22
+ field public static final int KEY_RTP_SPEECH_END_PORT = 36; // 0x24
+ field public static final int KEY_RTP_SPEECH_START_PORT = 35; // 0x23
+ field public static final int KEY_RTT_ENABLED = 66; // 0x42
+ field public static final int KEY_SIP_ACK_RECEIPT_WAIT_TIME_MS = 43; // 0x2b
+ field public static final int KEY_SIP_ACK_RETRANSMIT_WAIT_TIME_MS = 44; // 0x2c
+ field public static final int KEY_SIP_INVITE_ACK_WAIT_TIME_MS = 38; // 0x26
+ field public static final int KEY_SIP_INVITE_CANCELLATION_TIMER_MS = 4; // 0x4
+ field public static final int KEY_SIP_INVITE_REQUEST_TRANSMIT_INTERVAL_MS = 37; // 0x25
+ field public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_INTERVAL_MS = 42; // 0x2a
+ field public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_WAIT_TIME_MS = 39; // 0x27
+ field public static final int KEY_SIP_KEEP_ALIVE_ENABLED = 32; // 0x20
+ field public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMISSION_WAIT_TIME_MS = 45; // 0x2d
+ field public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMIT_INTERVAL_MS = 40; // 0x28
+ field public static final int KEY_SIP_NON_INVITE_RESPONSE_RETRANSMISSION_WAIT_TIME_MS = 46; // 0x2e
+ field public static final int KEY_SIP_NON_INVITE_TRANSACTION_TIMEOUT_TIMER_MS = 41; // 0x29
+ field public static final int KEY_SIP_SESSION_TIMER_SEC = 2; // 0x2
+ field public static final int KEY_SMS_FORMAT = 13; // 0xd
+ field public static final int KEY_SMS_OVER_IP_ENABLED = 14; // 0xe
+ field public static final int KEY_SMS_PUBLIC_SERVICE_IDENTITY = 54; // 0x36
field public static final int KEY_T1_TIMER_VALUE_MS = 7; // 0x7
+ field public static final int KEY_T2_TIMER_VALUE_MS = 8; // 0x8
+ field public static final int KEY_TF_TIMER_VALUE_MS = 9; // 0x9
+ field public static final int KEY_TRANSITION_TO_LTE_DELAY_MS = 5; // 0x5
+ field public static final int KEY_USE_GZIP_FOR_LIST_SUBSCRIPTION = 24; // 0x18
+ field public static final int KEY_VIDEO_QUALITY = 55; // 0x37
+ field public static final int KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE = 28; // 0x1c
field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a
field public static final int KEY_VOLTE_PROVISIONING_STATUS = 10; // 0xa
+ field public static final int KEY_VOLTE_USER_OPT_IN_STATUS = 30; // 0x1e
field public static final int KEY_VT_PROVISIONING_STATUS = 11; // 0xb
+ field public static final int KEY_WIFI_EPDG_TIMER_SEC = 63; // 0x3f
+ field public static final int KEY_WIFI_THRESHOLD_A = 60; // 0x3c
+ field public static final int KEY_WIFI_THRESHOLD_B = 61; // 0x3d
field public static final int PROVISIONING_RESULT_UNKNOWN = -1; // 0xffffffff
field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0
field public static final int PROVISIONING_VALUE_ENABLED = 1; // 0x1
+ field public static final int SMS_FORMAT_3GPP = 1; // 0x1
+ field public static final int SMS_FORMAT_3GPP2 = 0; // 0x0
field public static final String STRING_QUERY_RESULT_ERROR_GENERIC = "STRING_QUERY_RESULT_ERROR_GENERIC";
field public static final String STRING_QUERY_RESULT_ERROR_NOT_READY = "STRING_QUERY_RESULT_ERROR_NOT_READY";
+ field public static final int VIDEO_QUALITY_HIGH = 1; // 0x1
+ field public static final int VIDEO_QUALITY_LOW = 0; // 0x0
}
public static class ProvisioningManager.Callback {
@@ -10279,24 +10396,6 @@ package android.telephony.ims {
method @NonNull public android.telephony.ims.RcsContactUceCapability build();
}
- public interface RegistrationManager {
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
- field public static final int REGISTRATION_STATE_NOT_REGISTERED = 0; // 0x0
- field public static final int REGISTRATION_STATE_REGISTERED = 2; // 0x2
- field public static final int REGISTRATION_STATE_REGISTERING = 1; // 0x1
- }
-
- public static class RegistrationManager.RegistrationCallback {
- ctor public RegistrationManager.RegistrationCallback();
- method public void onRegistered(int);
- method public void onRegistering(int);
- method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo);
- method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo);
- }
-
}
package android.telephony.ims.feature {
@@ -10359,7 +10458,7 @@ package android.telephony.ims.feature {
method public void onFeatureReady();
method public void onFeatureRemoved();
method public boolean queryCapabilityConfiguration(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
- method public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus();
+ method @NonNull public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus();
method public void setUiTtyMode(int, @Nullable android.os.Message);
method @android.telephony.ims.feature.MmTelFeature.ProcessCallResult public int shouldProcessCall(@NonNull String[]);
field public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL";
@@ -10375,10 +10474,6 @@ package android.telephony.ims.feature {
method public final void addCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
method public final boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
method public final void removeCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
- field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8
- field public static final int CAPABILITY_TYPE_UT = 4; // 0x4
- field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2
- field public static final int CAPABILITY_TYPE_VOICE = 1; // 0x1
}
@IntDef(flag=true, value={android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MmTelFeature.MmTelCapabilities.MmTelCapability {
@@ -10562,6 +10657,7 @@ package android.telephony.ims.stub {
method public int transact(android.os.Bundle);
method public int updateCallBarring(int, int, String[]);
method public int updateCallBarringForServiceClass(int, int, String[], int);
+ method public int updateCallBarringWithPassword(int, int, @Nullable String[], int, @NonNull String);
method public int updateCallForward(int, int, String, int, int);
method public int updateCallWaiting(boolean, int);
method public int updateClip(boolean);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 57ee408c561c..5802f6cc09b6 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -130,18 +130,6 @@ package android.media.tv {
}
-package android.net {
-
- @Deprecated public final class StringNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
- ctor public StringNetworkSpecifier(@NonNull String);
- method public int describeContents();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.StringNetworkSpecifier> CREATOR;
- field @NonNull public final String specifier;
- }
-
-}
-
package android.net.wifi {
@Deprecated public class BatchedScanResult implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index de35bb3c5052..98b224d366b9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1361,6 +1361,32 @@ package android.net {
field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2
}
+ public final class CaptivePortalData implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getByteLimit();
+ method public long getExpiryTimeMillis();
+ method public long getRefreshTimeMillis();
+ method @Nullable public android.net.Uri getUserPortalUrl();
+ method @Nullable public android.net.Uri getVenueInfoUrl();
+ method public boolean isCaptive();
+ method public boolean isSessionExtendable();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR;
+ }
+
+ public static class CaptivePortalData.Builder {
+ ctor public CaptivePortalData.Builder();
+ ctor public CaptivePortalData.Builder(@Nullable android.net.CaptivePortalData);
+ method @NonNull public android.net.CaptivePortalData build();
+ method @NonNull public android.net.CaptivePortalData.Builder setBytesRemaining(long);
+ method @NonNull public android.net.CaptivePortalData.Builder setCaptive(boolean);
+ method @NonNull public android.net.CaptivePortalData.Builder setExpiryTime(long);
+ method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long);
+ method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
+ method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
+ method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
+ }
+
public class ConnectivityManager {
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
@@ -1391,6 +1417,8 @@ package android.net {
ctor public LinkProperties(@Nullable android.net.LinkProperties);
method public boolean addDnsServer(@NonNull java.net.InetAddress);
method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
+ method @Nullable public android.net.Uri getCaptivePortalApiUrl();
+ method @Nullable public android.net.CaptivePortalData getCaptivePortalData();
method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
method @Nullable public String getTcpBufferSizes();
method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
@@ -1401,9 +1429,12 @@ package android.net {
method public boolean isIpv6Provisioned();
method public boolean isProvisioned();
method public boolean isReachable(@NonNull java.net.InetAddress);
+ method @NonNull public android.net.LinkProperties makeSensitiveFieldsParcelingCopy();
method public boolean removeDnsServer(@NonNull java.net.InetAddress);
method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
method public boolean removeRoute(@NonNull android.net.RouteInfo);
+ method public void setCaptivePortalApiUrl(@Nullable android.net.Uri);
+ method public void setCaptivePortalData(@Nullable android.net.CaptivePortalData);
method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
method public void setPrivateDnsServerName(@Nullable String);
method public void setTcpBufferSizes(@Nullable String);
@@ -2853,6 +2884,8 @@ package android.telecom {
method @NonNull public android.telecom.ConnectionRequest.Builder setAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
method @NonNull public android.telecom.ConnectionRequest.Builder setAddress(@NonNull android.net.Uri);
method @NonNull public android.telecom.ConnectionRequest.Builder setExtras(@NonNull android.os.Bundle);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setIsAdhocConferenceCall(boolean);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setParticipants(@Nullable java.util.List<android.net.Uri>);
method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeFromInCall(@NonNull android.os.ParcelFileDescriptor);
method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeToInCall(@NonNull android.os.ParcelFileDescriptor);
method @NonNull public android.telecom.ConnectionRequest.Builder setShouldShowIncomingCallUi(boolean);
@@ -3153,7 +3186,8 @@ package android.telephony.ims {
field public static final int DIALSTRING_USSD = 2; // 0x2
field public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
field public static final String EXTRA_ADDITIONAL_SIP_INVITE_FIELDS = "android.telephony.ims.extra.ADDITIONAL_SIP_INVITE_FIELDS";
- field public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
+ field public static final String EXTRA_CALL_NETWORK_TYPE = "android.telephony.ims.extra.CALL_NETWORK_TYPE";
+ field @Deprecated public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
field public static final String EXTRA_CHILD_NUMBER = "ChildNum";
field public static final String EXTRA_CNA = "cna";
field public static final String EXTRA_CNAP = "cnap";
@@ -3186,8 +3220,8 @@ package android.telephony.ims {
method public void callSessionConferenceExtendReceived(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
method public void callSessionConferenceExtended(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
method public void callSessionConferenceStateUpdated(android.telephony.ims.ImsConferenceState);
- method public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo);
- method public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo);
+ method @Deprecated public void callSessionHandover(int, int, android.telephony.ims.ImsReasonInfo);
+ method @Deprecated public void callSessionHandoverFailed(int, int, android.telephony.ims.ImsReasonInfo);
method public void callSessionHeld(android.telephony.ims.ImsCallProfile);
method public void callSessionHoldFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionHoldReceived(android.telephony.ims.ImsCallProfile);
@@ -3195,7 +3229,7 @@ package android.telephony.ims {
method public void callSessionInitiatedFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionInviteParticipantsRequestDelivered();
method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo);
- method public void callSessionMayHandover(int, int);
+ method @Deprecated public void callSessionMayHandover(int, int);
method public void callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase);
method public void callSessionMergeFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
@@ -3217,6 +3251,9 @@ package android.telephony.ims {
method public void callSessionUpdateReceived(android.telephony.ims.ImsCallProfile);
method public void callSessionUpdated(android.telephony.ims.ImsCallProfile);
method public void callSessionUssdMessageReceived(int, String);
+ method public void onHandover(int, int, @Nullable android.telephony.ims.ImsReasonInfo);
+ method public void onHandoverFailed(int, int, @NonNull android.telephony.ims.ImsReasonInfo);
+ method public void onMayHandover(int, int);
}
public final class ImsConferenceState implements android.os.Parcelable {
@@ -3248,10 +3285,6 @@ package android.telephony.ims {
ctor public ImsException(@Nullable String);
ctor public ImsException(@Nullable String, int);
ctor public ImsException(@Nullable String, int, @Nullable Throwable);
- method public int getCode();
- field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1
- field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0
- field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2
}
public final class ImsExternalCallState implements android.os.Parcelable {
@@ -3274,26 +3307,19 @@ package android.telephony.ims {
method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int);
method @NonNull public android.telephony.ims.ImsRcsManager getImsRcsManager(int);
field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION";
+ field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR";
+ field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
+ field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE";
}
public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
- method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiModeSetting();
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiRoamingModeSetting();
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isAdvancedCallingSettingEnabled();
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isAvailable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException;
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isTtyOverVolteEnabled();
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isVoWiFiRoamingSettingEnabled();
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isVoWiFiSettingEnabled();
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isVtSettingEnabled();
method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException;
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(int);
@@ -3303,16 +3329,6 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean);
method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback);
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback);
- field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1
- field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0
- field public static final int WIFI_MODE_WIFI_PREFERRED = 2; // 0x2
- }
-
- public static class ImsMmTelManager.CapabilityCallback {
- ctor public ImsMmTelManager.CapabilityCallback();
- method public void onCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities);
}
@Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback {
@@ -3572,7 +3588,27 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean);
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback);
+ field public static final int KEY_1X_EPDG_TIMER_SEC = 64; // 0x40
+ field public static final int KEY_1X_THRESHOLD = 59; // 0x3b
+ field public static final int KEY_AMR_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 50; // 0x32
+ field public static final int KEY_AMR_CODEC_MODE_SET_VALUES = 0; // 0x0
+ field public static final int KEY_AMR_DEFAULT_ENCODING_MODE = 53; // 0x35
+ field public static final int KEY_AMR_OCTET_ALIGNED_PAYLOAD_TYPE = 49; // 0x31
+ field public static final int KEY_AMR_WB_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 48; // 0x30
+ field public static final int KEY_AMR_WB_CODEC_MODE_SET_VALUES = 1; // 0x1
+ field public static final int KEY_AMR_WB_OCTET_ALIGNED_PAYLOAD_TYPE = 47; // 0x2f
+ field public static final int KEY_DTMF_NB_PAYLOAD_TYPE = 52; // 0x34
+ field public static final int KEY_DTMF_WB_PAYLOAD_TYPE = 51; // 0x33
field public static final int KEY_EAB_PROVISIONING_STATUS = 25; // 0x19
+ field public static final int KEY_ENABLE_SILENT_REDIAL = 6; // 0x6
+ field public static final int KEY_LOCAL_BREAKOUT_PCSCF_ADDRESS = 31; // 0x1f
+ field public static final int KEY_LTE_EPDG_TIMER_SEC = 62; // 0x3e
+ field public static final int KEY_LTE_THRESHOLD_1 = 56; // 0x38
+ field public static final int KEY_LTE_THRESHOLD_2 = 57; // 0x39
+ field public static final int KEY_LTE_THRESHOLD_3 = 58; // 0x3a
+ field public static final int KEY_MINIMUM_SIP_SESSION_EXPIRATION_TIMER_SEC = 3; // 0x3
+ field public static final int KEY_MOBILE_DATA_ENABLED = 29; // 0x1d
+ field public static final int KEY_MULTIENDPOINT_ENABLED = 65; // 0x41
field public static final int KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC = 19; // 0x13
field public static final int KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC = 18; // 0x12
field public static final int KEY_RCS_CAPABILITIES_POLL_INTERVAL_SEC = 20; // 0x14
@@ -3582,16 +3618,52 @@ package android.telephony.ims {
field public static final int KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS = 21; // 0x15
field public static final int KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC = 16; // 0x10
field public static final int KEY_RCS_PUBLISH_TIMER_SEC = 15; // 0xf
+ field public static final int KEY_REGISTRATION_DOMAIN_NAME = 12; // 0xc
+ field public static final int KEY_REGISTRATION_RETRY_BASE_TIME_SEC = 33; // 0x21
+ field public static final int KEY_REGISTRATION_RETRY_MAX_TIME_SEC = 34; // 0x22
+ field public static final int KEY_RTP_SPEECH_END_PORT = 36; // 0x24
+ field public static final int KEY_RTP_SPEECH_START_PORT = 35; // 0x23
+ field public static final int KEY_RTT_ENABLED = 66; // 0x42
+ field public static final int KEY_SIP_ACK_RECEIPT_WAIT_TIME_MS = 43; // 0x2b
+ field public static final int KEY_SIP_ACK_RETRANSMIT_WAIT_TIME_MS = 44; // 0x2c
+ field public static final int KEY_SIP_INVITE_ACK_WAIT_TIME_MS = 38; // 0x26
+ field public static final int KEY_SIP_INVITE_CANCELLATION_TIMER_MS = 4; // 0x4
+ field public static final int KEY_SIP_INVITE_REQUEST_TRANSMIT_INTERVAL_MS = 37; // 0x25
+ field public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_INTERVAL_MS = 42; // 0x2a
+ field public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_WAIT_TIME_MS = 39; // 0x27
+ field public static final int KEY_SIP_KEEP_ALIVE_ENABLED = 32; // 0x20
+ field public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMISSION_WAIT_TIME_MS = 45; // 0x2d
+ field public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMIT_INTERVAL_MS = 40; // 0x28
+ field public static final int KEY_SIP_NON_INVITE_RESPONSE_RETRANSMISSION_WAIT_TIME_MS = 46; // 0x2e
+ field public static final int KEY_SIP_NON_INVITE_TRANSACTION_TIMEOUT_TIMER_MS = 41; // 0x29
+ field public static final int KEY_SIP_SESSION_TIMER_SEC = 2; // 0x2
+ field public static final int KEY_SMS_FORMAT = 13; // 0xd
+ field public static final int KEY_SMS_OVER_IP_ENABLED = 14; // 0xe
+ field public static final int KEY_SMS_PUBLIC_SERVICE_IDENTITY = 54; // 0x36
field public static final int KEY_T1_TIMER_VALUE_MS = 7; // 0x7
+ field public static final int KEY_T2_TIMER_VALUE_MS = 8; // 0x8
+ field public static final int KEY_TF_TIMER_VALUE_MS = 9; // 0x9
+ field public static final int KEY_TRANSITION_TO_LTE_DELAY_MS = 5; // 0x5
+ field public static final int KEY_USE_GZIP_FOR_LIST_SUBSCRIPTION = 24; // 0x18
+ field public static final int KEY_VIDEO_QUALITY = 55; // 0x37
+ field public static final int KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE = 28; // 0x1c
field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b
field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a
field public static final int KEY_VOLTE_PROVISIONING_STATUS = 10; // 0xa
+ field public static final int KEY_VOLTE_USER_OPT_IN_STATUS = 30; // 0x1e
field public static final int KEY_VT_PROVISIONING_STATUS = 11; // 0xb
+ field public static final int KEY_WIFI_EPDG_TIMER_SEC = 63; // 0x3f
+ field public static final int KEY_WIFI_THRESHOLD_A = 60; // 0x3c
+ field public static final int KEY_WIFI_THRESHOLD_B = 61; // 0x3d
field public static final int PROVISIONING_RESULT_UNKNOWN = -1; // 0xffffffff
field public static final int PROVISIONING_VALUE_DISABLED = 0; // 0x0
field public static final int PROVISIONING_VALUE_ENABLED = 1; // 0x1
+ field public static final int SMS_FORMAT_3GPP = 1; // 0x1
+ field public static final int SMS_FORMAT_3GPP2 = 0; // 0x0
field public static final String STRING_QUERY_RESULT_ERROR_GENERIC = "STRING_QUERY_RESULT_ERROR_GENERIC";
field public static final String STRING_QUERY_RESULT_ERROR_NOT_READY = "STRING_QUERY_RESULT_ERROR_NOT_READY";
+ field public static final int VIDEO_QUALITY_HIGH = 1; // 0x1
+ field public static final int VIDEO_QUALITY_LOW = 0; // 0x0
}
public static class ProvisioningManager.Callback {
@@ -3600,24 +3672,6 @@ package android.telephony.ims {
method public void onProvisioningStringChanged(int, @NonNull String);
}
- public interface RegistrationManager {
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
- method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
- field public static final int REGISTRATION_STATE_NOT_REGISTERED = 0; // 0x0
- field public static final int REGISTRATION_STATE_REGISTERED = 2; // 0x2
- field public static final int REGISTRATION_STATE_REGISTERING = 1; // 0x1
- }
-
- public static class RegistrationManager.RegistrationCallback {
- ctor public RegistrationManager.RegistrationCallback();
- method public void onRegistered(int);
- method public void onRegistering(int);
- method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo);
- method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo);
- }
-
}
package android.telephony.ims.feature {
@@ -3680,7 +3734,7 @@ package android.telephony.ims.feature {
method public void onFeatureReady();
method public void onFeatureRemoved();
method public boolean queryCapabilityConfiguration(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int);
- method public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus();
+ method @NonNull public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus();
method public void setUiTtyMode(int, @Nullable android.os.Message);
method @android.telephony.ims.feature.MmTelFeature.ProcessCallResult public int shouldProcessCall(@NonNull String[]);
field public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL";
@@ -3696,10 +3750,6 @@ package android.telephony.ims.feature {
method public final void addCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
method public final boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
method public final void removeCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int);
- field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8
- field public static final int CAPABILITY_TYPE_UT = 4; // 0x4
- field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2
- field public static final int CAPABILITY_TYPE_VOICE = 1; // 0x1
}
@IntDef(flag=true, value={android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MmTelFeature.MmTelCapabilities.MmTelCapability {
@@ -3883,6 +3933,7 @@ package android.telephony.ims.stub {
method public int transact(android.os.Bundle);
method public int updateCallBarring(int, int, String[]);
method public int updateCallBarringForServiceClass(int, int, String[], int);
+ method public int updateCallBarringWithPassword(int, int, @Nullable String[], int, @NonNull String);
method public int updateCallForward(int, int, String, int, int);
method public int updateCallWaiting(boolean, int);
method public int updateClip(boolean);
@@ -4084,138 +4135,10 @@ package android.util.proto {
method public void writeRawZigZag64(long);
}
- public final class ProtoOutputStream extends android.util.proto.ProtoStream {
- ctor public ProtoOutputStream();
- ctor public ProtoOutputStream(int);
- ctor public ProtoOutputStream(java.io.OutputStream);
- ctor public ProtoOutputStream(java.io.FileDescriptor);
- method public static int checkFieldId(long, long);
- method public void dump(String);
- method public void end(long);
- method @Deprecated public void endObject(long);
- method @Deprecated public void endRepeatedObject(long);
- method public void flush();
- method public byte[] getBytes();
- method public int getRawSize();
- method public static long makeFieldId(int, long);
- method public long start(long);
- method @Deprecated public long startObject(long);
- method @Deprecated public long startRepeatedObject(long);
- method public void write(long, double);
- method public void write(long, float);
- method public void write(long, int);
- method public void write(long, long);
- method public void write(long, boolean);
- method public void write(long, String);
- method public void write(long, byte[]);
- method @Deprecated public void writeBool(long, boolean);
- method @Deprecated public void writeBytes(long, byte[]);
- method @Deprecated public void writeDouble(long, double);
- method @Deprecated public void writeEnum(long, int);
- method @Deprecated public void writeFixed32(long, int);
- method @Deprecated public void writeFixed64(long, long);
- method @Deprecated public void writeFloat(long, float);
- method @Deprecated public void writeInt32(long, int);
- method @Deprecated public void writeInt64(long, long);
- method @Deprecated public void writeObject(long, byte[]);
- method @Deprecated public void writePackedBool(long, boolean[]);
- method @Deprecated public void writePackedDouble(long, double[]);
- method @Deprecated public void writePackedEnum(long, int[]);
- method @Deprecated public void writePackedFixed32(long, int[]);
- method @Deprecated public void writePackedFixed64(long, long[]);
- method @Deprecated public void writePackedFloat(long, float[]);
- method @Deprecated public void writePackedInt32(long, int[]);
- method @Deprecated public void writePackedInt64(long, long[]);
- method @Deprecated public void writePackedSFixed32(long, int[]);
- method @Deprecated public void writePackedSFixed64(long, long[]);
- method @Deprecated public void writePackedSInt32(long, int[]);
- method @Deprecated public void writePackedSInt64(long, long[]);
- method @Deprecated public void writePackedUInt32(long, int[]);
- method @Deprecated public void writePackedUInt64(long, long[]);
- method @Deprecated public void writeRepeatedBool(long, boolean);
- method @Deprecated public void writeRepeatedBytes(long, byte[]);
- method @Deprecated public void writeRepeatedDouble(long, double);
- method @Deprecated public void writeRepeatedEnum(long, int);
- method @Deprecated public void writeRepeatedFixed32(long, int);
- method @Deprecated public void writeRepeatedFixed64(long, long);
- method @Deprecated public void writeRepeatedFloat(long, float);
- method @Deprecated public void writeRepeatedInt32(long, int);
- method @Deprecated public void writeRepeatedInt64(long, long);
- method @Deprecated public void writeRepeatedObject(long, byte[]);
- method @Deprecated public void writeRepeatedSFixed32(long, int);
- method @Deprecated public void writeRepeatedSFixed64(long, long);
- method @Deprecated public void writeRepeatedSInt32(long, int);
- method @Deprecated public void writeRepeatedSInt64(long, long);
- method @Deprecated public void writeRepeatedString(long, String);
- method @Deprecated public void writeRepeatedUInt32(long, int);
- method @Deprecated public void writeRepeatedUInt64(long, long);
- method @Deprecated public void writeSFixed32(long, int);
- method @Deprecated public void writeSFixed64(long, long);
- method @Deprecated public void writeSInt32(long, int);
- method @Deprecated public void writeSInt64(long, long);
- method @Deprecated public void writeString(long, String);
- method public void writeTag(int, int);
- method @Deprecated public void writeUInt32(long, int);
- method @Deprecated public void writeUInt64(long, long);
- }
-
public class ProtoParseException extends java.lang.RuntimeException {
ctor public ProtoParseException(String);
}
- public abstract class ProtoStream {
- ctor public ProtoStream();
- method public static int convertObjectIdToOrdinal(int);
- method public static int getDepthFromToken(long);
- method public static String getFieldCountString(long);
- method public static String getFieldIdString(long);
- method public static String getFieldTypeString(long);
- method public static int getObjectIdFromToken(long);
- method public static int getOffsetFromToken(long);
- method public static boolean getRepeatedFromToken(long);
- method public static int getTagSizeFromToken(long);
- method public static String getWireTypeString(int);
- method public static long makeFieldId(int, long);
- method public static long makeToken(int, boolean, int, int, int);
- method public static String token2String(long);
- field public static final long FIELD_COUNT_MASK = 16492674416640L; // 0xf0000000000L
- field public static final long FIELD_COUNT_PACKED = 5497558138880L; // 0x50000000000L
- field public static final long FIELD_COUNT_REPEATED = 2199023255552L; // 0x20000000000L
- field public static final int FIELD_COUNT_SHIFT = 40; // 0x28
- field public static final long FIELD_COUNT_SINGLE = 1099511627776L; // 0x10000000000L
- field public static final long FIELD_COUNT_UNKNOWN = 0L; // 0x0L
- field public static final int FIELD_ID_MASK = -8; // 0xfffffff8
- field public static final int FIELD_ID_SHIFT = 3; // 0x3
- field public static final long FIELD_TYPE_BOOL = 34359738368L; // 0x800000000L
- field public static final long FIELD_TYPE_BYTES = 51539607552L; // 0xc00000000L
- field public static final long FIELD_TYPE_DOUBLE = 4294967296L; // 0x100000000L
- field public static final long FIELD_TYPE_ENUM = 60129542144L; // 0xe00000000L
- field public static final long FIELD_TYPE_FIXED32 = 30064771072L; // 0x700000000L
- field public static final long FIELD_TYPE_FIXED64 = 25769803776L; // 0x600000000L
- field public static final long FIELD_TYPE_FLOAT = 8589934592L; // 0x200000000L
- field public static final long FIELD_TYPE_INT32 = 21474836480L; // 0x500000000L
- field public static final long FIELD_TYPE_INT64 = 12884901888L; // 0x300000000L
- field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L
- field public static final long FIELD_TYPE_MESSAGE = 47244640256L; // 0xb00000000L
- field protected static final String[] FIELD_TYPE_NAMES;
- field public static final long FIELD_TYPE_SFIXED32 = 64424509440L; // 0xf00000000L
- field public static final long FIELD_TYPE_SFIXED64 = 68719476736L; // 0x1000000000L
- field public static final int FIELD_TYPE_SHIFT = 32; // 0x20
- field public static final long FIELD_TYPE_SINT32 = 73014444032L; // 0x1100000000L
- field public static final long FIELD_TYPE_SINT64 = 77309411328L; // 0x1200000000L
- field public static final long FIELD_TYPE_STRING = 38654705664L; // 0x900000000L
- field public static final long FIELD_TYPE_UINT32 = 55834574848L; // 0xd00000000L
- field public static final long FIELD_TYPE_UINT64 = 17179869184L; // 0x400000000L
- field public static final long FIELD_TYPE_UNKNOWN = 0L; // 0x0L
- field public static final int WIRE_TYPE_END_GROUP = 4; // 0x4
- field public static final int WIRE_TYPE_FIXED32 = 5; // 0x5
- field public static final int WIRE_TYPE_FIXED64 = 1; // 0x1
- field public static final int WIRE_TYPE_LENGTH_DELIMITED = 2; // 0x2
- field public static final int WIRE_TYPE_MASK = 7; // 0x7
- field public static final int WIRE_TYPE_START_GROUP = 3; // 0x3
- field public static final int WIRE_TYPE_VARINT = 0; // 0x0
- }
-
public class WireTypeMismatchException extends android.util.proto.ProtoParseException {
ctor public WireTypeMismatchException(String);
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 7d3cd28c22d6..6ff48eac6ca5 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -720,7 +720,18 @@ public class AppOpsManager {
/** @hide Capture the device's display contents and/or audio */
@UnsupportedAppUsage
public static final int OP_PROJECT_MEDIA = 46;
- /** @hide Activate a VPN connection without user intervention. */
+
+ /**
+ * Start (without additional user intervention) a VPN connection, as used by {@link
+ * android.net.VpnService} along with as Platform VPN connections, as used by {@link
+ * android.net.VpnManager}
+ *
+ * <p>This appop is granted to apps that have already been given user consent to start
+ * VpnService based VPN connections. As this is a superset of OP_ACTIVATE_PLATFORM_VPN, this
+ * appop also allows the starting of Platform VPNs.
+ *
+ * @hide
+ */
@UnsupportedAppUsage
public static final int OP_ACTIVATE_VPN = 47;
/** @hide Access the WallpaperManagerAPI to write wallpapers. */
@@ -840,10 +851,21 @@ public class AppOpsManager {
public static final int OP_READ_DEVICE_IDENTIFIERS = 89;
/** @hide Read location metadata from media */
public static final int OP_ACCESS_MEDIA_LOCATION = 90;
+ /**
+ * Start (without additional user intervention) a Platform VPN connection, as used by {@link
+ * android.net.VpnManager}
+ *
+ * <p>This appop is granted to apps that have already been given user consent to start Platform
+ * VPN connections. This appop is insufficient to start VpnService based VPNs (but the opposite
+ * is true).
+ *
+ * @hide
+ */
+ public static final int OP_ACTIVATE_PLATFORM_VPN = 91;
/** @hide */
@UnsupportedAppUsage
- public static final int _NUM_OP = 91;
+ public static final int _NUM_OP = 92;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1122,6 +1144,8 @@ public class AppOpsManager {
public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
/** @hide Read device identifiers */
public static final String OPSTR_READ_DEVICE_IDENTIFIERS = "android:read_device_identifiers";
+ /** @hide Start Platform VPN without user intervention */
+ public static final String OPSTR_ACTIVATE_PLATFORM_VPN = "android:activate_platform_vpn";
// Warning: If an permission is added here it also has to be added to
// com.android.packageinstaller.permission.utils.EventLogger
@@ -1285,6 +1309,7 @@ public class AppOpsManager {
OP_ACCESS_ACCESSIBILITY, // ACCESS_ACCESSIBILITY
OP_READ_DEVICE_IDENTIFIERS, // READ_DEVICE_IDENTIFIERS
OP_ACCESS_MEDIA_LOCATION, // ACCESS_MEDIA_LOCATION
+ OP_ACTIVATE_PLATFORM_VPN, // ACTIVATE_PLATFORM_VPN
};
/**
@@ -1382,6 +1407,7 @@ public class AppOpsManager {
OPSTR_ACCESS_ACCESSIBILITY,
OPSTR_READ_DEVICE_IDENTIFIERS,
OPSTR_ACCESS_MEDIA_LOCATION,
+ OPSTR_ACTIVATE_PLATFORM_VPN,
};
/**
@@ -1480,6 +1506,7 @@ public class AppOpsManager {
"ACCESS_ACCESSIBILITY",
"READ_DEVICE_IDENTIFIERS",
"ACCESS_MEDIA_LOCATION",
+ "ACTIVATE_PLATFORM_VPN"
};
/**
@@ -1579,6 +1606,7 @@ public class AppOpsManager {
null, // no permission for OP_ACCESS_ACCESSIBILITY
null, // no direct permission for OP_READ_DEVICE_IDENTIFIERS
Manifest.permission.ACCESS_MEDIA_LOCATION,
+ null, // no permission for OP_ACTIVATE_PLATFORM_VPN
};
/**
@@ -1678,6 +1706,7 @@ public class AppOpsManager {
null, // ACCESS_ACCESSIBILITY
null, // READ_DEVICE_IDENTIFIERS
null, // ACCESS_MEDIA_LOCATION
+ null, // ACTIVATE_PLATFORM_VPN
};
/**
@@ -1776,6 +1805,7 @@ public class AppOpsManager {
false, // ACCESS_ACCESSIBILITY
false, // READ_DEVICE_IDENTIFIERS
false, // ACCESS_MEDIA_LOCATION
+ false, // ACTIVATE_PLATFORM_VPN
};
/**
@@ -1873,6 +1903,7 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED, // ACCESS_ACCESSIBILITY
AppOpsManager.MODE_ERRORED, // READ_DEVICE_IDENTIFIERS
AppOpsManager.MODE_ALLOWED, // ALLOW_MEDIA_LOCATION
+ AppOpsManager.MODE_IGNORED, // ACTIVATE_PLATFORM_VPN
};
/**
@@ -1974,6 +2005,7 @@ public class AppOpsManager {
false, // ACCESS_ACCESSIBILITY
false, // READ_DEVICE_IDENTIFIERS
false, // ACCESS_MEDIA_LOCATION
+ false, // ACTIVATE_PLATFORM_VPN
};
/**
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 88976e182e6d..8e12a221b5f7 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -98,6 +98,7 @@ import android.media.session.MediaSessionManager;
import android.media.soundtrigger.SoundTriggerManager;
import android.media.tv.ITvInputManager;
import android.media.tv.TvInputManager;
+import android.net.ConnectivityDiagnosticsManager;
import android.net.ConnectivityManager;
import android.net.ConnectivityThread;
import android.net.EthernetManager;
@@ -369,6 +370,18 @@ final class SystemServiceRegistry {
return new IpSecManager(ctx, service);
}});
+ registerService(Context.CONNECTIVITY_DIAGNOSTICS_SERVICE,
+ ConnectivityDiagnosticsManager.class,
+ new CachedServiceFetcher<ConnectivityDiagnosticsManager>() {
+ @Override
+ public ConnectivityDiagnosticsManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ // ConnectivityDiagnosticsManager is backed by ConnectivityService
+ IBinder b = ServiceManager.getServiceOrThrow(Context.CONNECTIVITY_SERVICE);
+ IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
+ return new ConnectivityDiagnosticsManager(ctx, service);
+ }});
+
registerService(
Context.TEST_NETWORK_SERVICE,
TestNetworkManager.class,
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 1869c6fa7621..bd0a39c06b26 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1222,6 +1222,7 @@ public final class BluetoothAdapter {
if (mService != null) {
return mService.factoryReset();
}
+ Log.e(TAG, "factoryReset(): IBluetooth Service is null");
SystemProperties.set("persist.bluetooth.factoryreset", "true");
} catch (RemoteException e) {
Log.e(TAG, "", e);
@@ -1239,7 +1240,7 @@ public final class BluetoothAdapter {
*/
@UnsupportedAppUsage
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public @NonNull ParcelUuid[] getUuids() {
+ public @Nullable ParcelUuid[] getUuids() {
if (getState() != STATE_ON) {
return null;
}
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 024bb06098ab..ec63fd058b16 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -30,6 +30,7 @@ import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.CloseGuard;
import android.util.Log;
import java.lang.annotation.Retention;
@@ -50,10 +51,11 @@ import java.util.List;
* @hide
*/
@SystemApi
-public final class BluetoothPan implements BluetoothProfile {
+public final class BluetoothPan implements BluetoothProfile, AutoCloseable {
private static final String TAG = "BluetoothPan";
private static final boolean DBG = true;
private static final boolean VDBG = false;
+ private CloseGuard mCloseGuard;
/**
* Intent used to broadcast the change in connection state of the Pan
@@ -166,10 +168,15 @@ public final class BluetoothPan implements BluetoothProfile {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mContext = context;
mProfileConnector.connect(context, listener);
+ mCloseGuard = new CloseGuard();
+ mCloseGuard.open("close");
}
- @UnsupportedAppUsage
- /*package*/ void close() {
+ /**
+ * Closes the connection to the service and unregisters callbacks
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
+ public void close() {
if (VDBG) log("close()");
mProfileConnector.disconnect();
}
@@ -178,8 +185,11 @@ public final class BluetoothPan implements BluetoothProfile {
return mProfileConnector.getService();
}
-
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
protected void finalize() {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
close();
}
@@ -316,6 +326,7 @@ public final class BluetoothPan implements BluetoothProfile {
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothPan service = getService();
@@ -335,6 +346,7 @@ public final class BluetoothPan implements BluetoothProfile {
* {@inheritDoc}
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
public int getConnectionState(@Nullable BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
final IBluetoothPan service = getService();
@@ -355,6 +367,7 @@ public final class BluetoothPan implements BluetoothProfile {
*
* @param value is whether to enable or disable bluetooth tethering
*/
+ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public void setBluetoothTethering(boolean value) {
String pkgName = mContext.getOpPackageName();
if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName);
@@ -373,6 +386,7 @@ public final class BluetoothPan implements BluetoothProfile {
*
* @return true if tethering is on, false if not or some error occurred
*/
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
public boolean isTetheringOn() {
if (VDBG) log("isTetheringOn()");
final IBluetoothPan service = getService();
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 638e6de06be7..7538df8bbe5f 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -146,7 +146,7 @@ public interface BluetoothProfile {
*
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
int A2DP_SINK = 11;
/**
@@ -154,7 +154,7 @@ public interface BluetoothProfile {
*
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
int AVRCP_CONTROLLER = 12;
/**
@@ -169,6 +169,7 @@ public interface BluetoothProfile {
*
* @hide
*/
+ @SystemApi
int HEADSET_CLIENT = 16;
/**
@@ -176,6 +177,7 @@ public interface BluetoothProfile {
*
* @hide
*/
+ @SystemApi
int PBAP_CLIENT = 17;
/**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index cd4af968ebfc..725fd0531911 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3881,6 +3881,16 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve a {@link
+ * android.net.ConnectivityDiagnosticsManager} for performing network connectivity diagnostics
+ * as well as receiving network connectivity information from the system.
+ *
+ * @see #getSystemService(String)
+ * @see android.net.ConnectivityDiagnosticsManager
+ */
+ public static final String CONNECTIVITY_DIAGNOSTICS_SERVICE = "connectivity_diagnostics";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a {@link
* android.net.TestNetworkManager} for building TUNs and limited-use Networks
*
* @see #getSystemService(String)
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9c7bf1f7c996..9cba7aab3c87 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4011,6 +4011,7 @@ public class Intent implements Parcelable, Cloneable {
* <p>
* @see #EXTRA_SIM_STATE
* @see #EXTRA_SIM_LOCKED_REASON
+ * @see #EXTRA_REBROADCAST_ON_UNLOCK
*
* @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} or
* {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
@@ -4187,6 +4188,18 @@ public class Intent implements Parcelable, Cloneable {
public static final String SIM_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED";
/**
+ * The extra used with {@link #ACTION_SIM_STATE_CHANGED} for indicating whether this broadcast
+ * is a rebroadcast on unlock. Defaults to {@code false} if not specified.
+ *
+ * @hide
+ * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} or
+ * {@link #ACTION_SIM_APPLICATION_STATE_CHANGED}
+ */
+ @Deprecated
+ @SystemApi
+ public static final String EXTRA_REBROADCAST_ON_UNLOCK = "rebroadcastOnUnlock";
+
+ /**
* Broadcast Action: indicate that the phone service state has changed.
* The intent will have the following extra values:</p>
* <p>
diff --git a/core/java/android/debug/AdbManager.java b/core/java/android/debug/AdbManager.java
index ae3d79490c98..0a76bedcd66e 100644
--- a/core/java/android/debug/AdbManager.java
+++ b/core/java/android/debug/AdbManager.java
@@ -16,15 +16,17 @@
package android.debug;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.os.RemoteException;
/**
- * This class allows the control of ADB-related functions. Currently only ADB over USB is
- * supported, and none of the API is public.
- *
+ * This class allows the control of ADB-related functions.
* @hide
*/
+@SystemApi
@SystemService(Context.ADB_SERVICE)
public class AdbManager {
private static final String TAG = "AdbManager";
@@ -39,4 +41,33 @@ public class AdbManager {
mContext = context;
mService = service;
}
+
+ /**
+ * @return true if the device supports secure ADB over Wi-Fi.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING)
+ public boolean isAdbWifiSupported() {
+ try {
+ return mService.isAdbWifiSupported();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @return true if the device supports secure ADB over Wi-Fi and device pairing by
+ * QR code.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING)
+ public boolean isAdbWifiQrSupported() {
+ try {
+ return mService.isAdbWifiQrSupported();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/debug/IAdbManager.aidl b/core/java/android/debug/IAdbManager.aidl
index 79e0794fd9af..c48fc07791c0 100644
--- a/core/java/android/debug/IAdbManager.aidl
+++ b/core/java/android/debug/IAdbManager.aidl
@@ -41,4 +41,15 @@ interface IAdbManager {
* Clear all public keys installed for secure ADB debugging.
*/
void clearDebuggingKeys();
+
+ /**
+ * Returns true if device supports secure Adb over Wi-Fi.
+ */
+ boolean isAdbWifiSupported();
+
+ /**
+ * Returns true if device supports secure Adb over Wi-Fi and device pairing by
+ * QR code.
+ */
+ boolean isAdbWifiQrSupported();
}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 1142a07bc66c..2497ea9c7950 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -32,6 +32,7 @@ import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.security.identity.IdentityCredential;
import android.text.TextUtils;
import android.util.Log;
@@ -401,6 +402,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
super(mac);
}
+ public CryptoObject(@NonNull IdentityCredential credential) {
+ super(credential);
+ }
+
/**
* Get {@link Signature} object.
* @return {@link Signature} object or null if this doesn't contain one.
@@ -424,6 +429,14 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
public Mac getMac() {
return super.getMac();
}
+
+ /**
+ * Get {@link IdentityCredential} object.
+ * @return {@link IdentityCredential} object or null if this doesn't contain one.
+ */
+ public @Nullable IdentityCredential getIdentityCredential() {
+ return super.getIdentityCredential();
+ }
}
/**
diff --git a/core/java/android/hardware/biometrics/CryptoObject.java b/core/java/android/hardware/biometrics/CryptoObject.java
index 787dc6696cd3..0af18dfb0e3a 100644
--- a/core/java/android/hardware/biometrics/CryptoObject.java
+++ b/core/java/android/hardware/biometrics/CryptoObject.java
@@ -17,6 +17,7 @@
package android.hardware.biometrics;
import android.annotation.NonNull;
+import android.security.identity.IdentityCredential;
import android.security.keystore.AndroidKeyStoreProvider;
import java.security.Signature;
@@ -26,7 +27,8 @@ import javax.crypto.Mac;
/**
* A wrapper class for the crypto objects supported by BiometricPrompt and FingerprintManager.
- * Currently the framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
+ * Currently the framework supports {@link Signature}, {@link Cipher}, {@link Mac} and
+ * {@link IdentityCredential} objects.
* @hide
*/
public class CryptoObject {
@@ -44,6 +46,10 @@ public class CryptoObject {
mCrypto = mac;
}
+ public CryptoObject(@NonNull IdentityCredential credential) {
+ mCrypto = credential;
+ }
+
/**
* Get {@link Signature} object.
* @return {@link Signature} object or null if this doesn't contain one.
@@ -69,11 +75,23 @@ public class CryptoObject {
}
/**
+ * Get {@link IdentityCredential} object.
+ * @return {@link IdentityCredential} object or null if this doesn't contain one.
+ */
+ public IdentityCredential getIdentityCredential() {
+ return mCrypto instanceof IdentityCredential ? (IdentityCredential) mCrypto : null;
+ }
+
+ /**
* @hide
* @return the opId associated with this object or 0 if none
*/
public final long getOpId() {
- return mCrypto != null
- ? AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto) : 0;
+ if (mCrypto == null) {
+ return 0;
+ } else if (mCrypto instanceof IdentityCredential) {
+ return ((IdentityCredential) mCrypto).getCredstoreOperationHandle();
+ }
+ return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto);
}
};
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 315af32580aa..16f96888bb0a 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -44,6 +44,7 @@ import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.security.identity.IdentityCredential;
import android.util.Slog;
import java.security.Signature;
@@ -125,6 +126,10 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
super(mac);
}
+ public CryptoObject(@NonNull IdentityCredential credential) {
+ super(credential);
+ }
+
/**
* Get {@link Signature} object.
* @return {@link Signature} object or null if this doesn't contain one.
@@ -148,6 +153,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
public Mac getMac() {
return super.getMac();
}
+
+ /**
+ * Get {@link IdentityCredential} object.
+ * @return {@link IdentityCredential} object or null if this doesn't contain one.
+ */
+ public @Nullable IdentityCredential getIdentityCredential() {
+ return super.getIdentityCredential();
+ }
}
/**
diff --git a/core/java/android/net/CaptivePortalData.aidl b/core/java/android/net/CaptivePortalData.aidl
new file mode 100644
index 000000000000..1d57ee759136
--- /dev/null
+++ b/core/java/android/net/CaptivePortalData.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+@JavaOnlyStableParcelable parcelable CaptivePortalData;
diff --git a/core/java/android/net/CaptivePortalData.java b/core/java/android/net/CaptivePortalData.java
new file mode 100644
index 000000000000..1357803a6cb8
--- /dev/null
+++ b/core/java/android/net/CaptivePortalData.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Metadata sent by captive portals, see https://www.ietf.org/id/draft-ietf-capport-api-03.txt.
+ * @hide
+ */
+@SystemApi
+@TestApi
+public final class CaptivePortalData implements Parcelable {
+ private final long mRefreshTimeMillis;
+ @Nullable
+ private final Uri mUserPortalUrl;
+ @Nullable
+ private final Uri mVenueInfoUrl;
+ private final boolean mIsSessionExtendable;
+ private final long mByteLimit;
+ private final long mExpiryTimeMillis;
+ private final boolean mCaptive;
+
+ private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl,
+ boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive) {
+ mRefreshTimeMillis = refreshTimeMillis;
+ mUserPortalUrl = userPortalUrl;
+ mVenueInfoUrl = venueInfoUrl;
+ mIsSessionExtendable = isSessionExtendable;
+ mByteLimit = byteLimit;
+ mExpiryTimeMillis = expiryTimeMillis;
+ mCaptive = captive;
+ }
+
+ private CaptivePortalData(Parcel p) {
+ this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(),
+ p.readLong(), p.readLong(), p.readBoolean());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeLong(mRefreshTimeMillis);
+ dest.writeParcelable(mUserPortalUrl, 0);
+ dest.writeParcelable(mVenueInfoUrl, 0);
+ dest.writeBoolean(mIsSessionExtendable);
+ dest.writeLong(mByteLimit);
+ dest.writeLong(mExpiryTimeMillis);
+ dest.writeBoolean(mCaptive);
+ }
+
+ /**
+ * A builder to create new {@link CaptivePortalData}.
+ */
+ public static class Builder {
+ private long mRefreshTime;
+ private Uri mUserPortalUrl;
+ private Uri mVenueInfoUrl;
+ private boolean mIsSessionExtendable;
+ private long mBytesRemaining = -1;
+ private long mExpiryTime = -1;
+ private boolean mCaptive;
+
+ /**
+ * Create an empty builder.
+ */
+ public Builder() {}
+
+ /**
+ * Create a builder copying all data from existing {@link CaptivePortalData}.
+ */
+ public Builder(@Nullable CaptivePortalData data) {
+ if (data == null) return;
+ setRefreshTime(data.mRefreshTimeMillis)
+ .setUserPortalUrl(data.mUserPortalUrl)
+ .setVenueInfoUrl(data.mVenueInfoUrl)
+ .setSessionExtendable(data.mIsSessionExtendable)
+ .setBytesRemaining(data.mByteLimit)
+ .setExpiryTime(data.mExpiryTimeMillis)
+ .setCaptive(data.mCaptive);
+ }
+
+ /**
+ * Set the time at which data was last refreshed, as per {@link System#currentTimeMillis()}.
+ */
+ @NonNull
+ public Builder setRefreshTime(long refreshTime) {
+ mRefreshTime = refreshTime;
+ return this;
+ }
+
+ /**
+ * Set the URL to be used for users to login to the portal, if captive.
+ */
+ @NonNull
+ public Builder setUserPortalUrl(@Nullable Uri userPortalUrl) {
+ mUserPortalUrl = userPortalUrl;
+ return this;
+ }
+
+ /**
+ * Set the URL that can be used by users to view information about the network venue.
+ */
+ @NonNull
+ public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl) {
+ mVenueInfoUrl = venueInfoUrl;
+ return this;
+ }
+
+ /**
+ * Set whether the portal supports extending a user session on the portal URL page.
+ */
+ @NonNull
+ public Builder setSessionExtendable(boolean sessionExtendable) {
+ mIsSessionExtendable = sessionExtendable;
+ return this;
+ }
+
+ /**
+ * Set the number of bytes remaining on the network before the portal closes.
+ */
+ @NonNull
+ public Builder setBytesRemaining(long bytesRemaining) {
+ mBytesRemaining = bytesRemaining;
+ return this;
+ }
+
+ /**
+ * Set the time at the session will expire, as per {@link System#currentTimeMillis()}.
+ */
+ @NonNull
+ public Builder setExpiryTime(long expiryTime) {
+ mExpiryTime = expiryTime;
+ return this;
+ }
+
+ /**
+ * Set whether the network is captive (portal closed).
+ */
+ @NonNull
+ public Builder setCaptive(boolean captive) {
+ mCaptive = captive;
+ return this;
+ }
+
+ /**
+ * Create a new {@link CaptivePortalData}.
+ */
+ @NonNull
+ public CaptivePortalData build() {
+ return new CaptivePortalData(mRefreshTime, mUserPortalUrl, mVenueInfoUrl,
+ mIsSessionExtendable, mBytesRemaining, mExpiryTime, mCaptive);
+ }
+ }
+
+ /**
+ * Get the time at which data was last refreshed, as per {@link System#currentTimeMillis()}.
+ */
+ public long getRefreshTimeMillis() {
+ return mRefreshTimeMillis;
+ }
+
+ /**
+ * Get the URL to be used for users to login to the portal, or extend their session if
+ * {@link #isSessionExtendable()} is true.
+ */
+ @Nullable
+ public Uri getUserPortalUrl() {
+ return mUserPortalUrl;
+ }
+
+ /**
+ * Get the URL that can be used by users to view information about the network venue.
+ */
+ @Nullable
+ public Uri getVenueInfoUrl() {
+ return mVenueInfoUrl;
+ }
+
+ /**
+ * Indicates whether the user portal URL can be used to extend sessions, when the user is logged
+ * in and the session has a time or byte limit.
+ */
+ public boolean isSessionExtendable() {
+ return mIsSessionExtendable;
+ }
+
+ /**
+ * Get the remaining bytes on the captive portal session, at the time {@link CaptivePortalData}
+ * was refreshed. This may be different from the limit currently enforced by the portal.
+ * @return The byte limit, or -1 if not set.
+ */
+ public long getByteLimit() {
+ return mByteLimit;
+ }
+
+ /**
+ * Get the time at the session will expire, as per {@link System#currentTimeMillis()}.
+ * @return The expiry time, or -1 if unset.
+ */
+ public long getExpiryTimeMillis() {
+ return mExpiryTimeMillis;
+ }
+
+ /**
+ * Get whether the network is captive (portal closed).
+ */
+ public boolean isCaptive() {
+ return mCaptive;
+ }
+
+ @NonNull
+ public static final Creator<CaptivePortalData> CREATOR = new Creator<CaptivePortalData>() {
+ @Override
+ public CaptivePortalData createFromParcel(Parcel source) {
+ return new CaptivePortalData(source);
+ }
+
+ @Override
+ public CaptivePortalData[] newArray(int size) {
+ return new CaptivePortalData[size];
+ }
+ };
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRefreshTimeMillis, mUserPortalUrl, mVenueInfoUrl,
+ mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof CaptivePortalData)) return false;
+ final CaptivePortalData other = (CaptivePortalData) obj;
+ return mRefreshTimeMillis == other.mRefreshTimeMillis
+ && Objects.equals(mUserPortalUrl, other.mUserPortalUrl)
+ && Objects.equals(mVenueInfoUrl, other.mVenueInfoUrl)
+ && mIsSessionExtendable == other.mIsSessionExtendable
+ && mByteLimit == other.mByteLimit
+ && mExpiryTimeMillis == other.mExpiryTimeMillis
+ && mCaptive == other.mCaptive;
+ }
+
+ @Override
+ public String toString() {
+ return "CaptivePortalData {"
+ + "refreshTime: " + mRefreshTimeMillis
+ + ", userPortalUrl: " + mUserPortalUrl
+ + ", venueInfoUrl: " + mVenueInfoUrl
+ + ", isSessionExtendable: " + mIsSessionExtendable
+ + ", byteLimit: " + mByteLimit
+ + ", expiryTime: " + mExpiryTimeMillis
+ + ", captive: " + mCaptive
+ + "}";
+ }
+}
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.aidl b/core/java/android/net/ConnectivityDiagnosticsManager.aidl
new file mode 100644
index 000000000000..82ba0ca113c5
--- /dev/null
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.aidl
@@ -0,0 +1,21 @@
+/**
+ *
+ * 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.net;
+
+parcelable ConnectivityDiagnosticsManager.ConnectivityReport;
+parcelable ConnectivityDiagnosticsManager.DataStallReport; \ No newline at end of file
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
index 6afdb5ef1b16..a6f9b96269e1 100644
--- a/core/java/android/net/ConnectivityDiagnosticsManager.java
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -18,10 +18,18 @@ package android.net;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.PersistableBundle;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -47,38 +55,47 @@ import java.util.concurrent.Executor;
* </ul>
*/
public class ConnectivityDiagnosticsManager {
- public static final int DETECTION_METHOD_DNS_EVENTS = 1;
- public static final int DETECTION_METHOD_TCP_METRICS = 2;
+ private final Context mContext;
+ private final IConnectivityManager mService;
/** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(
- prefix = {"DETECTION_METHOD_"},
- value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS})
- public @interface DetectionMethod {}
+ public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) {
+ mContext = Preconditions.checkNotNull(context, "missing context");
+ mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
+ }
/** @hide */
- public ConnectivityDiagnosticsManager() {}
+ @VisibleForTesting
+ public static boolean persistableBundleEquals(
+ @Nullable PersistableBundle a, @Nullable PersistableBundle b) {
+ if (a == b) return true;
+ if (a == null || b == null) return false;
+ if (!Objects.equals(a.keySet(), b.keySet())) return false;
+ for (String key : a.keySet()) {
+ if (!Objects.equals(a.get(key), b.get(key))) return false;
+ }
+ return true;
+ }
/** Class that includes connectivity information for a specific Network at a specific time. */
- public static class ConnectivityReport {
+ public static final class ConnectivityReport implements Parcelable {
/** The Network for which this ConnectivityReport applied */
- @NonNull public final Network network;
+ @NonNull private final Network mNetwork;
/**
* The timestamp for the report. The timestamp is taken from {@link
* System#currentTimeMillis}.
*/
- public final long reportTimestamp;
+ private final long mReportTimestamp;
/** LinkProperties available on the Network at the reported timestamp */
- @NonNull public final LinkProperties linkProperties;
+ @NonNull private final LinkProperties mLinkProperties;
/** NetworkCapabilities available on the Network at the reported timestamp */
- @NonNull public final NetworkCapabilities networkCapabilities;
+ @NonNull private final NetworkCapabilities mNetworkCapabilities;
/** PersistableBundle that may contain additional info about the report */
- @NonNull public final PersistableBundle additionalInfo;
+ @NonNull private final PersistableBundle mAdditionalInfo;
/**
* Constructor for ConnectivityReport.
@@ -101,30 +118,148 @@ public class ConnectivityDiagnosticsManager {
@NonNull LinkProperties linkProperties,
@NonNull NetworkCapabilities networkCapabilities,
@NonNull PersistableBundle additionalInfo) {
- this.network = network;
- this.reportTimestamp = reportTimestamp;
- this.linkProperties = linkProperties;
- this.networkCapabilities = networkCapabilities;
- this.additionalInfo = additionalInfo;
+ mNetwork = network;
+ mReportTimestamp = reportTimestamp;
+ mLinkProperties = linkProperties;
+ mNetworkCapabilities = networkCapabilities;
+ mAdditionalInfo = additionalInfo;
+ }
+
+ /**
+ * Returns the Network for this ConnectivityReport.
+ *
+ * @return The Network for which this ConnectivityReport applied
+ */
+ @NonNull
+ public Network getNetwork() {
+ return mNetwork;
+ }
+
+ /**
+ * Returns the epoch timestamp (milliseconds) for when this report was taken.
+ *
+ * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}.
+ */
+ public long getReportTimestamp() {
+ return mReportTimestamp;
+ }
+
+ /**
+ * Returns the LinkProperties available when this report was taken.
+ *
+ * @return LinkProperties available on the Network at the reported timestamp
+ */
+ @NonNull
+ public LinkProperties getLinkProperties() {
+ return new LinkProperties(mLinkProperties);
}
+
+ /**
+ * Returns the NetworkCapabilities when this report was taken.
+ *
+ * @return NetworkCapabilities available on the Network at the reported timestamp
+ */
+ @NonNull
+ public NetworkCapabilities getNetworkCapabilities() {
+ return new NetworkCapabilities(mNetworkCapabilities);
+ }
+
+ /**
+ * Returns a PersistableBundle with additional info for this report.
+ *
+ * @return PersistableBundle that may contain additional info about the report
+ */
+ @NonNull
+ public PersistableBundle getAdditionalInfo() {
+ return new PersistableBundle(mAdditionalInfo);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ConnectivityReport)) return false;
+ final ConnectivityReport that = (ConnectivityReport) o;
+
+ // PersistableBundle is optimized to avoid unparcelling data unless fields are
+ // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over
+ // {@link PersistableBundle#kindofEquals}.
+ return mReportTimestamp == that.mReportTimestamp
+ && mNetwork.equals(that.mNetwork)
+ && mLinkProperties.equals(that.mLinkProperties)
+ && mNetworkCapabilities.equals(that.mNetworkCapabilities)
+ && persistableBundleEquals(mAdditionalInfo, that.mAdditionalInfo);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mNetwork,
+ mReportTimestamp,
+ mLinkProperties,
+ mNetworkCapabilities,
+ mAdditionalInfo);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mNetwork, flags);
+ dest.writeLong(mReportTimestamp);
+ dest.writeParcelable(mLinkProperties, flags);
+ dest.writeParcelable(mNetworkCapabilities, flags);
+ dest.writeParcelable(mAdditionalInfo, flags);
+ }
+
+ /** Implement the Parcelable interface */
+ public static final @NonNull Creator<ConnectivityReport> CREATOR =
+ new Creator<>() {
+ public ConnectivityReport createFromParcel(Parcel in) {
+ return new ConnectivityReport(
+ in.readParcelable(null),
+ in.readLong(),
+ in.readParcelable(null),
+ in.readParcelable(null),
+ in.readParcelable(null));
+ }
+
+ public ConnectivityReport[] newArray(int size) {
+ return new ConnectivityReport[size];
+ }
+ };
}
/** Class that includes information for a suspected data stall on a specific Network */
- public static class DataStallReport {
+ public static final class DataStallReport implements Parcelable {
+ public static final int DETECTION_METHOD_DNS_EVENTS = 1;
+ public static final int DETECTION_METHOD_TCP_METRICS = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(
+ prefix = {"DETECTION_METHOD_"},
+ value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS})
+ public @interface DetectionMethod {}
+
/** The Network for which this DataStallReport applied */
- @NonNull public final Network network;
+ @NonNull private final Network mNetwork;
/**
* The timestamp for the report. The timestamp is taken from {@link
* System#currentTimeMillis}.
*/
- public final long reportTimestamp;
+ private long mReportTimestamp;
/** The detection method used to identify the suspected data stall */
- @DetectionMethod public final int detectionMethod;
+ @DetectionMethod private final int mDetectionMethod;
/** PersistableBundle that may contain additional information on the suspected data stall */
- @NonNull public final PersistableBundle stallDetails;
+ @NonNull private final PersistableBundle mStallDetails;
/**
* Constructor for DataStallReport.
@@ -143,11 +278,101 @@ public class ConnectivityDiagnosticsManager {
long reportTimestamp,
@DetectionMethod int detectionMethod,
@NonNull PersistableBundle stallDetails) {
- this.network = network;
- this.reportTimestamp = reportTimestamp;
- this.detectionMethod = detectionMethod;
- this.stallDetails = stallDetails;
+ mNetwork = network;
+ mReportTimestamp = reportTimestamp;
+ mDetectionMethod = detectionMethod;
+ mStallDetails = stallDetails;
+ }
+
+ /**
+ * Returns the Network for this DataStallReport.
+ *
+ * @return The Network for which this DataStallReport applied
+ */
+ @NonNull
+ public Network getNetwork() {
+ return mNetwork;
+ }
+
+ /**
+ * Returns the epoch timestamp (milliseconds) for when this report was taken.
+ *
+ * @return The timestamp for the report. Taken from {@link System#currentTimeMillis}.
+ */
+ public long getReportTimestamp() {
+ return mReportTimestamp;
+ }
+
+ /**
+ * Returns the detection method used to identify this suspected data stall.
+ *
+ * @return The detection method used to identify the suspected data stall
+ */
+ public int getDetectionMethod() {
+ return mDetectionMethod;
+ }
+
+ /**
+ * Returns a PersistableBundle with additional info for this report.
+ *
+ * @return PersistableBundle that may contain additional information on the suspected data
+ * stall
+ */
+ @NonNull
+ public PersistableBundle getStallDetails() {
+ return new PersistableBundle(mStallDetails);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (!(o instanceof DataStallReport)) return false;
+ final DataStallReport that = (DataStallReport) o;
+
+ // PersistableBundle is optimized to avoid unparcelling data unless fields are
+ // referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over
+ // {@link PersistableBundle#kindofEquals}.
+ return mReportTimestamp == that.mReportTimestamp
+ && mDetectionMethod == that.mDetectionMethod
+ && mNetwork.equals(that.mNetwork)
+ && persistableBundleEquals(mStallDetails, that.mStallDetails);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNetwork, mReportTimestamp, mDetectionMethod, mStallDetails);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int describeContents() {
+ return 0;
}
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mNetwork, flags);
+ dest.writeLong(mReportTimestamp);
+ dest.writeInt(mDetectionMethod);
+ dest.writeParcelable(mStallDetails, flags);
+ }
+
+ /** Implement the Parcelable interface */
+ public static final @NonNull Creator<DataStallReport> CREATOR =
+ new Creator<DataStallReport>() {
+ public DataStallReport createFromParcel(Parcel in) {
+ return new DataStallReport(
+ in.readParcelable(null),
+ in.readLong(),
+ in.readInt(),
+ in.readParcelable(null));
+ }
+
+ public DataStallReport[] newArray(int size) {
+ return new DataStallReport[size];
+ }
+ };
}
/**
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 674c58d00dcd..11c1a9c32d8a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3169,24 +3169,25 @@ public class ConnectivityManager {
/**
* @hide
* Register a NetworkAgent with ConnectivityService.
- * @return NetID corresponding to NetworkAgent.
+ * @return Network corresponding to NetworkAgent.
*/
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
- NetworkCapabilities nc, int score, NetworkMisc misc) {
- return registerNetworkAgent(messenger, ni, lp, nc, score, misc, NetworkProvider.ID_NONE);
+ public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
+ NetworkCapabilities nc, int score, NetworkAgentConfig config) {
+ return registerNetworkAgent(messenger, ni, lp, nc, score, config, NetworkProvider.ID_NONE);
}
/**
* @hide
* Register a NetworkAgent with ConnectivityService.
- * @return NetID corresponding to NetworkAgent.
+ * @return Network corresponding to NetworkAgent.
*/
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
- NetworkCapabilities nc, int score, NetworkMisc misc, int providerId) {
+ public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
+ NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) {
+
try {
- return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc, providerId);
+ return mService.registerNetworkAgent(messenger, ni, lp, nc, score, config, providerId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index e6a0379ff629..186196bd31c7 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -20,9 +20,9 @@ import android.app.PendingIntent;
import android.net.ConnectionInfo;
import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
-import android.net.NetworkMisc;
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkState;
@@ -152,8 +152,9 @@ interface IConnectivityManager
void declareNetworkRequestUnfulfillable(in NetworkRequest request);
- int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
- in NetworkCapabilities nc, int score, in NetworkMisc misc, in int factorySerialNumber);
+ Network registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
+ in NetworkCapabilities nc, int score, in NetworkAgentConfig config,
+ in int factorySerialNumber);
NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
in Messenger messenger, int timeoutSec, in IBinder binder, int legacy);
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 2792c564988a..ec773ef4a1e2 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -70,6 +70,14 @@ public final class LinkProperties implements Parcelable {
private String mTcpBufferSizes;
private IpPrefix mNat64Prefix;
private boolean mWakeOnLanSupported;
+ private Uri mCaptivePortalApiUrl;
+ private CaptivePortalData mCaptivePortalData;
+
+ /**
+ * Indicates whether parceling should preserve fields that are set based on permissions of
+ * the process receiving the {@link LinkProperties}.
+ */
+ private final transient boolean mParcelSensitiveFields;
private static final int MIN_MTU = 68;
private static final int MIN_MTU_V6 = 1280;
@@ -174,6 +182,7 @@ public final class LinkProperties implements Parcelable {
* Constructs a new {@code LinkProperties} with default values.
*/
public LinkProperties() {
+ mParcelSensitiveFields = false;
}
/**
@@ -182,26 +191,32 @@ public final class LinkProperties implements Parcelable {
@SystemApi
@TestApi
public LinkProperties(@Nullable LinkProperties source) {
- if (source != null) {
- mIfaceName = source.mIfaceName;
- mLinkAddresses.addAll(source.mLinkAddresses);
- mDnses.addAll(source.mDnses);
- mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses);
- mUsePrivateDns = source.mUsePrivateDns;
- mPrivateDnsServerName = source.mPrivateDnsServerName;
- mPcscfs.addAll(source.mPcscfs);
- mDomains = source.mDomains;
- mRoutes.addAll(source.mRoutes);
- mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy);
- for (LinkProperties l: source.mStackedLinks.values()) {
- addStackedLink(l);
- }
- setMtu(source.mMtu);
- setDhcpServerAddress(source.getDhcpServerAddress());
- mTcpBufferSizes = source.mTcpBufferSizes;
- mNat64Prefix = source.mNat64Prefix;
- mWakeOnLanSupported = source.mWakeOnLanSupported;
+ this(source, false /* parcelSensitiveFields */);
+ }
+
+ private LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) {
+ mParcelSensitiveFields = parcelSensitiveFields;
+ if (source == null) return;
+ mIfaceName = source.mIfaceName;
+ mLinkAddresses.addAll(source.mLinkAddresses);
+ mDnses.addAll(source.mDnses);
+ mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses);
+ mUsePrivateDns = source.mUsePrivateDns;
+ mPrivateDnsServerName = source.mPrivateDnsServerName;
+ mPcscfs.addAll(source.mPcscfs);
+ mDomains = source.mDomains;
+ mRoutes.addAll(source.mRoutes);
+ mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy);
+ for (LinkProperties l: source.mStackedLinks.values()) {
+ addStackedLink(l);
}
+ setMtu(source.mMtu);
+ setDhcpServerAddress(source.getDhcpServerAddress());
+ mTcpBufferSizes = source.mTcpBufferSizes;
+ mNat64Prefix = source.mNat64Prefix;
+ mWakeOnLanSupported = source.mWakeOnLanSupported;
+ mCaptivePortalApiUrl = source.mCaptivePortalApiUrl;
+ mCaptivePortalData = source.mCaptivePortalData;
}
/**
@@ -860,6 +875,11 @@ public final class LinkProperties implements Parcelable {
* Clears this object to its initial state.
*/
public void clear() {
+ if (mParcelSensitiveFields) {
+ throw new UnsupportedOperationException(
+ "Cannot clear LinkProperties when parcelSensitiveFields is set");
+ }
+
mIfaceName = null;
mLinkAddresses.clear();
mDnses.clear();
@@ -875,6 +895,8 @@ public final class LinkProperties implements Parcelable {
mTcpBufferSizes = null;
mNat64Prefix = null;
mWakeOnLanSupported = false;
+ mCaptivePortalApiUrl = null;
+ mCaptivePortalData = null;
}
/**
@@ -945,6 +967,14 @@ public final class LinkProperties implements Parcelable {
resultJoiner.add(mDhcpServerAddress.toString());
}
+ if (mCaptivePortalApiUrl != null) {
+ resultJoiner.add("CaptivePortalApiUrl: " + mCaptivePortalApiUrl);
+ }
+
+ if (mCaptivePortalData != null) {
+ resultJoiner.add("CaptivePortalData: " + mCaptivePortalData);
+ }
+
if (mTcpBufferSizes != null) {
resultJoiner.add("TcpBufferSizes:");
resultJoiner.add(mTcpBufferSizes);
@@ -1479,6 +1509,28 @@ public final class LinkProperties implements Parcelable {
}
/**
+ * Compares this {@code LinkProperties}'s CaptivePortalApiUrl against the target.
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
+ */
+ public boolean isIdenticalCaptivePortalApiUrl(LinkProperties target) {
+ return Objects.equals(mCaptivePortalApiUrl, target.mCaptivePortalApiUrl);
+ }
+
+ /**
+ * Compares this {@code LinkProperties}'s CaptivePortalData against the target.
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
+ */
+ public boolean isIdenticalCaptivePortalData(LinkProperties target) {
+ return Objects.equals(mCaptivePortalData, target.mCaptivePortalData);
+ }
+
+ /**
* Set whether the network interface supports WakeOnLAN
*
* @param supported WakeOnLAN supported value
@@ -1499,6 +1551,73 @@ public final class LinkProperties implements Parcelable {
}
/**
+ * Set the URL of the captive portal API endpoint to get more information about the network.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public void setCaptivePortalApiUrl(@Nullable Uri url) {
+ mCaptivePortalApiUrl = url;
+ }
+
+ /**
+ * Get the URL of the captive portal API endpoint to get more information about the network.
+ *
+ * <p>This is null unless the application has
+ * {@link android.Manifest.permission.NETWORK_SETTINGS} or
+ * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions, and the network provided
+ * the URL.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @Nullable
+ public Uri getCaptivePortalApiUrl() {
+ return mCaptivePortalApiUrl;
+ }
+
+ /**
+ * Set the CaptivePortalData obtained from the captive portal API (RFC7710bis).
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public void setCaptivePortalData(@Nullable CaptivePortalData data) {
+ mCaptivePortalData = data;
+ }
+
+ /**
+ * Get the CaptivePortalData obtained from the captive portal API (RFC7710bis).
+ *
+ * <p>This is null unless the application has
+ * {@link android.Manifest.permission.NETWORK_SETTINGS} or
+ * {@link NetworkStack#PERMISSION_MAINLINE_NETWORK_STACK} permissions.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @Nullable
+ public CaptivePortalData getCaptivePortalData() {
+ return mCaptivePortalData;
+ }
+
+ /**
+ * Create a copy of this {@link LinkProperties} that will preserve fields that were set
+ * based on the permissions of the process that received this {@link LinkProperties}.
+ *
+ * <p>By default {@link LinkProperties} does not preserve such fields during parceling, as
+ * they should not be shared outside of the process that receives them without appropriate
+ * checks.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ @NonNull
+ public LinkProperties makeSensitiveFieldsParcelingCopy() {
+ return new LinkProperties(this, true /* parcelSensitiveFields */);
+ }
+
+ /**
* Compares this {@code LinkProperties} instance against the target
* LinkProperties in {@code obj}. Two LinkPropertieses are equal if
* all their fields are equal in values.
@@ -1537,7 +1656,9 @@ public final class LinkProperties implements Parcelable {
&& isIdenticalMtu(target)
&& isIdenticalTcpBufferSizes(target)
&& isIdenticalNat64Prefix(target)
- && isIdenticalWakeOnLan(target);
+ && isIdenticalWakeOnLan(target)
+ && isIdenticalCaptivePortalApiUrl(target)
+ && isIdenticalCaptivePortalData(target);
}
/**
@@ -1655,7 +1776,8 @@ public final class LinkProperties implements Parcelable {
+ mPcscfs.size() * 67
+ ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode())
+ Objects.hash(mNat64Prefix)
- + (mWakeOnLanSupported ? 71 : 0);
+ + (mWakeOnLanSupported ? 71 : 0)
+ + Objects.hash(mCaptivePortalApiUrl, mCaptivePortalData);
}
/**
@@ -1694,6 +1816,8 @@ public final class LinkProperties implements Parcelable {
dest.writeList(stackedLinks);
dest.writeBoolean(mWakeOnLanSupported);
+ dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalApiUrl : null, 0);
+ dest.writeParcelable(mParcelSensitiveFields ? mCaptivePortalData : null, 0);
}
private static void writeAddresses(@NonNull Parcel dest, @NonNull List<InetAddress> list) {
@@ -1785,6 +1909,9 @@ public final class LinkProperties implements Parcelable {
netProp.addStackedLink(stackedLink);
}
netProp.setWakeOnLanSupported(in.readBoolean());
+
+ netProp.setCaptivePortalApiUrl(in.readParcelable(null));
+ netProp.setCaptivePortalData(in.readParcelable(null));
return netProp;
}
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 5f6cc6eced5d..7316dfa5d1c6 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -43,11 +43,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
*
* @hide
*/
-public abstract class NetworkAgent extends Handler {
- // Guaranteed to be valid (not NETID_UNSET), otherwise registerNetworkAgent() would have thrown
- // an exception.
- public final int netId;
+public abstract class NetworkAgent {
+ public final Network network;
+ private final Handler mHandler;
private volatile AsyncChannel mAsyncChannel;
private final String LOG_TAG;
private static final boolean DBG = true;
@@ -222,8 +221,8 @@ public abstract class NetworkAgent extends Handler {
this(looper, context, logTag, ni, nc, lp, score, null, NetworkProvider.ID_NONE);
}
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
- NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
- this(looper, context, logTag, ni, nc, lp, score, misc, NetworkProvider.ID_NONE);
+ NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config) {
+ this(looper, context, logTag, ni, nc, lp, score, config, NetworkProvider.ID_NONE);
}
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
@@ -232,9 +231,9 @@ public abstract class NetworkAgent extends Handler {
}
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
- NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc,
+ NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config,
int providerId) {
- super(looper);
+ mHandler = new NetworkAgentHandler(looper);
LOG_TAG = logTag;
mContext = context;
mProviderId = providerId;
@@ -245,116 +244,124 @@ public abstract class NetworkAgent extends Handler {
if (VDBG) log("Registering NetworkAgent");
ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
- netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
- new LinkProperties(lp), new NetworkCapabilities(nc), score, misc, providerId);
+ network = cm.registerNetworkAgent(new Messenger(mHandler), new NetworkInfo(ni),
+ new LinkProperties(lp), new NetworkCapabilities(nc), score, config,
+ providerId);
}
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
- if (mAsyncChannel != null) {
- log("Received new connection while already connected!");
- } else {
- if (VDBG) log("NetworkAgent fully connected");
- AsyncChannel ac = new AsyncChannel();
- ac.connected(null, this, msg.replyTo);
- ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
- AsyncChannel.STATUS_SUCCESSFUL);
- synchronized (mPreConnectedQueue) {
- mAsyncChannel = ac;
- for (Message m : mPreConnectedQueue) {
- ac.sendMessage(m);
+ private class NetworkAgentHandler extends Handler {
+ NetworkAgentHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
+ if (mAsyncChannel != null) {
+ log("Received new connection while already connected!");
+ } else {
+ if (VDBG) log("NetworkAgent fully connected");
+ AsyncChannel ac = new AsyncChannel();
+ ac.connected(null, this, msg.replyTo);
+ ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
+ AsyncChannel.STATUS_SUCCESSFUL);
+ synchronized (mPreConnectedQueue) {
+ mAsyncChannel = ac;
+ for (Message m : mPreConnectedQueue) {
+ ac.sendMessage(m);
+ }
+ mPreConnectedQueue.clear();
}
- mPreConnectedQueue.clear();
}
+ break;
}
- break;
- }
- case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
- if (VDBG) log("CMD_CHANNEL_DISCONNECT");
- if (mAsyncChannel != null) mAsyncChannel.disconnect();
- break;
- }
- case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
- if (DBG) log("NetworkAgent channel lost");
- // let the client know CS is done with us.
- unwanted();
- synchronized (mPreConnectedQueue) {
- mAsyncChannel = null;
+ case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
+ if (VDBG) log("CMD_CHANNEL_DISCONNECT");
+ if (mAsyncChannel != null) mAsyncChannel.disconnect();
+ break;
}
- break;
- }
- case CMD_SUSPECT_BAD: {
- log("Unhandled Message " + msg);
- break;
- }
- case CMD_REQUEST_BANDWIDTH_UPDATE: {
- long currentTimeMs = System.currentTimeMillis();
- if (VDBG) {
- log("CMD_REQUEST_BANDWIDTH_UPDATE request received.");
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+ if (DBG) log("NetworkAgent channel lost");
+ // let the client know CS is done with us.
+ unwanted();
+ synchronized (mPreConnectedQueue) {
+ mAsyncChannel = null;
+ }
+ break;
}
- if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) {
- mPollLceScheduled = false;
- if (mPollLcePending.getAndSet(true) == false) {
- pollLceData();
+ case CMD_SUSPECT_BAD: {
+ log("Unhandled Message " + msg);
+ break;
+ }
+ case CMD_REQUEST_BANDWIDTH_UPDATE: {
+ long currentTimeMs = System.currentTimeMillis();
+ if (VDBG) {
+ log("CMD_REQUEST_BANDWIDTH_UPDATE request received.");
}
- } else {
- // deliver the request at a later time rather than discard it completely.
- if (!mPollLceScheduled) {
- long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS -
- currentTimeMs + 1;
- mPollLceScheduled = sendEmptyMessageDelayed(
- CMD_REQUEST_BANDWIDTH_UPDATE, waitTime);
+ if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) {
+ mPollLceScheduled = false;
+ if (!mPollLcePending.getAndSet(true)) {
+ pollLceData();
+ }
+ } else {
+ // deliver the request at a later time rather than discard it completely.
+ if (!mPollLceScheduled) {
+ long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS
+ - currentTimeMs + 1;
+ mPollLceScheduled = sendEmptyMessageDelayed(
+ CMD_REQUEST_BANDWIDTH_UPDATE, waitTime);
+ }
}
+ break;
}
- break;
- }
- case CMD_REPORT_NETWORK_STATUS: {
- String redirectUrl = ((Bundle)msg.obj).getString(REDIRECT_URL_KEY);
- if (VDBG) {
- log("CMD_REPORT_NETWORK_STATUS(" +
- (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ") + redirectUrl);
+ case CMD_REPORT_NETWORK_STATUS: {
+ String redirectUrl = ((Bundle) msg.obj).getString(REDIRECT_URL_KEY);
+ if (VDBG) {
+ log("CMD_REPORT_NETWORK_STATUS("
+ + (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ")
+ + redirectUrl);
+ }
+ networkStatus(msg.arg1, redirectUrl);
+ break;
+ }
+ case CMD_SAVE_ACCEPT_UNVALIDATED: {
+ saveAcceptUnvalidated(msg.arg1 != 0);
+ break;
+ }
+ case CMD_START_SOCKET_KEEPALIVE: {
+ startSocketKeepalive(msg);
+ break;
+ }
+ case CMD_STOP_SOCKET_KEEPALIVE: {
+ stopSocketKeepalive(msg);
+ break;
}
- networkStatus(msg.arg1, redirectUrl);
- break;
- }
- case CMD_SAVE_ACCEPT_UNVALIDATED: {
- saveAcceptUnvalidated(msg.arg1 != 0);
- break;
- }
- case CMD_START_SOCKET_KEEPALIVE: {
- startSocketKeepalive(msg);
- break;
- }
- case CMD_STOP_SOCKET_KEEPALIVE: {
- stopSocketKeepalive(msg);
- break;
- }
- case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: {
- ArrayList<Integer> thresholds =
- ((Bundle) msg.obj).getIntegerArrayList("thresholds");
- // TODO: Change signal strength thresholds API to use an ArrayList<Integer>
- // rather than convert to int[].
- int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0];
- for (int i = 0; i < intThresholds.length; i++) {
- intThresholds[i] = thresholds.get(i);
+ case CMD_SET_SIGNAL_STRENGTH_THRESHOLDS: {
+ ArrayList<Integer> thresholds =
+ ((Bundle) msg.obj).getIntegerArrayList("thresholds");
+ // TODO: Change signal strength thresholds API to use an ArrayList<Integer>
+ // rather than convert to int[].
+ int[] intThresholds = new int[(thresholds != null) ? thresholds.size() : 0];
+ for (int i = 0; i < intThresholds.length; i++) {
+ intThresholds[i] = thresholds.get(i);
+ }
+ setSignalStrengthThresholds(intThresholds);
+ break;
+ }
+ case CMD_PREVENT_AUTOMATIC_RECONNECT: {
+ preventAutomaticReconnect();
+ break;
+ }
+ case CMD_ADD_KEEPALIVE_PACKET_FILTER: {
+ addKeepalivePacketFilter(msg);
+ break;
+ }
+ case CMD_REMOVE_KEEPALIVE_PACKET_FILTER: {
+ removeKeepalivePacketFilter(msg);
+ break;
}
- setSignalStrengthThresholds(intThresholds);
- break;
- }
- case CMD_PREVENT_AUTOMATIC_RECONNECT: {
- preventAutomaticReconnect();
- break;
- }
- case CMD_ADD_KEEPALIVE_PACKET_FILTER: {
- addKeepalivePacketFilter(msg);
- break;
- }
- case CMD_REMOVE_KEEPALIVE_PACKET_FILTER: {
- removeKeepalivePacketFilter(msg);
- break;
}
}
}
diff --git a/core/java/android/net/NetworkMisc.aidl b/core/java/android/net/NetworkAgentConfig.aidl
index c65583fb530a..cb70bdd31260 100644
--- a/core/java/android/net/NetworkMisc.aidl
+++ b/core/java/android/net/NetworkAgentConfig.aidl
@@ -16,4 +16,4 @@
package android.net;
-parcelable NetworkMisc;
+parcelable NetworkAgentConfig;
diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java
new file mode 100644
index 000000000000..abc6b67efb11
--- /dev/null
+++ b/core/java/android/net/NetworkAgentConfig.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * Allows a network transport to provide the system with policy and configuration information about
+ * a particular network when registering a {@link NetworkAgent}. This information cannot change once
+ * the agent is registered.
+ *
+ * @hide
+ */
+@SystemApi
+public final class NetworkAgentConfig implements Parcelable {
+
+ /**
+ * If the {@link Network} is a VPN, whether apps are allowed to bypass the
+ * VPN. This is set by a {@link VpnService} and used by
+ * {@link ConnectivityManager} when creating a VPN.
+ *
+ * @hide
+ */
+ public boolean allowBypass;
+
+ /**
+ * Set if the network was manually/explicitly connected to by the user either from settings
+ * or a 3rd party app. For example, turning on cell data is not explicit but tapping on a wifi
+ * ap in the wifi settings to trigger a connection is explicit. A 3rd party app asking to
+ * connect to a particular access point is also explicit, though this may change in the future
+ * as we want apps to use the multinetwork apis.
+ *
+ * @hide
+ */
+ public boolean explicitlySelected;
+
+ /**
+ * Set if the user desires to use this network even if it is unvalidated. This field has meaning
+ * only if {@link explicitlySelected} is true. If it is, this field must also be set to the
+ * appropriate value based on previous user choice.
+ *
+ * @hide
+ */
+ public boolean acceptUnvalidated;
+
+ /**
+ * Whether the user explicitly set that this network should be validated even if presence of
+ * only partial internet connectivity.
+ *
+ * @hide
+ */
+ public boolean acceptPartialConnectivity;
+
+ /**
+ * Set to avoid surfacing the "Sign in to network" notification.
+ * if carrier receivers/apps are registered to handle the carrier-specific provisioning
+ * procedure, a carrier specific provisioning notification will be placed.
+ * only one notification should be displayed. This field is set based on
+ * which notification should be used for provisioning.
+ *
+ * @hide
+ */
+ public boolean provisioningNotificationDisabled;
+
+ /**
+ *
+ * @return whether the sign in to network notification is enabled by this configuration.
+ */
+ public boolean isProvisioningNotificationEnabled() {
+ return !provisioningNotificationDisabled;
+ }
+
+ /**
+ * For mobile networks, this is the subscriber ID (such as IMSI).
+ *
+ * @hide
+ */
+ public String subscriberId;
+
+ /**
+ * @return the subscriber ID, or null if none.
+ */
+ @Nullable
+ public String getSubscriberId() {
+ return subscriberId;
+ }
+
+ /**
+ * Set to skip 464xlat. This means the device will treat the network as IPv6-only and
+ * will not attempt to detect a NAT64 via RFC 7050 DNS lookups.
+ *
+ * @hide
+ */
+ public boolean skip464xlat;
+
+ /**
+ * @return whether NAT64 prefix detection is enabled.
+ */
+ public boolean isNat64DetectionEnabled() {
+ return !skip464xlat;
+ }
+
+ /**
+ * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network.
+ * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode.
+ *
+ * @hide
+ */
+ public boolean hasShownBroken;
+
+ /** @hide */
+ public NetworkAgentConfig() {
+ }
+
+ /** @hide */
+ public NetworkAgentConfig(@Nullable NetworkAgentConfig nac) {
+ if (nac != null) {
+ allowBypass = nac.allowBypass;
+ explicitlySelected = nac.explicitlySelected;
+ acceptUnvalidated = nac.acceptUnvalidated;
+ subscriberId = nac.subscriberId;
+ provisioningNotificationDisabled = nac.provisioningNotificationDisabled;
+ skip464xlat = nac.skip464xlat;
+ }
+ }
+
+ /**
+ * Builder class to facilitate constructing {@link NetworkAgentConfig} objects.
+ */
+ public static class Builder {
+ private final NetworkAgentConfig mConfig = new NetworkAgentConfig();
+
+ /**
+ * Sets the subscriber ID for this network.
+ *
+ * @return this builder, to facilitate chaining.
+ */
+ @NonNull
+ public Builder setSubscriberId(@Nullable String subscriberId) {
+ mConfig.subscriberId = subscriberId;
+ return this;
+ }
+
+ /**
+ * Disables active detection of NAT64 (e.g., via RFC 7050 DNS lookups). Used to save power
+ * and reduce idle traffic on networks that are known to be IPv6-only without a NAT64.
+ *
+ * @return this builder, to facilitate chaining.
+ */
+ @NonNull
+ public Builder disableNat64Detection() {
+ mConfig.skip464xlat = true;
+ return this;
+ }
+
+ /**
+ * Disables the "Sign in to network" notification. Used if the network transport will
+ * perform its own carrier-specific provisioning procedure.
+ *
+ * @return this builder, to facilitate chaining.
+ */
+ @NonNull
+ public Builder disableProvisioningNotification() {
+ mConfig.provisioningNotificationDisabled = true;
+ return this;
+ }
+
+ /**
+ * Returns the constructed {@link NetworkAgentConfig} object.
+ */
+ @NonNull
+ public NetworkAgentConfig build() {
+ return mConfig;
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeInt(allowBypass ? 1 : 0);
+ out.writeInt(explicitlySelected ? 1 : 0);
+ out.writeInt(acceptUnvalidated ? 1 : 0);
+ out.writeString(subscriberId);
+ out.writeInt(provisioningNotificationDisabled ? 1 : 0);
+ out.writeInt(skip464xlat ? 1 : 0);
+ }
+
+ public static final @NonNull Creator<NetworkAgentConfig> CREATOR =
+ new Creator<NetworkAgentConfig>() {
+ @Override
+ public NetworkAgentConfig createFromParcel(Parcel in) {
+ NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
+ networkAgentConfig.allowBypass = in.readInt() != 0;
+ networkAgentConfig.explicitlySelected = in.readInt() != 0;
+ networkAgentConfig.acceptUnvalidated = in.readInt() != 0;
+ networkAgentConfig.subscriberId = in.readString();
+ networkAgentConfig.provisioningNotificationDisabled = in.readInt() != 0;
+ networkAgentConfig.skip464xlat = in.readInt() != 0;
+ return networkAgentConfig;
+ }
+
+ @Override
+ public NetworkAgentConfig[] newArray(int size) {
+ return new NetworkAgentConfig[size];
+ }
+ };
+}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index f43385d1f2e0..8ebd1392240d 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -1283,6 +1283,7 @@ public final class NetworkCapabilities implements Parcelable {
* Gets the SSID of this network, or null if none or unknown.
* @hide
*/
+ @SystemApi
public @Nullable String getSSID() {
return mSSID;
}
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index 824ddb8dd260..e27103755e6d 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -115,13 +115,6 @@ public class NetworkFactory extends Handler {
*/
private static final int CMD_SET_FILTER = BASE + 3;
- /**
- * Sent by NetworkFactory to ConnectivityService to indicate that a request is
- * unfulfillable.
- * @see #releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest).
- */
- public static final int EVENT_UNFULFILLABLE_REQUEST = BASE + 4;
-
private final Context mContext;
private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>();
private final String LOG_TAG;
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
deleted file mode 100644
index 4ad52d5aa1bc..000000000000
--- a/core/java/android/net/NetworkMisc.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A grab-bag of information (metadata, policies, properties, etc) about a
- * {@link Network}. Since this contains PII, it should not be sent outside the
- * system.
- *
- * @hide
- */
-public class NetworkMisc implements Parcelable {
-
- /**
- * If the {@link Network} is a VPN, whether apps are allowed to bypass the
- * VPN. This is set by a {@link VpnService} and used by
- * {@link ConnectivityManager} when creating a VPN.
- */
- public boolean allowBypass;
-
- /**
- * Set if the network was manually/explicitly connected to by the user either from settings
- * or a 3rd party app. For example, turning on cell data is not explicit but tapping on a wifi
- * ap in the wifi settings to trigger a connection is explicit. A 3rd party app asking to
- * connect to a particular access point is also explicit, though this may change in the future
- * as we want apps to use the multinetwork apis.
- */
- public boolean explicitlySelected;
-
- /**
- * Set if the user desires to use this network even if it is unvalidated. This field has meaning
- * only if {@link explicitlySelected} is true. If it is, this field must also be set to the
- * appropriate value based on previous user choice.
- */
- public boolean acceptUnvalidated;
-
- /**
- * Whether the user explicitly set that this network should be validated even if presence of
- * only partial internet connectivity.
- */
- public boolean acceptPartialConnectivity;
-
- /**
- * Set to avoid surfacing the "Sign in to network" notification.
- * if carrier receivers/apps are registered to handle the carrier-specific provisioning
- * procedure, a carrier specific provisioning notification will be placed.
- * only one notification should be displayed. This field is set based on
- * which notification should be used for provisioning.
- */
- public boolean provisioningNotificationDisabled;
-
- /**
- * For mobile networks, this is the subscriber ID (such as IMSI).
- */
- public String subscriberId;
-
- /**
- * Set to skip 464xlat. This means the device will treat the network as IPv6-only and
- * will not attempt to detect a NAT64 via RFC 7050 DNS lookups.
- */
- public boolean skip464xlat;
-
- /**
- * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network.
- * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode.
- */
- public boolean hasShownBroken;
-
- public NetworkMisc() {
- }
-
- public NetworkMisc(NetworkMisc nm) {
- if (nm != null) {
- allowBypass = nm.allowBypass;
- explicitlySelected = nm.explicitlySelected;
- acceptUnvalidated = nm.acceptUnvalidated;
- subscriberId = nm.subscriberId;
- provisioningNotificationDisabled = nm.provisioningNotificationDisabled;
- skip464xlat = nm.skip464xlat;
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(allowBypass ? 1 : 0);
- out.writeInt(explicitlySelected ? 1 : 0);
- out.writeInt(acceptUnvalidated ? 1 : 0);
- out.writeString(subscriberId);
- out.writeInt(provisioningNotificationDisabled ? 1 : 0);
- out.writeInt(skip464xlat ? 1 : 0);
- }
-
- public static final @android.annotation.NonNull Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
- @Override
- public NetworkMisc createFromParcel(Parcel in) {
- NetworkMisc networkMisc = new NetworkMisc();
- networkMisc.allowBypass = in.readInt() != 0;
- networkMisc.explicitlySelected = in.readInt() != 0;
- networkMisc.acceptUnvalidated = in.readInt() != 0;
- networkMisc.subscriberId = in.readString();
- networkMisc.provisioningNotificationDisabled = in.readInt() != 0;
- networkMisc.skip464xlat = in.readInt() != 0;
- return networkMisc;
- }
-
- @Override
- public NetworkMisc[] newArray(int size) {
- return new NetworkMisc[size];
- }
- };
-}
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 3be49d530c64..ee4379a85b6b 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -467,6 +467,19 @@ public class NetworkRequest implements Parcelable {
}
/**
+ * Returns true iff. the capabilities requested in this NetworkRequest are satisfied by the
+ * provided {@link NetworkCapabilities}.
+ *
+ * @param nc Capabilities that should satisfy this NetworkRequest. null capabilities do not
+ * satisfy any request.
+ * @hide
+ */
+ @SystemApi
+ public boolean satisfiedBy(@Nullable NetworkCapabilities nc) {
+ return networkCapabilities.satisfiedByNetworkCapabilities(nc);
+ }
+
+ /**
* @see Builder#addTransportType(int)
*/
public boolean hasTransport(@Transport int transportType) {
diff --git a/core/java/android/net/StringNetworkSpecifier.java b/core/java/android/net/StringNetworkSpecifier.java
index 530c84a8f3f0..6ae59716cfd8 100644
--- a/core/java/android/net/StringNetworkSpecifier.java
+++ b/core/java/android/net/StringNetworkSpecifier.java
@@ -17,7 +17,6 @@
package android.net;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -26,17 +25,7 @@ import com.android.internal.util.Preconditions;
import java.util.Objects;
-/**
- * @deprecated use other subclass of {@link android.net.NetworkSpecifier},
- * eg. {@link android.net.TelephonyNetworkSpecifier},
- * {@link android.net.wifi.WifiNetworkSpecifier} instead.
- * @see {@link android.net.NetworkRequest#setNetworkSpecifier(String)} for details.
- * @removed this class was tentatively made SystemApi in December 2019 in the scramble for
- * publishing mainline APIs, it should be removed before R release is published.
- * @hide
- */
-@Deprecated
-@SystemApi
+/** @hide */
public final class StringNetworkSpecifier extends NetworkSpecifier implements Parcelable {
/**
* Arbitrary string used to pass (additional) information to the network factory.
diff --git a/core/java/android/net/Uri.aidl b/core/java/android/net/Uri.aidl
index 6bd3be5e041b..b85f63bbcdd2 100644
--- a/core/java/android/net/Uri.aidl
+++ b/core/java/android/net/Uri.aidl
@@ -16,4 +16,4 @@
package android.net;
-parcelable Uri;
+@JavaOnlyStableParcelable parcelable Uri;
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 8bb2df0bba58..b9e6ff4a5a9e 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -455,12 +455,12 @@ public final class Tag implements Parcelable {
*
* @hide
*/
- public synchronized void setConnectedTechnology(int technology) {
- if (mConnectedTechnology == -1) {
- mConnectedTechnology = technology;
- } else {
- throw new IllegalStateException("Close other technology first!");
+ public synchronized boolean setConnectedTechnology(int technology) {
+ if (mConnectedTechnology != -1) {
+ return false;
}
+ mConnectedTechnology = technology;
+ return true;
}
/**
diff --git a/core/java/android/nfc/tech/BasicTagTechnology.java b/core/java/android/nfc/tech/BasicTagTechnology.java
index b6b347ca0619..ae468fead7a2 100644
--- a/core/java/android/nfc/tech/BasicTagTechnology.java
+++ b/core/java/android/nfc/tech/BasicTagTechnology.java
@@ -75,7 +75,10 @@ abstract class BasicTagTechnology implements TagTechnology {
if (errorCode == ErrorCodes.SUCCESS) {
// Store this in the tag object
- mTag.setConnectedTechnology(mSelectedTechnology);
+ if (!mTag.setConnectedTechnology(mSelectedTechnology)) {
+ Log.e(TAG, "Close other technology first!");
+ throw new IOException("Only one TagTechnology can be connected at a time.");
+ }
mIsConnected = true;
} else if (errorCode == ErrorCodes.ERROR_NOT_SUPPORTED) {
throw new UnsupportedOperationException("Connecting to " +
diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java
index 6daa5b4dc6d8..92574968e965 100644
--- a/core/java/android/os/AppZygote.java
+++ b/core/java/android/os/AppZygote.java
@@ -21,6 +21,8 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import dalvik.system.VMRuntime;
+
/**
* AppZygote is responsible for interfacing with an application-specific zygote.
*
@@ -113,7 +115,7 @@ public class AppZygote {
"app_zygote", // seInfo
abi, // abi
abi, // acceptedAbiList
- null, // instructionSet
+ VMRuntime.getInstructionSet(abi), // instructionSet
mZygoteUidGidMin,
mZygoteUidGidMax);
diff --git a/core/java/android/se/omapi/ISecureElementReader.aidl b/core/java/android/se/omapi/ISecureElementReader.aidl
index a312c445395a..41244ab058e0 100644
--- a/core/java/android/se/omapi/ISecureElementReader.aidl
+++ b/core/java/android/se/omapi/ISecureElementReader.aidl
@@ -48,4 +48,10 @@ interface ISecureElementReader {
*/
void closeSessions();
+ /**
+ * Closes all the sessions opened on this reader and resets the reader.
+ * All the channels opened by all these sessions will be closed.
+ * @return true if the reset is successful, false otherwise.
+ */
+ boolean reset();
}
diff --git a/core/java/android/se/omapi/Reader.java b/core/java/android/se/omapi/Reader.java
index 80262f7533c8..7f68d9188650 100644
--- a/core/java/android/se/omapi/Reader.java
+++ b/core/java/android/se/omapi/Reader.java
@@ -23,6 +23,8 @@
package android.se.omapi;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.Log;
@@ -150,4 +152,25 @@ public final class Reader {
} catch (RemoteException ignore) { }
}
}
+
+ /**
+ * Close all the sessions opened on this reader and reset the reader.
+ * All the channels opened by all these sessions will be closed.
+ * @return <code>true</code> if reset success, <code>false</code> otherwise.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.SECURE_ELEMENT_PRIVILEGED)
+ public boolean reset() {
+ if (!mService.isConnected()) {
+ Log.e(TAG, "service is not connected");
+ return false;
+ }
+ synchronized (mLock) {
+ try {
+ closeSessions();
+ return mReader.reset();
+ } catch (RemoteException ignore) {return false;}
+ }
+ }
}
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index 00060ab8ef4a..a5c5c613e1f2 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -98,6 +98,8 @@ public final class SEService {
private static final String TAG = "OMAPI.SEService";
+ private static final String UICC_TERMINAL = "SIM";
+
private final Object mLock = new Object();
/** The client context (e.g. activity). */
@@ -190,32 +192,33 @@ public final class SEService {
* is of length 0.
*/
public @NonNull Reader[] getReaders() {
- if (mSecureElementService == null) {
- throw new IllegalStateException("service not connected to system");
- }
- String[] readerNames;
- try {
- readerNames = mSecureElementService.getReaders();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
+ loadReaders();
- Reader[] readers = new Reader[readerNames.length];
- int i = 0;
- for (String readerName : readerNames) {
- if (mReaders.get(readerName) == null) {
- try {
- mReaders.put(readerName, new Reader(this, readerName,
- getReader(readerName)));
- readers[i++] = mReaders.get(readerName);
- } catch (Exception e) {
- Log.e(TAG, "Error adding Reader: " + readerName, e);
- }
- } else {
- readers[i++] = mReaders.get(readerName);
- }
- }
- return readers;
+ return mReaders.values().toArray(new Reader[0]);
+ }
+
+ /**
+ * Obtain a UICC Reader instance with specific slot number from the SecureElementService
+ *
+ * @param slotNumber The index of the uicc slot. The index starts from 1.
+ * @throws IllegalArgumentException if the reader object corresponding to the uiccSlotNumber
+ * is not exist.
+ * @return A Reader object for this uicc slot.
+ */
+ public @NonNull Reader getUiccReader(int slotNumber) {
+ if (slotNumber < 1) {
+ throw new IllegalArgumentException("slotNumber should be larger than 0");
+ }
+ loadReaders();
+
+ String readerName = UICC_TERMINAL + slotNumber;
+ Reader reader = mReaders.get(readerName);
+
+ if (reader == null) {
+ throw new IllegalArgumentException("Reader:" + readerName + " doesn't exist");
+ }
+
+ return reader;
}
/**
@@ -270,4 +273,30 @@ public final class SEService {
throw new IllegalStateException(e.getMessage());
}
}
+
+ /**
+ * Load available Secure Element Readers
+ */
+ private void loadReaders() {
+ if (mSecureElementService == null) {
+ throw new IllegalStateException("service not connected to system");
+ }
+ String[] readerNames;
+ try {
+ readerNames = mSecureElementService.getReaders();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+
+ for (String readerName : readerNames) {
+ if (mReaders.get(readerName) == null) {
+ try {
+ mReaders.put(readerName, new Reader(this, readerName,
+ getReader(readerName)));
+ } catch (Exception e) {
+ Log.e(TAG, "Error adding Reader: " + readerName, e);
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index e08a06abad45..f886cf58b850 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -178,6 +178,10 @@ public class PhoneStateListener {
* Listen for {@link android.telephony.Annotation.PreciseCallStates} of ringing,
* background and foreground calls.
*
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
* @hide
*/
@RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
@@ -187,13 +191,13 @@ public class PhoneStateListener {
/**
* Listen for {@link PreciseDataConnectionState} on the data connection (cellular).
*
- * <p>Requires permission {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
* or the calling app has carrier privileges
* (see {@link TelephonyManager#hasCarrierPrivileges}).
*
* @see #onPreciseDataConnectionStateChanged
*/
- @RequiresPermission((android.Manifest.permission.MODIFY_PHONE_STATE))
+ @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 0x00001000;
/**
@@ -318,26 +322,36 @@ public class PhoneStateListener {
* Listen for call disconnect causes which contains {@link DisconnectCause} and
* {@link PreciseDisconnectCause}.
*
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
*/
@RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
public static final int LISTEN_CALL_DISCONNECT_CAUSES = 0x02000000;
/**
* Listen for changes to the call attributes of a currently active call.
- * {@more}
- * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
- * READ_PRECISE_PHONE_STATE}
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
*
* @see #onCallAttributesChanged
* @hide
*/
@SystemApi
+ @RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 0x04000000;
/**
* Listen for IMS call disconnect causes which contains
* {@link android.telephony.ims.ImsReasonInfo}
*
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}
+ * or the calling app has carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}).
+ *
* @see #onImsCallDisconnectCauseChanged(ImsReasonInfo)
*/
@RequiresPermission((android.Manifest.permission.READ_PRECISE_PHONE_STATE))
diff --git a/core/java/android/timezone/CountryTimeZones.java b/core/java/android/timezone/CountryTimeZones.java
index ada59d6d7d55..e5bbdf4b6eea 100644
--- a/core/java/android/timezone/CountryTimeZones.java
+++ b/core/java/android/timezone/CountryTimeZones.java
@@ -43,6 +43,7 @@ public final class CountryTimeZones {
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final class TimeZoneMapping {
+ @NonNull
private libcore.timezone.CountryTimeZones.TimeZoneMapping mDelegate;
TimeZoneMapping(libcore.timezone.CountryTimeZones.TimeZoneMapping delegate) {
diff --git a/core/java/android/timezone/TelephonyLookup.java b/core/java/android/timezone/TelephonyLookup.java
index 39dbe85cb485..eebccf4aa577 100644
--- a/core/java/android/timezone/TelephonyLookup.java
+++ b/core/java/android/timezone/TelephonyLookup.java
@@ -36,12 +36,8 @@ public class TelephonyLookup {
@GuardedBy("sLock")
private static TelephonyLookup sInstance;
- @NonNull
- private final libcore.timezone.TelephonyLookup mDelegate;
-
/**
- * Obtains an instance for use when resolving telephony time zone information. This method never
- * returns {@code null}.
+ * Obtains an instance for use when resolving telephony time zone information.
*/
@NonNull
public static TelephonyLookup getInstance() {
@@ -53,6 +49,9 @@ public class TelephonyLookup {
}
}
+ @NonNull
+ private final libcore.timezone.TelephonyLookup mDelegate;
+
private TelephonyLookup(@NonNull libcore.timezone.TelephonyLookup delegate) {
mDelegate = Objects.requireNonNull(delegate);
}
diff --git a/core/java/android/timezone/TelephonyNetworkFinder.java b/core/java/android/timezone/TelephonyNetworkFinder.java
index a81a516c4b33..079d0882f191 100644
--- a/core/java/android/timezone/TelephonyNetworkFinder.java
+++ b/core/java/android/timezone/TelephonyNetworkFinder.java
@@ -23,7 +23,7 @@ import android.annotation.SystemApi;
import java.util.Objects;
/**
- * A class that can find telephony networks loaded via {@link TelephonyLookup}.
+ * A class that can find telephony network information loaded via {@link TelephonyLookup}.
*
* @hide
*/
diff --git a/core/java/android/timezone/TimeZoneFinder.java b/core/java/android/timezone/TimeZoneFinder.java
index 15dfe62bb789..9327b001a9c8 100644
--- a/core/java/android/timezone/TimeZoneFinder.java
+++ b/core/java/android/timezone/TimeZoneFinder.java
@@ -22,8 +22,10 @@ import android.annotation.SystemApi;
import com.android.internal.annotations.GuardedBy;
+import java.util.Objects;
+
/**
- * A class that can be used to find time zones.
+ * A class that can be used to find time zones using information like country and offset.
*
* @hide
*/
@@ -34,15 +36,8 @@ public final class TimeZoneFinder {
@GuardedBy("sLock")
private static TimeZoneFinder sInstance;
- private final libcore.timezone.TimeZoneFinder mDelegate;
-
- private TimeZoneFinder(libcore.timezone.TimeZoneFinder delegate) {
- mDelegate = delegate;
- }
-
/**
- * Obtains an instance for use when resolving telephony time zone information. This method never
- * returns {@code null}.
+ * Obtains the singleton instance.
*/
@NonNull
public static TimeZoneFinder getInstance() {
@@ -54,6 +49,22 @@ public final class TimeZoneFinder {
return sInstance;
}
+ @NonNull
+ private final libcore.timezone.TimeZoneFinder mDelegate;
+
+ private TimeZoneFinder(@NonNull libcore.timezone.TimeZoneFinder delegate) {
+ mDelegate = Objects.requireNonNull(delegate);
+ }
+
+ /**
+ * Returns the IANA rules version associated with the data. If there is no version information
+ * or there is a problem reading the file then {@code null} is returned.
+ */
+ @Nullable
+ public String getIanaVersion() {
+ return mDelegate.getIanaVersion();
+ }
+
/**
* Returns a {@link CountryTimeZones} object associated with the specified country code.
* Caching is handled as needed. If the country code is not recognized or there is an error
diff --git a/core/java/android/timezone/TzDataSetVersion.java b/core/java/android/timezone/TzDataSetVersion.java
new file mode 100644
index 000000000000..aba7c4c15903
--- /dev/null
+++ b/core/java/android/timezone/TzDataSetVersion.java
@@ -0,0 +1,154 @@
+/*
+ * 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.timezone;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Version information associated with the set of time zone data on a device.
+ *
+ * <p>Time Zone Data Sets have a major ({@link #getFormatMajorVersion()}) and minor
+ * ({@link #currentFormatMinorVersion()}) version number:
+ * <ul>
+ * <li>Major version numbers are mutually incompatible. e.g. v2 is not compatible with a v1 or a
+ * v3 device.</li>
+ * <li>Minor version numbers are backwards compatible. e.g. a v2.2 data set will work
+ * on a v2.1 device but not a v2.3 device. The minor version is reset to 1 when the major version
+ * is incremented.</li>
+ * </ul>
+ *
+ * <p>Data sets contain time zone rules and other data associated wtih a tzdb release
+ * ({@link #getRulesVersion()}) and an additional Android-specific revision number
+ * ({@link #getRevision()}).
+ *
+ * <p>See platform/system/timezone/README.android for more information.
+ * @hide
+ */
+@VisibleForTesting
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class TzDataSetVersion {
+
+ /**
+ * Returns the major tz data format version supported by this device.
+ */
+ public static int currentFormatMajorVersion() {
+ return libcore.timezone.TzDataSetVersion.currentFormatMajorVersion();
+ }
+
+ /**
+ * Returns the minor tz data format version supported by this device.
+ */
+ public static int currentFormatMinorVersion() {
+ return libcore.timezone.TzDataSetVersion.currentFormatMinorVersion();
+ }
+
+ /**
+ * Returns true if the version information provided would be compatible with this device, i.e.
+ * with the current system image, and set of active modules.
+ */
+ public static boolean isCompatibleWithThisDevice(TzDataSetVersion tzDataSetVersion) {
+ return libcore.timezone.TzDataSetVersion.isCompatibleWithThisDevice(
+ tzDataSetVersion.mDelegate);
+ }
+
+ /**
+ * Reads the current Android time zone data set version file.
+ */
+ @NonNull
+ public static TzDataSetVersion read() throws IOException, TzDataSetException {
+ try {
+ return new TzDataSetVersion(
+ libcore.timezone.TzDataSetVersion.readTimeZoneModuleVersion());
+ } catch (libcore.timezone.TzDataSetVersion.TzDataSetException e) {
+ throw new TzDataSetException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * A checked exception used in connection with time zone data sets.
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static class TzDataSetException extends Exception {
+
+ /** Creates an instance with a message. */
+ public TzDataSetException(String message) {
+ super(message);
+ }
+
+ /** Creates an instance with a message and a cause. */
+ public TzDataSetException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ @NonNull
+ private final libcore.timezone.TzDataSetVersion mDelegate;
+
+ private TzDataSetVersion(@NonNull libcore.timezone.TzDataSetVersion delegate) {
+ mDelegate = Objects.requireNonNull(delegate);
+ }
+
+ /** Returns the major version number. See {@link TzDataSetVersion}. */
+ public int getFormatMajorVersion() {
+ return mDelegate.formatMajorVersion;
+ }
+
+ /** Returns the minor version number. See {@link TzDataSetVersion}. */
+ public int getFormatMinorVersion() {
+ return mDelegate.formatMinorVersion;
+ }
+
+ /** Returns the tzdb version string. See {@link TzDataSetVersion}. */
+ @NonNull
+ public String getRulesVersion() {
+ return mDelegate.rulesVersion;
+ }
+
+ /** Returns the Android revision. See {@link TzDataSetVersion}. */
+ public int getRevision() {
+ return mDelegate.revision;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ TzDataSetVersion that = (TzDataSetVersion) o;
+ return mDelegate.equals(that.mDelegate);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDelegate);
+ }
+
+ @Override
+ public String toString() {
+ return mDelegate.toString();
+ }
+}
diff --git a/core/java/android/timezone/ZoneInfoDb.java b/core/java/android/timezone/ZoneInfoDb.java
new file mode 100644
index 000000000000..eb191e8e3272
--- /dev/null
+++ b/core/java/android/timezone/ZoneInfoDb.java
@@ -0,0 +1,66 @@
+/*
+ * 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.timezone;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Objects;
+
+/**
+ * Android's internal factory for java.util.TimeZone objects. Provides access to core library time
+ * zone metadata not available via {@link java.util.TimeZone}.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class ZoneInfoDb {
+
+ private static Object sLock = new Object();
+ @GuardedBy("sLock")
+ private static ZoneInfoDb sInstance;
+
+ /**
+ * Obtains the singleton instance.
+ */
+ @NonNull
+ public static ZoneInfoDb getInstance() {
+ synchronized (sLock) {
+ if (sInstance == null) {
+ sInstance = new ZoneInfoDb(libcore.timezone.ZoneInfoDB.getInstance());
+ }
+ }
+ return sInstance;
+ }
+
+ @NonNull
+ private final libcore.timezone.ZoneInfoDB mDelegate;
+
+ private ZoneInfoDb(libcore.timezone.ZoneInfoDB delegate) {
+ mDelegate = Objects.requireNonNull(delegate);
+ }
+
+ /**
+ * Returns the tzdb version in use.
+ */
+ @NonNull
+ public String getVersion() {
+ return mDelegate.getVersion();
+ }
+}
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 8439f5aad0b1..dbd3f69e214e 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -88,7 +88,7 @@ public class TimeUtils {
*
* <p>The list returned may be different from other on-device sources like
* {@link android.icu.util.TimeZone#getRegion(String)} as it can be curated to avoid
- * contentious mappings.
+ * contentious or obsolete mappings.
*
* @param countryCode the ISO 3166-1 alpha-2 code for the country as can be obtained using
* {@link java.util.Locale#getCountry()}
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index 6efcfbfd05f8..7b24ba997307 100644
--- a/core/java/android/util/proto/ProtoOutputStream.java
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -16,7 +16,8 @@
package android.util.proto;
-import android.annotation.TestApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.util.Log;
import java.io.FileDescriptor;
@@ -28,19 +29,23 @@ import java.io.UnsupportedEncodingException;
/**
* Class to write to a protobuf stream.
*
- * Each write method takes an ID code from the protoc generated classes
- * and the value to write. To make a nested object, call #start
- * and then #end when you are done.
+ * <p>
+ * This API is not as convenient or type safe as the standard protobuf
+ * classes. If possible, the best recommended library is to use protobuf lite.
+ * However, in environements (such as the Android platform itself), a
+ * more memory efficient version is necessary.
*
- * The ID codes have type information embedded into them, so if you call
- * the incorrect function you will get an IllegalArgumentException.
+ * <p>Each write method takes an ID code from the protoc generated classes
+ * and the value to write. To make a nested object, call {@link #start(long)}
+ * and then {@link #end(long)} when you are done.
*
- * To retrieve the encoded protobuf stream, call getBytes().
+ * <p>The ID codes have type information embedded into them, so if you call
+ * the incorrect function you will get an {@link IllegalArgumentException}.
+ *
+ * <p>To retrieve the encoded protobuf stream, call {@link #getBytes()}.
*
- * TODO: Add a constructor that takes an OutputStream and write to that
* stream as the top-level objects are finished.
*
- * @hide
*/
/* IMPLEMENTATION NOTES
@@ -99,7 +104,6 @@ import java.io.UnsupportedEncodingException;
* correctly matched pairs of #start and #end calls, and issue
* errors if they are not matched.
*/
-@TestApi
public final class ProtoOutputStream extends ProtoStream {
/**
* @hide
@@ -124,7 +128,9 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* An ID given to objects and returned in the token from startObject
* and stored in the buffer until endObject is called, where the two
- * are checked. Starts at -1 and becomes more negative, so the values
+ * are checked.
+ *
+ * <p>Starts at -1 and becomes more negative, so the values
* aren't likely to alias with the size it will be overwritten with,
* which tend to be small, and we will be more likely to catch when
* the caller of endObject uses a stale token that they didn't intend
@@ -133,8 +139,9 @@ public final class ProtoOutputStream extends ProtoStream {
private int mNextObjectId = -1;
/**
- * The object token we are expecting in endObject. If another call to
- * startObject happens, this is written to that location, which gives
+ * The object token we are expecting in endObject.
+ *
+ * <p>If another call to startObject happens, this is written to that location, which gives
* us a stack, stored in the space for the as-yet unused size fields.
*/
private long mExpectedObjectToken;
@@ -151,39 +158,45 @@ public final class ProtoOutputStream extends ProtoStream {
private boolean mCompacted;
/**
- * Construct a ProtoOutputStream with the default chunk size.
+ * Construct a {@link ProtoOutputStream} with the default chunk size.
+ *
+ * <p>This is for an in-memory proto. The caller should use {@link #getBytes()} for the result.
*/
public ProtoOutputStream() {
this(0);
}
/**
- * Construct a ProtoOutputStream with the given chunk size.
+ * Construct a {@link ProtoOutputStream with the given chunk size.
+ *
+ * <p>This is for an in-memory proto. The caller should use {@link #getBytes()} for the result.
*/
public ProtoOutputStream(int chunkSize) {
mBuffer = new EncodedBuffer(chunkSize);
}
/**
- * Construct a ProtoOutputStream that sits on top of an OutputStream.
- * @more
- * The {@link #flush() flush()} method must be called when done writing
- * to flush any remanining data, althought data *may* be written at intermediate
+ * Construct a {@link ProtoOutputStream} that sits on top of an {@link OutputStream}.
+ *
+ * <p>The {@link #flush()} method must be called when done writing
+ * to flush any remaining data, although data *may* be written at intermediate
* points within the writing as well.
*/
- public ProtoOutputStream(OutputStream stream) {
+ public ProtoOutputStream(@NonNull OutputStream stream) {
this();
mStream = stream;
}
/**
- * Construct a ProtoOutputStream that sits on top of a FileDescriptor.
- * @more
- * The {@link #flush() flush()} method must be called when done writing
- * to flush any remanining data, althought data *may* be written at intermediate
+ * Construct a {@link ProtoOutputStream} that sits on top of a {@link FileDescriptor}.
+ *
+ * <p>The {@link #flush()} method must be called when done writing
+ * to flush any remaining data, although data *may* be written at intermediate
* points within the writing as well.
+ *
+ * @hide
*/
- public ProtoOutputStream(FileDescriptor fd) {
+ public ProtoOutputStream(@NonNull FileDescriptor fd) {
this(new FileOutputStream(fd));
}
@@ -202,7 +215,7 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a value for the given fieldId.
*
- * Will automatically convert for the following field types, and
+ * <p>Will automatically convert for the following field types, and
* throw an exception for others: double, float, int32, int64, uint32, uint64,
* sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
*
@@ -337,7 +350,7 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a value for the given fieldId.
*
- * Will automatically convert for the following field types, and
+ * <p>Will automatically convert for the following field types, and
* throw an exception for others: double, float, int32, int64, uint32, uint64,
* sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
*
@@ -472,7 +485,7 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a value for the given fieldId.
*
- * Will automatically convert for the following field types, and
+ * <p>Will automatically convert for the following field types, and
* throw an exception for others: double, float, int32, int64, uint32, uint64,
* sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
*
@@ -607,7 +620,7 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a value for the given fieldId.
*
- * Will automatically convert for the following field types, and
+ * <p>Will automatically convert for the following field types, and
* throw an exception for others: double, float, int32, int64, uint32, uint64,
* sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, enum.
*
@@ -742,7 +755,7 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a boolean value for the given fieldId.
*
- * If the field is not a bool field, an exception will be thrown.
+ * <p>If the field is not a bool field, an {@link IllegalStateException} will be thrown.
*
* @param fieldId The field identifier constant from the generated class.
* @param val The value.
@@ -771,12 +784,12 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a string value for the given fieldId.
*
- * If the field is not a string field, an exception will be thrown.
+ * <p>If the field is not a string field, an exception will be thrown.
*
* @param fieldId The field identifier constant from the generated class.
* @param val The value.
*/
- public void write(long fieldId, String val) {
+ public void write(long fieldId, @Nullable String val) {
assertNotCompacted();
final int id = (int)fieldId;
@@ -800,12 +813,12 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a byte[] value for the given fieldId.
*
- * If the field is not a bytes or object field, an exception will be thrown.
+ * <p>If the field is not a bytes or object field, an exception will be thrown.
*
* @param fieldId The field identifier constant from the generated class.
* @param val The value.
*/
- public void write(long fieldId, byte[] val) {
+ public void write(long fieldId, @Nullable byte[] val) {
assertNotCompacted();
final int id = (int)fieldId;
@@ -836,6 +849,9 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Start a sub object.
+ *
+ * @param fieldId The field identifier constant from the generated class.
+ * @return The token to call {@link #end(long)} with.
*/
public long start(long fieldId) {
assertNotCompacted();
@@ -855,6 +871,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* End the object started by start() that returned token.
+ *
+ * @param token The token returned from {@link #start(long)}
*/
public void end(long token) {
endObjectImpl(token, getRepeatedFromToken(token));
@@ -870,7 +888,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "double" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, double)} instead.
+ * @hide
*/
@Deprecated
public void writeDouble(long fieldId, double val) {
@@ -890,7 +909,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "double" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, double)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedDouble(long fieldId, double val) {
@@ -908,10 +928,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a list of packed proto "double" type field values.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, double)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedDouble(long fieldId, double[] val) {
+ public void writePackedDouble(long fieldId, @Nullable double[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_DOUBLE);
@@ -934,7 +955,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "float" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, float)} instead.
+ * @hide
*/
@Deprecated
public void writeFloat(long fieldId, float val) {
@@ -954,7 +976,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "float" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, float)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedFloat(long fieldId, float val) {
@@ -972,10 +995,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a list of packed proto "float" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, float)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedFloat(long fieldId, float[] val) {
+ public void writePackedFloat(long fieldId, @Nullable float[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FLOAT);
@@ -999,7 +1023,7 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Writes a java int as an usigned varint.
*
- * The unadorned int32 type in protobuf is unfortunate because it
+ * <p>The unadorned int32 type in protobuf is unfortunate because it
* is stored in memory as a signed value, but encodes as unsigned
* varints, which are formally always longs. So here, we encode
* negative values as 64 bits, which will get the sign-extension,
@@ -1017,11 +1041,12 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "int32" type field value.
*
- * Note that these are stored in memory as signed values and written as unsigned
+ * <p>Note that these are stored in memory as signed values and written as unsigned
* varints, which if negative, are 10 bytes long. If you know the data is likely
* to be negative, use "sint32".
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
public void writeInt32(long fieldId, int val) {
@@ -1041,11 +1066,12 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "int32" type field value.
*
- * Note that these are stored in memory as signed values and written as unsigned
+ * <p>Note that these are stored in memory as signed values and written as unsigned
* varints, which if negative, are 10 bytes long. If you know the data is likely
* to be negative, use "sint32".
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedInt32(long fieldId, int val) {
@@ -1063,14 +1089,15 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a list of packed proto "int32" type field value.
*
- * Note that these are stored in memory as signed values and written as unsigned
+ * <p>Note that these are stored in memory as signed values and written as unsigned
* varints, which if negative, are 10 bytes long. If you know the data is likely
* to be negative, use "sint32".
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedInt32(long fieldId, int[] val) {
+ public void writePackedInt32(long fieldId, @Nullable int[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT32);
@@ -1099,7 +1126,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "int64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
public void writeInt64(long fieldId, long val) {
@@ -1119,7 +1147,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "int64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedInt64(long fieldId, long val) {
@@ -1137,10 +1166,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a list of packed proto "int64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedInt64(long fieldId, long[] val) {
+ public void writePackedInt64(long fieldId, @Nullable long[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT64);
@@ -1168,7 +1198,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "uint32" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
public void writeUInt32(long fieldId, int val) {
@@ -1188,7 +1219,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "uint32" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedUInt32(long fieldId, int val) {
@@ -1206,10 +1238,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a list of packed proto "uint32" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedUInt32(long fieldId, int[] val) {
+ public void writePackedUInt32(long fieldId, @Nullable int[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT32);
@@ -1237,7 +1270,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "uint64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
public void writeUInt64(long fieldId, long val) {
@@ -1257,7 +1291,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "uint64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedUInt64(long fieldId, long val) {
@@ -1275,10 +1310,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "uint64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedUInt64(long fieldId, long[] val) {
+ public void writePackedUInt64(long fieldId, @Nullable long[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT64);
@@ -1306,7 +1342,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "sint32" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
public void writeSInt32(long fieldId, int val) {
@@ -1326,7 +1363,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "sint32" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedSInt32(long fieldId, int val) {
@@ -1344,10 +1382,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a list of packed proto "sint32" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedSInt32(long fieldId, int[] val) {
+ public void writePackedSInt32(long fieldId, @Nullable int[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT32);
@@ -1375,7 +1414,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "sint64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
public void writeSInt64(long fieldId, long val) {
@@ -1395,7 +1435,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "sint64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedSInt64(long fieldId, long val) {
@@ -1413,10 +1454,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a list of packed proto "sint64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedSInt64(long fieldId, long[] val) {
+ public void writePackedSInt64(long fieldId, @Nullable long[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT64);
@@ -1443,7 +1485,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "fixed32" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
public void writeFixed32(long fieldId, int val) {
@@ -1463,7 +1506,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "fixed32" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedFixed32(long fieldId, int val) {
@@ -1481,10 +1525,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a list of packed proto "fixed32" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedFixed32(long fieldId, int[] val) {
+ public void writePackedFixed32(long fieldId, @Nullable int[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED32);
@@ -1507,7 +1552,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "fixed64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
public void writeFixed64(long fieldId, long val) {
@@ -1527,7 +1573,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "fixed64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedFixed64(long fieldId, long val) {
@@ -1545,10 +1592,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a list of packed proto "fixed64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedFixed64(long fieldId, long[] val) {
+ public void writePackedFixed64(long fieldId, @Nullable long[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED64);
@@ -1570,7 +1618,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "sfixed32" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
public void writeSFixed32(long fieldId, int val) {
@@ -1590,7 +1639,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "sfixed32" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedSFixed32(long fieldId, int val) {
@@ -1608,10 +1658,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a list of packed proto "sfixed32" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedSFixed32(long fieldId, int[] val) {
+ public void writePackedSFixed32(long fieldId, @Nullable int[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED32);
@@ -1634,7 +1685,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "sfixed64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
public void writeSFixed64(long fieldId, long val) {
@@ -1654,7 +1706,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "sfixed64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedSFixed64(long fieldId, long val) {
@@ -1672,10 +1725,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a list of packed proto "sfixed64" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, long)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedSFixed64(long fieldId, long[] val) {
+ public void writePackedSFixed64(long fieldId, @Nullable long[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED64);
@@ -1698,7 +1752,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "bool" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, boolean)} instead.
+ * @hide
*/
@Deprecated
public void writeBool(long fieldId, boolean val) {
@@ -1719,7 +1774,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "bool" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, boolean)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedBool(long fieldId, boolean val) {
@@ -1737,10 +1793,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a list of packed proto "bool" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, boolean)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedBool(long fieldId, boolean[] val) {
+ public void writePackedBool(long fieldId, @Nullable boolean[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_BOOL);
@@ -1767,10 +1824,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "string" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, String)} instead.
+ * @hide
*/
@Deprecated
- public void writeString(long fieldId, String val) {
+ public void writeString(long fieldId, @Nullable String val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_STRING);
@@ -1786,10 +1844,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "string" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, String)} instead.
+ * @hide
*/
@Deprecated
- public void writeRepeatedString(long fieldId, String val) {
+ public void writeRepeatedString(long fieldId, @Nullable String val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_STRING);
@@ -1828,10 +1887,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto "bytes" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, byte[])} instead.
+ * @hide
*/
@Deprecated
- public void writeBytes(long fieldId, byte[] val) {
+ public void writeBytes(long fieldId, @Nullable byte[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES);
@@ -1848,10 +1908,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto "bytes" type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, byte[])} instead.
+ * @hide
*/
@Deprecated
- public void writeRepeatedBytes(long fieldId, byte[] val) {
+ public void writeRepeatedBytes(long fieldId, @Nullable byte[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BYTES);
@@ -1874,7 +1935,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single proto enum type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
public void writeEnum(long fieldId, int val) {
@@ -1894,7 +1956,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a single repeated proto enum type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
public void writeRepeatedEnum(long fieldId, int val) {
@@ -1912,10 +1975,11 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write a list of packed proto enum type field value.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, int)} instead.
+ * @hide
*/
@Deprecated
- public void writePackedEnum(long fieldId, int[] val) {
+ public void writePackedEnum(long fieldId, @Nullable int[] val) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_ENUM);
@@ -1940,7 +2004,8 @@ public final class ProtoOutputStream extends ProtoStream {
* Returns a token which should be passed to endObject. Calls to endObject must be
* nested properly.
*
- * @deprecated Use #start() instead.
+ * @deprecated Use {@link #start(long)} instead.
+ * @hide
*/
@Deprecated
public long startObject(long fieldId) {
@@ -1953,7 +2018,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* End a child object. Pass in the token from the correspoinding startObject call.
*
- * @deprecated Use #end() instead.
+ * @deprecated Use {@link #end(long)} instead.
+ * @hide
*/
@Deprecated
public void endObject(long token) {
@@ -1968,7 +2034,8 @@ public final class ProtoOutputStream extends ProtoStream {
* Returns a token which should be passed to endObject. Calls to endObject must be
* nested properly.
*
- * @deprecated Use #start() instead.
+ * @deprecated Use {@link #start(long)} instead.
+ * @hide
*/
@Deprecated
public long startRepeatedObject(long fieldId) {
@@ -1981,7 +2048,8 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* End a child object. Pass in the token from the correspoinding startRepeatedObject call.
*
- * @deprecated Use #end() instead.
+ * @deprecated Use {@link #end(long)} instead.
+ * @hide
*/
@Deprecated
public void endRepeatedObject(long token) {
@@ -2064,12 +2132,13 @@ public final class ProtoOutputStream extends ProtoStream {
}
/**
- * Write an object that has already been flattend.
+ * Write an object that has already been flattened.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, byte[])} instead.
+ * @hide
*/
@Deprecated
- public void writeObject(long fieldId, byte[] value) {
+ public void writeObject(long fieldId, @Nullable byte[] value) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_MESSAGE);
@@ -2084,12 +2153,13 @@ public final class ProtoOutputStream extends ProtoStream {
}
/**
- * Write an object that has already been flattend.
+ * Write an object that has already been flattened.
*
- * @deprecated Use #write instead.
+ * @deprecated Use {@link #write(long, byte[])} instead.
+ * @hide
*/
@Deprecated
- public void writeRepeatedObject(long fieldId, byte[] value) {
+ public void writeRepeatedObject(long fieldId, @Nullable byte[] value) {
assertNotCompacted();
final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_MESSAGE);
@@ -2115,11 +2185,11 @@ public final class ProtoOutputStream extends ProtoStream {
}
/**
- * Validates that the fieldId providied is of the type and count from expectedType.
+ * Validates that the fieldId provided is of the type and count from expectedType.
*
- * The type must match exactly to pass this check.
+ * <p>The type must match exactly to pass this check.
*
- * The count must match according to this truth table to pass the check:
+ * <p>The count must match according to this truth table to pass the check:
*
* expectedFlags
* UNKNOWN SINGLE REPEATED PACKED
@@ -2129,7 +2199,7 @@ public final class ProtoOutputStream extends ProtoStream {
* REPEATED x false true false
* PACKED x false true true
*
- * @throws IllegalArgumentException if it is not.
+ * @throws {@link IllegalArgumentException} if it is not.
*
* @return The raw ID of that field.
*/
@@ -2201,7 +2271,7 @@ public final class ProtoOutputStream extends ProtoStream {
}
/**
- * Write a field tage to the stream.
+ * Write a field tag to the stream.
*/
public void writeTag(int id, int wireType) {
mBuffer.writeRawVarint32((id << FIELD_ID_SHIFT) | wireType);
@@ -2239,10 +2309,10 @@ public final class ProtoOutputStream extends ProtoStream {
* Finish the encoding of the data, and return a byte[] with
* the protobuf formatted data.
*
- * After this call, do not call any of the write* functions. The
+ * <p>After this call, do not call any of the write* functions. The
* behavior is undefined.
*/
- public byte[] getBytes() {
+ public @NonNull byte[] getBytes() {
compactIfNecessary();
return mBuffer.getBytes(mBuffer.getReadableSize());
@@ -2289,7 +2359,7 @@ public final class ProtoOutputStream extends ProtoStream {
}
/**
- * First compaction pass. Iterate through the data, and fill in the
+ * First compaction pass. Iterate through the data, and fill in the
* nested object sizes so the next pass can compact them.
*/
private int editEncodedSize(int rawSize) {
@@ -2416,10 +2486,10 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Write remaining data to the output stream. If there is no output stream,
* this function does nothing. Any currently open objects (i.e. ones that
- * have not had endObject called for them will not be written). Whether this
+ * have not had {@link #end(long)} called for them will not be written). Whether this
* writes objects that are closed if there are remaining open objects is
* undefined (current implementation does not write it, future ones will).
- * For now, can either call getBytes() or flush(), but not both.
+ * For now, can either call {@link #getBytes()} or {@link #flush()}, but not both.
*/
public void flush() {
if (mStream == null) {
@@ -2457,7 +2527,7 @@ public final class ProtoOutputStream extends ProtoStream {
/**
* Dump debugging data about the buffers with the given log tag.
*/
- public void dump(String tag) {
+ public void dump(@NonNull String tag) {
Log.d(tag, mBuffer.getDebugString());
mBuffer.dumpBuffers(tag);
}
diff --git a/core/java/android/util/proto/ProtoStream.java b/core/java/android/util/proto/ProtoStream.java
index 9e2e95a5923d..4969d8a7fbe7 100644
--- a/core/java/android/util/proto/ProtoStream.java
+++ b/core/java/android/util/proto/ProtoStream.java
@@ -16,28 +16,104 @@
package android.util.proto;
-import android.annotation.TestApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
/**
- * Abstract base class for both protobuf streams.
+ * Base utility class for protobuf streams.
*
- * Contains a set of useful constants and methods used by both
- * ProtoOutputStream and ProtoInputStream
+ * Contains a set of constants and methods used in generated code for
+ * {@link ProtoOutputStream}.
*
* @hide
*/
-@TestApi
-public abstract class ProtoStream {
+public class ProtoStream {
+ /**
+ * Number of bits to shift the field number to form a tag.
+ *
+ * <pre>
+ * // Reading a field number from a tag.
+ * int fieldNumber = tag &gt;&gt;&gt; FIELD_ID_SHIFT;
+ *
+ * // Building a tag from a field number and a wire type.
+ * int tag = (fieldNumber &lt;&lt; FIELD_ID_SHIFT) | wireType;
+ * </pre>
+ *
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * Encoding</a>
+ */
public static final int FIELD_ID_SHIFT = 3;
+
+ /**
+ * Mask to select the wire type from a tag.
+ *
+ * <pre>
+ * // Reading a wire type from a tag.
+ * int wireType = tag &amp; WIRE_TYPE_MASK;
+ *
+ * // Building a tag from a field number and a wire type.
+ * int tag = (fieldNumber &lt;&lt; FIELD_ID_SHIFT) | wireType;
+ * </pre>
+ *
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * Encoding</a>
+ */
public static final int WIRE_TYPE_MASK = (1 << FIELD_ID_SHIFT) - 1;
+
+ /**
+ * Mask to select the field id from a tag.
+ * @hide (not used by anything, and not actually useful, because you also want
+ * to shift when you mask the field id).
+ */
public static final int FIELD_ID_MASK = ~WIRE_TYPE_MASK;
+ /**
+ * Varint wire type code.
+ *
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * Encoding</a>
+ */
public static final int WIRE_TYPE_VARINT = 0;
+
+ /**
+ * Fixed64 wire type code.
+ *
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * Encoding</a>
+ */
public static final int WIRE_TYPE_FIXED64 = 1;
+
+ /**
+ * Length delimited wire type code.
+ *
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * Encoding</a>
+ */
public static final int WIRE_TYPE_LENGTH_DELIMITED = 2;
+
+ /**
+ * Start group wire type code.
+ *
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * Encoding</a>
+ */
public static final int WIRE_TYPE_START_GROUP = 3;
+
+ /**
+ * End group wire type code.
+ *
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * Encoding</a>
+ */
public static final int WIRE_TYPE_END_GROUP = 4;
+
+ /**
+ * Fixed32 wire type code.
+ *
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * Encoding</a>
+ */
public static final int WIRE_TYPE_FIXED32 = 5;
/**
@@ -51,32 +127,147 @@ public abstract class ProtoStream {
*/
public static final long FIELD_TYPE_MASK = 0x0ffL << FIELD_TYPE_SHIFT;
+ /**
+ * Not a real wire type.
+ * @hide
+ */
public static final long FIELD_TYPE_UNKNOWN = 0;
+
+ /*
+ * The FIELD_TYPE_ constants are copied from
+ * external/protobuf/src/google/protobuf/descriptor.h directly, so no
+ * extra mapping needs to be maintained in this case.
+ */
+
/**
- * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly,
- * so no extra mapping needs to be maintained in this case.
+ * Field type code for double fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, double)
+ * ProtoOutputStream.write(long, double)} method.
*/
public static final long FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for float fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, float)
+ * ProtoOutputStream.write(long, float)} method.
+ */
public static final long FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for int64 fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, long)
+ * ProtoOutputStream.write(long, long)} method.
+ */
public static final long FIELD_TYPE_INT64 = 3L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for uint64 fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, long)
+ * ProtoOutputStream.write(long, long)} method.
+ */
public static final long FIELD_TYPE_UINT64 = 4L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for int32 fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, int)
+ * ProtoOutputStream.write(long, int)} method.
+ */
public static final long FIELD_TYPE_INT32 = 5L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for fixed64 fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, long)
+ * ProtoOutputStream.write(long, long)} method.
+ */
public static final long FIELD_TYPE_FIXED64 = 6L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for fixed32 fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, int)
+ * ProtoOutputStream.write(long, int)} method.
+ */
+
+ /**
+ * Field type code for fixed32 fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, int)
+ * ProtoOutputStream.write(long, int)} method.
+ */
public static final long FIELD_TYPE_FIXED32 = 7L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for bool fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, boolean)
+ * ProtoOutputStream.write(long, boolean)} method.
+ */
public static final long FIELD_TYPE_BOOL = 8L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for string fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, String)
+ * ProtoOutputStream.write(long, String)} method.
+ */
public static final long FIELD_TYPE_STRING = 9L << FIELD_TYPE_SHIFT;
+
// public static final long FIELD_TYPE_GROUP = 10L << FIELD_TYPE_SHIFT; // Deprecated.
+
+ /**
+ * Field type code for message fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#start(long)
+ * ProtoOutputStream.start(long)} method.
+ */
public static final long FIELD_TYPE_MESSAGE = 11L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for bytes fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, byte[])
+ * ProtoOutputStream.write(long, byte[])} method.
+ */
public static final long FIELD_TYPE_BYTES = 12L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for uint32 fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, int)
+ * ProtoOutputStream.write(long, int)} method.
+ */
public static final long FIELD_TYPE_UINT32 = 13L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for enum fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, int)
+ * ProtoOutputStream.write(long, int)} method.
+ */
public static final long FIELD_TYPE_ENUM = 14L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for sfixed32 fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, int)
+ * ProtoOutputStream.write(long, int)} method.
+ */
public static final long FIELD_TYPE_SFIXED32 = 15L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for sfixed64 fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, long)
+ * ProtoOutputStream.write(long, long)} method.
+ */
public static final long FIELD_TYPE_SFIXED64 = 16L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for sint32 fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, int)
+ * ProtoOutputStream.write(long, int)} method.
+ */
public static final long FIELD_TYPE_SINT32 = 17L << FIELD_TYPE_SHIFT;
+
+ /**
+ * Field type code for sint64 fields. Used to build constants in generated
+ * code for use with the {@link ProtoOutputStream#write(long, long)
+ * ProtoOutputStream.write(long, long)} method.
+ */
public static final long FIELD_TYPE_SINT64 = 18L << FIELD_TYPE_SHIFT;
- protected static final String[] FIELD_TYPE_NAMES = new String[]{
+ private static final @NonNull String[] FIELD_TYPE_NAMES = new String[]{
"Double",
"Float",
"Int64",
@@ -100,19 +291,94 @@ public abstract class ProtoStream {
//
// FieldId flags for whether the field is single, repeated or packed.
//
+ /**
+ * Bit offset for building a field id to be used with a
+ * <code>{@link ProtoOutputStream}.write(...)</code>.
+ *
+ * @see #FIELD_COUNT_MASK
+ * @see #FIELD_COUNT_UNKNOWN
+ * @see #FIELD_COUNT_SINGLE
+ * @see #FIELD_COUNT_REPEATED
+ * @see #FIELD_COUNT_PACKED
+ */
public static final int FIELD_COUNT_SHIFT = 40;
+
+ /**
+ * Bit mask for selecting the field count when reading a field id that
+ * is used with a <code>{@link ProtoOutputStream}.write(...)</code> method.
+ *
+ * @see #FIELD_COUNT_SHIFT
+ * @see #FIELD_COUNT_MASK
+ * @see #FIELD_COUNT_UNKNOWN
+ * @see #FIELD_COUNT_SINGLE
+ * @see #FIELD_COUNT_REPEATED
+ * @see #FIELD_COUNT_PACKED
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * Encoding</a>
+ */
public static final long FIELD_COUNT_MASK = 0x0fL << FIELD_COUNT_SHIFT;
+ /**
+ * Unknown field count, encoded into a field id used with a
+ * <code>{@link ProtoOutputStream}.write(...)</code> method.
+ *
+ * @see #FIELD_COUNT_SHIFT
+ * @see #FIELD_COUNT_MASK
+ * @see #FIELD_COUNT_SINGLE
+ * @see #FIELD_COUNT_REPEATED
+ * @see #FIELD_COUNT_PACKED
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * Encoding</a>
+ */
public static final long FIELD_COUNT_UNKNOWN = 0;
+
+ /**
+ * Single field count, encoded into a field id used with a
+ * <code>{@link ProtoOutputStream}.write(...)</code> method.
+ *
+ * @see #FIELD_COUNT_SHIFT
+ * @see #FIELD_COUNT_MASK
+ * @see #FIELD_COUNT_UNKNOWN
+ * @see #FIELD_COUNT_REPEATED
+ * @see #FIELD_COUNT_PACKED
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * Encoding</a>
+ */
public static final long FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
+
+ /**
+ * Repeated field count, encoded into a field id used with a
+ * <code>{@link ProtoOutputStream}.write(...)</code> method.
+ *
+ * @see #FIELD_COUNT_SHIFT
+ * @see #FIELD_COUNT_MASK
+ * @see #FIELD_COUNT_UNKNOWN
+ * @see #FIELD_COUNT_SINGLE
+ * @see #FIELD_COUNT_PACKED
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * Encoding</a>
+ */
public static final long FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
+
+ /**
+ * Repeated packed field count, encoded into a field id used with a
+ * <code>{@link ProtoOutputStream}.write(...)</code> method.
+ *
+ * @see #FIELD_COUNT_SHIFT
+ * @see #FIELD_COUNT_MASK
+ * @see #FIELD_COUNT_UNKNOWN
+ * @see #FIELD_COUNT_SINGLE
+ * @see #FIELD_COUNT_REPEATED
+ * @see <a href="https://developers.google.com/protocol-buffers/docs/encoding">Protobuf
+ * Encoding</a>
+ */
public static final long FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
/**
* Get the developer-usable name of a field type.
*/
- public static String getFieldTypeString(long fieldType) {
+ public static @Nullable String getFieldTypeString(long fieldType) {
int index = ((int) ((fieldType & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) - 1;
if (index >= 0 && index < FIELD_TYPE_NAMES.length) {
return FIELD_TYPE_NAMES[index];
@@ -124,7 +390,7 @@ public abstract class ProtoStream {
/**
* Get the developer-usable name of a field count.
*/
- public static String getFieldCountString(long fieldCount) {
+ public static @Nullable String getFieldCountString(long fieldCount) {
if (fieldCount == FIELD_COUNT_SINGLE) {
return "";
} else if (fieldCount == FIELD_COUNT_REPEATED) {
@@ -139,7 +405,7 @@ public abstract class ProtoStream {
/**
* Get the developer-usable name of a wire type.
*/
- public static String getWireTypeString(int wireType) {
+ public static @Nullable String getWireTypeString(int wireType) {
switch (wireType) {
case WIRE_TYPE_VARINT:
return "Varint";
@@ -161,7 +427,7 @@ public abstract class ProtoStream {
/**
* Get a debug string for a fieldId.
*/
- public static String getFieldIdString(long fieldId) {
+ public static @NonNull String getFieldIdString(long fieldId) {
final long fieldCount = fieldId & FIELD_COUNT_MASK;
String countString = getFieldCountString(fieldCount);
if (countString == null) {
@@ -218,29 +484,39 @@ public abstract class ProtoStream {
/**
* Get the encoded tag size from the token.
+ *
+ * @hide
*/
public static int getTagSizeFromToken(long token) {
return (int) (0x7 & (token >> 61));
}
/**
- * Get whether this is a call to startObject (false) or startRepeatedObject (true).
+ * Get whether the token has the repeated bit set to true or false
+ *
+ * @hide
*/
public static boolean getRepeatedFromToken(long token) {
return (0x1 & (token >> 60)) != 0;
}
/**
- * Get the nesting depth of startObject calls from the token.
+ * Get the nesting depth from the token.
+ *
+ * @hide
*/
public static int getDepthFromToken(long token) {
return (int) (0x01ff & (token >> 51));
}
/**
- * Get the object ID from the token. The object ID is a serial number for the
+ * Get the object ID from the token.
+ *
+ * <p>The object ID is a serial number for the
* startObject calls that have happened on this object. The values are truncated
* to 9 bits, but that is sufficient for error checking.
+ *
+ * @hide
*/
public static int getObjectIdFromToken(long token) {
return (int) (0x07ffff & (token >> 32));
@@ -248,6 +524,8 @@ public abstract class ProtoStream {
/**
* Get the location of the offset recorded in the token.
+ *
+ * @hide
*/
public static int getOffsetFromToken(long token) {
return (int) token;
@@ -255,8 +533,11 @@ public abstract class ProtoStream {
/**
* Convert the object ID to the ordinal value -- the n-th call to startObject.
- * The object IDs start at -1 and count backwards, so that the value is unlikely
+ *
+ * <p>The object IDs start at -1 and count backwards, so that the value is unlikely
* to alias with an actual size field that had been written.
+ *
+ * @hide
*/
public static int convertObjectIdToOrdinal(int objectId) {
return (-1 & 0x07ffff) - objectId;
@@ -265,7 +546,7 @@ public abstract class ProtoStream {
/**
* Return a debugging string of a token.
*/
- public static String token2String(long token) {
+ public static @NonNull String token2String(long token) {
if (token == 0L) {
return "Token(0)";
} else {
@@ -277,4 +558,9 @@ public abstract class ProtoStream {
+ ')';
}
}
+
+ /**
+ * @hide
+ */
+ protected ProtoStream() {}
}
diff --git a/core/java/android/util/proto/ProtoUtils.java b/core/java/android/util/proto/ProtoUtils.java
index 03bf590902c0..a71561b7614b 100644
--- a/core/java/android/util/proto/ProtoUtils.java
+++ b/core/java/android/util/proto/ProtoUtils.java
@@ -24,12 +24,12 @@ import java.io.IOException;
/**
* This class contains a list of helper functions to write common proto in
* //frameworks/base/core/proto/android/base directory
+ * @hide
*/
public class ProtoUtils {
/**
* Dump AggStats to ProtoOutputStream
- * @hide
*/
public static void toAggStatsProto(ProtoOutputStream proto, long fieldId,
long min, long average, long max) {
@@ -42,7 +42,6 @@ public class ProtoUtils {
/**
* Dump Duration to ProtoOutputStream
- * @hide
*/
public static void toDuration(ProtoOutputStream proto, long fieldId, long startMs, long endMs) {
final long token = proto.start(fieldId);
@@ -53,7 +52,6 @@ public class ProtoUtils {
/**
* Helper function to write bit-wise flags to proto as repeated enums
- * @hide
*/
public static void writeBitWiseFlagsToProtoEnum(ProtoOutputStream proto, long fieldId,
int flags, int[] origEnums, int[] protoEnums) {
diff --git a/core/java/android/util/proto/package.html b/core/java/android/util/proto/package.html
index a636bd457d3d..ef1125b5f248 100644
--- a/core/java/android/util/proto/package.html
+++ b/core/java/android/util/proto/package.html
@@ -1,5 +1,5 @@
+<html>
<body>
Provides utility classes to export protocol buffers from the system.
-
-{@hide}
</body>
+</html> \ No newline at end of file
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 52ce54bc8924..7bf35f9a9864 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -193,7 +193,8 @@ static int read_memtrack_memory(struct memtrack_proc* p, int pid,
{
int err = memtrack_proc_get(p, pid);
if (err != 0) {
- ALOGW("failed to get memory consumption info: %d", err);
+ // The memtrack HAL may not be available, do not log to avoid flooding
+ // logcat.
return err;
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 78ccba4c29dc..486df621f4f1 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1063,22 +1063,16 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
DropCapabilitiesBoundingSet(fail_fn);
- bool use_native_bridge = !is_system_server &&
- instruction_set.has_value() &&
- android::NativeBridgeAvailable() &&
- android::NeedsNativeBridge(instruction_set.value().c_str());
+ bool need_pre_initialize_native_bridge =
+ !is_system_server &&
+ instruction_set.has_value() &&
+ android::NativeBridgeAvailable() &&
+ // Native bridge may be already initialized if this
+ // is an app forked from app-zygote.
+ !android::NativeBridgeInitialized() &&
+ android::NeedsNativeBridge(instruction_set.value().c_str());
- if (use_native_bridge && !app_data_dir.has_value()) {
- // The app_data_dir variable should never be empty if we need to use a
- // native bridge. In general, app_data_dir will never be empty for normal
- // applications. It can only happen in special cases (for isolated
- // processes which are not associated with any app). These are launched by
- // the framework and should not be emulated anyway.
- use_native_bridge = false;
- ALOGW("Native bridge will not be used because managed_app_data_dir == nullptr.");
- }
-
- MountEmulatedStorage(uid, mount_external, use_native_bridge, fail_fn);
+ MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, fail_fn);
// If this zygote isn't root, it won't be able to create a process group,
// since the directory is owned by root.
@@ -1094,11 +1088,12 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
SetGids(env, gids, fail_fn);
SetRLimits(env, rlimits, fail_fn);
- if (use_native_bridge) {
- // Due to the logic behind use_native_bridge we know that both app_data_dir
- // and instruction_set contain values.
- android::PreInitializeNativeBridge(app_data_dir.value().c_str(),
- instruction_set.value().c_str());
+ if (need_pre_initialize_native_bridge) {
+ // Due to the logic behind need_pre_initialize_native_bridge we know that
+ // instruction_set contains a value.
+ android::PreInitializeNativeBridge(
+ app_data_dir.has_value() ? app_data_dir.value().c_str() : nullptr,
+ instruction_set.value().c_str());
}
if (setresgid(gid, gid, gid) == -1) {
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4aa44fc6ebaa..9bc0d969aed9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5393,6 +5393,10 @@
<!-- Description of media type: presentation file, such as PPT. The 'extension' variable is the file name extension. [CHAR LIMIT=32] -->
<string name="mime_type_presentation_ext"><xliff:g id="extension" example="PDF">%1$s</xliff:g> presentation</string>
+ <!-- Strings for Bluetooth service -->
+ <!-- toast message informing user that Bluetooth stays on after airplane mode is turned on. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_airplane_mode_toast">Bluetooth will stay on during airplane mode</string>
+
<!-- Strings for car -->
<!-- String displayed when loading a user in the car [CHAR LIMIT=30] -->
<string name="car_loading_profile">Loading</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 383fcd4753f0..cd43e9fca526 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3795,6 +3795,9 @@
<java-symbol type="string" name="mime_type_presentation" />
<java-symbol type="string" name="mime_type_presentation_ext" />
+ <!-- For Bluetooth service -->
+ <java-symbol type="string" name="bluetooth_airplane_mode_toast" />
+
<!-- For high refresh rate displays -->
<java-symbol type="integer" name="config_defaultPeakRefreshRate" />
<java-symbol type="integer" name="config_defaultRefreshRateInZone" />
diff --git a/core/tests/overlaytests/host/Android.bp b/core/tests/overlaytests/host/Android.bp
new file mode 100644
index 000000000000..a2fcef56b780
--- /dev/null
+++ b/core/tests/overlaytests/host/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_test_host {
+ name: "OverlayHostTests",
+ srcs: ["src/**/*.java"],
+ libs: ["tradefed"],
+ test_suites: ["general-tests"],
+ target_required: [
+ "OverlayHostTests_NonPlatformSignatureOverlay",
+ "OverlayHostTests_PlatformSignatureStaticOverlay",
+ "OverlayHostTests_PlatformSignatureOverlay",
+ "OverlayHostTests_UpdateOverlay",
+ "OverlayHostTests_FrameworkOverlayV1",
+ "OverlayHostTests_FrameworkOverlayV2",
+ "OverlayHostTests_AppOverlayV1",
+ "OverlayHostTests_AppOverlayV2",
+ ],
+}
diff --git a/core/tests/overlaytests/host/Android.mk b/core/tests/overlaytests/host/Android.mk
index e7348d52adfe..d58d9393c0b8 100644
--- a/core/tests/overlaytests/host/Android.mk
+++ b/core/tests/overlaytests/host/Android.mk
@@ -14,23 +14,6 @@
LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-java-files-under,src)
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE := OverlayHostTests
-LOCAL_JAVA_LIBRARIES := tradefed
-LOCAL_COMPATIBILITY_SUITE := general-tests
-LOCAL_TARGET_REQUIRED_MODULES := \
- OverlayHostTests_NonPlatformSignatureOverlay \
- OverlayHostTests_PlatformSignatureStaticOverlay \
- OverlayHostTests_PlatformSignatureOverlay \
- OverlayHostTests_UpdateOverlay \
- OverlayHostTests_FrameworkOverlayV1 \
- OverlayHostTests_FrameworkOverlayV2 \
- OverlayHostTests_AppOverlayV1 \
- OverlayHostTests_AppOverlayV2
-include $(BUILD_HOST_JAVA_LIBRARY)
-
# Include to build test-apps.
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index a818119f8103..eec2072c6d5d 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -67,7 +67,6 @@ applications that come with the platform
<privapp-permissions package="com.android.managedprovisioning">
<permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
<permission name="android.permission.CHANGE_CONFIGURATION"/>
- <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
<permission name="android.permission.CRYPT_KEEPER"/>
<permission name="android.permission.DELETE_PACKAGES"/>
<permission name="android.permission.INSTALL_PACKAGES"/>
@@ -362,7 +361,6 @@ applications that come with the platform
</privapp-permissions>
<privapp-permissions package="com.android.vpndialogs">
- <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
<permission name="android.permission.CONTROL_VPN"/>
</privapp-permissions>
diff --git a/identity/MODULE_LICENSE_APACHE2 b/identity/MODULE_LICENSE_APACHE2
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/identity/MODULE_LICENSE_APACHE2
diff --git a/identity/NOTICE b/identity/NOTICE
new file mode 100644
index 000000000000..64aaa8dbd68e
--- /dev/null
+++ b/identity/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2009, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/identity/OWNERS b/identity/OWNERS
new file mode 100644
index 000000000000..533d90b2cd13
--- /dev/null
+++ b/identity/OWNERS
@@ -0,0 +1,3 @@
+swillden@google.com
+zeuthen@google.com
+
diff --git a/identity/java/android/security/identity/AccessControlProfile.java b/identity/java/android/security/identity/AccessControlProfile.java
new file mode 100644
index 000000000000..10e451c97707
--- /dev/null
+++ b/identity/java/android/security/identity/AccessControlProfile.java
@@ -0,0 +1,131 @@
+/*
+ * 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.security.identity;
+
+import android.annotation.NonNull;
+
+import java.security.cert.X509Certificate;
+
+/**
+ * A class used to specify access controls.
+ */
+public class AccessControlProfile {
+ private AccessControlProfileId mAccessControlProfileId = new AccessControlProfileId(0);
+ private X509Certificate mReaderCertificate = null;
+ private boolean mUserAuthenticationRequired = true;
+ private long mUserAuthenticationTimeout = 0;
+
+ private AccessControlProfile() {
+ }
+
+ AccessControlProfileId getAccessControlProfileId() {
+ return mAccessControlProfileId;
+ }
+
+ long getUserAuthenticationTimeout() {
+ return mUserAuthenticationTimeout;
+ }
+
+ boolean isUserAuthenticationRequired() {
+ return mUserAuthenticationRequired;
+ }
+
+ X509Certificate getReaderCertificate() {
+ return mReaderCertificate;
+ }
+
+ /**
+ * A builder for {@link AccessControlProfile}.
+ */
+ public static final class Builder {
+ private AccessControlProfile mProfile;
+
+ /**
+ * Each access control profile has numeric identifier that must be unique within the
+ * context of a Credential and may be used to reference the profile.
+ *
+ * <p>By default, the resulting {@link AccessControlProfile} will require user
+ * authentication with a timeout of zero, thus requiring the holder to authenticate for
+ * every presentation where data elements using this access control profile is used.</p>
+ *
+ * @param accessControlProfileId the access control profile identifier.
+ */
+ public Builder(@NonNull AccessControlProfileId accessControlProfileId) {
+ mProfile = new AccessControlProfile();
+ mProfile.mAccessControlProfileId = accessControlProfileId;
+ }
+
+ /**
+ * Set whether user authentication is required.
+ *
+ * <p>This should be used sparingly since disabling user authentication on just a single
+ * data element can easily create a
+ * <a href="https://en.wikipedia.org/wiki/Relay_attack">Relay Attack</a> if the device
+ * on which the credential is stored is compromised.</p>
+ *
+ * @param userAuthenticationRequired Set to true if user authentication is required,
+ * false otherwise.
+ * @return The builder.
+ */
+ public @NonNull Builder setUserAuthenticationRequired(boolean userAuthenticationRequired) {
+ mProfile.mUserAuthenticationRequired = userAuthenticationRequired;
+ return this;
+ }
+
+ /**
+ * Sets the authentication timeout to use.
+ *
+ * <p>The authentication timeout specifies the amount of time, in milliseconds, for which a
+ * user authentication is valid, if user authentication is required (see
+ * {@link #setUserAuthenticationRequired(boolean)}).</p>
+ *
+ * <p>If the timeout is zero, then authentication is always required for each reader
+ * session.</p>
+ *
+ * @param userAuthenticationTimeoutMillis the authentication timeout, in milliseconds.
+ * @return The builder.
+ */
+ public @NonNull Builder setUserAuthenticationTimeout(long userAuthenticationTimeoutMillis) {
+ mProfile.mUserAuthenticationTimeout = userAuthenticationTimeoutMillis;
+ return this;
+ }
+
+ /**
+ * Sets the reader certificate to use when checking access control.
+ *
+ * <p>If set, this is checked against the certificate chain presented by
+ * reader. The access check is fulfilled only if one of the certificates
+ * in the chain, matches the certificate set by this method.</p>
+ *
+ * @param readerCertificate the certificate to use for the access control check.
+ * @return The builder.
+ */
+ public @NonNull Builder setReaderCertificate(@NonNull X509Certificate readerCertificate) {
+ mProfile.mReaderCertificate = readerCertificate;
+ return this;
+ }
+
+ /**
+ * Creates a new {@link AccessControlProfile} from the data supplied to the builder.
+ *
+ * @return The created {@link AccessControlProfile} object.
+ */
+ public @NonNull AccessControlProfile build() {
+ return mProfile;
+ }
+ }
+}
diff --git a/identity/java/android/security/identity/AccessControlProfileId.java b/identity/java/android/security/identity/AccessControlProfileId.java
new file mode 100644
index 000000000000..3d5945065ad7
--- /dev/null
+++ b/identity/java/android/security/identity/AccessControlProfileId.java
@@ -0,0 +1,42 @@
+/*
+ * 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.security.identity;
+
+/**
+ * A class used to wrap an access control profile identifiers.
+ */
+public class AccessControlProfileId {
+ private int mId = 0;
+
+ /**
+ * Constructs a new object holding a numerical identifier.
+ *
+ * @param id the identifier.
+ */
+ public AccessControlProfileId(int id) {
+ this.mId = id;
+ }
+
+ /**
+ * Gets the numerical identifier wrapped by this object.
+ *
+ * @return the identifier.
+ */
+ public int getId() {
+ return this.mId;
+ }
+}
diff --git a/identity/java/android/security/identity/AlreadyPersonalizedException.java b/identity/java/android/security/identity/AlreadyPersonalizedException.java
new file mode 100644
index 000000000000..1933882aa4bf
--- /dev/null
+++ b/identity/java/android/security/identity/AlreadyPersonalizedException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown if trying to create a credential which already exists.
+ */
+public class AlreadyPersonalizedException extends IdentityCredentialException {
+ /**
+ * Constructs a new {@link AlreadyPersonalizedException} exception.
+ *
+ * @param message the detail message.
+ */
+ public AlreadyPersonalizedException(@NonNull String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new {@link AlreadyPersonalizedException} exception.
+ *
+ * @param message the detail message.
+ * @param cause the cause.
+ */
+ public AlreadyPersonalizedException(@NonNull String message, @NonNull Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/identity/java/android/security/identity/CipherSuiteNotSupportedException.java b/identity/java/android/security/identity/CipherSuiteNotSupportedException.java
new file mode 100644
index 000000000000..e7a6c8969482
--- /dev/null
+++ b/identity/java/android/security/identity/CipherSuiteNotSupportedException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown if trying to use a cipher suite which isn't supported.
+ */
+public class CipherSuiteNotSupportedException extends IdentityCredentialException {
+ /**
+ * Constructs a new {@link CipherSuiteNotSupportedException} exception.
+ *
+ * @param message the detail message.
+ */
+ public CipherSuiteNotSupportedException(@NonNull String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new {@link CipherSuiteNotSupportedException} exception.
+ *
+ * @param message the detail message.
+ * @param cause the cause.
+ */
+ public CipherSuiteNotSupportedException(@NonNull String message, @NonNull Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/identity/java/android/security/identity/CredstoreIdentityCredential.java b/identity/java/android/security/identity/CredstoreIdentityCredential.java
new file mode 100644
index 000000000000..c520331ab72d
--- /dev/null
+++ b/identity/java/android/security/identity/CredstoreIdentityCredential.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.Map;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyAgreement;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+class CredstoreIdentityCredential extends IdentityCredential {
+
+ private static final String TAG = "CredstoreIdentityCredential";
+ private String mCredentialName;
+ private @IdentityCredentialStore.Ciphersuite int mCipherSuite;
+ private Context mContext;
+ private ICredential mBinder;
+
+ CredstoreIdentityCredential(Context context, String credentialName,
+ @IdentityCredentialStore.Ciphersuite int cipherSuite,
+ ICredential binder) {
+ mContext = context;
+ mCredentialName = credentialName;
+ mCipherSuite = cipherSuite;
+ mBinder = binder;
+ }
+
+ private KeyPair mEphemeralKeyPair = null;
+ private SecretKey mSecretKey = null;
+ private SecretKey mReaderSecretKey = null;
+ private int mEphemeralCounter;
+ private int mReadersExpectedEphemeralCounter;
+
+ private void ensureEphemeralKeyPair() {
+ if (mEphemeralKeyPair != null) {
+ return;
+ }
+ try {
+ // This PKCS#12 blob is generated in credstore, using BoringSSL.
+ //
+ // The main reason for this convoluted approach and not just sending the decomposed
+ // key-pair is that this would require directly using (device-side) BouncyCastle which
+ // is tricky due to various API hiding efforts. So instead we have credstore generate
+ // this PKCS#12 blob. The blob is encrypted with no password (sadly, also, BoringSSL
+ // doesn't support not using encryption when building a PKCS#12 blob).
+ //
+ byte[] pkcs12 = mBinder.createEphemeralKeyPair();
+ String alias = "ephemeralKey";
+ char[] password = {};
+
+ KeyStore ks = KeyStore.getInstance("PKCS12");
+ ByteArrayInputStream bais = new ByteArrayInputStream(pkcs12);
+ ks.load(bais, password);
+ PrivateKey privKey = (PrivateKey) ks.getKey(alias, password);
+
+ Certificate cert = ks.getCertificate(alias);
+ PublicKey pubKey = cert.getPublicKey();
+
+ mEphemeralKeyPair = new KeyPair(pubKey, privKey);
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ } catch (KeyStoreException
+ | CertificateException
+ | UnrecoverableKeyException
+ | NoSuchAlgorithmException
+ | IOException e) {
+ throw new RuntimeException("Unexpected exception ", e);
+ }
+ }
+
+ @Override
+ public @NonNull KeyPair createEphemeralKeyPair() {
+ ensureEphemeralKeyPair();
+ return mEphemeralKeyPair;
+ }
+
+ @Override
+ public void setReaderEphemeralPublicKey(@NonNull PublicKey readerEphemeralPublicKey)
+ throws InvalidKeyException {
+ try {
+ byte[] uncompressedForm =
+ Util.publicKeyEncodeUncompressedForm(readerEphemeralPublicKey);
+ mBinder.setReaderEphemeralPublicKey(uncompressedForm);
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+
+ ensureEphemeralKeyPair();
+
+ try {
+ KeyAgreement ka = KeyAgreement.getInstance("ECDH");
+ ka.init(mEphemeralKeyPair.getPrivate());
+ ka.doPhase(readerEphemeralPublicKey, true);
+ byte[] sharedSecret = ka.generateSecret();
+
+ byte[] salt = new byte[1];
+ byte[] info = new byte[0];
+
+ salt[0] = 0x01;
+ byte[] derivedKey = Util.computeHkdf("HmacSha256", sharedSecret, salt, info, 32);
+ mSecretKey = new SecretKeySpec(derivedKey, "AES");
+
+ salt[0] = 0x00;
+ derivedKey = Util.computeHkdf("HmacSha256", sharedSecret, salt, info, 32);
+ mReaderSecretKey = new SecretKeySpec(derivedKey, "AES");
+
+ mEphemeralCounter = 0;
+ mReadersExpectedEphemeralCounter = 0;
+
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("Error performing key agreement", e);
+ }
+ }
+
+ @Override
+ public @NonNull byte[] encryptMessageToReader(@NonNull byte[] messagePlaintext) {
+ byte[] messageCiphertextAndAuthTag = null;
+ try {
+ ByteBuffer iv = ByteBuffer.allocate(12);
+ iv.putInt(0, 0x00000000);
+ iv.putInt(4, 0x00000001);
+ iv.putInt(8, mEphemeralCounter);
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ GCMParameterSpec encryptionParameterSpec = new GCMParameterSpec(128, iv.array());
+ cipher.init(Cipher.ENCRYPT_MODE, mSecretKey, encryptionParameterSpec);
+ messageCiphertextAndAuthTag = cipher.doFinal(messagePlaintext);
+ } catch (BadPaddingException
+ | IllegalBlockSizeException
+ | NoSuchPaddingException
+ | InvalidKeyException
+ | NoSuchAlgorithmException
+ | InvalidAlgorithmParameterException e) {
+ throw new RuntimeException("Error encrypting message", e);
+ }
+ mEphemeralCounter += 1;
+ return messageCiphertextAndAuthTag;
+ }
+
+ @Override
+ public @NonNull byte[] decryptMessageFromReader(@NonNull byte[] messageCiphertext)
+ throws MessageDecryptionException {
+ ByteBuffer iv = ByteBuffer.allocate(12);
+ iv.putInt(0, 0x00000000);
+ iv.putInt(4, 0x00000000);
+ iv.putInt(8, mReadersExpectedEphemeralCounter);
+ byte[] plainText = null;
+ try {
+ final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(Cipher.DECRYPT_MODE, mReaderSecretKey,
+ new GCMParameterSpec(128, iv.array()));
+ plainText = cipher.doFinal(messageCiphertext);
+ } catch (BadPaddingException
+ | IllegalBlockSizeException
+ | InvalidAlgorithmParameterException
+ | InvalidKeyException
+ | NoSuchAlgorithmException
+ | NoSuchPaddingException e) {
+ throw new MessageDecryptionException("Error decrypting message", e);
+ }
+ mReadersExpectedEphemeralCounter += 1;
+ return plainText;
+ }
+
+ @Override
+ public @NonNull Collection<X509Certificate> getCredentialKeyCertificateChain() {
+ try {
+ byte[] certsBlob = mBinder.getCredentialKeyCertificateChain();
+ ByteArrayInputStream bais = new ByteArrayInputStream(certsBlob);
+
+ Collection<? extends Certificate> certs = null;
+ try {
+ CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ certs = factory.generateCertificates(bais);
+ } catch (CertificateException e) {
+ throw new RuntimeException("Error decoding certificates", e);
+ }
+
+ LinkedList<X509Certificate> x509Certs = new LinkedList<>();
+ for (Certificate cert : certs) {
+ x509Certs.add((X509Certificate) cert);
+ }
+ return x509Certs;
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+
+ private boolean mAllowUsingExhaustedKeys = true;
+
+ @Override
+ public void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys) {
+ mAllowUsingExhaustedKeys = allowUsingExhaustedKeys;
+ }
+
+ private boolean mOperationHandleSet = false;
+ private long mOperationHandle = 0;
+
+ /**
+ * Called by android.hardware.biometrics.CryptoObject#getOpId() to get an
+ * operation handle.
+ *
+ * @hide
+ */
+ @Override
+ public long getCredstoreOperationHandle() {
+ if (!mOperationHandleSet) {
+ try {
+ mOperationHandle = mBinder.selectAuthKey(mAllowUsingExhaustedKeys);
+ mOperationHandleSet = true;
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ if (e.errorCode == ICredentialStore.ERROR_NO_AUTHENTICATION_KEY_AVAILABLE) {
+ // The NoAuthenticationKeyAvailableException will be thrown when
+ // the caller proceeds to call getEntries().
+ }
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+ return mOperationHandle;
+ }
+
+ @NonNull
+ @Override
+ public ResultData getEntries(
+ @Nullable byte[] requestMessage,
+ @NonNull Map<String, Collection<String>> entriesToRequest,
+ @Nullable byte[] sessionTranscript,
+ @Nullable byte[] readerSignature)
+ throws SessionTranscriptMismatchException, NoAuthenticationKeyAvailableException,
+ InvalidReaderSignatureException, EphemeralPublicKeyNotFoundException,
+ InvalidRequestMessageException {
+
+ RequestNamespaceParcel[] rnsParcels = new RequestNamespaceParcel[entriesToRequest.size()];
+ int n = 0;
+ for (String namespaceName : entriesToRequest.keySet()) {
+ Collection<String> entryNames = entriesToRequest.get(namespaceName);
+ rnsParcels[n] = new RequestNamespaceParcel();
+ rnsParcels[n].namespaceName = namespaceName;
+ rnsParcels[n].entries = new RequestEntryParcel[entryNames.size()];
+ int m = 0;
+ for (String entryName : entryNames) {
+ rnsParcels[n].entries[m] = new RequestEntryParcel();
+ rnsParcels[n].entries[m].name = entryName;
+ m++;
+ }
+ n++;
+ }
+
+ GetEntriesResultParcel resultParcel = null;
+ try {
+ resultParcel = mBinder.getEntries(
+ requestMessage != null ? requestMessage : new byte[0],
+ rnsParcels,
+ sessionTranscript != null ? sessionTranscript : new byte[0],
+ readerSignature != null ? readerSignature : new byte[0],
+ mAllowUsingExhaustedKeys);
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ if (e.errorCode == ICredentialStore.ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND) {
+ throw new EphemeralPublicKeyNotFoundException(e.getMessage(), e);
+ } else if (e.errorCode == ICredentialStore.ERROR_INVALID_READER_SIGNATURE) {
+ throw new InvalidReaderSignatureException(e.getMessage(), e);
+ } else if (e.errorCode == ICredentialStore.ERROR_NO_AUTHENTICATION_KEY_AVAILABLE) {
+ throw new NoAuthenticationKeyAvailableException(e.getMessage(), e);
+ } else if (e.errorCode == ICredentialStore.ERROR_INVALID_ITEMS_REQUEST_MESSAGE) {
+ throw new InvalidRequestMessageException(e.getMessage(), e);
+ } else if (e.errorCode == ICredentialStore.ERROR_SESSION_TRANSCRIPT_MISMATCH) {
+ throw new SessionTranscriptMismatchException(e.getMessage(), e);
+ } else {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+
+ byte[] mac = resultParcel.mac;
+ if (mac != null && mac.length == 0) {
+ mac = null;
+ }
+ CredstoreResultData.Builder resultDataBuilder = new CredstoreResultData.Builder(
+ resultParcel.staticAuthenticationData, resultParcel.deviceNameSpaces, mac);
+
+ for (ResultNamespaceParcel resultNamespaceParcel : resultParcel.resultNamespaces) {
+ for (ResultEntryParcel resultEntryParcel : resultNamespaceParcel.entries) {
+ if (resultEntryParcel.status == ICredential.STATUS_OK) {
+ resultDataBuilder.addEntry(resultNamespaceParcel.namespaceName,
+ resultEntryParcel.name, resultEntryParcel.value);
+ } else {
+ resultDataBuilder.addErrorStatus(resultNamespaceParcel.namespaceName,
+ resultEntryParcel.name,
+ resultEntryParcel.status);
+ }
+ }
+ }
+ return resultDataBuilder.build();
+ }
+
+ @Override
+ public void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) {
+ try {
+ mBinder.setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+
+ @Override
+ public @NonNull Collection<X509Certificate> getAuthKeysNeedingCertification() {
+ try {
+ AuthKeyParcel[] authKeyParcels = mBinder.getAuthKeysNeedingCertification();
+ LinkedList<X509Certificate> x509Certs = new LinkedList<>();
+ CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ for (AuthKeyParcel authKeyParcel : authKeyParcels) {
+ Collection<? extends Certificate> certs = null;
+ ByteArrayInputStream bais = new ByteArrayInputStream(authKeyParcel.x509cert);
+ certs = factory.generateCertificates(bais);
+ if (certs.size() != 1) {
+ throw new RuntimeException("Returned blob yields more than one X509 cert");
+ }
+ X509Certificate authKeyCert = (X509Certificate) certs.iterator().next();
+ x509Certs.add(authKeyCert);
+ }
+ return x509Certs;
+ } catch (CertificateException e) {
+ throw new RuntimeException("Error decoding authenticationKey", e);
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+
+ @Override
+ public void storeStaticAuthenticationData(X509Certificate authenticationKey,
+ byte[] staticAuthData)
+ throws UnknownAuthenticationKeyException {
+ try {
+ AuthKeyParcel authKeyParcel = new AuthKeyParcel();
+ authKeyParcel.x509cert = authenticationKey.getEncoded();
+ mBinder.storeStaticAuthenticationData(authKeyParcel, staticAuthData);
+ } catch (CertificateEncodingException e) {
+ throw new RuntimeException("Error encoding authenticationKey", e);
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ if (e.errorCode == ICredentialStore.ERROR_AUTHENTICATION_KEY_NOT_FOUND) {
+ throw new UnknownAuthenticationKeyException(e.getMessage(), e);
+ } else {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+ }
+
+ @Override
+ public @NonNull int[] getAuthenticationDataUsageCount() {
+ try {
+ int[] usageCount = mBinder.getAuthenticationDataUsageCount();
+ return usageCount;
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+}
diff --git a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
new file mode 100644
index 000000000000..dcc6b95aec02
--- /dev/null
+++ b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.ServiceManager;
+
+class CredstoreIdentityCredentialStore extends IdentityCredentialStore {
+
+ private static final String TAG = "CredstoreIdentityCredentialStore";
+
+ private Context mContext = null;
+ private ICredentialStore mStore = null;
+
+ private CredstoreIdentityCredentialStore(@NonNull Context context, ICredentialStore store) {
+ mContext = context;
+ mStore = store;
+ }
+
+ static CredstoreIdentityCredentialStore getInstanceForType(@NonNull Context context,
+ int credentialStoreType) {
+ ICredentialStoreFactory storeFactory =
+ ICredentialStoreFactory.Stub.asInterface(
+ ServiceManager.getService("android.security.identity"));
+
+ ICredentialStore credStore = null;
+ try {
+ credStore = storeFactory.getCredentialStore(credentialStoreType);
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ if (e.errorCode == ICredentialStore.ERROR_GENERIC) {
+ return null;
+ } else {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+ if (credStore == null) {
+ return null;
+ }
+
+ return new CredstoreIdentityCredentialStore(context, credStore);
+ }
+
+ private static CredstoreIdentityCredentialStore sInstanceDefault = null;
+ private static CredstoreIdentityCredentialStore sInstanceDirectAccess = null;
+
+ public static @Nullable IdentityCredentialStore getInstance(@NonNull Context context) {
+ if (sInstanceDefault == null) {
+ sInstanceDefault = getInstanceForType(context,
+ ICredentialStoreFactory.CREDENTIAL_STORE_TYPE_DEFAULT);
+ }
+ return sInstanceDefault;
+ }
+
+ public static @Nullable IdentityCredentialStore getDirectAccessInstance(@NonNull
+ Context context) {
+ if (sInstanceDirectAccess == null) {
+ sInstanceDirectAccess = getInstanceForType(context,
+ ICredentialStoreFactory.CREDENTIAL_STORE_TYPE_DIRECT_ACCESS);
+ }
+ return sInstanceDirectAccess;
+ }
+
+ @Override
+ public @NonNull String[] getSupportedDocTypes() {
+ try {
+ SecurityHardwareInfoParcel info;
+ info = mStore.getSecurityHardwareInfo();
+ return info.supportedDocTypes;
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+
+ @Override public @NonNull WritableIdentityCredential createCredential(
+ @NonNull String credentialName,
+ @NonNull String docType) throws AlreadyPersonalizedException,
+ DocTypeNotSupportedException {
+ try {
+ IWritableCredential wc;
+ wc = mStore.createCredential(credentialName, docType);
+ return new CredstoreWritableIdentityCredential(mContext, credentialName, docType, wc);
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ if (e.errorCode == ICredentialStore.ERROR_ALREADY_PERSONALIZED) {
+ throw new AlreadyPersonalizedException(e.getMessage(), e);
+ } else if (e.errorCode == ICredentialStore.ERROR_DOCUMENT_TYPE_NOT_SUPPORTED) {
+ throw new DocTypeNotSupportedException(e.getMessage(), e);
+ } else {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+ }
+
+ @Override public @Nullable IdentityCredential getCredentialByName(
+ @NonNull String credentialName,
+ @Ciphersuite int cipherSuite) throws CipherSuiteNotSupportedException {
+ try {
+ ICredential credstoreCredential;
+ credstoreCredential = mStore.getCredentialByName(credentialName, cipherSuite);
+ return new CredstoreIdentityCredential(mContext, credentialName, cipherSuite,
+ credstoreCredential);
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ if (e.errorCode == ICredentialStore.ERROR_NO_SUCH_CREDENTIAL) {
+ return null;
+ } else if (e.errorCode == ICredentialStore.ERROR_CIPHER_SUITE_NOT_SUPPORTED) {
+ throw new CipherSuiteNotSupportedException(e.getMessage(), e);
+ } else {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+ }
+
+ @Override
+ public @Nullable byte[] deleteCredentialByName(@NonNull String credentialName) {
+ ICredential credstoreCredential = null;
+ try {
+ try {
+ credstoreCredential = mStore.getCredentialByName(credentialName,
+ CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256);
+ } catch (android.os.ServiceSpecificException e) {
+ if (e.errorCode == ICredentialStore.ERROR_NO_SUCH_CREDENTIAL) {
+ return null;
+ }
+ }
+ byte[] proofOfDeletion = credstoreCredential.deleteCredential();
+ return proofOfDeletion;
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+
+}
diff --git a/identity/java/android/security/identity/CredstoreResultData.java b/identity/java/android/security/identity/CredstoreResultData.java
new file mode 100644
index 000000000000..ef7afca6b888
--- /dev/null
+++ b/identity/java/android/security/identity/CredstoreResultData.java
@@ -0,0 +1,162 @@
+/*
+ * 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.security.identity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+ * An object that contains the result of retrieving data from a credential. This is used to return
+ * data requested from a {@link IdentityCredential}.
+ */
+class CredstoreResultData extends ResultData {
+
+ byte[] mStaticAuthenticationData = null;
+ byte[] mAuthenticatedData = null;
+ byte[] mMessageAuthenticationCode = null;
+
+ private Map<String, Map<String, EntryData>> mData = new LinkedHashMap<>();
+
+ private static class EntryData {
+ @Status
+ int mStatus;
+ byte[] mValue;
+
+ EntryData(byte[] value, @Status int status) {
+ this.mValue = value;
+ this.mStatus = status;
+ }
+ }
+
+ CredstoreResultData() {}
+
+ @Override
+ public @NonNull byte[] getAuthenticatedData() {
+ return mAuthenticatedData;
+ }
+
+ @Override
+ public @Nullable byte[] getMessageAuthenticationCode() {
+ return mMessageAuthenticationCode;
+ }
+
+ @Override
+ public @NonNull byte[] getStaticAuthenticationData() {
+ return mStaticAuthenticationData;
+ }
+
+ @Override
+ public @NonNull Collection<String> getNamespaceNames() {
+ return Collections.unmodifiableCollection(mData.keySet());
+ }
+
+ @Override
+ public @Nullable Collection<String> getEntryNames(@NonNull String namespaceName) {
+ Map<String, EntryData> innerMap = mData.get(namespaceName);
+ if (innerMap == null) {
+ return null;
+ }
+ return Collections.unmodifiableCollection(innerMap.keySet());
+ }
+
+ @Override
+ public @Nullable Collection<String> getRetrievedEntryNames(@NonNull String namespaceName) {
+ Map<String, EntryData> innerMap = mData.get(namespaceName);
+ if (innerMap == null) {
+ return null;
+ }
+ LinkedList<String> result = new LinkedList<String>();
+ for (Map.Entry<String, EntryData> entry : innerMap.entrySet()) {
+ if (entry.getValue().mStatus == STATUS_OK) {
+ result.add(entry.getKey());
+ }
+ }
+ return result;
+ }
+
+ private EntryData getEntryData(@NonNull String namespaceName, @NonNull String name) {
+ Map<String, EntryData> innerMap = mData.get(namespaceName);
+ if (innerMap == null) {
+ return null;
+ }
+ return innerMap.get(name);
+ }
+
+ @Override
+ @Status
+ public int getStatus(@NonNull String namespaceName, @NonNull String name) {
+ EntryData value = getEntryData(namespaceName, name);
+ if (value == null) {
+ return STATUS_NOT_REQUESTED;
+ }
+ return value.mStatus;
+ }
+
+ @Override
+ public @Nullable byte[] getEntry(@NonNull String namespaceName, @NonNull String name) {
+ EntryData value = getEntryData(namespaceName, name);
+ if (value == null) {
+ return null;
+ }
+ return value.mValue;
+ }
+
+ static class Builder {
+ private CredstoreResultData mResultData;
+
+ Builder(byte[] staticAuthenticationData,
+ byte[] authenticatedData,
+ byte[] messageAuthenticationCode) {
+ this.mResultData = new CredstoreResultData();
+ this.mResultData.mStaticAuthenticationData = staticAuthenticationData;
+ this.mResultData.mAuthenticatedData = authenticatedData;
+ this.mResultData.mMessageAuthenticationCode = messageAuthenticationCode;
+ }
+
+ private Map<String, EntryData> getOrCreateInnerMap(String namespaceName) {
+ Map<String, EntryData> innerMap = mResultData.mData.get(namespaceName);
+ if (innerMap == null) {
+ innerMap = new LinkedHashMap<>();
+ mResultData.mData.put(namespaceName, innerMap);
+ }
+ return innerMap;
+ }
+
+ Builder addEntry(String namespaceName, String name, byte[] value) {
+ Map<String, EntryData> innerMap = getOrCreateInnerMap(namespaceName);
+ innerMap.put(name, new EntryData(value, STATUS_OK));
+ return this;
+ }
+
+ Builder addErrorStatus(String namespaceName, String name, @Status int status) {
+ Map<String, EntryData> innerMap = getOrCreateInnerMap(namespaceName);
+ innerMap.put(name, new EntryData(null, status));
+ return this;
+ }
+
+ CredstoreResultData build() {
+ return mResultData;
+ }
+ }
+
+}
diff --git a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
new file mode 100644
index 000000000000..335636cb07ae
--- /dev/null
+++ b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.security.GateKeeper;
+
+import java.io.ByteArrayInputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.LinkedList;
+
+class CredstoreWritableIdentityCredential extends WritableIdentityCredential {
+
+ private static final String TAG = "CredstoreWritableIdentityCredential";
+
+ private String mDocType;
+ private String mCredentialName;
+ private Context mContext;
+ private IWritableCredential mBinder;
+
+ CredstoreWritableIdentityCredential(Context context,
+ @NonNull String credentialName,
+ @NonNull String docType,
+ IWritableCredential binder) {
+ mContext = context;
+ mDocType = docType;
+ mCredentialName = credentialName;
+ mBinder = binder;
+ }
+
+ @NonNull @Override
+ public Collection<X509Certificate> getCredentialKeyCertificateChain(@NonNull byte[] challenge) {
+ try {
+ byte[] certsBlob = mBinder.getCredentialKeyCertificateChain(challenge);
+ ByteArrayInputStream bais = new ByteArrayInputStream(certsBlob);
+
+ Collection<? extends Certificate> certs = null;
+ try {
+ CertificateFactory factory = CertificateFactory.getInstance("X.509");
+ certs = factory.generateCertificates(bais);
+ } catch (CertificateException e) {
+ throw new RuntimeException("Error decoding certificates", e);
+ }
+
+ LinkedList<X509Certificate> x509Certs = new LinkedList<>();
+ for (Certificate cert : certs) {
+ x509Certs.add((X509Certificate) cert);
+ }
+ return x509Certs;
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+
+ @NonNull @Override
+ public byte[] personalize(@NonNull PersonalizationData personalizationData) {
+
+ Collection<AccessControlProfile> accessControlProfiles =
+ personalizationData.getAccessControlProfiles();
+
+ AccessControlProfileParcel[] acpParcels =
+ new AccessControlProfileParcel[accessControlProfiles.size()];
+ boolean usingUserAuthentication = false;
+ int n = 0;
+ for (AccessControlProfile profile : accessControlProfiles) {
+ acpParcels[n] = new AccessControlProfileParcel();
+ acpParcels[n].id = profile.getAccessControlProfileId().getId();
+ X509Certificate cert = profile.getReaderCertificate();
+ if (cert != null) {
+ try {
+ acpParcels[n].readerCertificate = cert.getEncoded();
+ } catch (CertificateException e) {
+ throw new RuntimeException("Error encoding reader certificate", e);
+ }
+ } else {
+ acpParcels[n].readerCertificate = new byte[0];
+ }
+ acpParcels[n].userAuthenticationRequired = profile.isUserAuthenticationRequired();
+ acpParcels[n].userAuthenticationTimeoutMillis = profile.getUserAuthenticationTimeout();
+ if (profile.isUserAuthenticationRequired()) {
+ usingUserAuthentication = true;
+ }
+ n++;
+ }
+
+ Collection<String> namespaceNames = personalizationData.getNamespaceNames();
+
+ EntryNamespaceParcel[] ensParcels = new EntryNamespaceParcel[namespaceNames.size()];
+ n = 0;
+ for (String namespaceName : namespaceNames) {
+ PersonalizationData.NamespaceData nsd =
+ personalizationData.getNamespaceData(namespaceName);
+
+ ensParcels[n] = new EntryNamespaceParcel();
+ ensParcels[n].namespaceName = namespaceName;
+
+ Collection<String> entryNames = nsd.getEntryNames();
+ EntryParcel[] eParcels = new EntryParcel[entryNames.size()];
+ int m = 0;
+ for (String entryName : entryNames) {
+ eParcels[m] = new EntryParcel();
+ eParcels[m].name = entryName;
+ eParcels[m].value = nsd.getEntryValue(entryName);
+ Collection<AccessControlProfileId> acpIds =
+ nsd.getAccessControlProfileIds(entryName);
+ eParcels[m].accessControlProfileIds = new int[acpIds.size()];
+ int o = 0;
+ for (AccessControlProfileId acpId : acpIds) {
+ eParcels[m].accessControlProfileIds[o++] = acpId.getId();
+ }
+ m++;
+ }
+ ensParcels[n].entries = eParcels;
+ n++;
+ }
+
+ // Note: The value 0 is used to convey that no user-authentication is needed for this
+ // credential. This is to allow creating credentials w/o user authentication on devices
+ // where Secure lock screen is not enabled.
+ long secureUserId = 0;
+ if (usingUserAuthentication) {
+ secureUserId = getRootSid();
+ }
+ try {
+ byte[] personalizationReceipt = mBinder.personalize(acpParcels, ensParcels,
+ secureUserId);
+ return personalizationReceipt;
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+
+ private static long getRootSid() {
+ long rootSid = GateKeeper.getSecureUserId();
+ if (rootSid == 0) {
+ throw new IllegalStateException("Secure lock screen must be enabled"
+ + " to create credentials requiring user authentication");
+ }
+ return rootSid;
+ }
+
+
+}
diff --git a/identity/java/android/security/identity/DocTypeNotSupportedException.java b/identity/java/android/security/identity/DocTypeNotSupportedException.java
new file mode 100644
index 000000000000..754e44af5411
--- /dev/null
+++ b/identity/java/android/security/identity/DocTypeNotSupportedException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown if trying to create a credential with an unsupported document type.
+ */
+public class DocTypeNotSupportedException extends IdentityCredentialException {
+ /**
+ * Constructs a new {@link DocTypeNotSupportedException} exception.
+ *
+ * @param message the detail message.
+ */
+ public DocTypeNotSupportedException(@NonNull String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new {@link DocTypeNotSupportedException} exception.
+ *
+ * @param message the detail message.
+ * @param cause the cause.
+ */
+ public DocTypeNotSupportedException(@NonNull String message, @NonNull Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/identity/java/android/security/identity/EphemeralPublicKeyNotFoundException.java b/identity/java/android/security/identity/EphemeralPublicKeyNotFoundException.java
new file mode 100644
index 000000000000..265f271b54f7
--- /dev/null
+++ b/identity/java/android/security/identity/EphemeralPublicKeyNotFoundException.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown if the ephemeral public key was not found in the session transcript
+ * passed to {@link IdentityCredential#getEntries(byte[], Map, byte[], byte[])}.
+ */
+public class EphemeralPublicKeyNotFoundException extends IdentityCredentialException {
+ /**
+ * Constructs a new {@link EphemeralPublicKeyNotFoundException} exception.
+ *
+ * @param message the detail message.
+ */
+ public EphemeralPublicKeyNotFoundException(@NonNull String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new {@link EphemeralPublicKeyNotFoundException} exception.
+ *
+ * @param message the detail message.
+ * @param cause the cause.
+ */
+ public EphemeralPublicKeyNotFoundException(@NonNull String message, @NonNull Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
new file mode 100644
index 000000000000..bd439199f914
--- /dev/null
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Class used to read data from a previously provisioned credential.
+ *
+ * Use {@link IdentityCredentialStore#getCredentialByName(String, int)} to get a
+ * {@link IdentityCredential} instance.
+ */
+public abstract class IdentityCredential {
+ /**
+ * @hide
+ */
+ protected IdentityCredential() {}
+
+ /**
+ * Create an ephemeral key pair to use to establish a secure channel with a reader.
+ *
+ * <p>Most applications will use only the public key, and only to send it to the reader,
+ * allowing the private key to be used internally for {@link #encryptMessageToReader(byte[])}
+ * and {@link #decryptMessageFromReader(byte[])}. The private key is also provided for
+ * applications that wish to use a cipher suite that is not supported by
+ * {@link IdentityCredentialStore}.
+ *
+ * @return ephemeral key pair to use to establish a secure channel with a reader.
+ */
+ public @NonNull abstract KeyPair createEphemeralKeyPair();
+
+ /**
+ * Set the ephemeral public key provided by the reader. This must be called before
+ * {@link #encryptMessageToReader} or {@link #decryptMessageFromReader} can be called.
+ *
+ * @param readerEphemeralPublicKey The ephemeral public key provided by the reader to
+ * establish a secure session.
+ * @throws InvalidKeyException if the given key is invalid.
+ */
+ public abstract void setReaderEphemeralPublicKey(@NonNull PublicKey readerEphemeralPublicKey)
+ throws InvalidKeyException;
+
+ /**
+ * Encrypt a message for transmission to the reader.
+ *
+ * @param messagePlaintext unencrypted message to encrypt.
+ * @return encrypted message.
+ */
+ public @NonNull abstract byte[] encryptMessageToReader(@NonNull byte[] messagePlaintext);
+
+ /**
+ * Decrypt a message received from the reader.
+ *
+ * @param messageCiphertext encrypted message to decrypt.
+ * @return decrypted message.
+ * @throws MessageDecryptionException if the ciphertext couldn't be decrypted.
+ */
+ public @NonNull abstract byte[] decryptMessageFromReader(@NonNull byte[] messageCiphertext)
+ throws MessageDecryptionException;
+
+ /**
+ * Gets the X.509 certificate chain for the CredentialKey which identifies this
+ * credential to the issuing authority. This is the same certificate chain that
+ * was returned by {@link WritableIdentityCredential#getCredentialKeyCertificateChain(byte[])}
+ * when the credential was first created and its Android Keystore extension will
+ * contain the <code>challenge</code> data set at that time. See the documentation
+ * for that method for important information about this certificate chain.
+ *
+ * @return the certificate chain for this credential's CredentialKey.
+ */
+ public @NonNull abstract Collection<X509Certificate> getCredentialKeyCertificateChain();
+
+ /**
+ * Sets whether to allow using an authentication key which use count has been exceeded if no
+ * other key is available. This must be called prior to calling
+ * {@link #getEntries(byte[], Map, byte[], byte[])} or using a
+ * {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} which references this
+ * object.
+ *
+ * By default this is set to true.
+ *
+ * @param allowUsingExhaustedKeys whether to allow using an authentication key which use count
+ * has been exceeded if no other key is available.
+ */
+ public abstract void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys);
+
+ /**
+ * Called by android.hardware.biometrics.CryptoObject#getOpId() to get an
+ * operation handle.
+ *
+ * @hide
+ */
+ public abstract long getCredstoreOperationHandle();
+
+ /**
+ * Retrieve data entries and associated data from this {@code IdentityCredential}.
+ *
+ * <p>If an access control check fails for one of the requested entries or if the entry
+ * doesn't exist, the entry is simply not returned. The application can detect this
+ * by using the {@link ResultData#getStatus(String, String)} method on each of the requested
+ * entries.
+ *
+ * <p>It is the responsibility of the calling application to know if authentication is needed
+ * and use e.g. {@link android.hardware.biometrics.BiometricPrompt}) to make the user
+ * authenticate using a {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} which
+ * references this object. If needed, this must be done before calling
+ * {@link #getEntries(byte[], Map, byte[], byte[])}.
+ *
+ * <p>If this method returns successfully (i.e. without throwing an exception), it must not be
+ * called again on this instance.
+ *
+ * <p>If not {@code null} the {@code requestMessage} parameter must contain data for the request
+ * from the verifier. The content can be defined in the way appropriate for the credential, byt
+ * there are three requirements that must be met to work with this API:
+ * <ul>
+ * <li>The content must be a CBOR-encoded structure.</li>
+ * <li>The CBOR structure must be a map.</li>
+ * <li>The map must contain a tstr key "nameSpaces" whose value contains a map, as described in
+ * the example below.</li>
+ * </ul>
+ *
+ * <p>Here's an example of CBOR which conforms to this requirement:
+ * <pre>
+ * ItemsRequest = {
+ * ? "docType" : DocType,
+ * "nameSpaces" : NameSpaces,
+ * ? "RequestInfo" : {* tstr => any} ; Additional info the reader wants to provide
+ * }
+ *
+ * NameSpaces = {
+ * + NameSpace => DataElements ; Requested data elements for each NameSpace
+ * }
+ *
+ * NameSpace = tstr
+ *
+ * DataElements = {
+ * + DataElement => IntentToRetain
+ * }
+ *
+ * DataElement = tstr
+ * IntentToRetain = bool
+ * </pre>
+ *
+ * <p>If the {@code sessionTranscript} parameter is not {@code null}, it must contain CBOR
+ * data conforming to the following CDDL schema:
+ *
+ * <pre>
+ * SessionTranscript = [
+ * DeviceEngagementBytes,
+ * EReaderKeyBytes
+ * ]
+ *
+ * DeviceEngagementBytes = #6.24(bstr .cbor DeviceEngagement)
+ * EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub)
+ * </pre>
+ *
+ * <p>If the SessionTranscript is not empty, a COSE_Key structure for the public part
+ * of the key-pair previously generated by {@link #createEphemeralKeyPair()} must appear
+ * somewhere in {@code DeviceEngagement} and the X and Y coordinates must both be present
+ * in uncompressed form.
+ *
+ * <p>If {@code readerAuth} is not {@code null} it must be the bytes of a COSE_Sign1
+ * structure as defined in RFC 8152. For the payload nil shall be used and the
+ * detached payload is the ReaderAuthentication CBOR described below.
+ * <pre>
+ * ReaderAuthentication = [
+ * "ReaderAuthentication",
+ * SessionTranscript,
+ * ItemsRequestBytes
+ * ]
+ *
+ * ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest) ; Bytes of ItemsRequest
+ * </pre>
+ *
+ * <p>The public key corresponding to the key used to made signature, can be
+ * found in the {@code x5chain} unprotected header element of the COSE_Sign1
+ * structure (as as described in 'draft-ietf-cose-x509-04'). There will be at
+ * least one certificate in said element and there may be more (and if so,
+ * each certificate must be signed by its successor).
+ *
+ * <p>Data elements protected by reader authentication is returned if, and only if, they are
+ * mentioned in {@code requestMessage}, {@code requestMessage} is signed by the top-most
+ * certificate in {@code readerCertificateChain}, and the data element is configured
+ * with an {@link AccessControlProfile} with a {@link X509Certificate} in
+ * {@code readerCertificateChain}.
+ *
+ * <p>Note that only items referenced in {@code entriesToRequest} are returned - the
+ * {@code requestMessage} parameter is only used to for enforcing reader authentication.
+ *
+ * @param requestMessage If not {@code null}, must contain CBOR data conforming to
+ * the schema mentioned above.
+ * @param entriesToRequest The entries to request, organized as a map of namespace
+ * names with each value being a collection of data elements
+ * in the given namespace.
+ * @param readerSignature COSE_Sign1 structure as described above or {@code null}
+ * if reader authentication is not being used.
+ * @return A {@link ResultData} object containing entry data organized by namespace and a
+ * cryptographically authenticated representation of the same data.
+ * @throws SessionTranscriptMismatchException Thrown when trying use multiple different
+ * session transcripts in the same presentation
+ * session.
+ * @throws NoAuthenticationKeyAvailableException if authentication keys were never
+ * provisioned, the method
+ * {@link #setAvailableAuthenticationKeys(int, int)}
+ * was called with {@code keyCount} set to 0,
+ * the method
+ * {@link #setAllowUsingExhaustedKeys(boolean)}
+ * was called with {@code false} and all
+ * available authentication keys have been
+ * exhausted.
+ * @throws InvalidReaderSignatureException if the reader signature is invalid, or it
+ * doesn't contain a certificate chain, or if
+ * the signature failed to validate.
+ * @throws InvalidRequestMessageException if the requestMessage is malformed.
+ * @throws EphemeralPublicKeyNotFoundException if the ephemeral public key was not found in
+ * the session transcript.
+ */
+ public abstract @NonNull ResultData getEntries(
+ @Nullable byte[] requestMessage,
+ @NonNull Map<String, Collection<String>> entriesToRequest,
+ @Nullable byte[] sessionTranscript,
+ @Nullable byte[] readerSignature)
+ throws SessionTranscriptMismatchException, NoAuthenticationKeyAvailableException,
+ InvalidReaderSignatureException, EphemeralPublicKeyNotFoundException,
+ InvalidRequestMessageException;
+
+ /**
+ * Sets the number of dynamic authentication keys the {@code IdentityCredential} will maintain,
+ * and the number of times each should be used.
+ *
+ * <p>{@code IdentityCredential}s will select the least-used dynamic authentication key each
+ * time {@link #getEntries(byte[], Map, byte[], byte[])} is called. {@code IdentityCredential}s
+ * for which this method has not been called behave as though it had been called wit
+ * {@code keyCount} 0 and {@code maxUsesPerKey} 1.
+ *
+ * @param keyCount The number of active, certified dynamic authentication keys the
+ * {@code IdentityCredential} will try to keep available. This value
+ * must be non-negative.
+ * @param maxUsesPerKey The maximum number of times each of the keys will be used before it's
+ * eligible for replacement. This value must be greater than zero.
+ */
+ public abstract void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey);
+
+ /**
+ * Gets a collection of dynamic authentication keys that need certification.
+ *
+ * <p>When there aren't enough certified dynamic authentication keys, either because the key
+ * count has been increased or because one or more keys have reached their usage count, this
+ * method will generate replacement keys and certificates and return them for issuer
+ * certification. The issuer certificates and associated static authentication data must then
+ * be provided back to the {@code IdentityCredential} using
+ * {@link #storeStaticAuthenticationData(X509Certificate, byte[])}.
+ *
+ * <p>Each X.509 certificate is signed by CredentialKey. The certificate chain for CredentialKey
+ * can be obtained using the {@link #getCredentialKeyCertificateChain()} method.
+ *
+ * @return A collection of X.509 certificates for dynamic authentication keys that need issuer
+ * certification.
+ */
+ public @NonNull abstract Collection<X509Certificate> getAuthKeysNeedingCertification();
+
+ /**
+ * Store authentication data associated with a dynamic authentication key.
+ *
+ * This should only be called for an authenticated key returned by
+ * {@link #getAuthKeysNeedingCertification()}.
+ *
+ * @param authenticationKey The dynamic authentication key for which certification and
+ * associated static
+ * authentication data is being provided.
+ * @param staticAuthData Static authentication data provided by the issuer that validates
+ * the authenticity
+ * and integrity of the credential data fields.
+ * @throws UnknownAuthenticationKeyException If the given authentication key is not recognized.
+ */
+ public abstract void storeStaticAuthenticationData(
+ @NonNull X509Certificate authenticationKey,
+ @NonNull byte[] staticAuthData)
+ throws UnknownAuthenticationKeyException;
+
+ /**
+ * Get the number of times the dynamic authentication keys have been used.
+ *
+ * @return int array of dynamic authentication key usage counts.
+ */
+ public @NonNull abstract int[] getAuthenticationDataUsageCount();
+}
diff --git a/identity/java/android/security/identity/IdentityCredentialException.java b/identity/java/android/security/identity/IdentityCredentialException.java
new file mode 100644
index 000000000000..c8113803d5d3
--- /dev/null
+++ b/identity/java/android/security/identity/IdentityCredentialException.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+
+/**
+ * Base class for all Identity Credential exceptions.
+ */
+public class IdentityCredentialException extends Exception {
+ /**
+ * Constructs a new {@link IdentityCredentialException} exception.
+ *
+ * @param message the detail message.
+ */
+ public IdentityCredentialException(@NonNull String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new {@link IdentityCredentialException} exception.
+ *
+ * @param message the detail message.
+ * @param cause the cause.
+ */
+ public IdentityCredentialException(@NonNull String message, @NonNull Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/identity/java/android/security/identity/IdentityCredentialStore.java b/identity/java/android/security/identity/IdentityCredentialStore.java
new file mode 100644
index 000000000000..a1dfc77adb29
--- /dev/null
+++ b/identity/java/android/security/identity/IdentityCredentialStore.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An interface to a secure store for user identity documents.
+ *
+ * <p>This interface is deliberately fairly general and abstract. To the extent possible,
+ * specification of the message formats and semantics of communication with credential
+ * verification devices and issuing authorities (IAs) is out of scope. It provides the
+ * interface with secure storage but a credential-specific Android application will be
+ * required to implement the presentation and verification protocols and processes
+ * appropriate for the specific credential type.
+ *
+ * <p>Multiple credentials can be created. Each credential comprises:</p>
+ * <ul>
+ * <li>A document type, which is a string.</li>
+ *
+ * <li>A set of namespaces, which serve to disambiguate value names. It is recommended
+ * that namespaces be structured as reverse domain names so that IANA effectively serves
+ * as the namespace registrar.</li>
+ *
+ * <li>For each namespace, a set of name/value pairs, each with an associated set of
+ * access control profile IDs. Names are strings and values are typed and can be any
+ * value supported by <a href="http://cbor.io/">CBOR</a>.</li>
+ *
+ * <li>A set of access control profiles, each with a profile ID and a specification
+ * of the conditions which satisfy the profile's requirements.</li>
+ *
+ * <li>An asymmetric key pair which is used to authenticate the credential to the Issuing
+ * Authority, called the <em>CredentialKey</em>.</li>
+ *
+ * <li>A set of zero or more named reader authentication public keys, which are used to
+ * authenticate an authorized reader to the credential.</li>
+ *
+ * <li>A set of named signing keys, which are used to sign collections of values and session
+ * transcripts.</li>
+ * </ul>
+ *
+ * <p>Implementing support for user identity documents in secure storage requires dedicated
+ * hardware-backed support and may not always be available.
+ *
+ * <p>Two different credential stores exist - the <em>default</em> store and the
+ * <em>direct access</em> store. Most often credentials will be accessed through the default
+ * store but that requires that the Android device be powered up and fully functional.
+ * It is desirable to allow identity credential usage when the Android device's battery is too
+ * low to boot the Android operating system, so direct access to the secure hardware via NFC
+ * may allow data retrieval, if the secure hardware chooses to implement it.
+ *
+ * <p>Credentials provisioned to the direct access store should <strong>always</strong> use reader
+ * authentication to protect data elements. The reason for this is user authentication or user
+ * approval of data release is not possible when the device is off.
+ */
+public abstract class IdentityCredentialStore {
+ IdentityCredentialStore() {}
+
+ /**
+ * Specifies that the cipher suite that will be used to secure communications between the reader
+ * is:
+ *
+ * <ul>
+ * <li>ECDHE with HKDF-SHA-256 for key agreement.</li>
+ * <li>AES-256 with GCM block mode for authenticated encryption (nonces are incremented by one
+ * for every message).</li>
+ * <li>ECDSA with SHA-256 for signing (used for signing session transcripts to defeat
+ * man-in-the-middle attacks), signing keys are not ephemeral. See {@link IdentityCredential}
+ * for details on reader and prover signing keys.</li>
+ * </ul>
+ *
+ * <p>
+ * At present this is the only supported cipher suite.
+ */
+ public static final int CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 = 1;
+
+ /**
+ * Gets the default {@link IdentityCredentialStore}.
+ *
+ * @param context the application context.
+ * @return the {@link IdentityCredentialStore} or {@code null} if the device doesn't
+ * have hardware-backed support for secure storage of user identity documents.
+ */
+ public static @Nullable IdentityCredentialStore getInstance(@NonNull Context context) {
+ return CredstoreIdentityCredentialStore.getInstance(context);
+ }
+
+ /**
+ * Gets the {@link IdentityCredentialStore} for direct access.
+ *
+ * <p>Direct access requires specialized NFC hardware and may not be supported on all
+ * devices even if default store is available. Credentials provisioned to the direct
+ * access store should <strong>always</strong> use reader authentication to protect
+ * data elements.
+ *
+ * @param context the application context.
+ * @return the {@link IdentityCredentialStore} or {@code null} if direct access is not
+ * supported on this device.
+ */
+ public static @Nullable IdentityCredentialStore getDirectAccessInstance(@NonNull
+ Context context) {
+ return CredstoreIdentityCredentialStore.getDirectAccessInstance(context);
+ }
+
+ /**
+ * Gets a list of supported document types.
+ *
+ * <p>Only the direct-access store may restrict the kind of document types that can be used for
+ * credentials. The default store always supports any document type.
+ *
+ * @return The supported document types or the empty array if any document type is supported.
+ */
+ public abstract @NonNull String[] getSupportedDocTypes();
+
+ /**
+ * Creates a new credential.
+ *
+ * @param credentialName The name used to identify the credential.
+ * @param docType The document type for the credential.
+ * @return A @{link WritableIdentityCredential} that can be used to create a new credential.
+ * @throws AlreadyPersonalizedException if a credential with the given name already exists.
+ * @throws DocTypeNotSupportedException if the given document type isn't supported by the store.
+ */
+ public abstract @NonNull WritableIdentityCredential createCredential(
+ @NonNull String credentialName, @NonNull String docType)
+ throws AlreadyPersonalizedException, DocTypeNotSupportedException;
+
+ /**
+ * Retrieve a named credential.
+ *
+ * @param credentialName the name of the credential to retrieve.
+ * @param cipherSuite the cipher suite to use for communicating with the verifier.
+ * @return The named credential, or null if not found.
+ */
+ public abstract @Nullable IdentityCredential getCredentialByName(@NonNull String credentialName,
+ @Ciphersuite int cipherSuite)
+ throws CipherSuiteNotSupportedException;
+
+ /**
+ * Delete a named credential.
+ *
+ * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey
+ * with payload set to {@code ProofOfDeletion} as defined below:
+ *
+ * <pre>
+ * ProofOfDeletion = [
+ * "ProofOfDeletion", ; tstr
+ * tstr, ; DocType
+ * bool ; true if this is a test credential, should
+ * ; always be false.
+ * ]
+ * </pre>
+ *
+ * @param credentialName the name of the credential to delete.
+ * @return {@code null} if the credential was not found, the COSE_Sign1 data structure above
+ * if the credential was found and deleted.
+ */
+ public abstract @Nullable byte[] deleteCredentialByName(@NonNull String credentialName);
+
+ /** @hide */
+ @IntDef(value = {CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Ciphersuite {
+ }
+
+}
diff --git a/identity/java/android/security/identity/InvalidReaderSignatureException.java b/identity/java/android/security/identity/InvalidReaderSignatureException.java
new file mode 100644
index 000000000000..3f7027005830
--- /dev/null
+++ b/identity/java/android/security/identity/InvalidReaderSignatureException.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown if the reader signature is invalid, or it doesn't contain a certificate chain, or if the
+ * signature failed to validate.
+ */
+public class InvalidReaderSignatureException extends IdentityCredentialException {
+ /**
+ * Constructs a new {@link InvalidReaderSignatureException} exception.
+ *
+ * @param message the detail message.
+ */
+ public InvalidReaderSignatureException(@NonNull String message) {
+ super(message);
+ }
+
+
+ /**
+ * Constructs a new {@link InvalidReaderSignatureException} exception.
+ *
+ * @param message the detail message.
+ * @param cause the cause.
+ */
+ public InvalidReaderSignatureException(@NonNull String message,
+ @NonNull Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/identity/java/android/security/identity/InvalidRequestMessageException.java b/identity/java/android/security/identity/InvalidRequestMessageException.java
new file mode 100644
index 000000000000..b0c073c33a8d
--- /dev/null
+++ b/identity/java/android/security/identity/InvalidRequestMessageException.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown if message with the request doesn't satisfy the requirements documented in
+ * {@link IdentityCredential#getEntries(byte[], Map, byte[], byte[])}.
+ */
+public class InvalidRequestMessageException extends IdentityCredentialException {
+ /**
+ * Constructs a new {@link InvalidRequestMessageException} exception.
+ *
+ * @param message the detail message.
+ */
+ public InvalidRequestMessageException(@NonNull String message) {
+ super(message);
+ }
+
+
+ /**
+ * Constructs a new {@link InvalidRequestMessageException} exception.
+ *
+ * @param message the detail message.
+ * @param cause the cause.
+ */
+ public InvalidRequestMessageException(@NonNull String message,
+ @NonNull Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/identity/java/android/security/identity/MessageDecryptionException.java b/identity/java/android/security/identity/MessageDecryptionException.java
new file mode 100644
index 000000000000..7a6169ea1d5b
--- /dev/null
+++ b/identity/java/android/security/identity/MessageDecryptionException.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown when failing to decrypt a message from the reader device.
+ */
+public class MessageDecryptionException extends IdentityCredentialException {
+
+ /**
+ * Constructs a new {@link MessageDecryptionException} exception.
+ *
+ * @param message the detail message.
+ */
+ public MessageDecryptionException(@NonNull String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new {@link MessageDecryptionException} exception.
+ *
+ * @param message the detail message.
+ * @param cause the cause.
+ */
+ public MessageDecryptionException(@NonNull String message, @NonNull Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/identity/java/android/security/identity/NoAuthenticationKeyAvailableException.java b/identity/java/android/security/identity/NoAuthenticationKeyAvailableException.java
new file mode 100644
index 000000000000..7f404037fbb1
--- /dev/null
+++ b/identity/java/android/security/identity/NoAuthenticationKeyAvailableException.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown if no dynamic authentication keys are available.
+ */
+public class NoAuthenticationKeyAvailableException extends IdentityCredentialException {
+
+ /**
+ * Constructs a new {@link NoAuthenticationKeyAvailableException} exception.
+ *
+ * @param message the detail message.
+ */
+ public NoAuthenticationKeyAvailableException(@NonNull String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new {@link NoAuthenticationKeyAvailableException} exception.
+ *
+ * @param message the detail message.
+ * @param cause the cause.
+ */
+ public NoAuthenticationKeyAvailableException(@NonNull String message,
+ @NonNull Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/identity/java/android/security/identity/PersonalizationData.java b/identity/java/android/security/identity/PersonalizationData.java
new file mode 100644
index 000000000000..44370a1780f8
--- /dev/null
+++ b/identity/java/android/security/identity/PersonalizationData.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+
+/**
+ * An object that holds personalization data.
+ *
+ * This data includes access control profiles and a set of data entries and values, grouped by
+ * namespace.
+ *
+ * This is used to provision data into a {@link WritableIdentityCredential}.
+ *
+ * @see WritableIdentityCredential#personalize
+ */
+public class PersonalizationData {
+
+ private PersonalizationData() {
+ }
+
+ private LinkedList<AccessControlProfile> mProfiles = new LinkedList<>();
+
+ private LinkedHashMap<String, NamespaceData> mNamespaces = new LinkedHashMap<>();
+
+ Collection<AccessControlProfile> getAccessControlProfiles() {
+ return Collections.unmodifiableCollection(mProfiles);
+ }
+
+ Collection<String> getNamespaceNames() {
+ return Collections.unmodifiableCollection(mNamespaces.keySet());
+ }
+
+ NamespaceData getNamespaceData(String namespace) {
+ return mNamespaces.get(namespace);
+ }
+
+ static class NamespaceData {
+
+ private String mNamespace;
+ private LinkedHashMap<String, EntryData> mEntries = new LinkedHashMap<>();
+
+ private NamespaceData(String namespace) {
+ this.mNamespace = namespace;
+ }
+
+ String getNamespaceName() {
+ return mNamespace;
+ }
+
+ Collection<String> getEntryNames() {
+ return Collections.unmodifiableCollection(mEntries.keySet());
+ }
+
+ Collection<AccessControlProfileId> getAccessControlProfileIds(String name) {
+ EntryData value = mEntries.get(name);
+ if (value != null) {
+ return value.mAccessControlProfileIds;
+ }
+ return null;
+ }
+
+ byte[] getEntryValue(String name) {
+ EntryData value = mEntries.get(name);
+ if (value != null) {
+ return value.mValue;
+ }
+ return null;
+ }
+ }
+
+ private static class EntryData {
+ byte[] mValue;
+ Collection<AccessControlProfileId> mAccessControlProfileIds;
+
+ EntryData(byte[] value, Collection<AccessControlProfileId> accessControlProfileIds) {
+ this.mValue = value;
+ this.mAccessControlProfileIds = accessControlProfileIds;
+ }
+ }
+
+ /**
+ * A builder for {@link PersonalizationData}.
+ */
+ public static final class Builder {
+ private PersonalizationData mData;
+
+ /**
+ * Creates a new builder for a given namespace.
+ */
+ public Builder() {
+ this.mData = new PersonalizationData();
+ }
+
+ /**
+ * Adds a new entry to the builder.
+ *
+ * @param namespace The namespace to use, e.g. {@code org.iso.18013-5.2019}.
+ * @param name The name of the entry, e.g. {@code height}.
+ * @param accessControlProfileIds A set of access control profiles to use.
+ * @param value The value to add, in CBOR encoding.
+ * @return The builder.
+ */
+ public @NonNull Builder setEntry(@NonNull String namespace, @NonNull String name,
+ @NonNull Collection<AccessControlProfileId> accessControlProfileIds,
+ @NonNull byte[] value) {
+ NamespaceData namespaceData = mData.mNamespaces.get(namespace);
+ if (namespaceData == null) {
+ namespaceData = new NamespaceData(namespace);
+ mData.mNamespaces.put(namespace, namespaceData);
+ }
+ // TODO: validate/verify that value is proper CBOR.
+ namespaceData.mEntries.put(name, new EntryData(value, accessControlProfileIds));
+ return this;
+ }
+
+ /**
+ * Adds a new access control profile to the builder.
+ *
+ * @param profile The access control profile.
+ * @return The builder.
+ */
+ public @NonNull Builder addAccessControlProfile(@NonNull AccessControlProfile profile) {
+ mData.mProfiles.add(profile);
+ return this;
+ }
+
+ /**
+ * Creates a new {@link PersonalizationData} with all the entries added to the builder.
+ *
+ * @return A new {@link PersonalizationData} instance.
+ */
+ public @NonNull PersonalizationData build() {
+ return mData;
+ }
+ }
+
+}
diff --git a/identity/java/android/security/identity/ResultData.java b/identity/java/android/security/identity/ResultData.java
new file mode 100644
index 000000000000..0982c8a4ab31
--- /dev/null
+++ b/identity/java/android/security/identity/ResultData.java
@@ -0,0 +1,224 @@
+/*
+ * 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.security.identity;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.lang.annotation.Retention;
+import java.util.Collection;
+
+/**
+ * An object that contains the result of retrieving data from a credential. This is used to return
+ * data requested from a {@link IdentityCredential}.
+ */
+public abstract class ResultData {
+
+ /** Value was successfully retrieved. */
+ public static final int STATUS_OK = 0;
+
+ /** Requested entry does not exist. */
+ public static final int STATUS_NO_SUCH_ENTRY = 1;
+
+ /** Requested entry was not requested. */
+ public static final int STATUS_NOT_REQUESTED = 2;
+
+ /** Requested entry wasn't in the request message. */
+ public static final int STATUS_NOT_IN_REQUEST_MESSAGE = 3;
+
+ /** The requested entry was not retrieved because user authentication wasn't performed. */
+ public static final int STATUS_USER_AUTHENTICATION_FAILED = 4;
+
+ /** The requested entry was not retrieved because reader authentication wasn't performed. */
+ public static final int STATUS_READER_AUTHENTICATION_FAILED = 5;
+
+ /**
+ * The requested entry was not retrieved because it was configured without any access
+ * control profile.
+ */
+ public static final int STATUS_NO_ACCESS_CONTROL_PROFILES = 6;
+
+ /**
+ * @hide
+ */
+ protected ResultData() {}
+
+ /**
+ * Returns a CBOR structure containing the retrieved data.
+ *
+ * <p>This structure - along with the session transcript - may be cryptographically
+ * authenticated to prove to the reader that the data is from a trusted credential and
+ * {@link #getMessageAuthenticationCode()} can be used to get a MAC.
+ *
+ * <p>The CBOR structure which is cryptographically authenticated is the
+ * {@code DeviceAuthentication} structure according to the following
+ * <a href="https://tools.ietf.org/html/draft-ietf-cbor-cddl-06">CDDL</a> schema:
+ *
+ * <pre>
+ * DeviceAuthentication = [
+ * "DeviceAuthentication",
+ * SessionTranscript,
+ * DocType,
+ * DeviceNameSpacesBytes
+ * ]
+ *
+ * DocType = tstr
+ *
+ * SessionTranscript = [
+ * DeviceEngagementBytes,
+ * EReaderKeyBytes
+ * ]
+ *
+ * DeviceEngagementBytes = #6.24(bstr .cbor DeviceEngagement)
+ * EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub)
+ *
+ * DeviceNameSpacesBytes = #6.24(bstr .cbor DeviceNameSpaces)
+ * </pre>
+ *
+ * where
+ *
+ * <pre>
+ * DeviceNameSpaces = {
+ * * NameSpace => DeviceSignedItems
+ * }
+ *
+ * DeviceSignedItems = {
+ * + DataItemName => DataItemValue
+ * }
+ *
+ * NameSpace = tstr
+ * DataItemName = tstr
+ * DataItemValue = any
+ * </pre>
+ *
+ * <p>The returned data is the binary encoding of the {@code DeviceNameSpaces} structure
+ * as defined above.
+ *
+ * @return The bytes of the {@code DeviceNameSpaces} CBOR structure.
+ */
+ public abstract @NonNull byte[] getAuthenticatedData();
+
+ /**
+ * Returns a message authentication code over the data returned by
+ * {@link #getAuthenticatedData}, to prove to the reader that the data is from a trusted
+ * credential.
+ *
+ * <p>The MAC proves to the reader that the data is from a trusted credential. This code is
+ * produced by using the key agreement and key derivation function from the ciphersuite
+ * with the authentication private key and the reader ephemeral public key to compute a
+ * shared message authentication code (MAC) key, then using the MAC function from the
+ * ciphersuite to compute a MAC of the authenticated data.
+ *
+ * <p>If the {@code sessionTranscript} parameter passed to
+ * {@link IdentityCredential#getEntries(byte[], Map, byte[], byte[])} was {@code null}
+ * or the reader ephmeral public key was never set using
+ * {@link IdentityCredential#setReaderEphemeralPublicKey(PublicKey)}, no message
+ * authencation code will be produced and this method will return {@code null}.
+ *
+ * @return A COSE_Mac0 structure with the message authentication code as described above
+ * or {@code null} if the conditions specified above are not met.
+ */
+ public abstract @Nullable byte[] getMessageAuthenticationCode();
+
+ /**
+ * Returns the static authentication data associated with the dynamic authentication
+ * key used to sign or MAC the data returned by {@link #getAuthenticatedData()}.
+ *
+ * @return The static authentication data associated with dynamic authentication key used to
+ * MAC the data.
+ */
+ public abstract @NonNull byte[] getStaticAuthenticationData();
+
+ /**
+ * Gets the names of namespaces with retrieved entries.
+ *
+ * @return collection of name of namespaces containing retrieved entries. May be empty if no
+ * data was retrieved.
+ */
+ public abstract @NonNull Collection<String> getNamespaceNames();
+
+ /**
+ * Get the names of all entries.
+ *
+ * This includes the name of entries that wasn't successfully retrieved.
+ *
+ * @param namespaceName the namespace name to get entries for.
+ * @return A collection of names or {@code null} if there are no entries for the given
+ * namespace.
+ */
+ public abstract @Nullable Collection<String> getEntryNames(@NonNull String namespaceName);
+
+ /**
+ * Get the names of all entries that was successfully retrieved.
+ *
+ * This only return entries for which {@link #getStatus(String, String)} will return
+ * {@link #STATUS_OK}.
+ *
+ * @param namespaceName the namespace name to get entries for.
+ * @return A collection of names or {@code null} if there are no entries for the given
+ * namespace.
+ */
+ public abstract @Nullable Collection<String> getRetrievedEntryNames(
+ @NonNull String namespaceName);
+
+ /**
+ * Gets the status of an entry.
+ *
+ * This returns {@link #STATUS_OK} if the value was retrieved, {@link #STATUS_NO_SUCH_ENTRY}
+ * if the given entry wasn't retrieved, {@link #STATUS_NOT_REQUESTED} if it wasn't requested,
+ * {@link #STATUS_NOT_IN_REQUEST_MESSAGE} if the request message was set but the entry wasn't
+ * present in the request message,
+ * {@link #STATUS_USER_AUTHENTICATION_FAILED} if the value
+ * wasn't retrieved because the necessary user authentication wasn't performed,
+ * {@link #STATUS_READER_AUTHENTICATION_FAILED} if the supplied reader certificate chain
+ * didn't match the set of certificates the entry was provisioned with, or
+ * {@link #STATUS_NO_ACCESS_CONTROL_PROFILES} if the entry was configured without any
+ * access control profiles.
+ *
+ * @param namespaceName the namespace name of the entry.
+ * @param name the name of the entry to get the value for.
+ * @return the status indicating whether the value was retrieved and if not, why.
+ */
+ @Status
+ public abstract int getStatus(@NonNull String namespaceName, @NonNull String name);
+
+ /**
+ * Gets the raw CBOR data for the value of an entry.
+ *
+ * This should only be called on an entry for which the {@link #getStatus(String, String)}
+ * method returns {@link #STATUS_OK}.
+ *
+ * @param namespaceName the namespace name of the entry.
+ * @param name the name of the entry to get the value for.
+ * @return the raw CBOR data or {@code null} if no entry with the given name exists.
+ */
+ public abstract @Nullable byte[] getEntry(@NonNull String namespaceName, @NonNull String name);
+
+ /**
+ * The type of the entry status.
+ * @hide
+ */
+ @Retention(SOURCE)
+ @IntDef({STATUS_OK, STATUS_NO_SUCH_ENTRY, STATUS_NOT_REQUESTED, STATUS_NOT_IN_REQUEST_MESSAGE,
+ STATUS_USER_AUTHENTICATION_FAILED, STATUS_READER_AUTHENTICATION_FAILED,
+ STATUS_NO_ACCESS_CONTROL_PROFILES})
+ public @interface Status {
+ }
+}
diff --git a/identity/java/android/security/identity/SessionTranscriptMismatchException.java b/identity/java/android/security/identity/SessionTranscriptMismatchException.java
new file mode 100644
index 000000000000..8c2406043f67
--- /dev/null
+++ b/identity/java/android/security/identity/SessionTranscriptMismatchException.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown when trying use multiple different session transcripts in the same presentation session.
+ */
+public class SessionTranscriptMismatchException extends IdentityCredentialException {
+
+ /**
+ * Constructs a new {@link SessionTranscriptMismatchException} exception.
+ *
+ * @param message the detail message.
+ */
+ public SessionTranscriptMismatchException(@NonNull String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new {@link SessionTranscriptMismatchException} exception.
+ *
+ * @param message the detail message.
+ * @param cause the cause.
+ */
+ public SessionTranscriptMismatchException(@NonNull String message, @NonNull Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/identity/java/android/security/identity/UnknownAuthenticationKeyException.java b/identity/java/android/security/identity/UnknownAuthenticationKeyException.java
new file mode 100644
index 000000000000..f454b2ce2af9
--- /dev/null
+++ b/identity/java/android/security/identity/UnknownAuthenticationKeyException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+
+/**
+ * Thrown if trying to certify an unknown dynamic authentication key.
+ */
+public class UnknownAuthenticationKeyException extends IdentityCredentialException {
+ /**
+ * Constructs a new {@link UnknownAuthenticationKeyException} exception.
+ *
+ * @param message the detail message.
+ */
+ public UnknownAuthenticationKeyException(@NonNull String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new {@link UnknownAuthenticationKeyException} exception.
+ *
+ * @param message the detail message.
+ * @param cause the cause.
+ */
+ public UnknownAuthenticationKeyException(@NonNull String message, @NonNull Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/identity/java/android/security/identity/Util.java b/identity/java/android/security/identity/Util.java
new file mode 100644
index 000000000000..6eefeb8f3f2a
--- /dev/null
+++ b/identity/java/android/security/identity/Util.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECPoint;
+import java.util.Collection;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+class Util {
+ private static final String TAG = "Util";
+
+ static int[] integerCollectionToArray(Collection<Integer> collection) {
+ int[] result = new int[collection.size()];
+ int n = 0;
+ for (int item : collection) {
+ result[n++] = item;
+ }
+ return result;
+ }
+
+ static byte[] stripLeadingZeroes(byte[] value) {
+ int n = 0;
+ while (n < value.length && value[n] == 0) {
+ n++;
+ }
+ int newLen = value.length - n;
+ byte[] ret = new byte[newLen];
+ int m = 0;
+ while (n < value.length) {
+ ret[m++] = value[n++];
+ }
+ return ret;
+ }
+
+ static byte[] publicKeyEncodeUncompressedForm(PublicKey publicKey) {
+ ECPoint w = ((ECPublicKey) publicKey).getW();
+ // X and Y are always positive so for interop we remove any leading zeroes
+ // inserted by the BigInteger encoder.
+ byte[] x = stripLeadingZeroes(w.getAffineX().toByteArray());
+ byte[] y = stripLeadingZeroes(w.getAffineY().toByteArray());
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(0x04);
+ baos.write(x);
+ baos.write(y);
+ return baos.toByteArray();
+ } catch (IOException e) {
+ throw new RuntimeException("Unexpected IOException", e);
+ }
+ }
+
+ /**
+ * Computes an HKDF.
+ *
+ * This is based on https://github.com/google/tink/blob/master/java/src/main/java/com/google
+ * /crypto/tink/subtle/Hkdf.java
+ * which is also Copyright (c) Google and also licensed under the Apache 2 license.
+ *
+ * @param macAlgorithm the MAC algorithm used for computing the Hkdf. I.e., "HMACSHA1" or
+ * "HMACSHA256".
+ * @param ikm the input keying material.
+ * @param salt optional salt. A possibly non-secret random value. If no salt is
+ * provided (i.e. if
+ * salt has length 0) then an array of 0s of the same size as the hash
+ * digest is used as salt.
+ * @param info optional context and application specific information.
+ * @param size The length of the generated pseudorandom string in bytes. The maximal
+ * size is
+ * 255.DigestSize, where DigestSize is the size of the underlying HMAC.
+ * @return size pseudorandom bytes.
+ */
+ static byte[] computeHkdf(
+ String macAlgorithm, final byte[] ikm, final byte[] salt, final byte[] info, int size) {
+ Mac mac = null;
+ try {
+ mac = Mac.getInstance(macAlgorithm);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("No such algorithm: " + macAlgorithm, e);
+ }
+ if (size > 255 * mac.getMacLength()) {
+ throw new RuntimeException("size too large");
+ }
+ try {
+ if (salt == null || salt.length == 0) {
+ // According to RFC 5869, Section 2.2 the salt is optional. If no salt is provided
+ // then HKDF uses a salt that is an array of zeros of the same length as the hash
+ // digest.
+ mac.init(new SecretKeySpec(new byte[mac.getMacLength()], macAlgorithm));
+ } else {
+ mac.init(new SecretKeySpec(salt, macAlgorithm));
+ }
+ byte[] prk = mac.doFinal(ikm);
+ byte[] result = new byte[size];
+ int ctr = 1;
+ int pos = 0;
+ mac.init(new SecretKeySpec(prk, macAlgorithm));
+ byte[] digest = new byte[0];
+ while (true) {
+ mac.update(digest);
+ mac.update(info);
+ mac.update((byte) ctr);
+ digest = mac.doFinal();
+ if (pos + digest.length < size) {
+ System.arraycopy(digest, 0, result, pos, digest.length);
+ pos += digest.length;
+ ctr++;
+ } else {
+ System.arraycopy(digest, 0, result, pos, size - pos);
+ break;
+ }
+ }
+ return result;
+ } catch (InvalidKeyException e) {
+ throw new RuntimeException("Error MACing", e);
+ }
+ }
+
+}
diff --git a/identity/java/android/security/identity/WritableIdentityCredential.java b/identity/java/android/security/identity/WritableIdentityCredential.java
new file mode 100644
index 000000000000..e2a389bfd4da
--- /dev/null
+++ b/identity/java/android/security/identity/WritableIdentityCredential.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+
+/**
+ * Class used to personalize a new identity credential.
+ *
+ * <p>Credentials cannot be updated or modified after creation; any changes require deletion and
+ * re-creation.
+ *
+ * Use {@link IdentityCredentialStore#createCredential(String, String)} to create a new credential.
+ */
+public abstract class WritableIdentityCredential {
+ /**
+ * @hide
+ */
+ protected WritableIdentityCredential() {}
+
+ /**
+ * Generates and returns an X.509 certificate chain for the CredentialKey which identifies this
+ * credential to the issuing authority. The certificate contains an
+ * <a href="https://source.android.com/security/keystore/attestation">Android Keystore</a>
+ * attestation extension which describes the key and the security hardware in which it lives.
+ *
+ * <p>Additionally, the attestation extension will contain the tag TODO_IC_KEY which indicates
+ * it is an Identity Credential key (which can only sign/MAC very specific messages) and not
+ * an Android Keystore key (which can be used to sign/MAC anything).
+ *
+ * <p>The issuer <b>MUST</b> carefully examine this certificate chain including (but not
+ * limited to) checking that the root certificate is well-known, the tag TODO_IC_KEY is
+ * present, the passed in challenge is present, the device has verified boot enabled, that each
+ * certificate in the chain is signed by its successor, that none of the certificates have been
+ * revoked and so on.
+ *
+ * <p>It is not strictly necessary to use this method to provision a credential if the issuing
+ * authority doesn't care about the nature of the security hardware. If called, however, this
+ * method must be called before {@link #personalize(PersonalizationData)}.
+ *
+ * @param challenge is a byte array whose contents should be unique, fresh and provided by
+ * the issuing authority. The value provided is embedded in the attestation
+ * extension and enables the issuing authority to verify that the attestation
+ * certificate is fresh.
+ * @return the X.509 certificate for this credential's CredentialKey.
+ */
+ public abstract @NonNull Collection<X509Certificate> getCredentialKeyCertificateChain(
+ @NonNull byte[] challenge);
+
+ /**
+ * Stores all of the data in the credential, with the specified access control profiles.
+ *
+ * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey with payload
+ * set to {@code ProofOfProvisioning} as defined below.
+ *
+ * <pre>
+ * ProofOfProvisioning = [
+ * "ProofOfProvisioning", ; tstr
+ * tstr, ; DocType
+ * [ * AccessControlProfile ],
+ * ProvisionedData,
+ * bool ; true if this is a test credential, should
+ * ; always be false.
+ * ]
+ *
+ * AccessControlProfile = {
+ * "id": uint,
+ * ? "readerCertificate" : bstr,
+ * ? (
+ * "userAuthenticationRequired" : bool,
+ * "timeoutMillis" : uint,
+ * )
+ * }
+ *
+ * ProvisionedData = {
+ * * Namespace =&gt; [ + Entry ]
+ * },
+ *
+ * Namespace = tstr
+ *
+ * Entry = {
+ * "name" : tstr,
+ * "value" : any,
+ * "accessControlProfiles" : [ * uint ],
+ * }
+ * </pre>
+ *
+ * <p>This data structure provides a guarantee to the issuer about the data which may be
+ * returned in the CBOR returned by
+ * {@link ResultData#getAuthenticatedData()} during a credential
+ * presentation.
+ *
+ * @param personalizationData The data to provision, including access control profiles
+ * and data elements and their values, grouped into namespaces.
+ * @return A COSE_Sign1 data structure, see above.
+ */
+ public abstract @NonNull byte[] personalize(
+ @NonNull PersonalizationData personalizationData);
+}
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index 4318a0ae7d06..d4c4a62932e6 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -352,8 +352,7 @@ public final class TvTrackInfo implements Parcelable {
if (!TextUtils.equals(mId, obj.mId) || mType != obj.mType
|| !TextUtils.equals(mLanguage, obj.mLanguage)
|| !TextUtils.equals(mDescription, obj.mDescription)
- || mEncrypted != obj.mEncrypted
- || !Objects.equals(mExtra, obj.mExtra)) {
+ || mEncrypted != obj.mEncrypted) {
return false;
}
@@ -381,7 +380,16 @@ public final class TvTrackInfo implements Parcelable {
@Override
public int hashCode() {
- return Objects.hashCode(mId);
+ int result = Objects.hash(mId, mType, mLanguage, mDescription);
+
+ if (mType == TYPE_AUDIO) {
+ result = Objects.hash(result, mAudioChannelCount, mAudioSampleRate);
+ } else if (mType == TYPE_VIDEO) {
+ result = Objects.hash(result, mVideoWidth, mVideoHeight, mVideoFrameRate,
+ mVideoPixelAspectRatio);
+ }
+
+ return result;
}
public static final @android.annotation.NonNull Parcelable.Creator<TvTrackInfo> CREATOR =
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index abfee1d415d6..9765074a4927 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -184,13 +184,28 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
}
}
+ /**
+ * Connect this device.
+ *
+ * @param connectAllProfiles {@code true} to connect all profile, {@code false} otherwise.
+ *
+ * @deprecated use {@link #connect()} instead.
+ */
+ @Deprecated
public void connect(boolean connectAllProfiles) {
+ connect();
+ }
+
+ /**
+ * Connect this device.
+ */
+ public void connect() {
if (!ensurePaired()) {
return;
}
mConnectAttempted = SystemClock.elapsedRealtime();
- connectWithoutResettingTimer(connectAllProfiles);
+ connectAllEnabledProfiles();
}
public long getHiSyncId() {
@@ -211,10 +226,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
void onBondingDockConnect() {
// Attempt to connect if UUIDs are available. Otherwise,
// we will connect when the ACTION_UUID intent arrives.
- connect(false);
+ connect();
}
- private void connectWithoutResettingTimer(boolean connectAllProfiles) {
+ private void connectAllEnabledProfiles() {
synchronized (mProfileLock) {
// Try to initialize the profiles if they were not.
if (mProfiles.isEmpty()) {
@@ -229,36 +244,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
return;
}
- int preferredProfiles = 0;
- for (LocalBluetoothProfile profile : mProfiles) {
- if (connectAllProfiles ? profile.accessProfileEnabled()
- : profile.isAutoConnectable()) {
- if (profile.isPreferred(mDevice)) {
- ++preferredProfiles;
- connectInt(profile);
- }
- }
- }
- if (BluetoothUtils.D) Log.d(TAG, "Preferred profiles = " + preferredProfiles);
-
- if (preferredProfiles == 0) {
- connectAutoConnectableProfiles();
- }
- }
- }
-
- private void connectAutoConnectableProfiles() {
- if (!ensurePaired()) {
- return;
- }
-
- synchronized (mProfileLock) {
- for (LocalBluetoothProfile profile : mProfiles) {
- if (profile.isAutoConnectable()) {
- profile.setPreferred(mDevice, true);
- connectInt(profile);
- }
- }
+ mLocalAdapter.connectAllEnabledProfiles(mDevice);
}
}
@@ -625,7 +611,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
*/
if (!mProfiles.isEmpty()
&& ((mConnectAttempted + timeout) > SystemClock.elapsedRealtime())) {
- connectWithoutResettingTimer(false);
+ connectAllEnabledProfiles();
}
dispatchAttributesChanged();
@@ -644,7 +630,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
refresh();
if (bondState == BluetoothDevice.BOND_BONDED && mDevice.isBondingInitiatedLocally()) {
- connect(false);
+ connect();
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 4e16c66d736b..56b14c6b652d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -116,7 +116,7 @@ public class LocalMediaManager implements BluetoothCallback {
final CachedBluetoothDevice cachedDevice =
((BluetoothMediaDevice) device).getCachedDevice();
if (!cachedDevice.isConnected() && !cachedDevice.isBusy()) {
- cachedDevice.connect(true);
+ cachedDevice.connect();
return;
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 98bb74ad0718..4b9f6c22d78c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -127,7 +127,7 @@ public class LocalMediaManagerTest {
mLocalMediaManager.registerCallback(mCallback);
mLocalMediaManager.connectDevice(device);
- verify(cachedDevice).connect(true);
+ verify(cachedDevice).connect();
}
@Test
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 8d858dcb25df..1fb50a9a61de 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1061,7 +1061,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
// keep compatibility with apps that aren't direct boot aware.
// SysUI should just ignore this broadcast because it was already received
// and processed previously.
- if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
+ if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
// Guarantee mTelephonyCapable state after SysUI crash and restart
if (args.simState == State.ABSENT) {
mHandler.obtainMessage(MSG_TELEPHONY_CAPABLE, true).sendToTarget();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 17c200eaef6a..b2f4f16c8005 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -605,8 +605,7 @@ public class PhoneStatusBarPolicy
break;
case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
// Avoid rebroadcast because SysUI is direct boot aware.
- if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK,
- false)) {
+ if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
break;
}
updateSimState(intent);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 7a09455017dd..45233744eabd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -517,7 +517,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
break;
case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
// Avoid rebroadcast because SysUI is direct boot aware.
- if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
+ if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
break;
}
// Might have different subscriptions now.
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index db6177a63f96..21585ed5ccb7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -133,7 +133,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
Assert.assertTrue("onSimStateChanged not called",
mKeyguardUpdateMonitor.hasSimStateJustChanged());
- intent.putExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, true);
+ intent.putExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, true);
mKeyguardUpdateMonitor.mBroadcastReceiver.onReceive(getContext(), intent);
mTestableLooper.processAllMessages();
Assert.assertFalse("onSimStateChanged should have been skipped",
diff --git a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
new file mode 100644
index 000000000000..31cd5d519d87
--- /dev/null
+++ b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothProfile.ServiceListener;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * The BluetoothAirplaneModeListener handles system airplane mode change callback and checks
+ * whether we need to inform BluetoothManagerService on this change.
+ *
+ * The information of airplane mode turns on would not be passed to the BluetoothManagerService
+ * when Bluetooth is on and Bluetooth is in one of the following situations:
+ * 1. Bluetooth A2DP is connected.
+ * 2. Bluetooth Hearing Aid profile is connected.
+ */
+class BluetoothAirplaneModeListener {
+ private static final String TAG = "BluetoothAirplaneModeListener";
+ @VisibleForTesting static final String TOAST_COUNT = "bluetooth_airplane_toast_count";
+
+ private static final int MSG_AIRPLANE_MODE_CHANGED = 0;
+
+ @VisibleForTesting static final int MAX_TOAST_COUNT = 10; // 10 times
+
+ private final BluetoothManagerService mBluetoothManager;
+ private final BluetoothAirplaneModeHandler mHandler;
+ private AirplaneModeHelper mAirplaneHelper;
+
+ @VisibleForTesting int mToastCount = 0;
+
+ BluetoothAirplaneModeListener(BluetoothManagerService service, Looper looper, Context context) {
+ mBluetoothManager = service;
+
+ mHandler = new BluetoothAirplaneModeHandler(looper);
+ context.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
+ mAirplaneModeObserver);
+ }
+
+ private final ContentObserver mAirplaneModeObserver = new ContentObserver(null) {
+ @Override
+ public void onChange(boolean unused) {
+ // Post from system main thread to android_io thread.
+ Message msg = mHandler.obtainMessage(MSG_AIRPLANE_MODE_CHANGED);
+ mHandler.sendMessage(msg);
+ }
+ };
+
+ private class BluetoothAirplaneModeHandler extends Handler {
+ BluetoothAirplaneModeHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_AIRPLANE_MODE_CHANGED:
+ handleAirplaneModeChange();
+ break;
+ default:
+ Log.e(TAG, "Invalid message: " + msg.what);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Call after boot complete
+ */
+ @VisibleForTesting
+ void start(AirplaneModeHelper helper) {
+ Log.i(TAG, "start");
+ mAirplaneHelper = helper;
+ mToastCount = mAirplaneHelper.getSettingsInt(TOAST_COUNT);
+ }
+
+ @VisibleForTesting
+ boolean shouldPopToast() {
+ if (mToastCount >= MAX_TOAST_COUNT) {
+ return false;
+ }
+ mToastCount++;
+ mAirplaneHelper.setSettingsInt(TOAST_COUNT, mToastCount);
+ return true;
+ }
+
+ @VisibleForTesting
+ void handleAirplaneModeChange() {
+ if (shouldSkipAirplaneModeChange()) {
+ Log.i(TAG, "Ignore airplane mode change");
+ // We have to store Bluetooth state here, so if user turns off Bluetooth
+ // after airplane mode is turned on, we don't forget to turn on Bluetooth
+ // when airplane mode turns off.
+ mAirplaneHelper.setSettingsInt(Settings.Global.BLUETOOTH_ON,
+ BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
+ if (shouldPopToast()) {
+ mAirplaneHelper.showToastMessage();
+ }
+ return;
+ }
+ mAirplaneHelper.onAirplaneModeChanged(mBluetoothManager);
+ }
+
+ @VisibleForTesting
+ boolean shouldSkipAirplaneModeChange() {
+ if (mAirplaneHelper == null) {
+ return false;
+ }
+ if (!mAirplaneHelper.isBluetoothOn() || !mAirplaneHelper.isAirplaneModeOn()
+ || !mAirplaneHelper.isA2dpOrHearingAidConnected()) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Helper class that handles callout and callback methods without
+ * complex logic.
+ */
+ @VisibleForTesting
+ public static class AirplaneModeHelper {
+ private volatile BluetoothA2dp mA2dp;
+ private volatile BluetoothHearingAid mHearingAid;
+ private final BluetoothAdapter mAdapter;
+ private final Context mContext;
+
+ AirplaneModeHelper(Context context) {
+ mAdapter = BluetoothAdapter.getDefaultAdapter();
+ mContext = context;
+
+ mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP);
+ mAdapter.getProfileProxy(mContext, mProfileServiceListener,
+ BluetoothProfile.HEARING_AID);
+ }
+
+ private final ServiceListener mProfileServiceListener = new ServiceListener() {
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ // Setup Bluetooth profile proxies
+ switch (profile) {
+ case BluetoothProfile.A2DP:
+ mA2dp = (BluetoothA2dp) proxy;
+ break;
+ case BluetoothProfile.HEARING_AID:
+ mHearingAid = (BluetoothHearingAid) proxy;
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(int profile) {
+ // Clear Bluetooth profile proxies
+ switch (profile) {
+ case BluetoothProfile.A2DP:
+ mA2dp = null;
+ break;
+ case BluetoothProfile.HEARING_AID:
+ mHearingAid = null;
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ @VisibleForTesting
+ public boolean isA2dpOrHearingAidConnected() {
+ return isA2dpConnected() || isHearingAidConnected();
+ }
+
+ @VisibleForTesting
+ public boolean isBluetoothOn() {
+ final BluetoothAdapter adapter = mAdapter;
+ if (adapter == null) {
+ return false;
+ }
+ return adapter.getLeState() == BluetoothAdapter.STATE_ON;
+ }
+
+ @VisibleForTesting
+ public boolean isAirplaneModeOn() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+ }
+
+ @VisibleForTesting
+ public void onAirplaneModeChanged(BluetoothManagerService managerService) {
+ managerService.onAirplaneModeChanged();
+ }
+
+ @VisibleForTesting
+ public int getSettingsInt(String name) {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ name, 0);
+ }
+
+ @VisibleForTesting
+ public void setSettingsInt(String name, int value) {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ name, value);
+ }
+
+ @VisibleForTesting
+ public void showToastMessage() {
+ Resources r = mContext.getResources();
+ final CharSequence text = r.getString(
+ R.string.bluetooth_airplane_mode_toast, 0);
+ Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
+ }
+
+ private boolean isA2dpConnected() {
+ final BluetoothA2dp a2dp = mA2dp;
+ if (a2dp == null) {
+ return false;
+ }
+ return a2dp.getConnectedDevices().size() > 0;
+ }
+
+ private boolean isHearingAidConnected() {
+ final BluetoothHearingAid hearingAid = mHearingAid;
+ if (hearingAid == null) {
+ return false;
+ }
+ return hearingAid.getConnectedDevices().size() > 0;
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index cdfd310a85ae..fa8eda54e53c 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -68,6 +68,7 @@ import android.util.Slog;
import android.util.StatsLog;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.server.pm.UserRestrictionsUtils;
@@ -138,7 +139,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
// Bluetooth persisted setting is on
// but Airplane mode will affect Bluetooth state at start up
// and Airplane mode will have higher priority.
- private static final int BLUETOOTH_ON_AIRPLANE = 2;
+ @VisibleForTesting
+ static final int BLUETOOTH_ON_AIRPLANE = 2;
private static final int SERVICE_IBLUETOOTH = 1;
private static final int SERVICE_IBLUETOOTHGATT = 2;
@@ -159,6 +161,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
private boolean mBinding;
private boolean mUnbinding;
+ private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener;
+
// used inside handler thread
private boolean mQuietEnable = false;
private boolean mEnable;
@@ -257,68 +261,65 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
};
- private final ContentObserver mAirplaneModeObserver = new ContentObserver(null) {
- @Override
- public void onChange(boolean unused) {
- synchronized (this) {
- if (isBluetoothPersistedStateOn()) {
- if (isAirplaneModeOn()) {
- persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
- } else {
- persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
- }
+ public void onAirplaneModeChanged() {
+ synchronized (this) {
+ if (isBluetoothPersistedStateOn()) {
+ if (isAirplaneModeOn()) {
+ persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
+ } else {
+ persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
}
+ }
- int st = BluetoothAdapter.STATE_OFF;
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- st = mBluetooth.getState();
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call getState", e);
- return;
- } finally {
- mBluetoothLock.readLock().unlock();
+ int st = BluetoothAdapter.STATE_OFF;
+ try {
+ mBluetoothLock.readLock().lock();
+ if (mBluetooth != null) {
+ st = mBluetooth.getState();
}
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to call getState", e);
+ return;
+ } finally {
+ mBluetoothLock.readLock().unlock();
+ }
- Slog.d(TAG,
- "Airplane Mode change - current state: " + BluetoothAdapter.nameForState(
- st) + ", isAirplaneModeOn()=" + isAirplaneModeOn());
+ Slog.d(TAG,
+ "Airplane Mode change - current state: " + BluetoothAdapter.nameForState(
+ st) + ", isAirplaneModeOn()=" + isAirplaneModeOn());
- if (isAirplaneModeOn()) {
- // Clear registered LE apps to force shut-off
- clearBleApps();
+ if (isAirplaneModeOn()) {
+ // Clear registered LE apps to force shut-off
+ clearBleApps();
- // If state is BLE_ON make sure we trigger disableBLE
- if (st == BluetoothAdapter.STATE_BLE_ON) {
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- addActiveLog(
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
- mContext.getPackageName(), false);
- mBluetooth.onBrEdrDown();
- mEnable = false;
- mEnableExternal = false;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call onBrEdrDown", e);
- } finally {
- mBluetoothLock.readLock().unlock();
+ // If state is BLE_ON make sure we trigger disableBLE
+ if (st == BluetoothAdapter.STATE_BLE_ON) {
+ try {
+ mBluetoothLock.readLock().lock();
+ if (mBluetooth != null) {
+ addActiveLog(
+ BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
+ mContext.getPackageName(), false);
+ mBluetooth.onBrEdrDown();
+ mEnable = false;
+ mEnableExternal = false;
}
- } else if (st == BluetoothAdapter.STATE_ON) {
- sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
- mContext.getPackageName());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to call onBrEdrDown", e);
+ } finally {
+ mBluetoothLock.readLock().unlock();
}
- } else if (mEnableExternal) {
- sendEnableMsg(mQuietEnableExternal,
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
+ } else if (st == BluetoothAdapter.STATE_ON) {
+ sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
mContext.getPackageName());
}
+ } else if (mEnableExternal) {
+ sendEnableMsg(mQuietEnableExternal,
+ BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
+ mContext.getPackageName());
}
}
- };
+ }
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -430,9 +431,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
Settings.Global.getString(mContentResolver, Settings.Global.AIRPLANE_MODE_RADIOS);
if (airplaneModeRadios == null || airplaneModeRadios.contains(
Settings.Global.RADIO_BLUETOOTH)) {
- mContentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
- mAirplaneModeObserver);
+ mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener(
+ this, IoThread.get().getLooper(), context);
}
int systemUiUid = -1;
@@ -478,6 +478,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
return state != BLUETOOTH_OFF;
}
+ private boolean isBluetoothPersistedStateOnAirplane() {
+ if (!supportBluetoothPersistedState()) {
+ return false;
+ }
+ int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1);
+ if (DBG) {
+ Slog.d(TAG, "Bluetooth persisted state: " + state);
+ }
+ return state == BLUETOOTH_ON_AIRPLANE;
+ }
+
/**
* Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
*/
@@ -954,10 +965,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
synchronized (mReceiver) {
- if (persist) {
- persistBluetoothSetting(BLUETOOTH_OFF);
+ if (!isBluetoothPersistedStateOnAirplane()) {
+ if (persist) {
+ persistBluetoothSetting(BLUETOOTH_OFF);
+ }
+ mEnableExternal = false;
}
- mEnableExternal = false;
sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
packageName);
}
@@ -1185,6 +1198,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
mHandler.sendMessage(getMsg);
}
+ if (mBluetoothAirplaneModeListener != null) {
+ mBluetoothAirplaneModeListener.start(
+ new BluetoothAirplaneModeListener.AirplaneModeHelper(mContext));
+ }
}
/**
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 657207237bf0..76c119db0ad9 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -39,6 +39,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.uidRulesToString;
@@ -86,12 +87,11 @@ import android.net.MatchAllNetworkSpecifier;
import android.net.NattSocketKeepalive;
import android.net.Network;
import android.net.NetworkAgent;
+import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
-import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkMisc;
import android.net.NetworkMonitorManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkProvider;
@@ -1573,48 +1573,49 @@ public class ConnectivityService extends IConnectivityManager.Stub
enforceAccessPermission();
final int uid = Binder.getCallingUid();
NetworkState state = getUnfilteredActiveNetworkState(uid);
- return state.linkProperties;
+ if (state.linkProperties == null) return null;
+ return linkPropertiesRestrictedForCallerPermissions(state.linkProperties,
+ Binder.getCallingPid(), uid);
}
@Override
public LinkProperties getLinkPropertiesForType(int networkType) {
enforceAccessPermission();
NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
- if (nai != null) {
- synchronized (nai) {
- return new LinkProperties(nai.linkProperties);
- }
- }
- return null;
+ final LinkProperties lp = getLinkProperties(nai);
+ if (lp == null) return null;
+ return linkPropertiesRestrictedForCallerPermissions(
+ lp, Binder.getCallingPid(), Binder.getCallingUid());
}
// TODO - this should be ALL networks
@Override
public LinkProperties getLinkProperties(Network network) {
enforceAccessPermission();
- return getLinkProperties(getNetworkAgentInfoForNetwork(network));
+ final LinkProperties lp = getLinkProperties(getNetworkAgentInfoForNetwork(network));
+ if (lp == null) return null;
+ return linkPropertiesRestrictedForCallerPermissions(
+ lp, Binder.getCallingPid(), Binder.getCallingUid());
}
- private LinkProperties getLinkProperties(NetworkAgentInfo nai) {
+ @Nullable
+ private LinkProperties getLinkProperties(@Nullable NetworkAgentInfo nai) {
if (nai == null) {
return null;
}
synchronized (nai) {
- return new LinkProperties(nai.linkProperties);
+ return nai.linkProperties;
}
}
private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
- if (nai != null) {
- synchronized (nai) {
- if (nai.networkCapabilities != null) {
- return networkCapabilitiesRestrictedForCallerPermissions(
- nai.networkCapabilities,
- Binder.getCallingPid(), Binder.getCallingUid());
- }
- }
+ if (nai == null) return null;
+ synchronized (nai) {
+ if (nai.networkCapabilities == null) return null;
+ return networkCapabilitiesRestrictedForCallerPermissions(
+ nai.networkCapabilities,
+ Binder.getCallingPid(), Binder.getCallingUid());
}
- return null;
}
@Override
@@ -1636,6 +1637,29 @@ public class ConnectivityService extends IConnectivityManager.Stub
return newNc;
}
+ private LinkProperties linkPropertiesRestrictedForCallerPermissions(
+ LinkProperties lp, int callerPid, int callerUid) {
+ if (lp == null) return new LinkProperties();
+
+ // Only do a permission check if sanitization is needed, to avoid unnecessary binder calls.
+ final boolean needsSanitization =
+ (lp.getCaptivePortalApiUrl() != null || lp.getCaptivePortalData() != null);
+ if (!needsSanitization) {
+ return new LinkProperties(lp);
+ }
+
+ if (checkSettingsPermission(callerPid, callerUid)) {
+ return lp.makeSensitiveFieldsParcelingCopy();
+ }
+
+ final LinkProperties newLp = new LinkProperties(lp);
+ // Sensitive fields would not be parceled anyway, but sanitize for consistency before the
+ // object gets parceled.
+ newLp.setCaptivePortalApiUrl(null);
+ newLp.setCaptivePortalData(null);
+ return newLp;
+ }
+
private void restrictRequestUidsForCaller(NetworkCapabilities nc) {
if (!checkSettingsPermission()) {
nc.setSingleUid(Binder.getCallingUid());
@@ -2624,8 +2648,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (nai.everConnected) {
loge("ERROR: cannot call explicitlySelected on already-connected network");
}
- nai.networkMisc.explicitlySelected = toBool(msg.arg1);
- nai.networkMisc.acceptUnvalidated = toBool(msg.arg1) && toBool(msg.arg2);
+ nai.networkAgentConfig.explicitlySelected = toBool(msg.arg1);
+ nai.networkAgentConfig.acceptUnvalidated = toBool(msg.arg1) && toBool(msg.arg2);
// Mark the network as temporarily accepting partial connectivity so that it
// will be validated (and possibly become default) even if it only provides
// partial internet access. Note that if user connects to partial connectivity
@@ -2633,7 +2657,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// out of wifi coverage) and if the same wifi is available again, the device
// will auto connect to this wifi even though the wifi has "no internet".
// TODO: Evaluate using a separate setting in IpMemoryStore.
- nai.networkMisc.acceptPartialConnectivity = toBool(msg.arg2);
+ nai.networkAgentConfig.acceptPartialConnectivity = toBool(msg.arg2);
break;
}
case NetworkAgent.EVENT_SOCKET_KEEPALIVE: {
@@ -2665,10 +2689,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
// Only show the notification when the private DNS is broken and the
// PRIVATE_DNS_BROKEN notification hasn't shown since last valid.
- if (privateDnsBroken && !nai.networkMisc.hasShownBroken) {
+ if (privateDnsBroken && !nai.networkAgentConfig.hasShownBroken) {
showNetworkNotification(nai, NotificationType.PRIVATE_DNS_BROKEN);
}
- nai.networkMisc.hasShownBroken = privateDnsBroken;
+ nai.networkAgentConfig.hasShownBroken = privateDnsBroken;
} else if (nai.networkCapabilities.isPrivateDnsBroken()) {
// If probePrivateDnsCompleted is false but nai.networkCapabilities says
// private DNS is broken, it means this network is being reevaluated.
@@ -2678,7 +2702,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
nai.networkCapabilities.setPrivateDnsBroken(false);
final int oldScore = nai.getCurrentScore();
updateCapabilities(oldScore, nai, nai.networkCapabilities);
- nai.networkMisc.hasShownBroken = false;
+ nai.networkAgentConfig.hasShownBroken = false;
}
break;
}
@@ -2737,7 +2761,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// If network becomes valid, the hasShownBroken should be reset for
// that network so that the notification will be fired when the private
// DNS is broken again.
- nai.networkMisc.hasShownBroken = false;
+ nai.networkAgentConfig.hasShownBroken = false;
}
} else if (partialConnectivityChanged) {
updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
@@ -2796,9 +2820,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
break;
}
- if (!nai.networkMisc.provisioningNotificationDisabled) {
+ if (!nai.networkAgentConfig.provisioningNotificationDisabled) {
mNotifier.showNotification(netId, NotificationType.SIGN_IN, nai, null,
- (PendingIntent) msg.obj, nai.networkMisc.explicitlySelected);
+ (PendingIntent) msg.obj,
+ nai.networkAgentConfig.explicitlySelected);
}
}
break;
@@ -2835,26 +2860,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
return true;
}
- // TODO: delete when direct use of registerNetworkFactory is no longer supported.
- private boolean maybeHandleNetworkFactoryMessage(Message msg) {
- switch (msg.what) {
- default:
- return false;
- case NetworkFactory.EVENT_UNFULFILLABLE_REQUEST: {
- handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.sendingUid,
- /* callOnUnavailable */ true);
- break;
- }
- }
- return true;
- }
-
@Override
public void handleMessage(Message msg) {
if (!maybeHandleAsyncChannelMessage(msg)
&& !maybeHandleNetworkMonitorMessage(msg)
- && !maybeHandleNetworkAgentInfoMessage(msg)
- && !maybeHandleNetworkFactoryMessage(msg)) {
+ && !maybeHandleNetworkAgentInfoMessage(msg)) {
maybeHandleNetworkAgentMessage(msg);
}
}
@@ -3163,8 +3173,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// This should never fail. Specifying an already in use NetID will cause failure.
if (networkAgent.isVPN()) {
mNetd.networkCreateVpn(networkAgent.network.netId,
- (networkAgent.networkMisc == null
- || !networkAgent.networkMisc.allowBypass));
+ (networkAgent.networkAgentConfig == null
+ || !networkAgent.networkAgentConfig.allowBypass));
} else {
mNetd.networkCreatePhysical(networkAgent.network.netId,
getNetworkPermission(networkAgent.networkCapabilities));
@@ -3464,16 +3474,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
return;
}
- if (!nai.networkMisc.explicitlySelected) {
+ if (!nai.networkAgentConfig.explicitlySelected) {
Slog.wtf(TAG, "BUG: setAcceptUnvalidated non non-explicitly selected network");
}
- if (accept != nai.networkMisc.acceptUnvalidated) {
- nai.networkMisc.acceptUnvalidated = accept;
+ if (accept != nai.networkAgentConfig.acceptUnvalidated) {
+ nai.networkAgentConfig.acceptUnvalidated = accept;
// If network becomes partial connectivity and user already accepted to use this
// network, we should respect the user's option and don't need to popup the
// PARTIAL_CONNECTIVITY notification to user again.
- nai.networkMisc.acceptPartialConnectivity = accept;
+ nai.networkAgentConfig.acceptPartialConnectivity = accept;
rematchAllNetworksAndRequests();
sendUpdatedScoreToFactories(nai);
}
@@ -3510,8 +3520,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
return;
}
- if (accept != nai.networkMisc.acceptPartialConnectivity) {
- nai.networkMisc.acceptPartialConnectivity = accept;
+ if (accept != nai.networkAgentConfig.acceptPartialConnectivity) {
+ nai.networkAgentConfig.acceptPartialConnectivity = accept;
}
// TODO: Use the current design or save the user choice into IpMemoryStore.
@@ -3736,7 +3746,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
action = ConnectivityManager.ACTION_PROMPT_PARTIAL_CONNECTIVITY;
// Don't bother the user with a high-priority notification if the network was not
// explicitly selected by the user.
- highPriority = nai.networkMisc.explicitlySelected;
+ highPriority = nai.networkAgentConfig.explicitlySelected;
break;
default:
Slog.wtf(TAG, "Unknown notification type " + type);
@@ -3769,14 +3779,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
// automatically connects to a network that has partial Internet access, the user will
// always be able to use it, either because they've already chosen "don't ask again" or
// because we have prompt them.
- if (nai.partialConnectivity && !nai.networkMisc.acceptPartialConnectivity) {
+ if (nai.partialConnectivity && !nai.networkAgentConfig.acceptPartialConnectivity) {
return true;
}
// If a network has no Internet access, only prompt if the network was explicitly selected
// and if the user has not already told us to use the network regardless of whether it
// validated or not.
- if (nai.networkMisc.explicitlySelected && !nai.networkMisc.acceptUnvalidated) {
+ if (nai.networkAgentConfig.explicitlySelected
+ && !nai.networkAgentConfig.acceptUnvalidated) {
return true;
}
@@ -5496,11 +5507,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
// changes that would conflict throughout the automerger graph. Having this method temporarily
// helps with the process of going through with all these dependent changes across the entire
// tree.
- public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
+ /**
+ * Register a new agent. {@see #registerNetworkAgent} below.
+ */
+ public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- int currentScore, NetworkMisc networkMisc) {
+ int currentScore, NetworkAgentConfig networkAgentConfig) {
return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities,
- currentScore, networkMisc, NetworkProvider.ID_NONE);
+ currentScore, networkAgentConfig, NetworkProvider.ID_NONE);
}
/**
@@ -5515,12 +5529,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
* later : see {@link #updateCapabilities}.
* @param currentScore the initial score of the network. See
* {@link NetworkAgentInfo#getCurrentScore}.
- * @param networkMisc metadata about the network. This is never updated.
+ * @param networkAgentConfig metadata about the network. This is never updated.
* @param providerId the ID of the provider owning this NetworkAgent.
+ * @return the network created for this agent.
*/
- public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
+ public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- int currentScore, NetworkMisc networkMisc, int providerId) {
+ int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
enforceNetworkFactoryPermission();
LinkProperties lp = new LinkProperties(linkProperties);
@@ -5532,8 +5547,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
ns.putIntExtension(NetworkScore.LEGACY_SCORE, currentScore);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
- ns, mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd,
- mDnsResolver, mNMS, providerId);
+ ns, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig), this,
+ mNetd, mDnsResolver, mNMS, providerId);
// Make sure the network capabilities reflect what the agent info says.
nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
final String extraInfo = networkInfo.getExtraInfo();
@@ -5551,7 +5566,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// If the network disconnects or sends any other event before that, messages are deferred by
// NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the
// registration.
- return nai.network.netId;
+ return nai.network;
}
private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) {
@@ -5803,6 +5818,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
return INetd.PERMISSION_NONE;
}
+ private void updateNetworkPermissions(@NonNull final NetworkAgentInfo nai,
+ @NonNull final NetworkCapabilities newNc) {
+ final int oldPermission = getNetworkPermission(nai.networkCapabilities);
+ final int newPermission = getNetworkPermission(newNc);
+ if (oldPermission != newPermission && nai.created && !nai.isVPN()) {
+ try {
+ mNMS.setNetworkPermission(nai.network.netId, newPermission);
+ } catch (RemoteException e) {
+ loge("Exception in setNetworkPermission: " + e);
+ }
+ }
+ }
+
/**
* Augments the NetworkCapabilities passed in by a NetworkAgent with capabilities that are
* maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal,
@@ -5843,11 +5871,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
} else {
newNc.addCapability(NET_CAPABILITY_FOREGROUND);
}
- if (nai.isSuspended()) {
- newNc.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- } else {
- newNc.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- }
if (nai.partialConnectivity) {
newNc.addCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY);
} else {
@@ -5855,6 +5878,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
newNc.setPrivateDnsBroken(nai.networkCapabilities.isPrivateDnsBroken());
+ // TODO : remove this once all factories are updated to send NOT_SUSPENDED and NOT_ROAMING
+ if (!newNc.hasTransport(TRANSPORT_CELLULAR)) {
+ newNc.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ newNc.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ }
+
return newNc;
}
@@ -5874,21 +5903,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
* @param nai the network having its capabilities updated.
* @param nc the new network capabilities.
*/
- private void updateCapabilities(int oldScore, NetworkAgentInfo nai, NetworkCapabilities nc) {
+ private void updateCapabilities(final int oldScore, @NonNull final NetworkAgentInfo nai,
+ @NonNull final NetworkCapabilities nc) {
NetworkCapabilities newNc = mixInCapabilities(nai, nc);
-
if (Objects.equals(nai.networkCapabilities, newNc)) return;
-
- final int oldPermission = getNetworkPermission(nai.networkCapabilities);
- final int newPermission = getNetworkPermission(newNc);
- if (oldPermission != newPermission && nai.created && !nai.isVPN()) {
- try {
- mNMS.setNetworkPermission(nai.network.netId, newPermission);
- } catch (RemoteException e) {
- loge("Exception in setNetworkPermission: " + e);
- }
- }
-
+ updateNetworkPermissions(nai, newNc);
final NetworkCapabilities prevNc = nai.getAndSetNetworkCapabilities(newNc);
updateUids(nai, prevNc, newNc);
@@ -5899,6 +5918,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
// on this network. We might have been called by rematchNetworkAndRequests when a
// network changed foreground state.
processListenRequests(nai);
+ final boolean prevSuspended = !prevNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ final boolean suspended = !newNc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ final boolean prevRoaming = !prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ final boolean roaming = !newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ if (prevSuspended != suspended || prevRoaming != roaming) {
+ // TODO (b/73132094) : remove this call once the few users of onSuspended and
+ // onResumed have been removed.
+ notifyNetworkCallbacks(nai, suspended ? ConnectivityManager.CALLBACK_SUSPENDED
+ : ConnectivityManager.CALLBACK_RESUMED);
+ // updateNetworkInfo will mix in the suspended info from the capabilities and
+ // take appropriate action for the network having possibly changed state.
+ updateNetworkInfo(nai, nai.networkInfo);
+ }
} else {
// If the requestable capabilities have changed or the score changed, we can't have been
// called by rematchNetworkAndRequests, so it's safe to start a rematch.
@@ -5906,6 +5938,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
+ // TODO : static analysis indicates that prevNc can't be null here (getAndSetNetworkCaps
+ // never returns null), so mark the relevant members and functions in nai as @NonNull and
+ // remove this test
if (prevNc != null) {
final boolean oldMetered = prevNc.isMetered();
final boolean newMetered = newNc.isMetered();
@@ -5954,7 +5989,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
LinkProperties lp) {
if (nc == null || lp == null) return false;
return nai.isVPN()
- && !nai.networkMisc.allowBypass
+ && !nai.networkAgentConfig.allowBypass
&& nc.getEstablishingVpnAppUid() != Process.SYSTEM_UID
&& lp.getInterfaceName() != null
&& (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute());
@@ -6127,7 +6162,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
case ConnectivityManager.CALLBACK_AVAILABLE: {
putParcelable(bundle, networkCapabilitiesRestrictedForCallerPermissions(
networkAgent.networkCapabilities, nri.mPid, nri.mUid));
- putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));
+ putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
+ networkAgent.linkProperties, nri.mPid, nri.mUid));
// For this notification, arg1 contains the blocked status.
msg.arg1 = arg1;
break;
@@ -6144,7 +6180,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
break;
}
case ConnectivityManager.CALLBACK_IP_CHANGED: {
- putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));
+ putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
+ networkAgent.linkProperties, nri.mPid, nri.mUid));
break;
}
case ConnectivityManager.CALLBACK_BLK_CHANGED: {
@@ -6253,6 +6290,30 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ // An accumulator class to gather the list of changes that result from a rematch.
+ // TODO : enrich to represent an entire set of changes to apply.
+ private static class NetworkReassignment {
+ static class NetworkBgStatePair {
+ @NonNull final NetworkAgentInfo mNetwork;
+ final boolean mOldBackground;
+ NetworkBgStatePair(@NonNull final NetworkAgentInfo network,
+ final boolean oldBackground) {
+ mNetwork = network;
+ mOldBackground = oldBackground;
+ }
+ }
+
+ @NonNull private final Set<NetworkBgStatePair> mRematchedNetworks = new ArraySet<>();
+
+ @NonNull Iterable<NetworkBgStatePair> getRematchedNetworks() {
+ return mRematchedNetworks;
+ }
+
+ void addRematchedNetwork(@NonNull final NetworkBgStatePair network) {
+ mRematchedNetworks.add(network);
+ }
+ }
+
private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork(
@NonNull final NetworkAgentInfo newNetwork) {
final int score = newNetwork.getCurrentScore();
@@ -6298,8 +6359,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// needed. A network is needed if it is the best network for
// one or more NetworkRequests, or if it is a VPN.
//
- // - Tears down newNetwork if it just became validated
- // but turns out to be unneeded.
+ // - Writes into the passed reassignment object all changes that should be done for
+ // rematching this network with all requests, to be applied later.
//
// NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,
// it does not remove NetworkRequests that other Networks could better satisfy.
@@ -6307,15 +6368,22 @@ public class ConnectivityService extends IConnectivityManager.Stub
// This function should be used when possible instead of {@code rematchAllNetworksAndRequests}
// as it performs better by a factor of the number of Networks.
//
+ // TODO : stop writing to the passed reassignment. This is temporarily more useful, but
+ // it's unidiomatic Java and it's hard to read.
+ //
+ // @param changes a currently-building list of changes to write to
// @param newNetwork is the network to be matched against NetworkRequests.
// @param now the time the rematch starts, as returned by SystemClock.elapsedRealtime();
- private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, long now) {
+ private void rematchNetworkAndRequests(@NonNull final NetworkReassignment changes,
+ @NonNull final NetworkAgentInfo newNetwork, final long now) {
ensureRunningOnConnectivityServiceThread();
if (!newNetwork.everConnected) return;
boolean isNewDefault = false;
NetworkAgentInfo oldDefaultNetwork = null;
- final boolean wasBackgroundNetwork = newNetwork.isBackgroundNetwork();
+ changes.addRematchedNetwork(new NetworkReassignment.NetworkBgStatePair(newNetwork,
+ newNetwork.isBackgroundNetwork()));
+
final int score = newNetwork.getCurrentScore();
if (VDBG || DDBG) log("rematching " + newNetwork.name());
@@ -6418,39 +6486,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (newNetwork.getCurrentScore() != score) {
Slog.wtf(TAG, String.format(
"BUG: %s changed score during rematch: %d -> %d",
- newNetwork.name(), score, newNetwork.getCurrentScore()));
+ newNetwork.name(), score, newNetwork.getCurrentScore()));
}
// Notify requested networks are available after the default net is switched, but
// before LegacyTypeTracker sends legacy broadcasts
for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
-
- // Finally, process listen requests and update capabilities if the background state has
- // changed for this network. For consistency with previous behavior, send onLost callbacks
- // before onAvailable.
- processNewlyLostListenRequests(newNetwork);
-
- // Maybe the network changed background states. Update its capabilities.
- final boolean backgroundChanged = wasBackgroundNetwork != newNetwork.isBackgroundNetwork();
- if (backgroundChanged) {
- final NetworkCapabilities newNc = mixInCapabilities(newNetwork,
- newNetwork.networkCapabilities);
-
- final int oldPermission = getNetworkPermission(newNetwork.networkCapabilities);
- final int newPermission = getNetworkPermission(newNc);
- if (oldPermission != newPermission) {
- try {
- mNMS.setNetworkPermission(newNetwork.network.netId, newPermission);
- } catch (RemoteException e) {
- loge("Exception in setNetworkPermission: " + e);
- }
- }
-
- newNetwork.getAndSetNetworkCapabilities(newNc);
- notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_CAP_CHANGED);
- }
-
- processNewlySatisfiedListenRequests(newNetwork);
}
/**
@@ -6472,12 +6513,24 @@ public class ConnectivityService extends IConnectivityManager.Stub
// scoring network and then a higher scoring network, which could produce multiple
// callbacks.
Arrays.sort(nais);
+ final NetworkReassignment changes = new NetworkReassignment();
for (final NetworkAgentInfo nai : nais) {
- rematchNetworkAndRequests(nai, now);
+ rematchNetworkAndRequests(changes, nai, now);
}
final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork();
+ for (final NetworkReassignment.NetworkBgStatePair event : changes.getRematchedNetworks()) {
+ // Process listen requests and update capabilities if the background state has
+ // changed for this network. For consistency with previous behavior, send onLost
+ // callbacks before onAvailable.
+ processNewlyLostListenRequests(event.mNetwork);
+ if (event.mOldBackground != event.mNetwork.isBackgroundNetwork()) {
+ applyBackgroundChangeForRematch(event.mNetwork);
+ }
+ processNewlySatisfiedListenRequests(event.mNetwork);
+ }
+
for (final NetworkAgentInfo nai : nais) {
// Rematching may have altered the linger state of some networks, so update all linger
// timers. updateLingerState reads the state from the network agent and does nothing
@@ -6509,6 +6562,24 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ /**
+ * Apply a change in background state resulting from rematching networks with requests.
+ *
+ * During rematch, a network may change background states by starting to satisfy or stopping
+ * to satisfy a foreground request. Listens don't count for this. When a network changes
+ * background states, its capabilities need to be updated and callbacks fired for the
+ * capability change.
+ *
+ * @param nai The network that changed background states
+ */
+ private void applyBackgroundChangeForRematch(@NonNull final NetworkAgentInfo nai) {
+ final NetworkCapabilities newNc = mixInCapabilities(nai, nai.networkCapabilities);
+ if (Objects.equals(nai.networkCapabilities, newNc)) return;
+ updateNetworkPermissions(nai, newNc);
+ nai.getAndSetNetworkCapabilities(newNc);
+ notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
+ }
+
private void updateLegacyTypeTrackerAndVpnLockdownForRematch(
@Nullable final NetworkAgentInfo oldDefaultNetwork,
@Nullable final NetworkAgentInfo newDefaultNetwork,
@@ -6600,10 +6671,31 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
+ @NonNull
+ private NetworkInfo mixInInfo(@NonNull final NetworkAgentInfo nai, @NonNull NetworkInfo info) {
+ final NetworkInfo newInfo = new NetworkInfo(info);
+ // The suspended and roaming bits are managed in NetworkCapabilities.
+ final boolean suspended =
+ !nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ if (suspended && info.getDetailedState() == NetworkInfo.DetailedState.CONNECTED) {
+ // Only override the state with SUSPENDED if the network is currently in CONNECTED
+ // state. This is because the network could have been suspended before connecting,
+ // or it could be disconnecting while being suspended, and in both these cases
+ // the state should not be overridden. Note that the only detailed state that
+ // maps to State.CONNECTED is DetailedState.CONNECTED, so there is also no need to
+ // worry about multiple different substates of CONNECTED.
+ newInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, info.getReason(),
+ info.getExtraInfo());
+ }
+ newInfo.setRoaming(!nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ return newInfo;
+ }
+
+ private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo info) {
+ final NetworkInfo newInfo = mixInInfo(networkAgent, info);
+
final NetworkInfo.State state = newInfo.getState();
NetworkInfo oldInfo = null;
- final int oldScore = networkAgent.getCurrentScore();
synchronized (networkAgent) {
oldInfo = networkAgent.networkInfo;
networkAgent.networkInfo = newInfo;
@@ -6645,7 +6737,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// command must be sent after updating LinkProperties to maximize chances of
// NetworkMonitor seeing the correct LinkProperties when starting.
// TODO: pass LinkProperties to the NetworkMonitor in the notifyNetworkConnected call.
- if (networkAgent.networkMisc.acceptPartialConnectivity) {
+ if (networkAgent.networkAgentConfig.acceptPartialConnectivity) {
networkAgent.networkMonitor().setAcceptPartialConnectivity();
}
networkAgent.networkMonitor().notifyNetworkConnected(
@@ -6685,17 +6777,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
} else if (networkAgent.created && (oldInfo.getState() == NetworkInfo.State.SUSPENDED ||
state == NetworkInfo.State.SUSPENDED)) {
- // going into or coming out of SUSPEND: re-score and notify
- if (networkAgent.getCurrentScore() != oldScore) {
- rematchAllNetworksAndRequests();
- }
- updateCapabilities(networkAgent.getCurrentScore(), networkAgent,
- networkAgent.networkCapabilities);
- // TODO (b/73132094) : remove this call once the few users of onSuspended and
- // onResumed have been removed.
- notifyNetworkCallbacks(networkAgent, (state == NetworkInfo.State.SUSPENDED ?
- ConnectivityManager.CALLBACK_SUSPENDED :
- ConnectivityManager.CALLBACK_RESUMED));
mLegacyTypeTracker.update(networkAgent);
}
}
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 1ff455ea7a8f..c34dd984f865 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -16,15 +16,273 @@
package com.android.server;
-import android.os.IBinder;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.app.timedetector.NetworkTimeSuggestion;
+import android.app.timedetector.TimeDetector;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.os.TimestampedValue;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.NtpTrustedTime;
+import android.util.TimeUtils;
+
+import com.android.internal.util.DumpUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
/**
- * An interface for NetworkTimeUpdateService implementations. Eventually part or all of this service
- * will be subsumed into {@link com.android.server.timedetector.TimeDetectorService}. In the
- * meantime this interface allows Android to use either the old or new implementation.
+ * Monitors the network time. If looking up the network time fails for some reason, it tries a few
+ * times with a short interval and then resets to checking on longer intervals.
+ *
+ * <p>When available, the time is always suggested to the {@link
+ * com.android.server.timedetector.TimeDetectorService} where it may be used to set the device
+ * system clock, depending on user settings and what other signals are available.
*/
-public interface NetworkTimeUpdateService extends IBinder {
+public class NetworkTimeUpdateService extends Binder {
+
+ private static final String TAG = "NetworkTimeUpdateService";
+ private static final boolean DBG = false;
+
+ private static final int EVENT_AUTO_TIME_ENABLED = 1;
+ private static final int EVENT_POLL_NETWORK_TIME = 2;
+ private static final int EVENT_NETWORK_CHANGED = 3;
+
+ private static final String ACTION_POLL =
+ "com.android.server.NetworkTimeUpdateService.action.POLL";
+
+ private static final int POLL_REQUEST = 0;
+
+ private Network mDefaultNetwork = null;
+
+ private final Context mContext;
+ private final NtpTrustedTime mTime;
+ private final AlarmManager mAlarmManager;
+ private final TimeDetector mTimeDetector;
+ private final ConnectivityManager mCM;
+ private final PendingIntent mPendingPollIntent;
+ private final PowerManager.WakeLock mWakeLock;
+
+ // NTP lookup is done on this thread and handler
+ private Handler mHandler;
+ private AutoTimeSettingObserver mAutoTimeSettingObserver;
+ private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
+
+ // Normal polling frequency
+ private final long mPollingIntervalMs;
+ // Try-again polling interval, in case the network request failed
+ private final long mPollingIntervalShorterMs;
+ // Number of times to try again
+ private final int mTryAgainTimesMax;
+ // Keeps track of how many quick attempts were made to fetch NTP time.
+ // During bootup, the network may not have been up yet, or it's taking time for the
+ // connection to happen.
+ private int mTryAgainCounter;
+
+ public NetworkTimeUpdateService(Context context) {
+ mContext = context;
+ mTime = NtpTrustedTime.getInstance(context);
+ mAlarmManager = mContext.getSystemService(AlarmManager.class);
+ mTimeDetector = mContext.getSystemService(TimeDetector.class);
+ mCM = mContext.getSystemService(ConnectivityManager.class);
+
+ Intent pollIntent = new Intent(ACTION_POLL, null);
+ mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
+
+ mPollingIntervalMs = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpPollingInterval);
+ mPollingIntervalShorterMs = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpPollingIntervalShorter);
+ mTryAgainTimesMax = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_ntpRetry);
+
+ mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ }
/** Initialize the receivers and initiate the first NTP request */
- void systemRunning();
+ public void systemRunning() {
+ registerForAlarms();
+
+ HandlerThread thread = new HandlerThread(TAG);
+ thread.start();
+ mHandler = new MyHandler(thread.getLooper());
+ mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
+ mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
+
+ mAutoTimeSettingObserver = new AutoTimeSettingObserver(mContext, mHandler,
+ EVENT_AUTO_TIME_ENABLED);
+ mAutoTimeSettingObserver.observe();
+ }
+
+ private void registerForAlarms() {
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
+ }
+ }, new IntentFilter(ACTION_POLL));
+ }
+
+ private void onPollNetworkTime(int event) {
+ // If we don't have any default network, don't bother.
+ if (mDefaultNetwork == null) return;
+ mWakeLock.acquire();
+ try {
+ onPollNetworkTimeUnderWakeLock(event);
+ } finally {
+ mWakeLock.release();
+ }
+ }
+
+ private void onPollNetworkTimeUnderWakeLock(int event) {
+ // Force an NTP fix when outdated
+ NtpTrustedTime.TimeResult cachedNtpResult = mTime.getCachedTimeResult();
+ if (cachedNtpResult == null || cachedNtpResult.getAgeMillis() >= mPollingIntervalMs) {
+ if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
+ mTime.forceRefresh();
+ cachedNtpResult = mTime.getCachedTimeResult();
+ }
+
+ if (cachedNtpResult != null && cachedNtpResult.getAgeMillis() < mPollingIntervalMs) {
+ // Obtained fresh fix; schedule next normal update
+ resetAlarm(mPollingIntervalMs);
+
+ // Suggest the time to the time detector. It may choose use it to set the system clock.
+ TimestampedValue<Long> timeSignal = new TimestampedValue<>(
+ cachedNtpResult.getElapsedRealtimeMillis(), cachedNtpResult.getTimeMillis());
+ NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal);
+ timeSuggestion.addDebugInfo("Origin: NetworkTimeUpdateService. event=" + event);
+ mTimeDetector.suggestNetworkTime(timeSuggestion);
+ } else {
+ // No fresh fix; schedule retry
+ mTryAgainCounter++;
+ if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
+ resetAlarm(mPollingIntervalShorterMs);
+ } else {
+ // Try much later
+ mTryAgainCounter = 0;
+ resetAlarm(mPollingIntervalMs);
+ }
+ }
+ }
+
+ /**
+ * Cancel old alarm and starts a new one for the specified interval.
+ *
+ * @param interval when to trigger the alarm, starting from now.
+ */
+ private void resetAlarm(long interval) {
+ mAlarmManager.cancel(mPendingPollIntent);
+ long now = SystemClock.elapsedRealtime();
+ long next = now + interval;
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
+ }
+
+ /** Handler to do the network accesses on */
+ private class MyHandler extends Handler {
+
+ MyHandler(Looper l) {
+ super(l);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_AUTO_TIME_ENABLED:
+ case EVENT_POLL_NETWORK_TIME:
+ case EVENT_NETWORK_CHANGED:
+ onPollNetworkTime(msg.what);
+ break;
+ }
+ }
+ }
+
+ private class NetworkTimeUpdateCallback extends NetworkCallback {
+ @Override
+ public void onAvailable(Network network) {
+ Log.d(TAG, String.format("New default network %s; checking time.", network));
+ mDefaultNetwork = network;
+ // Running on mHandler so invoke directly.
+ onPollNetworkTime(EVENT_NETWORK_CHANGED);
+ }
+
+ @Override
+ public void onLost(Network network) {
+ if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
+ }
+ }
+
+ /**
+ * Observer to watch for changes to the AUTO_TIME setting. It only triggers when the setting
+ * is enabled.
+ */
+ private static class AutoTimeSettingObserver extends ContentObserver {
+
+ private final Context mContext;
+ private final int mMsg;
+ private final Handler mHandler;
+
+ AutoTimeSettingObserver(Context context, Handler handler, int msg) {
+ super(handler);
+ mContext = context;
+ mHandler = handler;
+ mMsg = msg;
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
+ false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ if (isAutomaticTimeEnabled()) {
+ mHandler.obtainMessage(mMsg).sendToTarget();
+ }
+ }
+
+ /**
+ * Checks if the user prefers to automatically set the time.
+ */
+ private boolean isAutomaticTimeEnabled() {
+ ContentResolver resolver = mContext.getContentResolver();
+ return Settings.Global.getInt(resolver, Settings.Global.AUTO_TIME, 0) != 0;
+ }
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ pw.print("PollingIntervalMs: ");
+ TimeUtils.formatDuration(mPollingIntervalMs, pw);
+ pw.print("\nPollingIntervalShorterMs: ");
+ TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
+ pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
+ pw.println("\nTryAgainCounter: " + mTryAgainCounter);
+ NtpTrustedTime.TimeResult ntpResult = mTime.getCachedTimeResult();
+ pw.println("NTP cache result: " + ntpResult);
+ if (ntpResult != null) {
+ pw.println("NTP result age: " + ntpResult.getAgeMillis());
+ }
+ pw.println();
+ }
}
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
deleted file mode 100644
index 7894788cb0b6..000000000000
--- a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.timedetector.NetworkTimeSuggestion;
-import android.app.timedetector.TimeDetector;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.Network;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.os.TimestampedValue;
-import android.provider.Settings;
-import android.util.Log;
-import android.util.NtpTrustedTime;
-import android.util.TimeUtils;
-
-import com.android.internal.util.DumpUtils;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Monitors the network time. If looking up the network time fails for some reason, it tries a few
- * times with a short interval and then resets to checking on longer intervals.
- *
- * <p>When available, the time is always suggested to the {@link
- * com.android.server.timedetector.TimeDetectorService} where it may be used to set the device
- * system clock, depending on user settings and what other signals are available.
- */
-public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeUpdateService {
-
- private static final String TAG = "NetworkTimeUpdateService";
- private static final boolean DBG = false;
-
- private static final int EVENT_AUTO_TIME_ENABLED = 1;
- private static final int EVENT_POLL_NETWORK_TIME = 2;
- private static final int EVENT_NETWORK_CHANGED = 3;
-
- private static final String ACTION_POLL =
- "com.android.server.NetworkTimeUpdateService.action.POLL";
-
- private static final int POLL_REQUEST = 0;
-
- private Network mDefaultNetwork = null;
-
- private final Context mContext;
- private final NtpTrustedTime mTime;
- private final AlarmManager mAlarmManager;
- private final TimeDetector mTimeDetector;
- private final ConnectivityManager mCM;
- private final PendingIntent mPendingPollIntent;
- private final PowerManager.WakeLock mWakeLock;
-
- // NTP lookup is done on this thread and handler
- private Handler mHandler;
- private AutoTimeSettingObserver mAutoTimeSettingObserver;
- private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
-
- // Normal polling frequency
- private final long mPollingIntervalMs;
- // Try-again polling interval, in case the network request failed
- private final long mPollingIntervalShorterMs;
- // Number of times to try again
- private final int mTryAgainTimesMax;
- // Keeps track of how many quick attempts were made to fetch NTP time.
- // During bootup, the network may not have been up yet, or it's taking time for the
- // connection to happen.
- private int mTryAgainCounter;
-
- public NetworkTimeUpdateServiceImpl(Context context) {
- mContext = context;
- mTime = NtpTrustedTime.getInstance(context);
- mAlarmManager = mContext.getSystemService(AlarmManager.class);
- mTimeDetector = mContext.getSystemService(TimeDetector.class);
- mCM = mContext.getSystemService(ConnectivityManager.class);
-
- Intent pollIntent = new Intent(ACTION_POLL, null);
- mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
-
- mPollingIntervalMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpPollingInterval);
- mPollingIntervalShorterMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpPollingIntervalShorter);
- mTryAgainTimesMax = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpRetry);
-
- mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK, TAG);
- }
-
- @Override
- public void systemRunning() {
- registerForAlarms();
-
- HandlerThread thread = new HandlerThread(TAG);
- thread.start();
- mHandler = new MyHandler(thread.getLooper());
- mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
- mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
-
- mAutoTimeSettingObserver = new AutoTimeSettingObserver(mContext, mHandler,
- EVENT_AUTO_TIME_ENABLED);
- mAutoTimeSettingObserver.observe();
- }
-
- private void registerForAlarms() {
- mContext.registerReceiver(
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
- }
- }, new IntentFilter(ACTION_POLL));
- }
-
- private void onPollNetworkTime(int event) {
- // If we don't have any default network, don't bother.
- if (mDefaultNetwork == null) return;
- mWakeLock.acquire();
- try {
- onPollNetworkTimeUnderWakeLock(event);
- } finally {
- mWakeLock.release();
- }
- }
-
- private void onPollNetworkTimeUnderWakeLock(int event) {
- // Force an NTP fix when outdated
- NtpTrustedTime.TimeResult cachedNtpResult = mTime.getCachedTimeResult();
- if (cachedNtpResult == null || cachedNtpResult.getAgeMillis() >= mPollingIntervalMs) {
- if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
- mTime.forceRefresh();
- cachedNtpResult = mTime.getCachedTimeResult();
- }
-
- if (cachedNtpResult != null && cachedNtpResult.getAgeMillis() < mPollingIntervalMs) {
- // Obtained fresh fix; schedule next normal update
- resetAlarm(mPollingIntervalMs);
-
- // Suggest the time to the time detector. It may choose use it to set the system clock.
- TimestampedValue<Long> timeSignal = new TimestampedValue<>(
- cachedNtpResult.getElapsedRealtimeMillis(), cachedNtpResult.getTimeMillis());
- NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal);
- timeSuggestion.addDebugInfo("Origin: NetworkTimeUpdateServiceImpl. event=" + event);
- mTimeDetector.suggestNetworkTime(timeSuggestion);
- } else {
- // No fresh fix; schedule retry
- mTryAgainCounter++;
- if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
- resetAlarm(mPollingIntervalShorterMs);
- } else {
- // Try much later
- mTryAgainCounter = 0;
- resetAlarm(mPollingIntervalMs);
- }
- }
- }
-
- /**
- * Cancel old alarm and starts a new one for the specified interval.
- *
- * @param interval when to trigger the alarm, starting from now.
- */
- private void resetAlarm(long interval) {
- mAlarmManager.cancel(mPendingPollIntent);
- long now = SystemClock.elapsedRealtime();
- long next = now + interval;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
- }
-
- /** Handler to do the network accesses on */
- private class MyHandler extends Handler {
-
- public MyHandler(Looper l) {
- super(l);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case EVENT_AUTO_TIME_ENABLED:
- case EVENT_POLL_NETWORK_TIME:
- case EVENT_NETWORK_CHANGED:
- onPollNetworkTime(msg.what);
- break;
- }
- }
- }
-
- private class NetworkTimeUpdateCallback extends NetworkCallback {
- @Override
- public void onAvailable(Network network) {
- Log.d(TAG, String.format("New default network %s; checking time.", network));
- mDefaultNetwork = network;
- // Running on mHandler so invoke directly.
- onPollNetworkTime(EVENT_NETWORK_CHANGED);
- }
-
- @Override
- public void onLost(Network network) {
- if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
- }
- }
-
- /**
- * Observer to watch for changes to the AUTO_TIME setting. It only triggers when the setting
- * is enabled.
- */
- private static class AutoTimeSettingObserver extends ContentObserver {
-
- private final Context mContext;
- private final int mMsg;
- private final Handler mHandler;
-
- AutoTimeSettingObserver(Context context, Handler handler, int msg) {
- super(handler);
- mContext = context;
- mHandler = handler;
- mMsg = msg;
- }
-
- void observe() {
- ContentResolver resolver = mContext.getContentResolver();
- resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
- false, this);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- if (isAutomaticTimeEnabled()) {
- mHandler.obtainMessage(mMsg).sendToTarget();
- }
- }
-
- /**
- * Checks if the user prefers to automatically set the time.
- */
- private boolean isAutomaticTimeEnabled() {
- ContentResolver resolver = mContext.getContentResolver();
- return Settings.Global.getInt(resolver, Settings.Global.AUTO_TIME, 0) != 0;
- }
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- pw.print("PollingIntervalMs: ");
- TimeUtils.formatDuration(mPollingIntervalMs, pw);
- pw.print("\nPollingIntervalShorterMs: ");
- TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
- pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
- pw.println("\nTryAgainCounter: " + mTryAgainCounter);
- NtpTrustedTime.TimeResult ntpResult = mTime.getCachedTimeResult();
- pw.println("NTP cache result: " + ntpResult);
- if (ntpResult != null) {
- pw.println("NTP result age: " + ntpResult.getAgeMillis());
- }
- pw.println();
- }
-}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 8b436c5f2435..62743aac55f6 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -287,7 +287,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_PRECISE_CALL_STATE
- | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE;
+ | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE
+ | PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES
+ | PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED
+ | PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES;
static final int READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK =
PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_CALL
@@ -2397,8 +2400,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
+ // check if calling app has either permission READ_PRECISE_PHONE_STATE
+ // or with carrier privileges
+ try {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
+ } catch (SecurityException se) {
+ TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext, subId, message);
+ }
}
if ((events & READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK) != 0) {
@@ -2416,16 +2425,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
}
- if ((events & PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES) != 0) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
- }
-
- if ((events & PhoneStateListener.LISTEN_CALL_ATTRIBUTES_CHANGED) != 0) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
- }
-
if ((events & PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
@@ -2436,11 +2435,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
}
- if ((events & PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES) != 0) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
- }
-
return true;
}
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index d19d2ddd7c3c..a7e36b23a98b 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -219,7 +219,7 @@ class TestNetworkService extends ITestNetworkManager.Stub {
// Has to be in TestNetworkAgent to ensure all teardown codepaths properly clean up
// resources, even for binder death or unwanted calls.
synchronized (mTestNetworkTracker) {
- mTestNetworkTracker.remove(netId);
+ mTestNetworkTracker.remove(network.netId);
}
}
}
@@ -338,7 +338,7 @@ class TestNetworkService extends ITestNetworkManager.Stub {
callingUid,
binder);
- mTestNetworkTracker.put(agent.netId, agent);
+ mTestNetworkTracker.put(agent.network.netId, agent);
}
} catch (SocketException e) {
throw new UncheckedIOException(e);
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index 7fd98e0043c9..c125b1baf860 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -17,6 +17,7 @@ package com.android.server.adb;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.debug.AdbManagerInternal;
import android.debug.IAdbManager;
@@ -260,6 +261,30 @@ public class AdbService extends IAdbManager.Stub {
}
}
+ /**
+ * @return true if the device supports secure ADB over Wi-Fi.
+ * @hide
+ */
+ @Override
+ public boolean isAdbWifiSupported() {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.MANAGE_DEBUGGING, "AdbService");
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
+ }
+
+ /**
+ * @return true if the device supports secure ADB over Wi-Fi and device pairing by
+ * QR code.
+ * @hide
+ */
+ @Override
+ public boolean isAdbWifiQrSupported() {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.MANAGE_DEBUGGING, "AdbService");
+ return isAdbWifiSupported() && mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_CAMERA_ANY);
+ }
+
private void setAdbEnabled(boolean enable) {
if (DEBUG) Slog.d(TAG, "setAdbEnabled(" + enable + "), mAdbEnabled=" + mAdbEnabled);
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index aea6d8d24312..f636d67c3d1d 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -116,7 +116,8 @@ public class Nat464Xlat extends BaseNetworkObserver {
&& !lp.hasIpv4Address();
// If the network tells us it doesn't use clat, respect that.
- final boolean skip464xlat = (nai.netMisc() != null) && nai.netMisc().skip464xlat;
+ final boolean skip464xlat = (nai.netAgentConfig() != null)
+ && nai.netAgentConfig().skip464xlat;
return supported && connected && isIpv6OnlyNetwork && !skip464xlat;
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 5e085ca293a4..d66aec576137 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -23,9 +23,9 @@ import android.net.INetd;
import android.net.INetworkMonitor;
import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
-import android.net.NetworkMisc;
import android.net.NetworkMonitorManager;
import android.net.NetworkRequest;
import android.net.NetworkScore;
@@ -127,7 +127,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// This should only be modified by ConnectivityService, via setNetworkCapabilities().
// TODO: make this private with a getter.
public NetworkCapabilities networkCapabilities;
- public final NetworkMisc networkMisc;
+ public final NetworkAgentConfig networkAgentConfig;
// Indicates if netd has been told to create this Network. From this point on the appropriate
// routing rules are setup and routes are added so packets can begin flowing over the Network.
// This is a sticky bit; once set it is never cleared.
@@ -261,7 +261,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, @NonNull NetworkScore ns, Context context,
- Handler handler, NetworkMisc misc, ConnectivityService connService, INetd netd,
+ Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber) {
this.messenger = messenger;
asyncChannel = ac;
@@ -274,7 +274,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
mConnService = connService;
mContext = context;
mHandler = handler;
- networkMisc = misc;
+ networkAgentConfig = config;
this.factorySerialNumber = factorySerialNumber;
}
@@ -309,8 +309,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
return mConnService;
}
- public NetworkMisc netMisc() {
- return networkMisc;
+ public NetworkAgentConfig netAgentConfig() {
+ return networkAgentConfig;
}
public Handler handler() {
@@ -451,15 +451,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
&& !isLingering();
}
- /**
- * Returns whether this network is currently suspended. A network is suspended if it is still
- * connected but data temporarily fails to transfer. See {@link NetworkInfo.State#SUSPENDED}
- * and {@link NetworkCapabilities#NET_CAPABILITY_NOT_SUSPENDED}.
- */
- public boolean isSuspended() {
- return networkInfo.getState() == NetworkInfo.State.SUSPENDED;
- }
-
// Does this network satisfy request?
public boolean satisfies(NetworkRequest request) {
return created &&
@@ -487,7 +478,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// selected and we're trying to see what its score could be. This ensures that we don't tear
// down an explicitly selected network before the user gets a chance to prefer it when
// a higher-scoring network (e.g., Ethernet) is available.
- if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) {
+ if (networkAgentConfig.explicitlySelected
+ && (networkAgentConfig.acceptUnvalidated || pretendValidated)) {
return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE;
}
@@ -533,7 +525,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
synchronized (this) {
// Network objects are outwardly immutable so there is no point in duplicating.
// Duplicating also precludes sharing socket factories and connection pools.
- final String subscriberId = (networkMisc != null) ? networkMisc.subscriberId : null;
+ final String subscriberId = (networkAgentConfig != null)
+ ? networkAgentConfig.subscriberId : null;
return new NetworkState(new NetworkInfo(networkInfo),
new LinkProperties(linkProperties),
new NetworkCapabilities(networkCapabilities), network, subscriberId, null);
@@ -641,13 +634,13 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
+ "nc{" + networkCapabilities + "} Score{" + getCurrentScore() + "} "
+ "everValidated{" + everValidated + "} lastValidated{" + lastValidated + "} "
+ "created{" + created + "} lingering{" + isLingering() + "} "
- + "explicitlySelected{" + networkMisc.explicitlySelected + "} "
- + "acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} "
+ + "explicitlySelected{" + networkAgentConfig.explicitlySelected + "} "
+ + "acceptUnvalidated{" + networkAgentConfig.acceptUnvalidated + "} "
+ "everCaptivePortalDetected{" + everCaptivePortalDetected + "} "
+ "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} "
+ "captivePortalValidationPending{" + captivePortalValidationPending + "} "
+ "partialConnectivity{" + partialConnectivity + "} "
- + "acceptPartialConnectivity{" + networkMisc.acceptPartialConnectivity + "} "
+ + "acceptPartialConnectivity{" + networkAgentConfig.acceptPartialConnectivity + "} "
+ "clat{" + clatd + "} "
+ "}";
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a46ada873408..69ab47a61362 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -53,10 +53,10 @@ import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.net.Network;
import android.net.NetworkAgent;
+import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkMisc;
import android.net.NetworkProvider;
import android.net.RouteInfo;
import android.net.UidRange;
@@ -848,7 +848,7 @@ public class Vpn {
}
public int getNetId() {
- return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET;
+ return mNetworkAgent != null ? mNetworkAgent.network.netId : NETID_UNSET;
}
private LinkProperties makeLinkProperties() {
@@ -914,7 +914,7 @@ public class Vpn {
* has certain changes, in which case this method would just return {@code false}.
*/
private boolean updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig) {
- // NetworkMisc cannot be updated without registering a new NetworkAgent.
+ // NetworkAgentConfig cannot be updated without registering a new NetworkAgent.
if (oldConfig.allowBypass != mConfig.allowBypass) {
Log.i(TAG, "Handover not possible due to changes to allowBypass");
return false;
@@ -947,8 +947,8 @@ public class Vpn {
mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, null);
- NetworkMisc networkMisc = new NetworkMisc();
- networkMisc.allowBypass = mConfig.allowBypass && !mLockdown;
+ NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
+ networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown;
mNetworkCapabilities.setEstablishingVpnAppUid(Binder.getCallingUid());
mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserHandle,
@@ -957,7 +957,7 @@ public class Vpn {
try {
mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */,
mNetworkInfo, mNetworkCapabilities, lp,
- ConnectivityConstants.VPN_DEFAULT_SCORE, networkMisc,
+ ConnectivityConstants.VPN_DEFAULT_SCORE, networkAgentConfig,
NetworkProvider.ID_VPN) {
@Override
public void unwanted() {
diff --git a/services/core/java/com/android/server/lights/OWNERS b/services/core/java/com/android/server/lights/OWNERS
index c7c6d5658d1d..0e795b9a5ef8 100644
--- a/services/core/java/com/android/server/lights/OWNERS
+++ b/services/core/java/com/android/server/lights/OWNERS
@@ -1,2 +1,3 @@
michaelwr@google.com
-dangittik@google.com
+santoscordon@google.com
+flc@google.com
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index c60fed073a15..9760185ca6df 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -169,6 +169,7 @@ import android.os.BestClock;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IDeviceIdleController;
import android.os.INetworkManagementService;
@@ -876,7 +877,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// Listen for subscriber changes
mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener(
- new OnSubscriptionsChangedListener(mHandler.getLooper()) {
+ new HandlerExecutor(mHandler),
+ new OnSubscriptionsChangedListener() {
@Override
public void onSubscriptionsChanged() {
updateNetworksInternal();
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index e991a91fe8ba..609a41560e7b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1159,7 +1159,7 @@ class PackageManagerShellCommand extends ShellCommand {
}
abandonSession = false;
- if (!params.sessionParams.isStaged || !params.waitForStagedSessionReady) {
+ if (!params.sessionParams.isStaged || !params.mWaitForStagedSessionReady) {
pw.println("Success");
return 0;
}
@@ -1197,7 +1197,7 @@ class PackageManagerShellCommand extends ShellCommand {
+ si.getStagedSessionErrorMessage() + "]");
return 1;
}
- pw.println("Success");
+ pw.println("Success. Reboot device to apply staged session");
return 0;
} finally {
if (abandonSession) {
@@ -2487,7 +2487,7 @@ class PackageManagerShellCommand extends ShellCommand {
SessionParams sessionParams;
String installerPackageName;
int userId = UserHandle.USER_ALL;
- boolean waitForStagedSessionReady = false;
+ boolean mWaitForStagedSessionReady = true;
long timeoutMs = DEFAULT_WAIT_MS;
}
@@ -2615,13 +2615,16 @@ class PackageManagerShellCommand extends ShellCommand {
sessionParams.installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
break;
case "--wait":
- params.waitForStagedSessionReady = true;
+ params.mWaitForStagedSessionReady = true;
try {
params.timeoutMs = Long.parseLong(peekNextArg());
getNextArg();
} catch (NumberFormatException ignore) {
}
break;
+ case "--no-wait":
+ params.mWaitForStagedSessionReady = false;
+ break;
default:
throw new IllegalArgumentException("Unknown option " + opt);
}
diff --git a/services/core/java/com/android/server/policy/GlobalKeyManager.java b/services/core/java/com/android/server/policy/GlobalKeyManager.java
index e08c004866ea..157f8256ce50 100644
--- a/services/core/java/com/android/server/policy/GlobalKeyManager.java
+++ b/services/core/java/com/android/server/policy/GlobalKeyManager.java
@@ -74,7 +74,7 @@ final class GlobalKeyManager {
Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON)
.setComponent(component)
.setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
- .putExtra(Intent.EXTRA_KEY_EVENT, event);
+ .putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(event));
context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null);
return true;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b5b21f4189b4..c56634146c7b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1695,7 +1695,7 @@ public final class SystemServer {
if (!isWatch && !disableNetworkTime) {
traceBeginAndSlog("StartNetworkTimeUpdateService");
try {
- networkTimeUpdater = new NetworkTimeUpdateServiceImpl(context);
+ networkTimeUpdater = new NetworkTimeUpdateService(context);
ServiceManager.addService("network_time_update_service", networkTimeUpdater);
} catch (Throwable e) {
reportWtf("starting NetworkTimeUpdate service", e);
diff --git a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java b/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java
new file mode 100644
index 000000000000..968a402ff3b7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static org.mockito.Mockito.*;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.os.Looper;
+import android.provider.Settings;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.BluetoothAirplaneModeListener.AirplaneModeHelper;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class BluetoothAirplaneModeListenerTest {
+ private Context mContext;
+ private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener;
+ private BluetoothAdapter mBluetoothAdapter;
+ private AirplaneModeHelper mHelper;
+
+ @Mock BluetoothManagerService mBluetoothManagerService;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+
+ mHelper = mock(AirplaneModeHelper.class);
+ when(mHelper.getSettingsInt(BluetoothAirplaneModeListener.TOAST_COUNT))
+ .thenReturn(BluetoothAirplaneModeListener.MAX_TOAST_COUNT);
+ doNothing().when(mHelper).setSettingsInt(anyString(), anyInt());
+ doNothing().when(mHelper).showToastMessage();
+ doNothing().when(mHelper).onAirplaneModeChanged(any(BluetoothManagerService.class));
+
+ mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener(
+ mBluetoothManagerService, Looper.getMainLooper(), mContext);
+ mBluetoothAirplaneModeListener.start(mHelper);
+ }
+
+ @Test
+ public void testIgnoreOnAirplanModeChange() {
+ Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
+
+ when(mHelper.isBluetoothOn()).thenReturn(true);
+ Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
+
+ when(mHelper.isA2dpOrHearingAidConnected()).thenReturn(true);
+ Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
+
+ when(mHelper.isAirplaneModeOn()).thenReturn(true);
+ Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
+ }
+
+ @Test
+ public void testHandleAirplaneModeChange_InvokeAirplaneModeChanged() {
+ mBluetoothAirplaneModeListener.handleAirplaneModeChange();
+ verify(mHelper).onAirplaneModeChanged(mBluetoothManagerService);
+ }
+
+ @Test
+ public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_NotPopToast() {
+ mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT;
+ when(mHelper.isBluetoothOn()).thenReturn(true);
+ when(mHelper.isA2dpOrHearingAidConnected()).thenReturn(true);
+ when(mHelper.isAirplaneModeOn()).thenReturn(true);
+ mBluetoothAirplaneModeListener.handleAirplaneModeChange();
+
+ verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON,
+ BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
+ verify(mHelper, times(0)).showToastMessage();
+ verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService);
+ }
+
+ @Test
+ public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_PopToast() {
+ mBluetoothAirplaneModeListener.mToastCount = 0;
+ when(mHelper.isBluetoothOn()).thenReturn(true);
+ when(mHelper.isA2dpOrHearingAidConnected()).thenReturn(true);
+ when(mHelper.isAirplaneModeOn()).thenReturn(true);
+ mBluetoothAirplaneModeListener.handleAirplaneModeChange();
+
+ verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON,
+ BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
+ verify(mHelper).showToastMessage();
+ verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService);
+ }
+
+ @Test
+ public void testIsPopToast_PopToast() {
+ mBluetoothAirplaneModeListener.mToastCount = 0;
+ Assert.assertTrue(mBluetoothAirplaneModeListener.shouldPopToast());
+ verify(mHelper).setSettingsInt(BluetoothAirplaneModeListener.TOAST_COUNT, 1);
+ }
+
+ @Test
+ public void testIsPopToast_NotPopToast() {
+ mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT;
+ Assert.assertFalse(mBluetoothAirplaneModeListener.shouldPopToast());
+ verify(mHelper, times(0)).setSettingsInt(anyString(), anyInt());
+ }
+}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 826a89eb38bb..acf51f3856d3 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -547,8 +547,14 @@ public final class Call {
*/
public static final int PROPERTY_VOIP_AUDIO_MODE = 0x00001000;
+ /**
+ * Indicates that the call is an adhoc conference call. This property can be set for both
+ * incoming and outgoing calls.
+ */
+ public static final int PROPERTY_IS_ADHOC_CONFERENCE = 0x00002000;
+
//******************************************************************************************
- // Next PROPERTY value: 0x00002000
+ // Next PROPERTY value: 0x00004000
//******************************************************************************************
private final String mTelecomCallId;
@@ -726,6 +732,9 @@ public final class Call {
if (hasProperty(properties, PROPERTY_VOIP_AUDIO_MODE)) {
builder.append(" PROPERTY_VOIP_AUDIO_MODE");
}
+ if (hasProperty(properties, PROPERTY_IS_ADHOC_CONFERENCE)) {
+ builder.append(" PROPERTY_IS_ADHOC_CONFERENCE");
+ }
builder.append("]");
return builder.toString();
}
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 456290cd772a..6b0845f5d12b 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -69,6 +69,7 @@ public abstract class Conference extends Conferenceable {
public void onConnectionEvent(Conference c, String event, Bundle extras) {}
public void onCallerDisplayNameChanged(
Conference c, String callerDisplayName, int presentation) {}
+ public void onRingbackRequested(Conference c, boolean ringback) {}
}
private final Set<Listener> mListeners = new CopyOnWriteArraySet<>();
@@ -97,6 +98,7 @@ public abstract class Conference extends Conferenceable {
private int mAddressPresentation;
private String mCallerDisplayName;
private int mCallerDisplayNamePresentation;
+ private boolean mRingbackRequested = false;
private final Connection.Listener mConnectionDeathListener = new Connection.Listener() {
@Override
@@ -170,6 +172,14 @@ public abstract class Conference extends Conferenceable {
}
/**
+ * Returns whether this conference is requesting that the system play a ringback tone
+ * on its behalf.
+ */
+ public final boolean isRingbackRequested() {
+ return mRingbackRequested;
+ }
+
+ /**
* Returns the capabilities of the conference. See {@code CAPABILITY_*} constants in class
* {@link Connection} for valid values.
*
@@ -308,6 +318,35 @@ public abstract class Conference extends Conferenceable {
public void onConnectionAdded(Connection connection) {}
/**
+ * Notifies this Conference, which is in {@code STATE_RINGING}, of
+ * a request to accept.
+ * For managed {@link ConnectionService}s, this will be called when the user answers a call via
+ * the default dialer's {@link InCallService}.
+ *
+ * @param videoState The video state in which to answer the connection.
+ */
+ public void onAnswer(int videoState) {}
+
+ /**
+ * Notifies this Conference, which is in {@code STATE_RINGING}, of
+ * a request to accept.
+ * For managed {@link ConnectionService}s, this will be called when the user answers a call via
+ * the default dialer's {@link InCallService}.
+ * @hide
+ */
+ public final void onAnswer() {
+ onAnswer(VideoProfile.STATE_AUDIO_ONLY);
+ }
+
+ /**
+ * Notifies this Conference, which is in {@code STATE_RINGING}, of
+ * a request to reject.
+ * For managed {@link ConnectionService}s, this will be called when the user rejects a call via
+ * the default dialer's {@link InCallService}.
+ */
+ public void onReject() {}
+
+ /**
* Sets state to be on hold.
*/
public final void setOnHold() {
@@ -322,9 +361,17 @@ public abstract class Conference extends Conferenceable {
}
/**
+ * Sets state to be ringing.
+ */
+ public final void setRinging() {
+ setState(Connection.STATE_RINGING);
+ }
+
+ /**
* Sets state to be active.
*/
public final void setActive() {
+ setRingbackRequested(false);
setState(Connection.STATE_ACTIVE);
}
@@ -436,6 +483,21 @@ public abstract class Conference extends Conferenceable {
}
/**
+ * Requests that the framework play a ringback tone. This is to be invoked by implementations
+ * that do not play a ringback tone themselves in the conference's audio stream.
+ *
+ * @param ringback Whether the ringback tone is to be played.
+ */
+ public final void setRingbackRequested(boolean ringback) {
+ if (mRingbackRequested != ringback) {
+ mRingbackRequested = ringback;
+ for (Listener l : mListeners) {
+ l.onRingbackRequested(this, ringback);
+ }
+ }
+ }
+
+ /**
* Set the video state for the conference.
* Valid values: {@link VideoProfile#STATE_AUDIO_ONLY},
* {@link VideoProfile#STATE_BIDIRECTIONAL},
@@ -640,14 +702,6 @@ public abstract class Conference extends Conferenceable {
}
private void setState(int newState) {
- if (newState != Connection.STATE_ACTIVE &&
- newState != Connection.STATE_HOLDING &&
- newState != Connection.STATE_DISCONNECTED) {
- Log.w(this, "Unsupported state transition for Conference call.",
- Connection.stateToString(newState));
- return;
- }
-
if (mState != newState) {
int oldState = mState;
mState = newState;
@@ -657,6 +711,37 @@ public abstract class Conference extends Conferenceable {
}
}
+ private static class FailureSignalingConference extends Conference {
+ private boolean mImmutable = false;
+ public FailureSignalingConference(DisconnectCause disconnectCause,
+ PhoneAccountHandle phoneAccount) {
+ super(phoneAccount);
+ setDisconnected(disconnectCause);
+ mImmutable = true;
+ }
+ public void checkImmutable() {
+ if (mImmutable) {
+ throw new UnsupportedOperationException("Conference is immutable");
+ }
+ }
+ }
+
+ /**
+ * Return a {@code Conference} which represents a failed conference attempt. The returned
+ * {@code Conference} will have a {@link android.telecom.DisconnectCause} and as specified,
+ * and a {@link #getState()} of {@code STATE_DISCONNECTED}.
+ * <p>
+ * The returned {@code Conference} can be assumed to {@link #destroy()} itself when appropriate,
+ * so users of this method need not maintain a reference to its return value to destroy it.
+ *
+ * @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}).
+ * @return A {@code Conference} which indicates failure.
+ */
+ public @NonNull static Conference createFailedConference(
+ @NonNull DisconnectCause disconnectCause, @NonNull PhoneAccountHandle phoneAccount) {
+ return new FailureSignalingConference(disconnectCause, phoneAccount);
+ }
+
private final void clearConferenceableList() {
for (Connection c : mConferenceableConnections) {
c.removeConnectionListener(mConnectionDeathListener);
@@ -667,11 +752,13 @@ public abstract class Conference extends Conferenceable {
@Override
public String toString() {
return String.format(Locale.US,
- "[State: %s,Capabilites: %s, VideoState: %s, VideoProvider: %s, ThisObject %s]",
+ "[State: %s,Capabilites: %s, VideoState: %s, VideoProvider: %s,"
+ + "isRingbackRequested: %s, ThisObject %s]",
Connection.stateToString(mState),
Call.Details.capabilitiesToString(mConnectionCapabilities),
getVideoState(),
getVideoProvider(),
+ isRingbackRequested() ? "Y" : "N",
super.toString());
}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index f205ec64f49b..c934625f588b 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -497,8 +497,17 @@ public abstract class Connection extends Conferenceable {
@TestApi
public static final int PROPERTY_REMOTELY_HOSTED = 1 << 11;
+ /**
+ * Set by the framework to indicate that it is an adhoc conference call.
+ * <p>
+ * This is used for Outgoing and incoming conference calls.
+ *
+ */
+ public static final int PROPERTY_IS_ADHOC_CONFERENCE = 1 << 12;
+
+
//**********************************************************************************************
- // Next PROPERTY value: 1<<12
+ // Next PROPERTY value: 1<<13
//**********************************************************************************************
/**
@@ -1018,6 +1027,10 @@ public abstract class Connection extends Conferenceable {
builder.append(isLong ? " PROPERTY_REMOTELY_HOSTED" : " remote_hst");
}
+ if ((properties & PROPERTY_IS_ADHOC_CONFERENCE) == PROPERTY_IS_ADHOC_CONFERENCE) {
+ builder.append(isLong ? " PROPERTY_IS_ADHOC_CONFERENCE" : " adhoc_conf");
+ }
+
builder.append("]");
return builder.toString();
}
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index 221f8f129744..6d7ceca0a2cd 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -26,6 +26,9 @@ import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Simple data container encapsulating a request to some entity to
* create a new {@link Connection}.
@@ -46,6 +49,8 @@ public final class ConnectionRequest implements Parcelable {
private boolean mShouldShowIncomingCallUi = false;
private ParcelFileDescriptor mRttPipeToInCall;
private ParcelFileDescriptor mRttPipeFromInCall;
+ private List<Uri> mParticipants;
+ private boolean mIsAdhocConference = false;
public Builder() { }
@@ -59,6 +64,15 @@ public final class ConnectionRequest implements Parcelable {
}
/**
+ * Sets the participants for the resulting {@link ConnectionRequest}
+ * @param participants The participants to which the {@link Connection} is to connect.
+ */
+ public @NonNull Builder setParticipants(@Nullable List<Uri> participants) {
+ this.mParticipants = participants;
+ return this;
+ }
+
+ /**
* Sets the address for the resulting {@link ConnectionRequest}
* @param address The address(e.g., phone number) to which the {@link Connection} is to
* connect.
@@ -108,6 +122,16 @@ public final class ConnectionRequest implements Parcelable {
}
/**
+ * Sets isAdhocConference for the resulting {@link ConnectionRequest}
+ * @param isAdhocConference {@code true} if it is a adhoc conference call
+ * {@code false}, if not a adhoc conference call
+ */
+ public @NonNull Builder setIsAdhocConferenceCall(boolean isAdhocConference) {
+ this.mIsAdhocConference = isAdhocConference;
+ return this;
+ }
+
+ /**
* Sets the RTT pipe for transferring text into the {@link ConnectionService} for the
* resulting {@link ConnectionRequest}
* @param rttPipeFromInCall The data pipe to read from.
@@ -141,7 +165,9 @@ public final class ConnectionRequest implements Parcelable {
mTelecomCallId,
mShouldShowIncomingCallUi,
mRttPipeFromInCall,
- mRttPipeToInCall);
+ mRttPipeToInCall,
+ mParticipants,
+ mIsAdhocConference);
}
}
@@ -155,6 +181,8 @@ public final class ConnectionRequest implements Parcelable {
private final ParcelFileDescriptor mRttPipeFromInCall;
// Cached return value of getRttTextStream -- we don't want to wrap it more than once.
private Connection.RttTextStream mRttTextStream;
+ private List<Uri> mParticipants;
+ private final boolean mIsAdhocConference;
/**
* @param accountHandle The accountHandle which should be used to place the call.
@@ -214,6 +242,21 @@ public final class ConnectionRequest implements Parcelable {
boolean shouldShowIncomingCallUi,
ParcelFileDescriptor rttPipeFromInCall,
ParcelFileDescriptor rttPipeToInCall) {
+ this(accountHandle, handle, extras, videoState, telecomCallId,
+ shouldShowIncomingCallUi, rttPipeFromInCall, rttPipeToInCall, null, false);
+ }
+
+ private ConnectionRequest(
+ PhoneAccountHandle accountHandle,
+ Uri handle,
+ Bundle extras,
+ int videoState,
+ String telecomCallId,
+ boolean shouldShowIncomingCallUi,
+ ParcelFileDescriptor rttPipeFromInCall,
+ ParcelFileDescriptor rttPipeToInCall,
+ List<Uri> participants,
+ boolean isAdhocConference) {
mAccountHandle = accountHandle;
mAddress = handle;
mExtras = extras;
@@ -222,6 +265,8 @@ public final class ConnectionRequest implements Parcelable {
mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
mRttPipeFromInCall = rttPipeFromInCall;
mRttPipeToInCall = rttPipeToInCall;
+ mParticipants = participants;
+ mIsAdhocConference = isAdhocConference;
}
private ConnectionRequest(Parcel in) {
@@ -233,6 +278,11 @@ public final class ConnectionRequest implements Parcelable {
mShouldShowIncomingCallUi = in.readInt() == 1;
mRttPipeFromInCall = in.readParcelable(getClass().getClassLoader());
mRttPipeToInCall = in.readParcelable(getClass().getClassLoader());
+
+ mParticipants = new ArrayList<Uri>();
+ in.readList(mParticipants, getClass().getClassLoader());
+
+ mIsAdhocConference = in.readInt() == 1;
}
/**
@@ -246,6 +296,11 @@ public final class ConnectionRequest implements Parcelable {
public Uri getAddress() { return mAddress; }
/**
+ * The participants to which the {@link Connection} is to connect.
+ */
+ public @Nullable List<Uri> getParticipants() { return mParticipants; }
+
+ /**
* Application-specific extra data. Used for passing back information from an incoming
* call {@code Intent}, and for any proprietary extensions arranged between a client
* and servant {@code ConnectionService} which agree on a vocabulary for such data.
@@ -290,6 +345,13 @@ public final class ConnectionRequest implements Parcelable {
}
/**
+ * @return {@code true} if the call is a adhoc conference call else @return {@code false}
+ */
+ public boolean isAdhocConferenceCall() {
+ return mIsAdhocConference;
+ }
+
+ /**
* Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the connection
* service to the in-call UI. In order to obtain an
* {@link java.io.InputStream} from this {@link ParcelFileDescriptor}, use
@@ -345,11 +407,12 @@ public final class ConnectionRequest implements Parcelable {
@Override
public String toString() {
- return String.format("ConnectionRequest %s %s",
+ return String.format("ConnectionRequest %s %s isAdhocConf: %s",
mAddress == null
? Uri.EMPTY
: Connection.toLogSafePhoneNumber(mAddress.toString()),
- bundleToString(mExtras));
+ bundleToString(mExtras),
+ isAdhocConferenceCall() ? "Y" : "N");
}
private static String bundleToString(Bundle extras){
@@ -406,5 +469,7 @@ public final class ConnectionRequest implements Parcelable {
destination.writeInt(mShouldShowIncomingCallUi ? 1 : 0);
destination.writeParcelable(mRttPipeFromInCall, 0);
destination.writeParcelable(mRttPipeToInCall, 0);
+ destination.writeList(mParticipants);
+ destination.writeInt(mIsAdhocConference ? 1 : 0);
}
}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 3a0494e17db9..440f044fdcf7 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -154,6 +154,9 @@ public abstract class ConnectionService extends Service {
private static final String SESSION_CONNECTION_SERVICE_FOCUS_LOST = "CS.cSFL";
private static final String SESSION_CONNECTION_SERVICE_FOCUS_GAINED = "CS.cSFG";
private static final String SESSION_HANDOVER_FAILED = "CS.haF";
+ private static final String SESSION_CREATE_CONF = "CS.crConf";
+ private static final String SESSION_CREATE_CONF_COMPLETE = "CS.crConfC";
+ private static final String SESSION_CREATE_CONF_FAILED = "CS.crConfF";
private static final int MSG_ADD_CONNECTION_SERVICE_ADAPTER = 1;
private static final int MSG_CREATE_CONNECTION = 2;
@@ -188,6 +191,9 @@ public abstract class ConnectionService extends Service {
private static final int MSG_HANDOVER_FAILED = 32;
private static final int MSG_HANDOVER_COMPLETE = 33;
private static final int MSG_DEFLECT = 34;
+ private static final int MSG_CREATE_CONFERENCE = 35;
+ private static final int MSG_CREATE_CONFERENCE_COMPLETE = 36;
+ private static final int MSG_CREATE_CONFERENCE_FAILED = 37;
private static Connection sNullConnection;
@@ -291,6 +297,63 @@ public abstract class ConnectionService extends Service {
}
@Override
+ public void createConference(
+ PhoneAccountHandle connectionManagerPhoneAccount,
+ String id,
+ ConnectionRequest request,
+ boolean isIncoming,
+ boolean isUnknown,
+ Session.Info sessionInfo) {
+ Log.startSession(sessionInfo, SESSION_CREATE_CONF);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = connectionManagerPhoneAccount;
+ args.arg2 = id;
+ args.arg3 = request;
+ args.arg4 = Log.createSubsession();
+ args.argi1 = isIncoming ? 1 : 0;
+ args.argi2 = isUnknown ? 1 : 0;
+ mHandler.obtainMessage(MSG_CREATE_CONFERENCE, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void createConferenceComplete(String id, Session.Info sessionInfo) {
+ Log.startSession(sessionInfo, SESSION_CREATE_CONF_COMPLETE);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = id;
+ args.arg2 = Log.createSubsession();
+ mHandler.obtainMessage(MSG_CREATE_CONFERENCE_COMPLETE, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
+ public void createConferenceFailed(
+ PhoneAccountHandle connectionManagerPhoneAccount,
+ String callId,
+ ConnectionRequest request,
+ boolean isIncoming,
+ Session.Info sessionInfo) {
+ Log.startSession(sessionInfo, SESSION_CREATE_CONF_FAILED);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = request;
+ args.arg3 = Log.createSubsession();
+ args.arg4 = connectionManagerPhoneAccount;
+ args.argi1 = isIncoming ? 1 : 0;
+ mHandler.obtainMessage(MSG_CREATE_CONFERENCE_FAILED, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
public void handoverFailed(String callId, ConnectionRequest request, int reason,
Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_HANDOVER_FAILED);
@@ -802,6 +865,106 @@ public abstract class ConnectionService extends Service {
}
break;
}
+ case MSG_CREATE_CONFERENCE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Log.continueSession((Session) args.arg4, SESSION_HANDLER + SESSION_CREATE_CONN);
+ try {
+ final PhoneAccountHandle connectionManagerPhoneAccount =
+ (PhoneAccountHandle) args.arg1;
+ final String id = (String) args.arg2;
+ final ConnectionRequest request = (ConnectionRequest) args.arg3;
+ final boolean isIncoming = args.argi1 == 1;
+ final boolean isUnknown = args.argi2 == 1;
+ if (!mAreAccountsInitialized) {
+ Log.d(this, "Enqueueing pre-initconference request %s", id);
+ mPreInitializationConnectionRequests.add(
+ new android.telecom.Logging.Runnable(
+ SESSION_HANDLER + SESSION_CREATE_CONF + ".pIConfR",
+ null /*lock*/) {
+ @Override
+ public void loggedRun() {
+ createConference(connectionManagerPhoneAccount,
+ id,
+ request,
+ isIncoming,
+ isUnknown);
+ }
+ }.prepare());
+ } else {
+ createConference(connectionManagerPhoneAccount,
+ id,
+ request,
+ isIncoming,
+ isUnknown);
+ }
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
+ case MSG_CREATE_CONFERENCE_COMPLETE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Log.continueSession((Session) args.arg2,
+ SESSION_HANDLER + SESSION_CREATE_CONN_COMPLETE);
+ try {
+ final String id = (String) args.arg1;
+ if (!mAreAccountsInitialized) {
+ Log.d(this, "Enqueueing pre-init conference request %s", id);
+ mPreInitializationConnectionRequests.add(
+ new android.telecom.Logging.Runnable(
+ SESSION_HANDLER + SESSION_CREATE_CONF_COMPLETE
+ + ".pIConfR",
+ null /*lock*/) {
+ @Override
+ public void loggedRun() {
+ notifyCreateConferenceComplete(id);
+ }
+ }.prepare());
+ } else {
+ notifyCreateConferenceComplete(id);
+ }
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
+ case MSG_CREATE_CONFERENCE_FAILED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Log.continueSession((Session) args.arg3, SESSION_HANDLER +
+ SESSION_CREATE_CONN_FAILED);
+ try {
+ final String id = (String) args.arg1;
+ final ConnectionRequest request = (ConnectionRequest) args.arg2;
+ final boolean isIncoming = args.argi1 == 1;
+ final PhoneAccountHandle connectionMgrPhoneAccount =
+ (PhoneAccountHandle) args.arg4;
+ if (!mAreAccountsInitialized) {
+ Log.d(this, "Enqueueing pre-init conference request %s", id);
+ mPreInitializationConnectionRequests.add(
+ new android.telecom.Logging.Runnable(
+ SESSION_HANDLER + SESSION_CREATE_CONF_FAILED
+ + ".pIConfR",
+ null /*lock*/) {
+ @Override
+ public void loggedRun() {
+ createConferenceFailed(connectionMgrPhoneAccount, id,
+ request, isIncoming);
+ }
+ }.prepare());
+ } else {
+ Log.i(this, "createConferenceFailed %s", id);
+ createConferenceFailed(connectionMgrPhoneAccount, id, request,
+ isIncoming);
+ }
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
+
case MSG_HANDOVER_FAILED: {
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg3, SESSION_HANDLER +
@@ -1162,6 +1325,12 @@ public abstract class ConnectionService extends Service {
public void onStateChanged(Conference conference, int oldState, int newState) {
String id = mIdByConference.get(conference);
switch (newState) {
+ case Connection.STATE_RINGING:
+ mAdapter.setRinging(id);
+ break;
+ case Connection.STATE_DIALING:
+ mAdapter.setDialing(id);
+ break;
case Connection.STATE_ACTIVE:
mAdapter.setActive(id);
break;
@@ -1292,6 +1461,13 @@ public abstract class ConnectionService extends Service {
mAdapter.onConnectionEvent(id, event, extras);
}
}
+
+ @Override
+ public void onRingbackRequested(Conference c, boolean ringback) {
+ String id = mIdByConference.get(c);
+ Log.d(this, "Adapter conference onRingback %b", ringback);
+ mAdapter.setRingbackRequested(id, ringback);
+ }
};
private final Connection.Listener mConnectionListener = new Connection.Listener() {
@@ -1534,6 +1710,70 @@ public abstract class ConnectionService extends Service {
return super.onUnbind(intent);
}
+
+ /**
+ * This can be used by telecom to either create a new outgoing conference call or attach
+ * to an existing incoming conference call. In either case, telecom will cycle through a
+ * set of services and call createConference until a connection service cancels the process
+ * or completes it successfully.
+ */
+ private void createConference(
+ final PhoneAccountHandle callManagerAccount,
+ final String callId,
+ final ConnectionRequest request,
+ boolean isIncoming,
+ boolean isUnknown) {
+
+ Conference conference = null;
+ conference = isIncoming ? onCreateIncomingConference(callManagerAccount, request)
+ : onCreateOutgoingConference(callManagerAccount, request);
+
+ Log.d(this, "createConference, conference: %s", conference);
+ if (conference == null) {
+ Log.i(this, "createConference, implementation returned null conference.");
+ conference = Conference.createFailedConference(
+ new DisconnectCause(DisconnectCause.ERROR, "IMPL_RETURNED_NULL_CONFERENCE"),
+ request.getAccountHandle());
+ }
+ if (conference.getExtras() != null) {
+ conference.getExtras().putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
+ }
+ mConferenceById.put(callId, conference);
+ mIdByConference.put(conference, callId);
+ conference.addListener(mConferenceListener);
+ ParcelableConference parcelableConference = new ParcelableConference(
+ request.getAccountHandle(),
+ conference.getState(),
+ conference.getConnectionCapabilities(),
+ conference.getConnectionProperties(),
+ Collections.<String>emptyList(), //connectionIds
+ conference.getVideoProvider() == null ?
+ null : conference.getVideoProvider().getInterface(),
+ conference.getVideoState(),
+ conference.getConnectTimeMillis(),
+ conference.getConnectionStartElapsedRealTime(),
+ conference.getStatusHints(),
+ conference.getExtras(),
+ conference.getAddress(),
+ conference.getAddressPresentation(),
+ conference.getCallerDisplayName(),
+ conference.getCallerDisplayNamePresentation(),
+ conference.getDisconnectCause(),
+ conference.isRingbackRequested());
+ if (conference.getState() != Connection.STATE_DISCONNECTED) {
+ conference.setTelecomCallId(callId);
+ mAdapter.setVideoProvider(callId, conference.getVideoProvider());
+ mAdapter.setVideoState(callId, conference.getVideoState());
+ onConferenceAdded(conference);
+ }
+
+ Log.d(this, "createConference, calling handleCreateConferenceSuccessful %s", callId);
+ mAdapter.handleCreateConferenceComplete(
+ callId,
+ request,
+ parcelableConference);
+ }
+
/**
* This can be used by telecom to either create a new outgoing call or attach to an existing
* incoming call. In either case, telecom will cycle through a set of services and call
@@ -1645,6 +1885,18 @@ public abstract class ConnectionService extends Service {
}
}
+ private void createConferenceFailed(final PhoneAccountHandle callManagerAccount,
+ final String callId, final ConnectionRequest request,
+ boolean isIncoming) {
+
+ Log.i(this, "createConferenceFailed %s", callId);
+ if (isIncoming) {
+ onCreateIncomingConferenceFailed(callManagerAccount, request);
+ } else {
+ onCreateOutgoingConferenceFailed(callManagerAccount, request);
+ }
+ }
+
private void handoverFailed(final String callId, final ConnectionRequest request,
int reason) {
@@ -1669,6 +1921,24 @@ public abstract class ConnectionService extends Service {
"notifyCreateConnectionComplete"));
}
+ /**
+ * Called by Telecom when the creation of a new Conference has completed and it is now added
+ * to Telecom.
+ * @param callId The ID of the connection.
+ */
+ private void notifyCreateConferenceComplete(final String callId) {
+ Log.i(this, "notifyCreateConferenceComplete %s", callId);
+ if (callId == null) {
+ // This could happen if the conference fails quickly and is removed from the
+ // ConnectionService before Telecom sends the create conference complete callback.
+ Log.w(this, "notifyCreateConferenceComplete: callId is null.");
+ return;
+ }
+ onCreateConferenceComplete(findConferenceForAction(callId,
+ "notifyCreateConferenceComplete"));
+ }
+
+
private void abort(String callId) {
Log.d(this, "abort %s", callId);
findConnectionForAction(callId, "abort").onAbort();
@@ -1676,12 +1946,20 @@ public abstract class ConnectionService extends Service {
private void answerVideo(String callId, int videoState) {
Log.d(this, "answerVideo %s", callId);
- findConnectionForAction(callId, "answer").onAnswer(videoState);
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "answer").onAnswer(videoState);
+ } else {
+ findConferenceForAction(callId, "answer").onAnswer(videoState);
+ }
}
private void answer(String callId) {
Log.d(this, "answer %s", callId);
- findConnectionForAction(callId, "answer").onAnswer();
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "answer").onAnswer();
+ } else {
+ findConferenceForAction(callId, "answer").onAnswer();
+ }
}
private void deflect(String callId, Uri address) {
@@ -1691,7 +1969,11 @@ public abstract class ConnectionService extends Service {
private void reject(String callId) {
Log.d(this, "reject %s", callId);
- findConnectionForAction(callId, "reject").onReject();
+ if (mConnectionById.containsKey(callId)) {
+ findConnectionForAction(callId, "reject").onReject();
+ } else {
+ findConferenceForAction(callId, "reject").onReject();
+ }
}
private void reject(String callId, String rejectWithMessage) {
@@ -2198,6 +2480,21 @@ public abstract class ConnectionService extends Service {
ConnectionRequest request) {
return null;
}
+ /**
+ * Create a {@code Connection} given an incoming request. This is used to attach to existing
+ * incoming conference call.
+ *
+ * @param connectionManagerPhoneAccount See description at
+ * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
+ * @param request Details about the incoming call.
+ * @return The {@code Connection} object to satisfy this call, or {@code null} to
+ * not handle the call.
+ */
+ public @Nullable Conference onCreateIncomingConference(
+ @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
+ @Nullable ConnectionRequest request) {
+ return null;
+ }
/**
* Called after the {@link Connection} returned by
@@ -2212,6 +2509,19 @@ public abstract class ConnectionService extends Service {
}
/**
+ * Called after the {@link Conference} returned by
+ * {@link #onCreateIncomingConference(PhoneAccountHandle, ConnectionRequest)}
+ * or {@link #onCreateOutgoingConference(PhoneAccountHandle, ConnectionRequest)} has been
+ * added to the {@link ConnectionService} and sent to Telecom.
+ *
+ * @param conference the {@link Conference}.
+ * @hide
+ */
+ public void onCreateConferenceComplete(Conference conference) {
+ }
+
+
+ /**
* Called by Telecom to inform the {@link ConnectionService} that its request to create a new
* incoming {@link Connection} was denied.
* <p>
@@ -2250,6 +2560,47 @@ public abstract class ConnectionService extends Service {
}
/**
+ * Called by Telecom to inform the {@link ConnectionService} that its request to create a new
+ * incoming {@link Conference} was denied.
+ * <p>
+ * Used when a self-managed {@link ConnectionService} attempts to create a new incoming
+ * {@link Conference}, but Telecom has determined that the call cannot be allowed at this time.
+ * The {@link ConnectionService} is responsible for silently rejecting the new incoming
+ * {@link Conference}.
+ * <p>
+ * See {@link TelecomManager#isIncomingCallPermitted(PhoneAccountHandle)} for more information.
+ *
+ * @param connectionManagerPhoneAccount See description at
+ * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
+ * @param request The incoming connection request.
+ */
+ public void onCreateIncomingConferenceFailed(
+ @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
+ @Nullable ConnectionRequest request) {
+ }
+
+ /**
+ * Called by Telecom to inform the {@link ConnectionService} that its request to create a new
+ * outgoing {@link Conference} was denied.
+ * <p>
+ * Used when a self-managed {@link ConnectionService} attempts to create a new outgoing
+ * {@link Conference}, but Telecom has determined that the call cannot be placed at this time.
+ * The {@link ConnectionService} is responisible for informing the user that the
+ * {@link Conference} cannot be made at this time.
+ * <p>
+ * See {@link TelecomManager#isOutgoingCallPermitted(PhoneAccountHandle)} for more information.
+ *
+ * @param connectionManagerPhoneAccount See description at
+ * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
+ * @param request The outgoing connection request.
+ */
+ public void onCreateOutgoingConferenceFailed(
+ @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
+ @Nullable ConnectionRequest request) {
+ }
+
+
+ /**
* Trigger recalculate functinality for conference calls. This is used when a Telephony
* Connection is part of a conference controller but is not yet added to Connection
* Service and hence cannot be added to the conference call.
@@ -2289,6 +2640,36 @@ public abstract class ConnectionService extends Service {
}
/**
+ * Create a {@code Conference} given an outgoing request. This is used to initiate new
+ * outgoing conference call.
+ *
+ * @param connectionManagerPhoneAccount The connection manager account to use for managing
+ * this call.
+ * <p>
+ * If this parameter is not {@code null}, it means that this {@code ConnectionService}
+ * has registered one or more {@code PhoneAccount}s having
+ * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}. This parameter will contain
+ * one of these {@code PhoneAccount}s, while the {@code request} will contain another
+ * (usually but not always distinct) {@code PhoneAccount} to be used for actually
+ * making the connection.
+ * <p>
+ * If this parameter is {@code null}, it means that this {@code ConnectionService} is
+ * being asked to make a direct connection. The
+ * {@link ConnectionRequest#getAccountHandle()} of parameter {@code request} will be
+ * a {@code PhoneAccount} registered by this {@code ConnectionService} to use for
+ * making the connection.
+ * @param request Details about the outgoing call.
+ * @return The {@code Conference} object to satisfy this call, or the result of an invocation
+ * of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call.
+ */
+ public @Nullable Conference onCreateOutgoingConference(
+ @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
+ @Nullable ConnectionRequest request) {
+ return null;
+ }
+
+
+ /**
* Called by Telecom to request that a {@link ConnectionService} creates an instance of an
* outgoing handover {@link Connection}.
* <p>
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
index 04e930ccd954..8f273233044e 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -100,6 +100,19 @@ final class ConnectionServiceAdapter implements DeathRecipient {
}
}
+ void handleCreateConferenceComplete(
+ String id,
+ ConnectionRequest request,
+ ParcelableConference conference) {
+ for (IConnectionServiceAdapter adapter : mAdapters) {
+ try {
+ adapter.handleCreateConferenceComplete(id, request, conference,
+ Log.getExternalSession());
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
/**
* Sets a call's state to active (e.g., an ongoing call where two parties can actively
* communicate).
diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
index 60b2172fdeca..79ad51b92b81 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -75,6 +75,7 @@ final class ConnectionServiceAdapterServant {
private static final int MSG_SET_PHONE_ACCOUNT_CHANGED = 34;
private static final int MSG_CONNECTION_SERVICE_FOCUS_RELEASED = 35;
private static final int MSG_SET_CONFERENCE_STATE = 36;
+ private static final int MSG_HANDLE_CREATE_CONFERENCE_COMPLETE = 37;
private final IConnectionServiceAdapter mDelegate;
@@ -103,6 +104,19 @@ final class ConnectionServiceAdapterServant {
}
break;
}
+ case MSG_HANDLE_CREATE_CONFERENCE_COMPLETE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ mDelegate.handleCreateConferenceComplete(
+ (String) args.arg1,
+ (ConnectionRequest) args.arg2,
+ (ParcelableConference) args.arg3,
+ null /*Session.Info*/);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
case MSG_SET_ACTIVE:
mDelegate.setActive((String) msg.obj, null /*Session.Info*/);
break;
@@ -366,6 +380,20 @@ final class ConnectionServiceAdapterServant {
}
@Override
+ public void handleCreateConferenceComplete(
+ String id,
+ ConnectionRequest request,
+ ParcelableConference conference,
+ Session.Info sessionInfo) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = id;
+ args.arg2 = request;
+ args.arg3 = conference;
+ mHandler.obtainMessage(MSG_HANDLE_CREATE_CONFERENCE_COMPLETE, args).sendToTarget();
+ }
+
+
+ @Override
public void setActive(String connectionId, Session.Info sessionInfo) {
mHandler.obtainMessage(MSG_SET_ACTIVE, connectionId).sendToTarget();
}
diff --git a/telecomm/java/android/telecom/ParcelableConference.java b/telecomm/java/android/telecom/ParcelableConference.java
index ede05943772e..90b69a338c7e 100644
--- a/telecomm/java/android/telecom/ParcelableConference.java
+++ b/telecomm/java/android/telecom/ParcelableConference.java
@@ -47,6 +47,34 @@ public final class ParcelableConference implements Parcelable {
private final int mAddressPresentation;
private final String mCallerDisplayName;
private final int mCallerDisplayNamePresentation;
+ private DisconnectCause mDisconnectCause;
+ private boolean mRingbackRequested;
+
+ public ParcelableConference(
+ PhoneAccountHandle phoneAccount,
+ int state,
+ int connectionCapabilities,
+ int connectionProperties,
+ List<String> connectionIds,
+ IVideoProvider videoProvider,
+ int videoState,
+ long connectTimeMillis,
+ long connectElapsedTimeMillis,
+ StatusHints statusHints,
+ Bundle extras,
+ Uri address,
+ int addressPresentation,
+ String callerDisplayName,
+ int callerDisplayNamePresentation,
+ DisconnectCause disconnectCause,
+ boolean ringbackRequested) {
+ this(phoneAccount, state, connectionCapabilities, connectionProperties, connectionIds,
+ videoProvider, videoState, connectTimeMillis, connectElapsedTimeMillis,
+ statusHints, extras, address, addressPresentation, callerDisplayName,
+ callerDisplayNamePresentation);
+ mDisconnectCause = disconnectCause;
+ mRingbackRequested = ringbackRequested;
+ }
public ParcelableConference(
PhoneAccountHandle phoneAccount,
@@ -79,6 +107,8 @@ public final class ParcelableConference implements Parcelable {
mAddressPresentation = addressPresentation;
mCallerDisplayName = callerDisplayName;
mCallerDisplayNamePresentation = callerDisplayNamePresentation;
+ mDisconnectCause = null;
+ mRingbackRequested = false;
}
@Override
@@ -100,6 +130,10 @@ public final class ParcelableConference implements Parcelable {
.append(mVideoState)
.append(", VideoProvider: ")
.append(mVideoProvider)
+ .append(", isRingbackRequested: ")
+ .append(mRingbackRequested)
+ .append(", disconnectCause: ")
+ .append(mDisconnectCause)
.toString();
}
@@ -151,6 +185,13 @@ public final class ParcelableConference implements Parcelable {
return mAddress;
}
+ public final DisconnectCause getDisconnectCause() {
+ return mDisconnectCause;
+ }
+
+ public boolean isRingbackRequested() {
+ return mRingbackRequested;
+ }
public int getHandlePresentation() {
return mAddressPresentation;
}
@@ -177,11 +218,14 @@ public final class ParcelableConference implements Parcelable {
int addressPresentation = source.readInt();
String callerDisplayName = source.readString();
int callerDisplayNamePresentation = source.readInt();
+ DisconnectCause disconnectCause = source.readParcelable(classLoader);
+ boolean isRingbackRequested = source.readInt() == 1;
return new ParcelableConference(phoneAccount, state, capabilities, properties,
connectionIds, videoCallProvider, videoState, connectTimeMillis,
connectElapsedTimeMillis, statusHints, extras, address, addressPresentation,
- callerDisplayName, callerDisplayNamePresentation);
+ callerDisplayName, callerDisplayNamePresentation, disconnectCause,
+ isRingbackRequested);
}
@Override
@@ -215,5 +259,7 @@ public final class ParcelableConference implements Parcelable {
destination.writeInt(mAddressPresentation);
destination.writeString(mCallerDisplayName);
destination.writeInt(mCallerDisplayNamePresentation);
+ destination.writeParcelable(mDisconnectCause, 0);
+ destination.writeInt(mRingbackRequested ? 1 : 0);
}
}
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index bb858cb0761b..abb210f13376 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -331,7 +331,17 @@ public final class PhoneAccount implements Parcelable {
*/
public static final int CAPABILITY_EMERGENCY_PREFERRED = 0x2000;
- /* NEXT CAPABILITY: 0x4000 */
+ /**
+ * An adhoc conference call is established by providing a list of addresses to
+ * {@code TelecomManager#startConference(List<Uri>, int videoState)} where the
+ * {@link ConnectionService} is responsible for connecting all indicated participants
+ * to a conference simultaneously.
+ * This is in contrast to conferences formed by merging calls together (e.g. using
+ * {@link android.telecom.Call#mergeConference()}).
+ */
+ public static final int CAPABILITY_ADHOC_CONFERENCE_CALLING = 0x4000;
+
+ /* NEXT CAPABILITY: 0x8000 */
/**
* URI scheme for telephone number URIs.
@@ -1054,6 +1064,9 @@ public final class PhoneAccount implements Parcelable {
if (hasCapabilities(CAPABILITY_RTT)) {
sb.append("Rtt");
}
+ if (hasCapabilities(CAPABILITY_ADHOC_CONFERENCE_CALLING)) {
+ sb.append("AdhocConf");
+ }
return sb.toString();
}
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 1e73bd61d68e..76640e036eeb 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -101,6 +101,14 @@ final class RemoteConnectionService {
}
@Override
+ public void handleCreateConferenceComplete(
+ String id,
+ ConnectionRequest request,
+ ParcelableConference parcel,
+ Session.Info info) {
+ }
+
+ @Override
public void setActive(String callId, Session.Info sessionInfo) {
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "setActive")
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index ffb27797d340..f1dca0387369 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1803,6 +1803,45 @@ public class TelecomManager {
}
/**
+ * Registers a new incoming conference. A {@link ConnectionService} should invoke this method
+ * when it has an incoming conference. For managed {@link ConnectionService}s, the specified
+ * {@link PhoneAccountHandle} must have been registered with {@link #registerPhoneAccount} and
+ * the user must have enabled the corresponding {@link PhoneAccount}. This can be checked using
+ * {@link #getPhoneAccount}. Self-managed {@link ConnectionService}s must have
+ * {@link android.Manifest.permission#MANAGE_OWN_CALLS} to add a new incoming call.
+ * <p>
+ * The incoming conference you are adding is assumed to have a video state of
+ * {@link VideoProfile#STATE_AUDIO_ONLY}, unless the extra value
+ * {@link #EXTRA_INCOMING_VIDEO_STATE} is specified.
+ * <p>
+ * Once invoked, this method will cause the system to bind to the {@link ConnectionService}
+ * associated with the {@link PhoneAccountHandle} and request additional information about the
+ * call (See {@link ConnectionService#onCreateIncomingConference}) before starting the incoming
+ * call UI.
+ * <p>
+ * For a managed {@link ConnectionService}, a {@link SecurityException} will be thrown if either
+ * the {@link PhoneAccountHandle} does not correspond to a registered {@link PhoneAccount} or
+ * the associated {@link PhoneAccount} is not currently enabled by the user.
+ *
+ * @param phoneAccount A {@link PhoneAccountHandle} registered with
+ * {@link #registerPhoneAccount}.
+ * @param extras A bundle that will be passed through to
+ * {@link ConnectionService#onCreateIncomingConference}.
+ */
+
+ public void addNewIncomingConference(@NonNull PhoneAccountHandle phoneAccount,
+ @NonNull Bundle extras) {
+ try {
+ if (isServiceConnected()) {
+ getTelecomService().addNewIncomingConference(
+ phoneAccount, extras == null ? new Bundle() : extras);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException adding a new incoming conference: " + phoneAccount, e);
+ }
+ }
+
+ /**
* Registers a new unknown call with Telecom. This can only be called by the system Telephony
* service. This is invoked when Telephony detects a new unknown connection that was neither
* a new incoming call, nor an user-initiated outgoing call.
@@ -2006,6 +2045,42 @@ public class TelecomManager {
}
}
+
+ /**
+ * Place a new conference call with the provided participants using the system telecom service
+ * This method doesn't support placing of emergency calls.
+ *
+ * An adhoc conference call is established by providing a list of addresses to
+ * {@code TelecomManager#startConference(List<Uri>, int videoState)} where the
+ * {@link ConnectionService} is responsible for connecting all indicated participants
+ * to a conference simultaneously.
+ * This is in contrast to conferences formed by merging calls together (e.g. using
+ * {@link android.telecom.Call#mergeConference()}).
+ *
+ * The following keys are supported in the supplied extras.
+ * <ul>
+ * <li>{@link #EXTRA_PHONE_ACCOUNT_HANDLE}</li>
+ * <li>{@link #EXTRA_START_CALL_WITH_SPEAKERPHONE}</li>
+ * <li>{@link #EXTRA_START_CALL_WITH_VIDEO_STATE}</li>
+ * </ul>
+ *
+ * @param participants List of participants to start conference with
+ * @param extras Bundle of extras to use with the call
+ */
+ @RequiresPermission(android.Manifest.permission.CALL_PHONE)
+ public void startConference(@NonNull List<Uri> participants,
+ @NonNull Bundle extras) {
+ ITelecomService service = getTelecomService();
+ if (service != null) {
+ try {
+ service.startConference(participants, extras,
+ mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecomService#placeCall", e);
+ }
+ }
+ }
+
/**
* Enables and disables specified phone account.
*
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index e35093c9656a..96f2483f32f9 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -53,6 +53,20 @@ oneway interface IConnectionService {
void createConnectionFailed(in PhoneAccountHandle connectionManagerPhoneAccount, String callId,
in ConnectionRequest request, boolean isIncoming, in Session.Info sessionInfo);
+ void createConference(
+ in PhoneAccountHandle connectionManagerPhoneAccount,
+ String callId,
+ in ConnectionRequest request,
+ boolean isIncoming,
+ boolean isUnknown,
+ in Session.Info sessionInfo);
+
+ void createConferenceComplete(String callId, in Session.Info sessionInfo);
+
+ void createConferenceFailed(in PhoneAccountHandle connectionManagerPhoneAccount, String callId,
+ in ConnectionRequest request, boolean isIncoming, in Session.Info sessionInfo);
+
+
void abort(String callId, in Session.Info sessionInfo);
void answerVideo(String callId, int videoState, in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
index 9cf098c75177..4f63e08abce6 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -44,6 +44,12 @@ oneway interface IConnectionServiceAdapter {
in ParcelableConnection connection,
in Session.Info sessionInfo);
+ void handleCreateConferenceComplete(
+ String callId,
+ in ConnectionRequest request,
+ in ParcelableConference connection,
+ in Session.Info sessionInfo);
+
void setActive(String callId, in Session.Info sessionInfo);
void setRinging(String callId, in Session.Info sessionInfo);
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 204c37e9aa38..9a47ae15e64a 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -242,11 +242,22 @@ interface ITelecomService {
void addNewIncomingCall(in PhoneAccountHandle phoneAccount, in Bundle extras);
/**
+ * @see TelecomServiceImpl#addNewIncomingConference
+ */
+ void addNewIncomingConference(in PhoneAccountHandle phoneAccount, in Bundle extras);
+
+ /**
* @see TelecomServiceImpl#addNewUnknownCall
*/
void addNewUnknownCall(in PhoneAccountHandle phoneAccount, in Bundle extras);
/**
+ * @see TelecomServiceImpl#startConference
+ */
+ void startConference(in List<Uri> participants, in Bundle extras,
+ String callingPackage);
+
+ /**
* @see TelecomServiceImpl#placeCall
*/
void placeCall(in Uri handle, in Bundle extras, String callingPackage);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 61e67be2333f..71aaa6e95352 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1079,6 +1079,14 @@ public class CarrierConfigManager {
public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL =
"ignore_rtt_mode_setting_bool";
+
+ /**
+ * Determines whether adhoc conference calls are supported by a carrier. When {@code true},
+ * adhoc conference calling is supported, {@code false otherwise}.
+ */
+ public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL =
+ "support_adhoc_conference_calls_bool";
+
/**
* Determines whether conference calls are supported by a carrier. When {@code true},
* conference calling is supported, {@code false otherwise}.
@@ -3111,7 +3119,6 @@ public class CarrierConfigManager {
* 1 - yes. This is default.
* @hide
*/
- // TODO(b/119567985): name this key properly
public static final String KEY_SUPL_ES_STRING = KEY_PREFIX + "supl_es";
/**
@@ -3523,6 +3530,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL, false);
sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, false);
sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0);
+ sDefaults.putBoolean(KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL, false);
sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true);
sDefaults.putBoolean(KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL, true);
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index c706d288b7f2..9b4292f42172 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -54,6 +54,43 @@ public class ImsManager {
"com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION";
/**
+ * An intent action indicating that IMS registration for WiFi calling has resulted in an error.
+ * Contains error information that should be displayed to the user.
+ * <p>
+ * This intent will contain the following extra key/value pairs:
+ * {@link #EXTRA_WFC_REGISTRATION_FAILURE_TITLE}
+ * and {@link #EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE}, which contain carrier specific
+ * error information that should be displayed to the user.
+ * <p>
+ * Usage: This intent is sent as an ordered broadcast. If the settings application is going
+ * to show the error information specified to the user, it should respond to
+ * {@link android.content.BroadcastReceiver#setResultCode(int)} with
+ * {@link android.app.Activity#RESULT_CANCELED}, which will signal to the framework that the
+ * event was handled. If the framework does not receive a response to the ordered broadcast,
+ * it will then show a notification to the user indicating that there was a registration
+ * failure.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_WFC_IMS_REGISTRATION_ERROR =
+ "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR";
+
+ /**
+ * An extra key corresponding to a String value which contains the carrier specific title to be
+ * displayed as part of the message shown to the user when there is an error registering for
+ * WiFi calling.
+ */
+ public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE =
+ "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE";
+
+ /**
+ * An extra key corresponding to a String value which contains the carrier specific message to
+ * be displayed as part of the message shown to the user when there is an error registering for
+ * WiFi calling.
+ */
+ public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE =
+ "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE";
+
+ /**
* Use {@link Context#getSystemService(String)} to get an instance of this class.
* @hide
*/
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 2f9e6ac0f9ff..0074772a221d 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -28,7 +28,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
-import android.location.CountryDetector;
import android.net.Uri;
import android.os.PersistableBundle;
import android.provider.Contacts;
@@ -2032,6 +2031,7 @@ public class PhoneNumberUtils {
private static boolean isEmergencyNumberInternal(int subId, String number,
String defaultCountryIso,
boolean useExactMatch) {
+ // TODO: clean up all the callers that pass in a defaultCountryIso, since it's ignored now.
try {
if (useExactMatch) {
return TelephonyManager.getDefault().isEmergencyNumber(number);
@@ -2193,18 +2193,7 @@ public class PhoneNumberUtils {
private static boolean isLocalEmergencyNumberInternal(int subId, String number,
Context context,
boolean useExactMatch) {
- String countryIso;
- CountryDetector detector = (CountryDetector) context.getSystemService(
- Context.COUNTRY_DETECTOR);
- if (detector != null && detector.detectCountry() != null) {
- countryIso = detector.detectCountry().getCountryIso();
- } else {
- Locale locale = context.getResources().getConfiguration().locale;
- countryIso = locale.getCountry();
- Rlog.w(LOG_TAG, "No CountryDetector; falling back to countryIso based on locale: "
- + countryIso);
- }
- return isEmergencyNumberInternal(subId, number, countryIso, useExactMatch);
+ return isEmergencyNumberInternal(subId, number, null /* unused */, useExactMatch);
}
/**
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index b5dea7c02148..0ba36b17f4ad 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -1577,7 +1577,7 @@ public final class SmsManager {
}
/**
- * Copy a raw SMS PDU to the ICC.
+ * Copies a raw SMS PDU to the ICC.
* ICC (Integrated Circuit Card) is the card of the device.
* For example, this can be the SIM or USIM for GSM.
*
@@ -1591,21 +1591,26 @@ public final class SmsManager {
* operation is performed on the correct subscription.
* </p>
*
- * @param smsc the SMSC for this message, or NULL for the default SMSC
- * @param pdu the raw PDU to store
- * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
- * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
- * @return true for success
+ * @param smsc the SMSC for this messag or null for the default SMSC.
+ * @param pdu the raw PDU to store.
+ * @param status message status. One of these status:
+ * <code>STATUS_ON_ICC_READ</code>
+ * <code>STATUS_ON_ICC_UNREAD</code>
+ * <code>STATUS_ON_ICC_SENT</code>
+ * <code>STATUS_ON_ICC_UNSENT</code>
+ * @return true for success. Otherwise false.
*
- * @throws IllegalArgumentException if pdu is NULL
- * {@hide}
+ * @throws IllegalArgumentException if pdu is null.
+ * @hide
*/
- @UnsupportedAppUsage
- public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) {
+ @SystemApi
+ @RequiresPermission(Manifest.permission.ACCESS_MESSAGES_ON_ICC)
+ public boolean copyMessageToIcc(
+ @Nullable byte[] smsc, @NonNull byte[] pdu, @StatusOnIcc int status) {
boolean success = false;
- if (null == pdu) {
- throw new IllegalArgumentException("pdu is NULL");
+ if (pdu == null) {
+ throw new IllegalArgumentException("pdu is null");
}
try {
ISms iSms = getISmsService();
@@ -1622,7 +1627,7 @@ public final class SmsManager {
}
/**
- * Delete the specified message from the ICC.
+ * Deletes the specified message from the ICC.
* ICC (Integrated Circuit Card) is the card of the device.
* For example, this can be the SIM or USIM for GSM.
*
@@ -1706,7 +1711,7 @@ public final class SmsManager {
}
/**
- * Retrieves all messages currently stored on ICC.
+ * Retrieves all messages currently stored on the ICC.
* ICC (Integrated Circuit Card) is the card of the device.
* For example, this can be the SIM or USIM for GSM.
*
@@ -1872,8 +1877,7 @@ public final class SmsManager {
}
/**
- * Create a list of <code>SmsMessage</code>s from a list of RawSmsData
- * records returned by <code>getAllMessagesFromIcc()</code>
+ * Creates a list of <code>SmsMessage</code>s from a list of SmsRawData records.
*
* <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
* applications or the Telephony framework and will never trigger an SMS disambiguation
@@ -1885,8 +1889,7 @@ public final class SmsManager {
* operation is performed on the correct subscription.
* </p>
*
- * @param records SMS EF records, returned by
- * <code>getAllMessagesFromIcc</code>
+ * @param records SMS EF records.
* @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
*/
private ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
@@ -1897,7 +1900,7 @@ public final class SmsManager {
SmsRawData data = records.get(i);
// List contains all records, including "free" records (null)
if (data != null) {
- SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes(),
+ SmsMessage sms = SmsMessage.createFromEfRecord(i + 1, data.getBytes(),
getSubscriptionId());
if (sms != null) {
messages.add(sms);
@@ -2037,6 +2040,17 @@ public final class SmsManager {
return ret;
}
+ /** @hide */
+ @IntDef(prefix = { "STATUS_ON_ICC_" }, value = {
+ STATUS_ON_ICC_FREE,
+ STATUS_ON_ICC_READ,
+ STATUS_ON_ICC_UNREAD,
+ STATUS_ON_ICC_SENT,
+ STATUS_ON_ICC_UNSENT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StatusOnIcc {}
+
// see SmsMessage.getStatusOnIcc
/** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 30a61c31ab81..8d9b1dd438ea 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -278,41 +278,24 @@ public class SmsMessage {
}
/**
- * Create an SmsMessage from an SMS EF record.
+ * Creates an SmsMessage from an SMS EF record.
*
- * @param index Index of SMS record. This should be index in ArrayList
- * returned by SmsManager.getAllMessagesFromSim + 1.
+ * @param index Index of SMS EF record.
* @param data Record data.
* @return An SmsMessage representing the record.
*
* @hide
*/
public static SmsMessage createFromEfRecord(int index, byte[] data) {
- SmsMessageBase wrappedMessage;
-
- if (isCdmaVoice()) {
- wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord(
- index, data);
- } else {
- wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord(
- index, data);
- }
-
- if (wrappedMessage != null) {
- return new SmsMessage(wrappedMessage);
- } else {
- Rlog.e(LOG_TAG, "createFromEfRecord(): wrappedMessage is null");
- return null;
- }
+ return createFromEfRecord(index, data, SmsManager.getDefaultSmsSubscriptionId());
}
/**
- * Create an SmsMessage from an SMS EF record.
+ * Creates an SmsMessage from an SMS EF record.
*
- * @param index Index of SMS record. This should be index in ArrayList
- * returned by SmsManager.getAllMessagesFromSim + 1.
+ * @param index Index of SMS EF record.
* @param data Record data.
- * @param subId Subscription Id of the SMS
+ * @param subId Subscription Id associated with the record.
* @return An SmsMessage representing the record.
*
* @hide
@@ -602,13 +585,15 @@ public class SmsMessage {
*/
/**
- * Get an SMS-SUBMIT PDU for a destination address and a message.
+ * Gets an SMS-SUBMIT PDU for a destination address and a message.
* This method will not attempt to use any GSM national language 7 bit encodings.
*
- * @param scAddress Service Centre address. Null means use default.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param message string representation of the message payload.
+ * @param statusReportRequested indicates whether a report is requested for this message.
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
*/
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, String message, boolean statusReportRequested) {
@@ -621,17 +606,16 @@ public class SmsMessage {
}
/**
- * Get an SMS-SUBMIT PDU for a destination address and a message.
+ * Gets an SMS-SUBMIT PDU for a destination address and a message.
* This method will not attempt to use any GSM national language 7 bit encodings.
*
- * @param scAddress Service Centre address. Null means use default.
+ * @param scAddress Service Centre address. Null means use default.
* @param destinationAddress the address of the destination for the message.
- * @param message String representation of the message payload.
- * @param statusReportRequested Indicates whether a report is requested for this message.
- * @param subId Subscription of the message
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @param message string representation of the message payload.
+ * @param statusReportRequested indicates whether a report is requested for this message.
+ * @param subId subscription of the message.
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
* @hide
*/
public static SubmitPdu getSubmitPdu(String scAddress,
@@ -649,17 +633,16 @@ public class SmsMessage {
}
/**
- * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
+ * Gets an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
* This method will not attempt to use any GSM national language 7 bit encodings.
*
- * @param scAddress Service Centre address. null == use default
- * @param destinationAddress the address of the destination for the message
- * @param destinationPort the port to deliver the message to at the
- * destination
- * @param data the data for the message
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param destinationPort the port to deliver the message to at the destination.
+ * @param data the data for the message.
+ * @param statusReportRequested indicates whether a report is requested for this message.
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
*/
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, short destinationPort, byte[] data,
@@ -677,6 +660,55 @@ public class SmsMessage {
return new SubmitPdu(spb);
}
+ // TODO: SubmitPdu class is used for SMS-DELIVER also now. Refactor for SubmitPdu and new
+ // DeliverPdu accordingly.
+
+ /**
+ * Gets an SMS PDU to store in the ICC.
+ *
+ * @param subId subscription of the message.
+ * @param status message status. One of these status:
+ * <code>SmsManager.STATUS_ON_ICC_READ</code>
+ * <code>SmsManager.STATUS_ON_ICC_UNREAD</code>
+ * <code>SmsManager.STATUS_ON_ICC_SENT</code>
+ * <code>SmsManager.STATUS_ON_ICC_UNSENT</code>
+ * @param scAddress Service Centre address. Null means use default.
+ * @param address destination or originating address.
+ * @param message string representation of the message payload.
+ * @param date the time stamp the message was received.
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
+ * @hide
+ */
+ @SystemApi
+ @Nullable
+ public static SubmitPdu getSmsPdu(int subId, @SmsManager.StatusOnIcc int status,
+ @Nullable String scAddress, @NonNull String address, @NonNull String message,
+ long date) {
+ SubmitPduBase spb;
+ if (isCdmaVoice(subId)) { // 3GPP2 format
+ if (status == SmsManager.STATUS_ON_ICC_READ
+ || status == SmsManager.STATUS_ON_ICC_UNREAD) { // Deliver PDU
+ spb = com.android.internal.telephony.cdma.SmsMessage.getDeliverPdu(address,
+ message, date);
+ } else { // Submit PDU
+ spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
+ address, message, false /* statusReportRequested */, null /* smsHeader */);
+ }
+ } else { // 3GPP format
+ if (status == SmsManager.STATUS_ON_ICC_READ
+ || status == SmsManager.STATUS_ON_ICC_UNREAD) { // Deliver PDU
+ spb = com.android.internal.telephony.gsm.SmsMessage.getDeliverPdu(scAddress,
+ address, message, date);
+ } else { // Submit PDU
+ spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
+ address, message, false /* statusReportRequested */, null /* header */);
+ }
+ }
+
+ return spb != null ? new SubmitPdu(spb) : null;
+ }
+
/**
* Get an SMS-SUBMIT PDU's encoded message.
* This is used by Bluetooth MAP profile to handle long non UTF-8 SMS messages.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index bd8321e21f1b..839889f91c4a 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -196,11 +196,8 @@ public class TelephonyManager {
NETWORK_SELECTION_MODE_MANUAL})
public @interface NetworkSelectionMode {}
- /** @hide */
public static final int NETWORK_SELECTION_MODE_UNKNOWN = 0;
- /** @hide */
public static final int NETWORK_SELECTION_MODE_AUTO = 1;
- /** @hide */
public static final int NETWORK_SELECTION_MODE_MANUAL = 2;
/** The otaspMode passed to PhoneStateListener#onOtaspChanged */
@@ -2349,7 +2346,7 @@ public class TelephonyManager {
@UnsupportedAppUsage
public boolean isNetworkRoaming(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
- return getTelephonyProperty(subId, TelephonyProperties.operator_is_roaming(), false);
+ return getTelephonyProperty(phoneId, TelephonyProperties.operator_is_roaming(), false);
}
/**
@@ -7524,14 +7521,18 @@ public class TelephonyManager {
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
* given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
-
- * @return the network selection mode.
+ * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
- * @hide
+ * @return the network selection mode.
*/
- @NetworkSelectionMode
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public int getNetworkSelectionMode() {
+ @SuppressAutoDoc // No support for carrier privileges (b/72967236).
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE
+ })
+ public @NetworkSelectionMode int getNetworkSelectionMode() {
int mode = NETWORK_SELECTION_MODE_UNKNOWN;
try {
ITelephony telephony = getITelephony();
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index d6dea2c8974b..a7d553b60abf 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -294,15 +294,30 @@ public final class ImsCallProfile implements Parcelable {
* updateImsCallRatFromExtras(Bundle)} to determine whether to set the
* {@link android.telecom.TelecomManager#EXTRA_CALL_NETWORK_TYPE} extra value and
* {@link android.telecom.Connection#PROPERTY_WIFI} property on a connection.
+ * @deprecated the constants associated with this extra are hidden, instead use
+ * {@link #EXTRA_CALL_NETWORK_TYPE}.
*/
+ @Deprecated
public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
/**
+ * Extra key with an {@code int} value which can be set in {@link #setCallExtraInt(String, int)}
+ * to indicate the network type used for a call.
+ * <p>
+ * Valid values are defined by {@code TelephonyManager.NETWORK_TYPE_*} constants. An example may
+ * be {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}.
+ */
+ public static final String EXTRA_CALL_NETWORK_TYPE =
+ "android.telephony.ims.extra.CALL_NETWORK_TYPE";
+
+ /**
* Similar to {@link #EXTRA_CALL_RAT_TYPE}, except with a lowercase 'c'. Used to ensure
* compatibility with modems that are non-compliant with the {@link #EXTRA_CALL_RAT_TYPE}
* extra key. Should be removed when the non-compliant modems are fixed.
* @hide
+ * @deprecated Use {@link #EXTRA_CALL_NETWORK_TYPE} instead.
*/
+ @Deprecated
public static final String EXTRA_CALL_RAT_TYPE_ALT = "callRadioTech";
/** @hide */
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index 5adc99e11478..1b583fd29965 100644
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -25,8 +25,6 @@ import android.util.Log;
import com.android.ims.internal.IImsCallSession;
import com.android.ims.internal.IImsVideoCallProvider;
-import java.util.Objects;
-
/**
* Provides the call initiation/termination, and media exchange between two IMS endpoints.
* It directly communicates with IMS service which implements the IMS protocol behavior.
@@ -346,7 +344,7 @@ public class ImsCallSession {
}
/**
- * Called when an {@link ImsCallSession} may handover from one radio technology to another.
+ * Called when an {@link ImsCallSession} may handover from one network type to another.
* For example, the session may handover from WIFI to LTE if conditions are right.
* <p>
* If handover is attempted,
@@ -355,24 +353,24 @@ public class ImsCallSession {
* called to indicate the success or failure of the handover.
*
* @param session IMS session object
- * @param srcAccessTech original access technology
- * @param targetAccessTech new access technology
+ * @param srcNetworkType original network type
+ * @param targetNetworkType new network type
*/
- public void callSessionMayHandover(ImsCallSession session, int srcAccessTech,
- int targetAccessTech) {
+ public void callSessionMayHandover(ImsCallSession session, int srcNetworkType,
+ int targetNetworkType) {
// no-op
}
/**
- * Called when session access technology changes
+ * Called when session network type changes
*
* @param session IMS session object
- * @param srcAccessTech original access technology
- * @param targetAccessTech new access technology
+ * @param srcNetworkType original network type
+ * @param targetNetworkType new network type
* @param reasonInfo
*/
public void callSessionHandover(ImsCallSession session,
- int srcAccessTech, int targetAccessTech,
+ int srcNetworkType, int targetNetworkType,
ImsReasonInfo reasonInfo) {
// no-op
}
@@ -381,12 +379,12 @@ public class ImsCallSession {
* Called when session access technology change fails
*
* @param session IMS session object
- * @param srcAccessTech original access technology
- * @param targetAccessTech new access technology
+ * @param srcNetworkType original access technology
+ * @param targetNetworkType new access technology
* @param reasonInfo handover failure reason
*/
public void callSessionHandoverFailed(ImsCallSession session,
- int srcAccessTech, int targetAccessTech,
+ int srcNetworkType, int targetNetworkType,
ImsReasonInfo reasonInfo) {
// no-op
}
@@ -1303,20 +1301,19 @@ public class ImsCallSession {
/**
* Notifies of a case where a {@link ImsCallSession} may
* potentially handover from one radio technology to another.
- * @param srcAccessTech The source radio access technology; one of the access technology
- * constants defined in {@link android.telephony.ServiceState}. For
- * example
- * {@link android.telephony.ServiceState#RIL_RADIO_TECHNOLOGY_LTE}.
- * @param targetAccessTech The target radio access technology; one of the access technology
- * constants defined in {@link android.telephony.ServiceState}. For
- * example
- * {@link android.telephony.ServiceState#RIL_RADIO_TECHNOLOGY_LTE}.
+ * @param srcNetworkType The source network type; one of the network type constants defined
+ * in {@link android.telephony.TelephonyManager}. For example
+ * {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}.
+ * @param targetNetworkType The target radio access technology; one of the network type
+ * constants defined in {@link android.telephony.TelephonyManager}.
+ * For example
+ * {@link android.telephony.TelephonyManager#NETWORK_TYPE_LTE}.
*/
@Override
- public void callSessionMayHandover(int srcAccessTech, int targetAccessTech) {
+ public void callSessionMayHandover(int srcNetworkType, int targetNetworkType) {
if (mListener != null) {
- mListener.callSessionMayHandover(ImsCallSession.this, srcAccessTech,
- targetAccessTech);
+ mListener.callSessionMayHandover(ImsCallSession.this, srcNetworkType,
+ targetNetworkType);
}
}
@@ -1324,11 +1321,11 @@ public class ImsCallSession {
* Notifies of handover information for this call
*/
@Override
- public void callSessionHandover(int srcAccessTech, int targetAccessTech,
+ public void callSessionHandover(int srcNetworkType, int targetNetworkType,
ImsReasonInfo reasonInfo) {
if (mListener != null) {
- mListener.callSessionHandover(ImsCallSession.this, srcAccessTech,
- targetAccessTech, reasonInfo);
+ mListener.callSessionHandover(ImsCallSession.this, srcNetworkType,
+ targetNetworkType, reasonInfo);
}
}
@@ -1336,11 +1333,11 @@ public class ImsCallSession {
* Notifies of handover failure info for this call
*/
@Override
- public void callSessionHandoverFailed(int srcAccessTech, int targetAccessTech,
+ public void callSessionHandoverFailed(int srcNetworkType, int targetNetworkType,
ImsReasonInfo reasonInfo) {
if (mListener != null) {
- mListener.callSessionHandoverFailed(ImsCallSession.this, srcAccessTech,
- targetAccessTech, reasonInfo);
+ mListener.callSessionHandoverFailed(ImsCallSession.this, srcNetworkType,
+ targetNetworkType, reasonInfo);
}
}
diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
index e11886f2bea5..025721c89f70 100644
--- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java
+++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
@@ -17,10 +17,13 @@
package android.telephony.ims;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.RemoteException;
+import android.telephony.Annotation;
import android.telephony.CallQuality;
+import android.telephony.ServiceState;
import android.telephony.ims.aidl.IImsCallSessionListener;
import android.telephony.ims.stub.ImsCallSessionImplBase;
@@ -476,11 +479,27 @@ public class ImsCallSessionListener {
* @param targetAccessTech The target radio access technology; one of the access technology
* constants defined in {@link android.telephony.ServiceState}. For example
* {@link android.telephony.ServiceState#RIL_RADIO_TECHNOLOGY_LTE}.
+ * @deprecated Uses hidden constants for radio access technology, use
+ * {@link #onMayHandover(int, int)} instead.
*/
- public void callSessionMayHandover(int srcAccessTech, int targetAccessTech)
- {
+ @Deprecated
+ public void callSessionMayHandover(int srcAccessTech, int targetAccessTech) {
+ // Use new API internally.
+ onMayHandover(ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech),
+ ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech));
+ }
+
+ /**
+ * Notify the framework that the associated {@link ImsCallSession} may handover from one network
+ * type to another.
+ *
+ * @param srcNetworkType The source network type.
+ * @param targetNetworkType The target network type.
+ */
+ public void onMayHandover(@Annotation.NetworkType int srcNetworkType,
+ @Annotation.NetworkType int targetNetworkType) {
try {
- mListener.callSessionMayHandover(srcAccessTech, targetAccessTech);
+ mListener.callSessionMayHandover(srcNetworkType, targetNetworkType);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -494,11 +513,29 @@ public class ImsCallSessionListener {
* @param targetAccessTech new access technology, defined in
* {@link android.telephony.ServiceState}.
* @param reasonInfo The {@link ImsReasonInfo} associated with this handover.
+ * @deprecated Uses hidden radio access technology constants, use
+ * {@link #onHandover(int, int, ImsReasonInfo)} instead.
*/
+ @Deprecated
public void callSessionHandover(int srcAccessTech, int targetAccessTech,
ImsReasonInfo reasonInfo) {
+ // Use new API internally.
+ onHandover(ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech),
+ ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech), reasonInfo);
+ }
+
+ /**
+ * Notify the framework that the associated {@link ImsCallSession} has handed over from one
+ * network type to another.
+ *
+ * @param srcNetworkType original network type.
+ * @param targetNetworkType target network type after handover..
+ * @param reasonInfo An optional {@link ImsReasonInfo} associated with this handover.
+ */
+ public void onHandover(@Annotation.NetworkType int srcNetworkType,
+ @Annotation.NetworkType int targetNetworkType, @Nullable ImsReasonInfo reasonInfo) {
try {
- mListener.callSessionHandover(srcAccessTech, targetAccessTech, reasonInfo);
+ mListener.callSessionHandover(srcNetworkType, targetNetworkType, reasonInfo);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -510,11 +547,28 @@ public class ImsCallSessionListener {
* @param srcAccessTech original access technology
* @param targetAccessTech new access technology
* @param reasonInfo An {@link ImsReasonInfo} detailing the reason for the failure.
+ * @deprecated Uses hidden radio access technology constants, use
+ * {@link #onHandoverFailed(int, int, ImsReasonInfo)} instead
*/
+ @Deprecated
public void callSessionHandoverFailed(int srcAccessTech, int targetAccessTech,
ImsReasonInfo reasonInfo) {
+ // Use new API internally.
+ onHandoverFailed(ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech),
+ ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech), reasonInfo);
+ }
+
+ /**
+ * The IMS call session's access technology change has failed..
+ *
+ * @param srcNetworkType original network type.
+ * @param targetNetworkType target network type that the handover failed for.
+ * @param reasonInfo An {@link ImsReasonInfo} detailing the reason for the failure.
+ */
+ public void onHandoverFailed(@Annotation.NetworkType int srcNetworkType,
+ @Annotation.NetworkType int targetNetworkType, @NonNull ImsReasonInfo reasonInfo) {
try {
- mListener.callSessionHandoverFailed(srcAccessTech, targetAccessTech, reasonInfo);
+ mListener.callSessionHandoverFailed(srcNetworkType, targetNetworkType, reasonInfo);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java
index 39af2e770882..cb3f0f92625e 100644
--- a/telephony/java/android/telephony/ims/ImsException.java
+++ b/telephony/java/android/telephony/ims/ImsException.java
@@ -30,10 +30,7 @@ import java.lang.annotation.RetentionPolicy;
/**
* This class defines an IMS-related exception that has been thrown while interacting with a
* device or carrier provided ImsService implementation.
- * @hide
*/
-@SystemApi
-@TestApi
public final class ImsException extends Exception {
/**
@@ -83,7 +80,10 @@ public final class ImsException extends Exception {
/**
* A new {@link ImsException} with an unspecified {@link ImsErrorCode} code.
* @param message an optional message to detail the error condition more specifically.
+ * @hide
*/
+ @SystemApi
+ @TestApi
public ImsException(@Nullable String message) {
super(getMessage(message, CODE_ERROR_UNSPECIFIED));
}
@@ -91,7 +91,10 @@ public final class ImsException extends Exception {
/**
* A new {@link ImsException} that includes an {@link ImsErrorCode} error code.
* @param message an optional message to detail the error condition more specifically.
+ * @hide
*/
+ @SystemApi
+ @TestApi
public ImsException(@Nullable String message, @ImsErrorCode int code) {
super(getMessage(message, code));
mCode = code;
@@ -102,7 +105,10 @@ public final class ImsException extends Exception {
* {@link Throwable} that contains the original error that was thrown to lead to this Exception.
* @param message an optional message to detail the error condition more specifically.
* @param cause the {@link Throwable} that caused this {@link ImsException} to be created.
+ * @hide
*/
+ @SystemApi
+ @TestApi
public ImsException(@Nullable String message, @ImsErrorCode int code,
@Nullable Throwable cause) {
super(getMessage(message, code), cause);
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 5fd0af564d34..c66672f13129 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -23,6 +23,8 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressAutoDoc;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.content.Context;
@@ -56,10 +58,7 @@ import java.util.function.Consumer;
* associated subscription.
*
* @see #createForSubscriptionId(int)
- * @hide
*/
-@SystemApi
-@TestApi
public class ImsMmTelManager implements RegistrationManager {
/**
@@ -94,9 +93,11 @@ public class ImsMmTelManager implements RegistrationManager {
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
* @see #unregisterImsRegistrationCallback(RegistrationCallback)
* @deprecated Use {@link RegistrationManager.RegistrationCallback} instead.
+ * @hide
*/
// Do not add to this class, add to RegistrationManager.RegistrationCallback instead.
@Deprecated
+ @SystemApi @TestApi
public static class RegistrationCallback extends RegistrationManager.RegistrationCallback {
/**
@@ -141,7 +142,7 @@ public class ImsMmTelManager implements RegistrationManager {
/**
* Receives IMS capability status updates from the ImsService. This information is also
- * available via the {@link #isAvailable(int, int)} method below.
+ * available via the {@see #isAvailable(int, int)} method below.
*
* @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback)
* @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
@@ -190,7 +191,7 @@ public class ImsMmTelManager implements RegistrationManager {
* If unavailable, the feature is not able to support the unavailable capability at this
* time.
*
- * This information can also be queried using the {@link #isAvailable(int, int)} API.
+ * This information can also be queried using the {@see #isAvailable(int, int)} API.
*
* @param capabilities The new availability of the capabilities.
*/
@@ -218,8 +219,20 @@ public class ImsMmTelManager implements RegistrationManager {
*
* @param subId The ID of the subscription that this ImsMmTelManager will use.
* @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList()
+ *
+ * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
* @throws IllegalArgumentException if the subscription is invalid.
+ *
*/
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE
+ })
+ @SuppressLint("ManagerLookup")
public static @NonNull ImsMmTelManager createForSubscriptionId(int subId) {
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid subscription ID");
@@ -258,8 +271,10 @@ public class ImsMmTelManager implements RegistrationManager {
* reason.
* @deprecated Use {@link RegistrationManager#registerImsRegistrationCallback(Executor,
* RegistrationManager.RegistrationCallback)} instead.
+ * @hide
*/
@Deprecated
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull RegistrationCallback c) throws ImsException {
@@ -284,9 +299,20 @@ public class ImsMmTelManager implements RegistrationManager {
}
}
- /**{@inheritDoc}*/
+ /**
+ *
+ * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * {@inheritDoc}
+ *
+ */
@Override
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull RegistrationManager.RegistrationCallback c) throws ImsException {
if (c == null) {
@@ -317,8 +343,10 @@ public class ImsMmTelManager implements RegistrationManager {
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
* @deprecated Use {@link #unregisterImsRegistrationCallback(
* RegistrationManager.RegistrationCallback)}.
+ * @hide
*/
@Deprecated
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
if (c == null) {
@@ -331,9 +359,20 @@ public class ImsMmTelManager implements RegistrationManager {
}
}
- /**{@inheritDoc}*/
+ /**
+ *
+ * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ * Access by profile owners is deprecated and will be removed in a future release.
+ *
+ *{@inheritDoc}
+ */
@Override
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public void unregisterImsRegistrationCallback(
@NonNull RegistrationManager.RegistrationCallback c) {
if (c == null) {
@@ -346,9 +385,13 @@ public class ImsMmTelManager implements RegistrationManager {
}
}
- /**{@inheritDoc}*/
+ /**
+ * {@inheritDoc}
+ * @hide
+ */
@Override
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SystemApi @TestApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
@NonNull @ImsRegistrationState Consumer<Integer> stateCallback) {
if (stateCallback == null) {
@@ -369,9 +412,19 @@ public class ImsMmTelManager implements RegistrationManager {
}
}
- /**{@inheritDoc}*/
+ /**
+ * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ * Access by profile owners is deprecated and will be removed in a future release.
+ *
+ *{@inheritDoc}
+ */
@Override
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor,
@NonNull @AccessNetworkConstants.TransportType
Consumer<Integer> transportTypeCallback) {
@@ -397,12 +450,25 @@ public class ImsMmTelManager implements RegistrationManager {
/**
* Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
* availability updates for the subscription specified in
- * {@link #createForSubscriptionId(int)}. The method {@link #isAvailable(int, int)}
+ * {@link #createForSubscriptionId(int)}. The method {@see #isAvailable(int, int)}
* can also be used to query this information at any time.
*
* Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
* subscription changed events and call
* {@link #unregisterMmTelCapabilityCallback(CapabilityCallback)} to clean up.
+ * <p>This API requires one of the following:
+ * <ul>
+ * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
+ * <li>If the caller is the device or profile owner, the caller holds the
+ * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
+ * <li>The caller has carrier privileges (see
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
+ * active subscription.</li>
+ * <li>The caller is the default SMS app for the device.</li>
+ * </ul>
+ * <p>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>.
+ * Access by profile owners is deprecated and will be removed in a future release.
*
* When the callback is registered, it will initiate the callback c to be called with the
* current capabilities.
@@ -418,7 +484,10 @@ public class ImsMmTelManager implements RegistrationManager {
* the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
* reason.
*/
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public void registerMmTelCapabilityCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull CapabilityCallback c) throws ImsException {
if (c == null) {
@@ -450,10 +519,27 @@ public class ImsMmTelManager implements RegistrationManager {
* When the subscription associated with this callback is removed (SIM removed, ESIM swap,
* etc...), this callback will automatically be removed. If this method is called for an
* inactive subscription, it will result in a no-op.
+ * <p>This API requires one of the following:
+ * <ul>
+ * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
+ * <li>If the caller is the device or profile owner, the caller holds the
+ * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
+ * <li>The caller has carrier privileges (see
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
+ * active subscription.</li>
+ * <li>The caller is the default SMS app for the device.</li>
+ * </ul>
+ * <p>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>.
+ * Access by profile owners is deprecated and will be removed in a future release.
+ *
* @param c The MmTel {@link CapabilityCallback} to be removed.
* @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
*/
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
@@ -475,6 +561,19 @@ public class ImsMmTelManager implements RegistrationManager {
* <p>
* Note: If the carrier configuration for advanced calling is not editable or hidden, this
* method will always return the default value.
+ * <p>This API requires one of the following:
+ * <ul>
+ * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
+ * <li>If the caller is the device or profile owner, the caller holds the
+ * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
+ * <li>The caller has carrier privileges (see
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
+ * active subscription.</li>
+ * <li>The caller is the default SMS app for the device.</li>
+ * </ul>
+ * <p>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>.
+ * Access by profile owners is deprecated and will be removed in a future release.
*
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
* @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL
@@ -486,7 +585,10 @@ public class ImsMmTelManager implements RegistrationManager {
* active (SIM is not inserted, ESIM inactive) or invalid.
* @return true if the user's setting for advanced calling is enabled, false otherwise.
*/
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public boolean isAdvancedCallingSettingEnabled() {
try {
return getITelephony().isAdvancedCallingSettingEnabled(mSubId);
@@ -524,8 +626,10 @@ public class ImsMmTelManager implements RegistrationManager {
* @see #isAdvancedCallingSettingEnabled()
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
+ * @hide
*/
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ @SystemApi @TestApi
public void setAdvancedCallingSettingEnabled(boolean isEnabled) {
try {
getITelephony().setAdvancedCallingSettingEnabled(mSubId, isEnabled);
@@ -556,13 +660,15 @@ public class ImsMmTelManager implements RegistrationManager {
* {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
* @param capability The IMS MmTel capability to query, can be one of the following:
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO,
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT},
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}
* @return {@code true} if the MmTel IMS capability is capable for this subscription, false
* otherwise.
+ * @hide
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SystemApi @TestApi
public boolean isCapable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
try {
@@ -583,12 +689,14 @@ public class ImsMmTelManager implements RegistrationManager {
* {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
* @param capability The IMS MmTel capability to query, can be one of the following:
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO,
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT},
* {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}
* @return {@code true} if the MmTel IMS capability is available for this subscription, false
* otherwise.
+ * @hide
*/
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isAvailable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
@@ -613,7 +721,9 @@ public class ImsMmTelManager implements RegistrationManager {
* capability is supported on this carrier network for the transport specified.
* @throws ImsException if the subscription is no longer valid or the IMS service is not
* available.
+ * @hide
*/
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void isSupported(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
@AccessNetworkConstants.TransportType int transportType,
@@ -642,12 +752,32 @@ public class ImsMmTelManager implements RegistrationManager {
/**
* The user's setting for whether or not they have enabled the "Video Calling" setting.
*
+ * <p>
+ * Note: If the carrier configuration for advanced calling is not editable or hidden, this
+ * method will always return the default value.
+ * <p>This API requires one of the following:
+ * <ul>
+ * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
+ * <li>If the caller is the device or profile owner, the caller holds the
+ * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
+ * <li>The caller has carrier privileges (see
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
+ * active subscription.</li>
+ * <li>The caller is the default SMS app for the device.</li>
+ * </ul>
+ * <p>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>.
+ * Access by profile owners is deprecated and will be removed in a future release.
+ *
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @return true if the user’s “Video Calling” setting is currently enabled.
* @see #setVtSettingEnabled(boolean)
*/
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE})
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
public boolean isVtSettingEnabled() {
try {
return getITelephony().isVtSettingEnabled(mSubId);
@@ -669,7 +799,9 @@ public class ImsMmTelManager implements RegistrationManager {
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @see #isVtSettingEnabled()
+ * @hide
*/
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVtSettingEnabled(boolean isEnabled) {
try {
@@ -689,11 +821,28 @@ public class ImsMmTelManager implements RegistrationManager {
/**
* @return true if the user's setting for Voice over WiFi is enabled and false if it is not.
*
+ * <p>This API requires one of the following:
+ * <ul>
+ * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
+ * <li>If the caller is the device or profile owner, the caller holds the
+ * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
+ * <li>The caller has carrier privileges (see
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
+ * active subscription.</li>
+ * <li>The caller is the default SMS app for the device.</li>
+ * </ul>
+ * <p>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>.
+ * Access by profile owners is deprecated and will be removed in a future release.
+ *
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @see #setVoWiFiSettingEnabled(boolean)
*/
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public boolean isVoWiFiSettingEnabled() {
try {
return getITelephony().isVoWiFiSettingEnabled(mSubId);
@@ -716,7 +865,9 @@ public class ImsMmTelManager implements RegistrationManager {
* active (SIM is not inserted, ESIM inactive) or invalid.
* @param isEnabled true if the user's setting for Voice over WiFi is enabled, false otherwise=
* @see #isVoWiFiSettingEnabled()
+ * @hide
*/
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiSettingEnabled(boolean isEnabled) {
try {
@@ -736,13 +887,30 @@ public class ImsMmTelManager implements RegistrationManager {
/**
* Returns the user's voice over WiFi roaming setting associated with the current subscription.
*
+ * <p>This API requires one of the following:
+ * <ul>
+ * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
+ * <li>If the caller is the device or profile owner, the caller holds the
+ * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
+ * <li>The caller has carrier privileges (see
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
+ * active subscription.</li>
+ * <li>The caller is the default SMS app for the device.</li>
+ * </ul>
+ * <p>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>.
+ * Access by profile owners is deprecated and will be removed in a future release.
+ *
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @return true if the user's setting for Voice over WiFi while roaming is enabled, false
* if disabled.
* @see #setVoWiFiRoamingSettingEnabled(boolean)
*/
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public boolean isVoWiFiRoamingSettingEnabled() {
try {
return getITelephony().isVoWiFiRoamingSettingEnabled(mSubId);
@@ -766,7 +934,9 @@ public class ImsMmTelManager implements RegistrationManager {
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @see #isVoWiFiRoamingSettingEnabled()
+ * @hide
*/
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingSettingEnabled(boolean isEnabled) {
try {
@@ -796,7 +966,9 @@ public class ImsMmTelManager implements RegistrationManager {
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @see #setVoWiFiSettingEnabled(boolean)
+ * @hide
*/
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiNonPersistent(boolean isCapable, int mode) {
try {
@@ -816,6 +988,20 @@ public class ImsMmTelManager implements RegistrationManager {
/**
* Returns the user's voice over WiFi Roaming mode setting associated with the device.
*
+ * <p>This API requires one of the following:
+ * <ul>
+ * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
+ * <li>If the caller is the device or profile owner, the caller holds the
+ * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
+ * <li>The caller has carrier privileges (see
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
+ * active subscription.</li>
+ * <li>The caller is the default SMS app for the device.</li>
+ * </ul>
+ * <p>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>.
+ * Access by profile owners is deprecated and will be removed in a future release.
+ *
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @return The Voice over WiFi Mode preference set by the user, which can be one of the
@@ -825,7 +1011,10 @@ public class ImsMmTelManager implements RegistrationManager {
* - {@link #WIFI_MODE_WIFI_PREFERRED}
* @see #setVoWiFiSettingEnabled(boolean)
*/
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public @WiFiCallingMode int getVoWiFiModeSetting() {
try {
return getITelephony().getVoWiFiModeSetting(mSubId);
@@ -851,7 +1040,9 @@ public class ImsMmTelManager implements RegistrationManager {
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @see #getVoWiFiModeSetting()
+ * @hide
*/
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiModeSetting(@WiFiCallingMode int mode) {
try {
@@ -880,7 +1071,9 @@ public class ImsMmTelManager implements RegistrationManager {
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @see #setVoWiFiRoamingSettingEnabled(boolean)
+ * @hide
*/
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @WiFiCallingMode int getVoWiFiRoamingModeSetting() {
try {
@@ -909,7 +1102,9 @@ public class ImsMmTelManager implements RegistrationManager {
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @see #getVoWiFiRoamingModeSetting()
+ * @hide
*/
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) {
try {
@@ -936,7 +1131,9 @@ public class ImsMmTelManager implements RegistrationManager {
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @param isEnabled if true RTT should be enabled during calls made on this subscription.
+ * @hide
*/
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setRttCapabilitySetting(boolean isEnabled) {
try {
@@ -956,12 +1153,29 @@ public class ImsMmTelManager implements RegistrationManager {
/**
* @return true if TTY over VoLTE is supported
*
+ * <p>This API requires one of the following:
+ * <ul>
+ * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
+ * <li>If the caller is the device or profile owner, the caller holds the
+ * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
+ * <li>The caller has carrier privileges (see
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
+ * active subscription.</li>
+ * <li>The caller is the default SMS app for the device.</li>
+ * </ul>
+ * <p>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>.
+ * Access by profile owners is deprecated and will be removed in a future release.
+ *
* @throws IllegalArgumentException if the subscription associated with this operation is not
* active (SIM is not inserted, ESIM inactive) or invalid.
* @see android.telecom.TelecomManager#getCurrentTtyMode
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
*/
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public boolean isTtyOverVolteEnabled() {
try {
return getITelephony().isTtyOverVolteEnabled(mSubId);
@@ -988,7 +1202,9 @@ public class ImsMmTelManager implements RegistrationManager {
* specified when the service state has been retrieved from the IMS service.
* @throws ImsException if the IMS service associated with this subscription is not available or
* the IMS service is not available.
+ * @hide
*/
+ @SystemApi @TestApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void getFeatureState(@NonNull @CallbackExecutor Executor executor,
@NonNull @ImsFeature.ImsState Consumer<Integer> callback) throws ImsException {
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 666a688e8cc0..aa4f77d09212 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -102,6 +102,101 @@ public class ProvisioningManager {
// Inheriting values from ImsConfig for backwards compatibility.
/**
+ * AMR CODEC Mode Value set, 0-7 in comma separated sequence.
+ * <p>
+ * This corresponds to the {@code mode-set} parameter for the AMR codec.
+ * See 3GPP TS 26.101 Table 1A for more information.
+ * <p>
+ * <UL>
+ * <LI>0 - AMR 4.75 kbit/s</LI>
+ * <LI>1 - AMR 5.15 kbit/s</LI>
+ * <LI>2 - AMR 5.90 kbit/s</LI>
+ * <LI>3 - AMR 6.70 kbit/s (PDC-EFR)</LI>
+ * <LI>4 - AMR 7.40 kbit/s (TDMA-EFR)</LI>
+ * <LI>5 - AMR 7.95 kbit/s</LI>
+ * <LI>6 - AMR 10.2 kbit/s</LI>
+ * <LI>7 - AMR 12.2 kbit/s (GSM-EFR)</LI>
+ * </UL>
+ * <p>
+ * Value is in String format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_AMR_CODEC_MODE_SET_VALUES = 0;
+
+ /**
+ * Wide Band AMR CODEC Mode Value set,0-7 in comma separated sequence.
+ * <p>
+ * This corresponds to the {@code mode-set} parameter for the AMR wideband codec.
+ * See 3GPP TS 26.101 Table 1A for more information.
+ * <p>
+ * <UL>
+ * <LI>0 - AMR 4.75 kbit/s</LI>
+ * <LI>1 - AMR 5.15 kbit/s</LI>
+ * <LI>2 - AMR 5.90 kbit/s</LI>
+ * <LI>3 - AMR 6.70 kbit/s (PDC-EFR)</LI>
+ * <LI>4 - AMR 7.40 kbit/s (TDMA-EFR)</LI>
+ * <LI>5 - AMR 7.95 kbit/s</LI>
+ * <LI>6 - AMR 10.2 kbit/s</LI>
+ * <LI>7 - AMR 12.2 kbit/s (GSM-EFR)</LI>
+ * </UL>
+ * <p>
+ * Value is in String format.
+ * @see #setProvisioningStringValue(int, String)
+ * @see #getProvisioningStringValue(int)
+ */
+ public static final int KEY_AMR_WB_CODEC_MODE_SET_VALUES = 1;
+
+ /**
+ * SIP Session Timer value (seconds).
+ * <p>
+ * See RFC4028 for more information.
+ * <p>
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SIP_SESSION_TIMER_SEC = 2;
+
+ /**
+ * Minimum SIP Session Expiration Timer in (seconds).
+ * <p>
+ * See RFC4028 for more information.
+ * <p>
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_MINIMUM_SIP_SESSION_EXPIRATION_TIMER_SEC = 3;
+
+ /**
+ * SIP_INVITE cancellation time out value (in milliseconds). Integer format.
+ * <p>
+ * See RFC4028 for more information.
+ * <p>
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SIP_INVITE_CANCELLATION_TIMER_MS = 4;
+
+ /**
+ * Delay time when an iRAT transitions from eHRPD/HRPD/1xRTT to LTE.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_TRANSITION_TO_LTE_DELAY_MS = 5;
+
+ /**
+ * Silent redial status of Enabled (True), or Disabled (False).
+ * Value is in boolean format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_ENABLE_SILENT_REDIAL = 6;
+
+ /**
* An integer key representing the SIP T1 timer value in milliseconds for the associated
* subscription.
* <p>
@@ -117,6 +212,28 @@ public class ProvisioningManager {
public static final int KEY_T1_TIMER_VALUE_MS = 7;
/**
+ * SIP T2 timer value in milliseconds. See RFC 3261 for information.
+ * <p>
+ * The T2 timer is the maximum retransmit interval for non-INVITE requests and INVITE responses.
+ * <p>
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_T2_TIMER_VALUE_MS = 8;
+
+ /**
+ * SIP TF timer value in milliseconds. See RFC 3261 for information.
+ * <p>
+ * The TF timer is the non-INVITE transaction timeout timer.
+ * <p>
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_TF_TIMER_VALUE_MS = 9;
+
+ /**
* An integer key representing the voice over LTE (VoLTE) provisioning status for the
* associated subscription. Determines whether the user can register for voice services over
* LTE.
@@ -141,6 +258,43 @@ public class ProvisioningManager {
public static final int KEY_VT_PROVISIONING_STATUS = 11;
/**
+ * Domain Name for the device to populate the request URI for REGISTRATION.
+ * Value is in String format.
+ * @see #setProvisioningStringValue(int, String)
+ * @see #getProvisioningStringValue(int)
+ */
+ public static final int KEY_REGISTRATION_DOMAIN_NAME = 12;
+
+ /**
+ * Device Outgoing SMS based on either 3GPP or 3GPP2 standards.
+ * Value is in Integer format.
+ * Valid values are {@link #SMS_FORMAT_3GPP} and {@link #SMS_FORMAT_3GPP2}.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SMS_FORMAT = 13;
+
+ /**
+ * Value used with {@link #KEY_SMS_FORMAT} to indicate 3GPP2 SMS format is used.
+ * See {@link android.telephony.SmsMessage#FORMAT_3GPP2} for more information.
+ */
+ public static final int SMS_FORMAT_3GPP2 = 0;
+
+ /**
+ * Value used with {@link #KEY_SMS_FORMAT} to indicate 3GPP SMS format is used.
+ * See {@link android.telephony.SmsMessage#FORMAT_3GPP} for more information.
+ */
+ public static final int SMS_FORMAT_3GPP = 1;
+
+ /**
+ * Turns SMS over IMS ON/OFF on the device.
+ * Value is in Integer format. ON (1), OFF(0).
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SMS_OVER_IP_ENABLED = 14;
+
+ /**
* An integer key associated with the carrier configured SIP PUBLISH timer, which dictates the
* expiration time in seconds for published online availability in RCS presence.
* <p>
@@ -223,7 +377,7 @@ public class ProvisioningManager {
public static final int KEY_RCS_MAX_NUM_ENTRIES_IN_RCL = 22;
/**
- * An integer associated with the expiration timer used duriing the SIP subscription of a
+ * An integer associated with the expiration timer used during the SIP subscription of a
* Request Contained List (RCL), which is used to retrieve the RCS capabilities of the contact
* book.
* <p>
@@ -234,6 +388,14 @@ public class ProvisioningManager {
public static final int KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC = 23;
/**
+ * Applies compression to LIST Subscription.
+ * Value is in Integer format. Enable (1), Disable(0).
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_USE_GZIP_FOR_LIST_SUBSCRIPTION = 24;
+
+ /**
* An integer key representing the RCS enhanced address book (EAB) provisioning status for the
* associated subscription. Determines whether or not SIP OPTIONS or presence will be used to
* retrieve RCS capabilities for the user's contacts.
@@ -271,6 +433,349 @@ public class ProvisioningManager {
public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27;
/**
+ * Enable voice over wifi. Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE = 28;
+
+ /**
+ * Mobile data enabled.
+ * Value is in Integer format. On (1), OFF(0).
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_MOBILE_DATA_ENABLED = 29;
+
+ /**
+ * VoLTE user opted in status.
+ * Value is in Integer format. Opted-in (1) Opted-out (0).
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_VOLTE_USER_OPT_IN_STATUS = 30;
+
+ /**
+ * Proxy for Call Session Control Function(P-CSCF) address for Local-BreakOut(LBO).
+ * Value is in String format.
+ */
+ public static final int KEY_LOCAL_BREAKOUT_PCSCF_ADDRESS = 31;
+
+ /**
+ * Keep Alive Enabled for SIP.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SIP_KEEP_ALIVE_ENABLED = 32;
+
+ /**
+ * Registration retry Base Time value in seconds.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_REGISTRATION_RETRY_BASE_TIME_SEC = 33;
+
+ /**
+ * Registration retry Max Time value in seconds.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_REGISTRATION_RETRY_MAX_TIME_SEC = 34;
+
+ /**
+ * Smallest RTP port for speech codec.
+ * Value is in integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+
+ public static final int KEY_RTP_SPEECH_START_PORT = 35;
+
+ /**
+ * Largest RTP port for speech code.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_RTP_SPEECH_END_PORT = 36;
+
+ /**
+ * SIP Timer A's value in milliseconds. Timer A is the INVITE request retransmit interval (in
+ * milliseconds), for UDP only.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SIP_INVITE_REQUEST_TRANSMIT_INTERVAL_MS = 37;
+
+ /**
+ * SIP Timer B's value in milliseconds. Timer B is the wait time for INVITE message to be,
+ * in milliseconds.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SIP_INVITE_ACK_WAIT_TIME_MS = 38;
+
+ /**
+ * SIP Timer D's value in milliseconds. Timer D is the wait time for response retransmits of
+ * the invite client transactions, in milliseconds.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_WAIT_TIME_MS = 39;
+
+ /**
+ * SIP Timer E's value in milliseconds. Timer E is the value Non-INVITE request retransmit
+ * interval (in milliseconds), for UDP only.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMIT_INTERVAL_MS = 40;
+
+ /**
+ * SIP Timer F's value in milliseconds. Timer F is the Non-INVITE transaction timeout timer,
+ * in milliseconds.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SIP_NON_INVITE_TRANSACTION_TIMEOUT_TIMER_MS = 41;
+
+ /**
+ * SIP Timer G's value in milliseconds. Timer G is the value of INVITE response
+ * retransmit interval.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SIP_INVITE_RESPONSE_RETRANSMIT_INTERVAL_MS = 42;
+
+ /**
+ * SIP Timer H's value in milliseconds. Timer H is the value of wait time for
+ * ACK receipt.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SIP_ACK_RECEIPT_WAIT_TIME_MS = 43;
+
+ /**
+ * SIP Timer I's value in milliseconds. Timer I is the value of wait time for
+ * ACK retransmits.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SIP_ACK_RETRANSMIT_WAIT_TIME_MS = 44;
+
+ /**
+ * SIP Timer J's value in milliseconds. Timer J is the value of wait time for
+ * non-invite request retransmission.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SIP_NON_INVITE_REQUEST_RETRANSMISSION_WAIT_TIME_MS = 45;
+
+ /**
+ * SIP Timer K's value in milliseconds. Timer K is the value of wait time for
+ * non-invite response retransmits.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_SIP_NON_INVITE_RESPONSE_RETRANSMISSION_WAIT_TIME_MS = 46;
+
+ /**
+ * AMR WB octet aligned dynamic payload type.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_AMR_WB_OCTET_ALIGNED_PAYLOAD_TYPE = 47;
+
+ /**
+ * AMR WB bandwidth efficient payload type.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_AMR_WB_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 48;
+
+ /**
+ * AMR octet aligned dynamic payload type.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_AMR_OCTET_ALIGNED_PAYLOAD_TYPE = 49;
+
+ /**
+ * AMR bandwidth efficient payload type.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_AMR_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE = 50;
+
+ /**
+ * DTMF WB payload type.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_DTMF_WB_PAYLOAD_TYPE = 51;
+
+ /**
+ * DTMF NB payload type.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_DTMF_NB_PAYLOAD_TYPE = 52;
+
+ /**
+ * AMR Default encoding mode.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_AMR_DEFAULT_ENCODING_MODE = 53;
+
+ /**
+ * SMS Public Service Identity.
+ * Value is in String format.
+ */
+ public static final int KEY_SMS_PUBLIC_SERVICE_IDENTITY = 54;
+
+ /**
+ * Video Quality - VideoQualityFeatureValuesConstants.
+ * Valid values are: {@link #VIDEO_QUALITY_HIGH} and {@link #VIDEO_QUALITY_LOW}.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_VIDEO_QUALITY = 55;
+
+ /**
+ * Used with {@link #KEY_VIDEO_QUALITY} to indicate low video quality.
+ */
+ public static final int VIDEO_QUALITY_LOW = 0;
+
+ /**
+ * Used with {@link #KEY_VIDEO_QUALITY} to indicate high video quality.
+ */
+ public static final int VIDEO_QUALITY_HIGH = 1;
+
+ /**
+ * LTE to WIFI handover threshold.
+ * Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= {@link #KEY_WIFI_THRESHOLD_A}.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_LTE_THRESHOLD_1 = 56;
+
+ /**
+ * WIFI to LTE handover threshold.
+ * Handover from WiFi to LTE if LTE >= {@link #KEY_LTE_THRESHOLD_3} or (WiFi < {@link
+ * #KEY_WIFI_THRESHOLD_B} and LTE >= {@link #KEY_LTE_THRESHOLD_2}).
+ * Value is in Integer format.
+ *
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_LTE_THRESHOLD_2 = 57;
+
+ /**
+ * LTE to WIFI handover threshold.
+ * Handover from WiFi to LTE if LTE >= {@link #KEY_LTE_THRESHOLD_3} or (WiFi < {@link
+ * #KEY_WIFI_THRESHOLD_B} and LTE >= {@link #KEY_LTE_THRESHOLD_2}).
+ * Value is in Integer format.
+ *
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_LTE_THRESHOLD_3 = 58;
+
+ /**
+ * 1x to WIFI handover threshold.
+ * Handover from 1x to WiFi if 1x < {@link #KEY_1X_THRESHOLD}.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_1X_THRESHOLD = 59;
+
+ /**
+ * LTE to WIFI threshold A.
+ * Handover from LTE to WiFi if LTE < {@link #KEY_LTE_THRESHOLD_1} and WiFi >= {@link
+ * #KEY_WIFI_THRESHOLD_A}.
+ * Value is in Integer format.
+ *
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_WIFI_THRESHOLD_A = 60;
+
+ /**
+ * WiFi to LTRE handover threshold B.
+ * Handover from WiFi to LTE if LTE >= {@link #KEY_LTE_THRESHOLD_3} or (WiFi <
+ * {@link #KEY_WIFI_THRESHOLD_B} and LTE >= {@link #KEY_LTE_THRESHOLD_2}).
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_WIFI_THRESHOLD_B = 61;
+
+ /**
+ * LTE ePDG timer (in seconds).
+ * Device shall not handover back to LTE until the T_ePDG_LTE timer expires.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_LTE_EPDG_TIMER_SEC = 62;
+
+ /**
+ * WiFi ePDG timer (in seconds).
+ * Device shall not handover back to WiFi until the T_ePDG_WiFi timer expires.
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_WIFI_EPDG_TIMER_SEC = 63;
+
+ /**
+ * 1x ePDG timer (in seconds).
+ * Device shall not re-register on 1x until the T_ePDG_1x timer expires.
+ */
+ public static final int KEY_1X_EPDG_TIMER_SEC = 64;
+
+ /**
+ * MultiEndpoint status: Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_MULTIENDPOINT_ENABLED = 65;
+
+ /**
+ * RTT status: Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ * @see #setProvisioningIntValue(int, int)
+ * @see #getProvisioningIntValue(int)
+ */
+ public static final int KEY_RTT_ENABLED = 66;
+
+ /**
* Callback for IMS provisioning changes.
*/
public static class Callback {
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index 99bb259602e5..a1f6b78ba7c5 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -22,8 +22,6 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.net.Uri;
import android.os.Binder;
import android.telephony.AccessNetworkConstants;
@@ -41,10 +39,7 @@ import java.util.function.Consumer;
/**
* Manages IMS Service registration state for associated {@link ImsFeature}s.
- * @hide
*/
-@SystemApi
-@TestApi
public interface RegistrationManager {
/**
@@ -139,7 +134,6 @@ public interface RegistrationManager {
getAccessType(imsRadioTech), info)));
}
- @Override
public void onSubscriberAssociatedUriChanged(Uri[] uris) {
if (mLocalCallback == null) return;
@@ -225,7 +219,11 @@ public interface RegistrationManager {
/**
* Registers a {@link RegistrationCallback} with the system. Use
- * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
+ * @param executor The {@link Executor} that will be used to call the IMS registration state
+ * callback.
+ * @param c A callback called on the supplied {@link Executor} that will contain the
+ * registration state of the IMS service, which will be one of the
+ * {@see SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
* events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
*
* When the callback is registered, it will initiate the callback c to be called with the
@@ -275,10 +273,10 @@ public interface RegistrationManager {
* Gets the Transport Type associated with the current IMS registration.
* @param executor The {@link Executor} that will be used to call the transportTypeCallback.
* @param transportTypeCallback The transport type associated with the current IMS registration,
- * which will be one of following:
- * {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN},
- * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or
- * {@link AccessNetworkConstants#TRANSPORT_TYPE_INVALID}.
+ * which will be one of following:
+ * {@see AccessNetworkConstants#TRANSPORT_TYPE_WWAN},
+ * {@see AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or
+ * {@see AccessNetworkConstants#TRANSPORT_TYPE_INVALID}.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
void getRegistrationTransportType(
diff --git a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
index d64e67a40201..cc2ebb9b20bd 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
@@ -92,11 +92,11 @@ oneway interface IImsCallSessionListener {
/**
* Notifies of handover information for this call
*/
- void callSessionHandover(int srcAccessTech, int targetAccessTech,
+ void callSessionHandover(int srcNetworkType, int targetNetworkType,
in ImsReasonInfo reasonInfo);
- void callSessionHandoverFailed(int srcAccessTech, int targetAccessTech,
+ void callSessionHandoverFailed(int srcNetworkType, int targetNetworkType,
in ImsReasonInfo reasonInfo);
- void callSessionMayHandover(int srcAccessTech, int targetAccessTech);
+ void callSessionMayHandover(int srcNetworkType, int targetNetworkType);
/**
* Notifies the TTY mode change by remote party.
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
index acab738737f4..75bd6a7dc648 100644
--- a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
@@ -20,6 +20,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.os.Message;
import android.os.RemoteException;
import android.telephony.CallQuality;
+import android.telephony.ServiceState;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsCallSession;
import android.telephony.ims.ImsConferenceState;
@@ -547,19 +548,25 @@ public class ImsCallSessionImplBase extends IImsCallSession.Stub {
@Override
public void callSessionHandover(IImsCallSession i, int srcAccessTech, int targetAccessTech,
ImsReasonInfo reasonInfo) throws RemoteException {
- mNewListener.callSessionHandover(srcAccessTech, targetAccessTech, reasonInfo);
+ mNewListener.callSessionHandover(
+ ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech),
+ ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech), reasonInfo);
}
@Override
public void callSessionHandoverFailed(IImsCallSession i, int srcAccessTech,
int targetAccessTech, ImsReasonInfo reasonInfo) throws RemoteException {
- mNewListener.callSessionHandoverFailed(srcAccessTech, targetAccessTech, reasonInfo);
+ mNewListener.callSessionHandoverFailed(
+ ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech),
+ ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech), reasonInfo);
}
@Override
public void callSessionMayHandover(IImsCallSession i, int srcAccessTech, int targetAccessTech)
throws RemoteException {
- mNewListener.callSessionMayHandover(srcAccessTech, targetAccessTech);
+ mNewListener.callSessionMayHandover(
+ ServiceState.rilRadioTechnologyToNetworkType(srcAccessTech),
+ ServiceState.rilRadioTechnologyToNetworkType(targetAccessTech));
}
@Override
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index f14270f99c83..5d102cb4ac06 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -60,15 +60,21 @@ public abstract class ImsFeature {
* This feature supports emergency calling over MMTEL. If defined, the framework will try to
* place an emergency call over IMS first. If it is not defined, the framework will only use
* CSFB for emergency calling.
+ * @hide
*/
+ @SystemApi @TestApi
public static final int FEATURE_EMERGENCY_MMTEL = 0;
/**
* This feature supports the MMTEL feature.
+ * @hide
*/
+ @SystemApi @TestApi
public static final int FEATURE_MMTEL = 1;
/**
* This feature supports the RCS feature.
+ * @hide
*/
+ @SystemApi @TestApi
public static final int FEATURE_RCS = 2;
/**
* Total number of features defined
@@ -116,18 +122,24 @@ public abstract class ImsFeature {
* This {@link ImsFeature}'s state is unavailable and should not be communicated with. This will
* remove all bindings back to the framework. Any attempt to communicate with the framework
* during this time will result in an {@link IllegalStateException}.
+ * @hide
*/
+ @SystemApi @TestApi
public static final int STATE_UNAVAILABLE = 0;
/**
* This {@link ImsFeature} state is initializing and should not be communicated with. This will
* remove all bindings back to the framework. Any attempt to communicate with the framework
* during this time will result in an {@link IllegalStateException}.
+ * @hide
*/
+ @SystemApi @TestApi
public static final int STATE_INITIALIZING = 1;
/**
* This {@link ImsFeature} is ready for communication. Do not attempt to call framework methods
- * until {@link #onFeatureReady()} is called.
+ * until {@see #onFeatureReady()} is called.
+ * @hide
*/
+ @SystemApi @TestApi
public static final int STATE_READY = 2;
/**
@@ -155,11 +167,15 @@ public abstract class ImsFeature {
/**
* The capability was unable to be changed.
+ * @hide
*/
+ @SystemApi @TestApi
public static final int CAPABILITY_ERROR_GENERIC = -1;
/**
* The capability was able to be changed.
+ * @hide
*/
+ @SystemApi @TestApi
public static final int CAPABILITY_SUCCESS = 0;
/**
@@ -331,7 +347,9 @@ public abstract class ImsFeature {
*
* @see SubscriptionManager#getSubscriptionIds(int) for more information on getting the
* subscription IDs associated with this slot.
+ * @hide
*/
+ @SystemApi @TestApi
public final int getSlotIndex() {
return mSlotId;
}
@@ -339,7 +357,9 @@ public abstract class ImsFeature {
/**
* @return The current state of the ImsFeature, set previously by {@link #setFeatureState(int)}
* or {@link #STATE_UNAVAILABLE} if it has not been updated yet.
+ * @hide
*/
+ @SystemApi @TestApi
public @ImsState int getFeatureState() {
synchronized (mLock) {
return mState;
@@ -351,7 +371,9 @@ public abstract class ImsFeature {
* stop communication, depending on the state sent.
* @param state The ImsFeature's state, defined as {@link #STATE_UNAVAILABLE},
* {@link #STATE_INITIALIZING}, or {@link #STATE_READY}.
+ * @hide
*/
+ @SystemApi @TestApi
public final void setFeatureState(@ImsState int state) {
synchronized (mLock) {
if (mState != state) {
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 56c87710244c..0d5a979e5894 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -52,14 +52,18 @@ import java.lang.annotation.RetentionPolicy;
*
* Any class wishing to use MmTelFeature should extend this class and implement all methods that the
* service supports.
- * @hide
*/
-@SystemApi
-@TestApi
public class MmTelFeature extends ImsFeature {
private static final String LOG_TAG = "MmTelFeature";
+ /**
+ * @hide
+ */
+ @SystemApi @TestApi
+ public MmTelFeature() {
+ }
+
private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() {
@Override
@@ -215,11 +219,11 @@ public class MmTelFeature extends ImsFeature {
* {@link MmTelCapabilities#CAPABILITY_TYPE_SMS}.
*
* The capabilities of this MmTelFeature will be set by the framework and can be queried with
- * {@link #queryCapabilityStatus()}.
+ * {@see #queryCapabilityStatus()}.
*
* This MmTelFeature can then return the status of each of these capabilities (enabled or not)
- * by sending a {@link #notifyCapabilitiesStatusChanged} callback to the framework. The current
- * status can also be queried using {@link #queryCapabilityStatus()}.
+ * by sending a {@see #notifyCapabilitiesStatusChanged} callback to the framework. The current
+ * status can also be queried using {@see #queryCapabilityStatus()}.
* @see #isCapable(int)
*/
public static class MmTelCapabilities extends Capabilities {
@@ -228,13 +232,18 @@ public class MmTelFeature extends ImsFeature {
* Create a new empty {@link MmTelCapabilities} instance.
* @see #addCapabilities(int)
* @see #removeCapabilities(int)
+ * @hide
*/
+ @SystemApi @TestApi
public MmTelCapabilities() {
super();
}
- /**@deprecated Use {@link MmTelCapabilities} to construct a new instance instead.*/
+ /**@deprecated Use {@link MmTelCapabilities} to construct a new instance instead.
+ * @hide
+ */
@Deprecated
+ @SystemApi @TestApi
public MmTelCapabilities(Capabilities c) {
mCapabilities = c.mCapabilities;
}
@@ -243,11 +252,17 @@ public class MmTelFeature extends ImsFeature {
* Create a new {link @MmTelCapabilities} instance with the provided capabilities.
* @param capabilities The capabilities that are supported for MmTel in the form of a
* bitfield.
+ * @hide
*/
+ @SystemApi @TestApi
public MmTelCapabilities(@MmTelCapability int capabilities) {
super(capabilities);
}
+ /**
+ * @hide
+ */
+ @SystemApi @TestApi
@IntDef(flag = true,
value = {
CAPABILITY_TYPE_VOICE,
@@ -278,23 +293,39 @@ public class MmTelFeature extends ImsFeature {
*/
public static final int CAPABILITY_TYPE_SMS = 1 << 3;
+ /**
+ * @hide
+ */
@Override
+ @SystemApi @TestApi
public final void addCapabilities(@MmTelCapability int capabilities) {
super.addCapabilities(capabilities);
}
+ /**
+ * @hide
+ */
@Override
+ @SystemApi @TestApi
public final void removeCapabilities(@MmTelCapability int capability) {
super.removeCapabilities(capability);
}
+ /**
+ * @hide
+ */
@Override
+ @SystemApi @TestApi
public final boolean isCapable(@MmTelCapability int capabilities) {
return super.isCapable(capabilities);
}
+ /**
+ * @hide
+ */
@NonNull
@Override
+ @SystemApi @TestApi
public String toString() {
StringBuilder builder = new StringBuilder("MmTel Capabilities - [");
builder.append("Voice: ");
@@ -319,8 +350,10 @@ public class MmTelFeature extends ImsFeature {
/**
* Called when the IMS provider receives an incoming call.
* @param c The {@link ImsCallSession} associated with the new call.
+ * @hide
*/
@Override
+ @SystemApi @TestApi
public void onIncomingCall(IImsCallSession c, Bundle extras) {
}
@@ -329,8 +362,10 @@ public class MmTelFeature extends ImsFeature {
* Called when the IMS provider implicitly rejects an incoming call during setup.
* @param callProfile An {@link ImsCallProfile} with the call details.
* @param reason The {@link ImsReasonInfo} reason for call rejection.
+ * @hide
*/
@Override
+ @SystemApi @TestApi
public void onRejectedCall(ImsCallProfile callProfile, ImsReasonInfo reason) {
}
@@ -338,8 +373,10 @@ public class MmTelFeature extends ImsFeature {
/**
* Updates the Listener when the voice message count for IMS has changed.
* @param count an integer representing the new message count.
+ * @hide
*/
@Override
+ @SystemApi @TestApi
public void onVoiceMessageCountUpdate(int count) {
}
@@ -348,14 +385,22 @@ public class MmTelFeature extends ImsFeature {
/**
* To be returned by {@link #shouldProcessCall(String[])} when the ImsService should process the
* outgoing call as IMS.
+ * @hide
*/
+ @SystemApi @TestApi
public static final int PROCESS_CALL_IMS = 0;
/**
* To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should
* not process the outgoing call as IMS and should instead use circuit switch.
+ * @hide
*/
+ @SystemApi @TestApi
public static final int PROCESS_CALL_CSFB = 1;
+ /**
+ * @hide
+ */
+ @SystemApi @TestApi
@IntDef(flag = true,
value = {
PROCESS_CALL_IMS,
@@ -368,7 +413,9 @@ public class MmTelFeature extends ImsFeature {
* If the flag is present and true, it indicates that the incoming call is for USSD.
* <p>
* This is an optional boolean flag.
+ * @hide
*/
+ @SystemApi @TestApi
public static final String EXTRA_IS_USSD = "android.telephony.ims.feature.extra.IS_USSD";
/**
@@ -379,7 +426,9 @@ public class MmTelFeature extends ImsFeature {
* certain situations.
* <p>
* This is an optional boolean flag.
+ * @hide
*/
+ @SystemApi @TestApi
public static final String EXTRA_IS_UNKNOWN_CALL =
"android.telephony.ims.feature.extra.IS_UNKNOWN_CALL";
@@ -388,6 +437,7 @@ public class MmTelFeature extends ImsFeature {
/**
* @param listener A {@link Listener} used when the MmTelFeature receives an incoming call and
* notifies the framework.
+ * @hide
*/
private void setListener(IImsMmTelListener listener) {
synchronized (mLock) {
@@ -406,9 +456,11 @@ public class MmTelFeature extends ImsFeature {
* Should be a subset of the capabilities that are enabled by the framework in
* {@link #changeEnabledCapabilities}.
* @return A copy of the current MmTelFeature capability status.
+ * @hide
*/
@Override
- public final MmTelCapabilities queryCapabilityStatus() {
+ @SystemApi @TestApi
+ public @NonNull final MmTelCapabilities queryCapabilityStatus() {
return new MmTelCapabilities(super.queryCapabilityStatus());
}
@@ -420,7 +472,9 @@ public class MmTelFeature extends ImsFeature {
* the status of that capability is disabled. This can happen if the network does not currently
* support the capability that is enabled. A capability that is disabled by the framework (via
* {@link #changeEnabledCapabilities}) should also show the status as disabled.
+ * @hide
*/
+ @SystemApi @TestApi
public final void notifyCapabilitiesStatusChanged(@NonNull MmTelCapabilities c) {
if (c == null) {
throw new IllegalArgumentException("MmTelCapabilities must be non-null!");
@@ -433,7 +487,9 @@ public class MmTelFeature extends ImsFeature {
* @param c The {@link ImsCallSessionImplBase} of the new incoming call.
* @param extras A bundle containing extra parameters related to the call. See
* {@link #EXTRA_IS_UNKNOWN_CALL} and {@link #EXTRA_IS_USSD} above.
+ * @hide
*/
+ @SystemApi @TestApi
public final void notifyIncomingCall(@NonNull ImsCallSessionImplBase c,
@NonNull Bundle extras) {
if (c == null || extras == null) {
@@ -458,7 +514,9 @@ public class MmTelFeature extends ImsFeature {
* @param callProfile The {@link ImsCallProfile} IMS call profile with details.
* This can be null if no call information is available for the rejected call.
* @param reason The {@link ImsReasonInfo} call rejection reason.
+ * * @hide
*/
+ @SystemApi @TestApi
public final void notifyRejectedCall(@NonNull ImsCallProfile callProfile,
@NonNull ImsReasonInfo reason) {
if (callProfile == null || reason == null) {
@@ -497,7 +555,9 @@ public class MmTelFeature extends ImsFeature {
/**
* Notify the framework of a change in the Voice Message count.
* @link count the new Voice Message count.
+ * @hide
*/
+ @SystemApi @TestApi
public final void notifyVoiceMessageCountUpdate(int count) {
synchronized (mLock) {
if (mListener == null) {
@@ -518,8 +578,10 @@ public class MmTelFeature extends ImsFeature {
* status for capability A.
* @param capability The capability that we are querying the configuration for.
* @return true if the capability is enabled, false otherwise.
+ * @hide
*/
@Override
+ @SystemApi @TestApi
public boolean queryCapabilityConfiguration(@MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
// Base implementation - Override to provide functionality
@@ -537,8 +599,10 @@ public class MmTelFeature extends ImsFeature {
* Enabling/Disabling a capability here indicates that the capability should be registered or
* deregistered (depending on the capability change) and become available or unavailable to
* the framework.
+ * * @hide
*/
@Override
+ @SystemApi @TestApi
public void changeEnabledCapabilities(@NonNull CapabilityChangeRequest request,
@NonNull CapabilityCallbackProxy c) {
// Base implementation, no-op
@@ -561,7 +625,9 @@ public class MmTelFeature extends ImsFeature {
* {@link ImsCallProfile#CALL_TYPE_VS_TX}
* {@link ImsCallProfile#CALL_TYPE_VS_RX}
* @return a {@link ImsCallProfile} object
+ * @hide
*/
+ @SystemApi @TestApi
public @Nullable ImsCallProfile createCallProfile(int callSessionType, int callType) {
// Base Implementation - Should be overridden
return null;
@@ -582,7 +648,9 @@ public class MmTelFeature extends ImsFeature {
* {@link ImsCallSession} directly.
*
* @param profile a call profile to make the call
+ * @hide
*/
+ @SystemApi @TestApi
public @Nullable ImsCallSessionImplBase createCallSession(@NonNull ImsCallProfile profile) {
// Base Implementation - Should be overridden
return null;
@@ -599,7 +667,9 @@ public class MmTelFeature extends ImsFeature {
* call as a conference.
* @return a {@link ProcessCallResult} to the framework, which will be used to determine if the
* call will be placed over IMS or via CSFB.
+ * @hide
*/
+ @SystemApi @TestApi
public @ProcessCallResult int shouldProcessCall(@NonNull String[] numbers) {
return PROCESS_CALL_IMS;
}
@@ -632,7 +702,9 @@ public class MmTelFeature extends ImsFeature {
/**
* @return The {@link ImsUtImplBase} Ut interface implementation for the supplementary service
* configuration.
+ * @hide
*/
+ @SystemApi @TestApi
public @NonNull ImsUtImplBase getUt() {
// Base Implementation - Should be overridden
return new ImsUtImplBase();
@@ -641,7 +713,9 @@ public class MmTelFeature extends ImsFeature {
/**
* @return The {@link ImsEcbmImplBase} Emergency call-back mode interface for emergency VoLTE
* calls that support it.
+ * @hide
*/
+ @SystemApi @TestApi
public @NonNull ImsEcbmImplBase getEcbm() {
// Base Implementation - Should be overridden
return new ImsEcbmImplBase();
@@ -650,7 +724,9 @@ public class MmTelFeature extends ImsFeature {
/**
* @return The {@link ImsMultiEndpointImplBase} implementation for implementing Dialog event
* package processing for multi-endpoint.
+ * @hide
*/
+ @SystemApi @TestApi
public @NonNull ImsMultiEndpointImplBase getMultiEndpoint() {
// Base Implementation - Should be overridden
return new ImsMultiEndpointImplBase();
@@ -676,7 +752,9 @@ public class MmTelFeature extends ImsFeature {
* // Remote side is dead
* }
* }
+ * @hide
*/
+ @SystemApi @TestApi
public void setUiTtyMode(int mode, @Nullable Message onCompleteMessage) {
// Base Implementation - Should be overridden
}
@@ -710,7 +788,9 @@ public class MmTelFeature extends ImsFeature {
*
* @return an instance of {@link ImsSmsImplBase} which should be implemented by the IMS
* Provider.
+ * @hide
*/
+ @SystemApi @TestApi
public @NonNull ImsSmsImplBase getSmsImplementation() {
return new ImsSmsImplBase();
}
@@ -719,14 +799,22 @@ public class MmTelFeature extends ImsFeature {
return getSmsImplementation().getSmsFormat();
}
- /**{@inheritDoc}*/
+ /**
+ * {@inheritDoc}
+ * @hide
+ */
@Override
+ @SystemApi @TestApi
public void onFeatureRemoved() {
// Base Implementation - Should be overridden
}
- /**{@inheritDoc}*/
+ /**
+ * {@inheritDoc}
+ * @hide
+ */
@Override
+ @SystemApi @TestApi
public void onFeatureReady() {
// Base Implementation - Should be overridden
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index 3ec4f3468497..f13371c1d0fa 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -17,6 +17,8 @@
package android.telephony.ims.stub;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.Bundle;
@@ -206,6 +208,13 @@ public class ImsUtImplBase {
return ImsUtImplBase.this.updateCallBarringForServiceClass(
cbType, action, barrList, serviceClass);
}
+
+ @Override
+ public int updateCallBarringWithPassword(int cbType, int action, String[] barrList,
+ int serviceClass, String password) throws RemoteException {
+ return ImsUtImplBase.this.updateCallBarringWithPassword(
+ cbType, action, barrList, serviceClass, password);
+ }
};
/**
@@ -328,6 +337,14 @@ public class ImsUtImplBase {
}
/**
+ * Updates the configuration of the call barring for specified service class with password.
+ */
+ public int updateCallBarringWithPassword(int cbType, int action, @Nullable String[] barrList,
+ int serviceClass, @NonNull String password) {
+ return -1;
+ }
+
+ /**
* Updates the configuration of the call forward.
*/
public int updateCallForward(int action, int condition, String number, int serviceClass,
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index 0d86e2b7c2b1..0f6ce13a6ce4 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -135,374 +135,596 @@ public class ImsConfig {
/**
* AMR CODEC Mode Value set, 0-7 in comma separated sequence.
* Value is in String format.
+ * @deprecated use {@link ProvisioningManager#KEY_AMR_CODEC_MODE_SET_VALUES} instead.
*/
- public static final int VOCODER_AMRMODESET = CONFIG_START;
+ @Deprecated
+ public static final int VOCODER_AMRMODESET =
+ ProvisioningManager.KEY_AMR_CODEC_MODE_SET_VALUES;
/**
* Wide Band AMR CODEC Mode Value set,0-7 in comma separated sequence.
* Value is in String format.
+ * @deprecated use {@link ProvisioningManager#KEY_AMR_WB_CODEC_MODE_SET_VALUES} instead.
*/
- public static final int VOCODER_AMRWBMODESET = 1;
+ @Deprecated
+ public static final int VOCODER_AMRWBMODESET =
+ ProvisioningManager.KEY_AMR_WB_CODEC_MODE_SET_VALUES;
/**
* SIP Session Timer value (seconds).
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_SIP_SESSION_TIMER_SEC} instead.
*/
- public static final int SIP_SESSION_TIMER = 2;
+ @Deprecated
+ public static final int SIP_SESSION_TIMER = ProvisioningManager.KEY_SIP_SESSION_TIMER_SEC;
/**
* Minimum SIP Session Expiration Timer in (seconds).
* Value is in Integer format.
+ * @deprecated use
+ * {@link ProvisioningManager#KEY_MINIMUM_SIP_SESSION_EXPIRATION_TIMER_SEC} instead.
*/
- public static final int MIN_SE = 3;
+ @Deprecated
+ public static final int MIN_SE =
+ ProvisioningManager.KEY_MINIMUM_SIP_SESSION_EXPIRATION_TIMER_SEC;
/**
* SIP_INVITE cancellation time out value (in milliseconds). Integer format.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_SIP_INVITE_CANCELLATION_TIMER_MS} instead.
*/
- public static final int CANCELLATION_TIMER = 4;
+ @Deprecated
+ public static final int CANCELLATION_TIMER =
+ ProvisioningManager.KEY_SIP_INVITE_CANCELLATION_TIMER_MS;
/**
* Delay time when an iRAT transition from eHRPD/HRPD/1xRTT to LTE.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_TRANSITION_TO_LTE_DELAY_MS} instead.
*/
- public static final int TDELAY = 5;
+ @Deprecated
+ public static final int TDELAY = ProvisioningManager.KEY_TRANSITION_TO_LTE_DELAY_MS;
/**
* Silent redial status of Enabled (True), or Disabled (False).
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_ENABLE_SILENT_REDIAL} instead.
*/
- public static final int SILENT_REDIAL_ENABLE = 6;
+ @Deprecated
+ public static final int SILENT_REDIAL_ENABLE = ProvisioningManager.KEY_ENABLE_SILENT_REDIAL;
/**
* SIP T1 timer value in milliseconds. See RFC 3261 for define.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_T1_TIMER_VALUE_MS} instead.
*/
+ @Deprecated
public static final int SIP_T1_TIMER = ProvisioningManager.KEY_T1_TIMER_VALUE_MS;
/**
* SIP T2 timer value in milliseconds. See RFC 3261 for define.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_T2_TIMER_VALUE_MS} instead.
*/
- public static final int SIP_T2_TIMER = 8;
+ @Deprecated
+ public static final int SIP_T2_TIMER = ProvisioningManager.KEY_T2_TIMER_VALUE_MS;
- /**
+ /**
* SIP TF timer value in milliseconds. See RFC 3261 for define.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_TF_TIMER_VALUE_MS} instead.
*/
- public static final int SIP_TF_TIMER = 9;
+ @Deprecated
+ public static final int SIP_TF_TIMER = ProvisioningManager.KEY_TF_TIMER_VALUE_MS;
/**
* VoLTE status for VLT/s status of Enabled (1), or Disabled (0).
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_VOLTE_PROVISIONING_STATUS} instead.
*/
+ @Deprecated
public static final int VLT_SETTING_ENABLED =
ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS;
/**
* VoLTE status for LVC/s status of Enabled (1), or Disabled (0).
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_VT_PROVISIONING_STATUS} instead.
*/
+ @Deprecated
public static final int LVC_SETTING_ENABLED =
ProvisioningManager.KEY_VT_PROVISIONING_STATUS;
+
/**
* Domain Name for the device to populate the request URI for REGISTRATION.
* Value is in String format.
+ * @deprecated use {@link ProvisioningManager#KEY_REGISTRATION_DOMAIN_NAME}.
*/
- public static final int DOMAIN_NAME = 12;
+ @Deprecated
+ public static final int DOMAIN_NAME = ProvisioningManager.KEY_REGISTRATION_DOMAIN_NAME;
+
/**
* Device Outgoing SMS based on either 3GPP or 3GPP2 standards.
* Value is in Integer format. 3GPP2(0), 3GPP(1)
- */
- public static final int SMS_FORMAT = 13;
+ * @deprecated use {@link ProvisioningManager#KEY_SMS_FORMAT}.
+ */
+ @Deprecated
+ public static final int SMS_FORMAT = ProvisioningManager.KEY_SMS_FORMAT;
+
/**
* Turns IMS ON/OFF on the device.
* Value is in Integer format. ON (1), OFF(0).
- */
- public static final int SMS_OVER_IP = 14;
+ * @deprecated use {@link ProvisioningManager#KEY_SMS_OVER_IP_ENABLED}.
+ */
+ @Deprecated
+ public static final int SMS_OVER_IP = ProvisioningManager.KEY_SMS_OVER_IP_ENABLED;
+
/**
* Requested expiration for Published Online availability.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_RCS_PUBLISH_TIMER_SEC}.
*/
+ @Deprecated
public static final int PUBLISH_TIMER = ProvisioningManager.KEY_RCS_PUBLISH_TIMER_SEC;
+
/**
* Requested expiration for Published Offline availability.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC}.
*/
+ @Deprecated
public static final int PUBLISH_TIMER_EXTENDED =
ProvisioningManager.KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC;
+
/**
*
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_RCS_CAPABILITY_DISCOVERY_ENABLED}.
*/
+ @Deprecated
public static final int CAPABILITY_DISCOVERY_ENABLED =
ProvisioningManager.KEY_RCS_CAPABILITY_DISCOVERY_ENABLED;
+
/**
- * Period of time the capability information of the contact is cached on handset.
+ * Period of time the capability information of the contact is cached on handset.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC}.
*/
+ @Deprecated
public static final int CAPABILITIES_CACHE_EXPIRATION =
ProvisioningManager.KEY_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC;
+
/**
* Peiod of time the availability information of a contact is cached on device.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC}.
*/
+ @Deprecated
public static final int AVAILABILITY_CACHE_EXPIRATION =
ProvisioningManager.KEY_RCS_AVAILABILITY_CACHE_EXPIRATION_SEC;
+
/**
* Interval between successive capabilities polling.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_RCS_CAPABILITIES_POLL_INTERVAL_SEC}.
*/
+ @Deprecated
public static final int CAPABILITIES_POLL_INTERVAL =
ProvisioningManager.KEY_RCS_CAPABILITIES_POLL_INTERVAL_SEC;
+
/**
* Minimum time between two published messages from the device.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS}.
*/
+ @Deprecated
public static final int SOURCE_THROTTLE_PUBLISH =
ProvisioningManager.KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS;
+
/**
* The Maximum number of MDNs contained in one Request Contained List.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_RCS_MAX_NUM_ENTRIES_IN_RCL}.
*/
+ @Deprecated
public static final int MAX_NUMENTRIES_IN_RCL =
ProvisioningManager.KEY_RCS_MAX_NUM_ENTRIES_IN_RCL;
+
/**
* Expiration timer for subscription of a Request Contained List, used in capability
* polling.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC}.
*/
+ @Deprecated
public static final int CAPAB_POLL_LIST_SUB_EXP =
ProvisioningManager.KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC;
+
/**
* Applies compression to LIST Subscription.
* Value is in Integer format. Enable (1), Disable(0).
+ * @deprecated use {@link ProvisioningManager#KEY_USE_GZIP_FOR_LIST_SUBSCRIPTION}.
*/
- public static final int GZIP_FLAG = 24;
+ @Deprecated
+ public static final int GZIP_FLAG = ProvisioningManager.KEY_USE_GZIP_FOR_LIST_SUBSCRIPTION;
+
/**
* VOLTE Status for EAB/s status of Enabled (1), or Disabled (0).
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_EAB_PROVISIONING_STATUS}.
*/
+ @Deprecated
public static final int EAB_SETTING_ENABLED =
ProvisioningManager.KEY_EAB_PROVISIONING_STATUS;
+
/**
* Wi-Fi calling roaming status.
* Value is in Integer format. ON (1), OFF(0).
+ * @deprecated use {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE}
+ * instead.
*/
+ @Deprecated
public static final int VOICE_OVER_WIFI_ROAMING =
ProvisioningManager.KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE;
+
/**
- * Wi-Fi calling modem - WfcModeFeatureValueConstants.
+ * Wi-Fi calling mode - WfcModeFeatureValueConstants.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_MODE_OVERRIDE}
+ * instead.
*/
+ @Deprecated
public static final int VOICE_OVER_WIFI_MODE =
ProvisioningManager.KEY_VOICE_OVER_WIFI_MODE_OVERRIDE;
+
/**
* VOLTE Status for voice over wifi status of Enabled (1), or Disabled (0).
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE}.
*/
- public static final int VOICE_OVER_WIFI_SETTING_ENABLED = 28;
+ @Deprecated
+ public static final int VOICE_OVER_WIFI_SETTING_ENABLED =
+ ProvisioningManager.KEY_VOICE_OVER_WIFI_ENABLED_OVERRIDE;
+
+
/**
* Mobile data enabled.
* Value is in Integer format. On (1), OFF(0).
+ * @deprecated use {@link ProvisioningManager#KEY_MOBILE_DATA_ENABLED}.
*/
- public static final int MOBILE_DATA_ENABLED = 29;
+ @Deprecated
+ public static final int MOBILE_DATA_ENABLED = ProvisioningManager.KEY_MOBILE_DATA_ENABLED;
+
/**
* VoLTE user opted in status.
* Value is in Integer format. Opted-in (1) Opted-out (0).
+ * @deprecated use {@link ProvisioningManager#KEY_VOLTE_USER_OPT_IN_STATUS}.
*/
- public static final int VOLTE_USER_OPT_IN_STATUS = 30;
+ @Deprecated
+ public static final int VOLTE_USER_OPT_IN_STATUS =
+ ProvisioningManager.KEY_VOLTE_USER_OPT_IN_STATUS;
+
/**
* Proxy for Call Session Control Function(P-CSCF) address for Local-BreakOut(LBO).
* Value is in String format.
+ * @deprecated use {@link ProvisioningManager#KEY_LOCAL_BREAKOUT_PCSCF_ADDRESS}.
*/
- public static final int LBO_PCSCF_ADDRESS = 31;
+ @Deprecated
+ public static final int LBO_PCSCF_ADDRESS =
+ ProvisioningManager.KEY_LOCAL_BREAKOUT_PCSCF_ADDRESS;
+
/**
* Keep Alive Enabled for SIP.
* Value is in Integer format. On(1), OFF(0).
+ * @deprecated use {@link ProvisioningManager#KEY_SIP_KEEP_ALIVE_ENABLED}.
*/
- public static final int KEEP_ALIVE_ENABLED = 32;
+ @Deprecated
+ public static final int KEEP_ALIVE_ENABLED = ProvisioningManager.KEY_SIP_KEEP_ALIVE_ENABLED;
+
/**
* Registration retry Base Time value in seconds.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_REGISTRATION_RETRY_BASE_TIME_SEC}.
*/
- public static final int REGISTRATION_RETRY_BASE_TIME_SEC = 33;
+ @Deprecated
+ public static final int REGISTRATION_RETRY_BASE_TIME_SEC =
+ ProvisioningManager.KEY_REGISTRATION_RETRY_BASE_TIME_SEC;
+
/**
* Registration retry Max Time value in seconds.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_REGISTRATION_RETRY_MAX_TIME_SEC}.
*/
- public static final int REGISTRATION_RETRY_MAX_TIME_SEC = 34;
+ @Deprecated
+ public static final int REGISTRATION_RETRY_MAX_TIME_SEC =
+ ProvisioningManager.KEY_REGISTRATION_RETRY_MAX_TIME_SEC;
+
/**
* Smallest RTP port for speech codec.
* Value is in integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_RTP_SPEECH_START_PORT}.
*/
- public static final int SPEECH_START_PORT = 35;
+ @Deprecated
+ public static final int SPEECH_START_PORT = ProvisioningManager.KEY_RTP_SPEECH_START_PORT;
+
/**
* Largest RTP port for speech code.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_RTP_SPEECH_END_PORT}.
*/
- public static final int SPEECH_END_PORT = 36;
+ @Deprecated
+ public static final int SPEECH_END_PORT = ProvisioningManager.KEY_RTP_SPEECH_END_PORT;
+
/**
* SIP Timer A's value in milliseconds. Timer A is the INVITE request
* retransmit interval, for UDP only.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_SIP_INVITE_REQUEST_TRANSMIT_INTERVAL_MS}.
*/
- public static final int SIP_INVITE_REQ_RETX_INTERVAL_MSEC = 37;
+ @Deprecated
+ public static final int SIP_INVITE_REQ_RETX_INTERVAL_MSEC =
+ ProvisioningManager.KEY_SIP_INVITE_REQUEST_TRANSMIT_INTERVAL_MS;
+
/**
* SIP Timer B's value in milliseconds. Timer B is the wait time for
* INVITE message to be acknowledged.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_SIP_INVITE_ACK_WAIT_TIME_MS}.
*/
- public static final int SIP_INVITE_RSP_WAIT_TIME_MSEC = 38;
+ @Deprecated
+ public static final int SIP_INVITE_RSP_WAIT_TIME_MSEC =
+ ProvisioningManager.KEY_SIP_INVITE_ACK_WAIT_TIME_MS;
+
/**
* SIP Timer D's value in milliseconds. Timer D is the wait time for
* response retransmits of the invite client transactions.
* Value is in Integer format.
+ * @deprecated use
+ * {@link ProvisioningManager#KEY_SIP_INVITE_RESPONSE_RETRANSMIT_WAIT_TIME_MS}.
*/
- public static final int SIP_INVITE_RSP_RETX_WAIT_TIME_MSEC = 39;
+ @Deprecated
+ public static final int SIP_INVITE_RSP_RETX_WAIT_TIME_MSEC =
+ ProvisioningManager.KEY_SIP_INVITE_RESPONSE_RETRANSMIT_WAIT_TIME_MS;
+
/**
* SIP Timer E's value in milliseconds. Timer E is the value Non-INVITE
* request retransmit interval, for UDP only.
* Value is in Integer format.
+ * @deprecated use
+ * {@link ProvisioningManager#KEY_SIP_NON_INVITE_REQUEST_RETRANSMIT_INTERVAL_MS}.
*/
- public static final int SIP_NON_INVITE_REQ_RETX_INTERVAL_MSEC = 40;
+ @Deprecated
+ public static final int SIP_NON_INVITE_REQ_RETX_INTERVAL_MSEC =
+ ProvisioningManager.KEY_SIP_NON_INVITE_REQUEST_RETRANSMIT_INTERVAL_MS;
+
/**
* SIP Timer F's value in milliseconds. Timer F is the Non-INVITE transaction
* timeout timer.
* Value is in Integer format.
+ * @deprecated use
+ * {@link ProvisioningManager#KEY_SIP_NON_INVITE_TRANSACTION_TIMEOUT_TIMER_MS}.
*/
- public static final int SIP_NON_INVITE_TXN_TIMEOUT_TIMER_MSEC = 41;
+ @Deprecated
+ public static final int SIP_NON_INVITE_TXN_TIMEOUT_TIMER_MSEC =
+ ProvisioningManager.KEY_SIP_NON_INVITE_TRANSACTION_TIMEOUT_TIMER_MS;
+
/**
* SIP Timer G's value in milliseconds. Timer G is the value of INVITE response
* retransmit interval.
* Value is in Integer format.
+ * @deprecated use
+ * {@link ProvisioningManager#KEY_SIP_INVITE_RESPONSE_RETRANSMIT_INTERVAL_MS}.
*/
- public static final int SIP_INVITE_RSP_RETX_INTERVAL_MSEC = 42;
+ @Deprecated
+ public static final int SIP_INVITE_RSP_RETX_INTERVAL_MSEC =
+ ProvisioningManager.KEY_SIP_INVITE_RESPONSE_RETRANSMIT_INTERVAL_MS;
+
/**
* SIP Timer H's value in milliseconds. Timer H is the value of wait time for
* ACK receipt.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_SIP_ACK_RECEIPT_WAIT_TIME_MS}.
*/
- public static final int SIP_ACK_RECEIPT_WAIT_TIME_MSEC = 43;
+ @Deprecated
+ public static final int SIP_ACK_RECEIPT_WAIT_TIME_MSEC =
+ ProvisioningManager.KEY_SIP_ACK_RECEIPT_WAIT_TIME_MS;
+
/**
* SIP Timer I's value in milliseconds. Timer I is the value of wait time for
* ACK retransmits.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_SIP_ACK_RETRANSMIT_WAIT_TIME_MS}.
*/
- public static final int SIP_ACK_RETX_WAIT_TIME_MSEC = 44;
+ @Deprecated
+ public static final int SIP_ACK_RETX_WAIT_TIME_MSEC =
+ ProvisioningManager.KEY_SIP_ACK_RETRANSMIT_WAIT_TIME_MS;
+
/**
* SIP Timer J's value in milliseconds. Timer J is the value of wait time for
* non-invite request retransmission.
* Value is in Integer format.
+ * @deprecated use
+ * {@link ProvisioningManager#KEY_SIP_NON_INVITE_REQUEST_RETRANSMISSION_WAIT_TIME_MS}.
*/
- public static final int SIP_NON_INVITE_REQ_RETX_WAIT_TIME_MSEC = 45;
+ @Deprecated
+ public static final int SIP_NON_INVITE_REQ_RETX_WAIT_TIME_MSEC =
+ ProvisioningManager.KEY_SIP_NON_INVITE_REQUEST_RETRANSMISSION_WAIT_TIME_MS;
+
/**
* SIP Timer K's value in milliseconds. Timer K is the value of wait time for
* non-invite response retransmits.
* Value is in Integer format.
+ * @deprecated use
+ * {@link ProvisioningManager#KEY_SIP_NON_INVITE_RESPONSE_RETRANSMISSION_WAIT_TIME_MS}.
*/
- public static final int SIP_NON_INVITE_RSP_RETX_WAIT_TIME_MSEC = 46;
+ @Deprecated
+ public static final int SIP_NON_INVITE_RSP_RETX_WAIT_TIME_MSEC =
+ ProvisioningManager.KEY_SIP_NON_INVITE_RESPONSE_RETRANSMISSION_WAIT_TIME_MS;
+
/**
* AMR WB octet aligned dynamic payload type.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_AMR_WB_OCTET_ALIGNED_PAYLOAD_TYPE}.
*/
- public static final int AMR_WB_OCTET_ALIGNED_PT = 47;
+ @Deprecated
+ public static final int AMR_WB_OCTET_ALIGNED_PT =
+ ProvisioningManager.KEY_AMR_WB_OCTET_ALIGNED_PAYLOAD_TYPE;
+
/**
* AMR WB bandwidth efficient payload type.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_AMR_WB_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE}.
*/
- public static final int AMR_WB_BANDWIDTH_EFFICIENT_PT = 48;
+ @Deprecated
+ public static final int AMR_WB_BANDWIDTH_EFFICIENT_PT =
+ ProvisioningManager.KEY_AMR_WB_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE;
+
/**
* AMR octet aligned dynamic payload type.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_AMR_OCTET_ALIGNED_PAYLOAD_TYPE}.
*/
- public static final int AMR_OCTET_ALIGNED_PT = 49;
+ @Deprecated
+ public static final int AMR_OCTET_ALIGNED_PT =
+ ProvisioningManager.KEY_AMR_OCTET_ALIGNED_PAYLOAD_TYPE;
+
/**
* AMR bandwidth efficient payload type.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_AMR_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE}.
*/
- public static final int AMR_BANDWIDTH_EFFICIENT_PT = 50;
+ @Deprecated
+ public static final int AMR_BANDWIDTH_EFFICIENT_PT =
+ ProvisioningManager.KEY_AMR_BANDWIDTH_EFFICIENT_PAYLOAD_TYPE;
+
/**
* DTMF WB payload type.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_DTMF_WB_PAYLOAD_TYPE}.
*/
- public static final int DTMF_WB_PT = 51;
+ @Deprecated
+ public static final int DTMF_WB_PT = ProvisioningManager.KEY_DTMF_WB_PAYLOAD_TYPE;
+
/**
* DTMF NB payload type.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_DTMF_NB_PAYLOAD_TYPE}.
*/
- public static final int DTMF_NB_PT = 52;
+ @Deprecated
+ public static final int DTMF_NB_PT = ProvisioningManager.KEY_DTMF_NB_PAYLOAD_TYPE;
+
/**
* AMR Default encoding mode.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_AMR_DEFAULT_ENCODING_MODE}.
*/
- public static final int AMR_DEFAULT_MODE = 53;
+ @Deprecated
+ public static final int AMR_DEFAULT_MODE =
+ ProvisioningManager.KEY_AMR_DEFAULT_ENCODING_MODE;
+
/**
* SMS Public Service Identity.
* Value is in String format.
+ * @deprecated use {@link ProvisioningManager#KEY_SMS_PUBLIC_SERVICE_IDENTITY}.
*/
- public static final int SMS_PSI = 54;
+ @Deprecated
+ public static final int SMS_PSI = ProvisioningManager.KEY_SMS_PUBLIC_SERVICE_IDENTITY;
+
/**
* Video Quality - VideoQualityFeatureValuesConstants.
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_VIDEO_QUALITY}.
*/
- public static final int VIDEO_QUALITY = 55;
+ @Deprecated
+ public static final int VIDEO_QUALITY = ProvisioningManager.KEY_VIDEO_QUALITY;
+
/**
* LTE threshold.
* Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= VOWT_A.
+ * @deprecated use {@link ProvisioningManager#KEY_LTE_THRESHOLD_1}.
*/
- public static final int TH_LTE1 = 56;
+ @Deprecated
+ public static final int TH_LTE1 = ProvisioningManager.KEY_LTE_THRESHOLD_1;
+
/**
* LTE threshold.
* Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+ * @deprecated use {@link ProvisioningManager#KEY_LTE_THRESHOLD_2}.
*/
- public static final int TH_LTE2 = 57;
+ @Deprecated
+ public static final int TH_LTE2 = ProvisioningManager.KEY_LTE_THRESHOLD_2;
+
/**
* LTE threshold.
* Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+ * @deprecated use {@link ProvisioningManager#KEY_LTE_THRESHOLD_3}.
*/
- public static final int TH_LTE3 = 58;
+ @Deprecated
+ public static final int TH_LTE3 = ProvisioningManager.KEY_LTE_THRESHOLD_3;
+
/**
* 1x threshold.
* Handover from 1x to WiFi if 1x < TH1x
+ * @deprecated use {@link ProvisioningManager#KEY_1X_THRESHOLD}.
*/
- public static final int TH_1x = 59;
+ @Deprecated
+ public static final int TH_1x = ProvisioningManager.KEY_1X_THRESHOLD;
+
/**
* WiFi threshold.
* Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= VOWT_A.
+ * @deprecated use {@link ProvisioningManager#KEY_WIFI_THRESHOLD_A}.
*/
- public static final int VOWT_A = 60;
+ @Deprecated
+ public static final int VOWT_A = ProvisioningManager.KEY_WIFI_THRESHOLD_A;
+
/**
* WiFi threshold.
* Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+ * @deprecated use {@link ProvisioningManager#KEY_WIFI_THRESHOLD_B}.
*/
- public static final int VOWT_B = 61;
+ @Deprecated
+ public static final int VOWT_B = ProvisioningManager.KEY_WIFI_THRESHOLD_B;
+
/**
* LTE ePDG timer.
* Device shall not handover back to LTE until the T_ePDG_LTE timer expires.
+ * @deprecated use {@link ProvisioningManager#KEY_LTE_EPDG_TIMER_SEC}.
*/
- public static final int T_EPDG_LTE = 62;
+ @Deprecated
+ public static final int T_EPDG_LTE = ProvisioningManager.KEY_LTE_EPDG_TIMER_SEC;
+
/**
* WiFi ePDG timer.
* Device shall not handover back to WiFi until the T_ePDG_WiFi timer expires.
+ * @deprecated use {@link ProvisioningManager#KEY_WIFI_EPDG_TIMER_SEC}.
*/
- public static final int T_EPDG_WIFI = 63;
+ @Deprecated
+ public static final int T_EPDG_WIFI = ProvisioningManager.KEY_WIFI_EPDG_TIMER_SEC;
+
/**
* 1x ePDG timer.
* Device shall not re-register on 1x until the T_ePDG_1x timer expires.
+ * @deprecated use {@link ProvisioningManager#KEY_1X_EPDG_TIMER_SEC}.
*/
- public static final int T_EPDG_1X = 64;
+ @Deprecated
+ public static final int T_EPDG_1X = ProvisioningManager.KEY_1X_EPDG_TIMER_SEC;
+
/**
* MultiEndpoint status: Enabled (1), or Disabled (0).
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_MULTIENDPOINT_ENABLED}.
*/
- public static final int VICE_SETTING_ENABLED = 65;
+ @Deprecated
+ public static final int VICE_SETTING_ENABLED = ProvisioningManager.KEY_MULTIENDPOINT_ENABLED;
/**
* RTT status: Enabled (1), or Disabled (0).
* Value is in Integer format.
+ * @deprecated use {@link ProvisioningManager#KEY_RTT_ENABLED}.
*/
- public static final int RTT_SETTING_ENABLED = 66;
+ @Deprecated
+ public static final int RTT_SETTING_ENABLED = ProvisioningManager.KEY_RTT_ENABLED;
// Expand the operator config items as needed here, need to change
// PROVISIONED_CONFIG_END after that.
diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java
index 15f837189843..4a5380e4551b 100644
--- a/telephony/java/com/android/ims/ImsUtInterface.java
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -166,6 +166,12 @@ public interface ImsUtInterface {
String[] barrList, int serviceClass);
/**
+ * Modifies the configuration of the call barring for specified service class with password.
+ */
+ public void updateCallBarring(int cbType, int action, Message result,
+ String[] barrList, int serviceClass, String password);
+
+ /**
* Modifies the configuration of the call forward.
*/
public void updateCallForward(int action, int condition, String number,
diff --git a/telephony/java/com/android/ims/internal/IImsUt.aidl b/telephony/java/com/android/ims/internal/IImsUt.aidl
index 4f97cc5cfb22..302be65070f7 100644
--- a/telephony/java/com/android/ims/internal/IImsUt.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUt.aidl
@@ -122,4 +122,10 @@ interface IImsUt {
*/
int updateCallBarringForServiceClass(int cbType, int action, in String[] barrList,
int serviceClass);
+
+ /**
+ * Updates the configuration of the call barring for specified service class with password.
+ */
+ int updateCallBarringWithPassword(int cbType, int action, in String[] barrList,
+ int serviceClass, String password);
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index b4d3ec9fc87d..eef96c4e04a3 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -205,8 +205,6 @@ public class TelephonyIntents {
public static final String ACTION_SIM_STATE_CHANGED
= Intent.ACTION_SIM_STATE_CHANGED;
- public static final String EXTRA_REBROADCAST_ON_UNLOCK= "rebroadcastOnUnlock";
-
/**
* <p>Broadcast Action: It indicates the Emergency callback mode blocks datacall/sms
* <p class="note">.
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 832502cae37d..d0c8024c56fe 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -148,10 +148,9 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Create an SmsMessage from an SMS EF record.
+ * Creates an SmsMessage from an SMS EF record.
*
- * @param index Index of SMS record. This should be index in ArrayList
- * returned by RuimSmsInterfaceManager.getAllMessagesFromIcc + 1.
+ * @param index Index of SMS EF record.
* @param data Record data.
* @return An SmsMessage representing the record.
*
@@ -202,26 +201,16 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * TODO(cleanup): why do getSubmitPdu methods take an scAddr input
- * and do nothing with it? GSM allows us to specify a SC (eg,
- * when responding to an SMS that explicitly requests the response
- * is sent to a specific SC), or pass null to use the default
- * value. Is there no similar notion in CDMA? Or do we just not
- * have it hooked up?
- */
-
- /**
- * Get an SMS-SUBMIT PDU for a destination address and a message
+ * Gets an SMS-SUBMIT PDU for a destination address and a message.
*
- * @param scAddr Service Centre address. Null means use default.
- * @param destAddr Address of the recipient.
- * @param message String representation of the message payload.
- * @param statusReportRequested Indicates whether a report is requested for this message.
- * @param smsHeader Array containing the data for the User Data Header, preceded
- * by the Element Identifiers.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @param scAddr Service Centre address. No use for this message.
+ * @param destAddr the address of the destination for the message.
+ * @param message string representation of the message payload.
+ * @param statusReportRequested indicates whether a report is requested for this message.
+ * @param smsHeader array containing the data for the User Data Header, preceded by the Element
+ * Identifiers.
+ * @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns
+ * null on encode error.
* @hide
*/
@UnsupportedAppUsage
@@ -231,18 +220,17 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Get an SMS-SUBMIT PDU for a destination address and a message
+ * Gets an SMS-SUBMIT PDU for a destination address and a message.
*
- * @param scAddr Service Centre address. Null means use default.
- * @param destAddr Address of the recipient.
- * @param message String representation of the message payload.
- * @param statusReportRequested Indicates whether a report is requested for this message.
- * @param smsHeader Array containing the data for the User Data Header, preceded
- * by the Element Identifiers.
- * @param priority Priority level of the message
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @param scAddr Service Centre address. No use for this message.
+ * @param destAddr the address of the destination for the message.
+ * @param message string representation of the message payload.
+ * @param statusReportRequested indicates whether a report is requested for this message.
+ * @param smsHeader array containing the data for the User Data Header, preceded by the Element
+ * Identifiers.
+ * @param priority priority level of the message.
+ * @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns
+ * null on encode error.
* @hide
*/
@UnsupportedAppUsage
@@ -265,16 +253,15 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Get an SMS-SUBMIT PDU for a data message to a destination address and port.
+ * Gets an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
*
- * @param scAddr Service Centre address. null == use default
- * @param destAddr the address of the destination for the message
- * @param destPort the port to deliver the message to at the
- * destination
- * @param data the data for the message
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @param scAddr Service Centre address. No use for this message.
+ * @param destAddr the address of the destination for the message.
+ * @param destPort the port to deliver the message to at the destination.
+ * @param data the data for the message.
+ * @param statusReportRequested indicates whether a report is requested for this message.
+ * @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns
+ * null on encode error.
*/
@UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, int destPort,
@@ -305,14 +292,13 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
+ * Gets an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
*
- * @param destAddr the address of the destination for the message
- * @param userData the data for the message
- * @param statusReportRequested Indicates whether a report is requested for this message.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @param destAddr the address of the destination for the message.
+ * @param userData the data for the message.
+ * @param statusReportRequested indicates whether a report is requested for this message.
+ * @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns
+ * null on encode error.
*/
@UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String destAddr, UserData userData,
@@ -321,15 +307,14 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
+ * Gets an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
*
- * @param destAddr the address of the destination for the message
- * @param userData the data for the message
- * @param statusReportRequested Indicates whether a report is requested for this message.
- * @param priority Priority level of the message
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @param destAddr the address of the destination for the message.
+ * @param userData the data for the message.
+ * @param statusReportRequested indicates whether a report is requested for this message.
+ * @param priority Priority level of the message.
+ * @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns
+ * null on encode error.
*/
@UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String destAddr, UserData userData,
@@ -1059,6 +1044,72 @@ public class SmsMessage extends SmsMessageBase {
}
/**
+ * Gets an SMS-DELIVER PDU for a originating address and a message.
+ *
+ * @param origAddr the address of the originating for the message.
+ * @param message string representation of the message payload.
+ * @param date the time stamp the message was received.
+ * @return a <code>SubmitPdu</code> containing null SC address and the encoded message. Returns
+ * null on encode error.
+ * @hide
+ */
+ public static SubmitPdu getDeliverPdu(String origAddr, String message, long date) {
+ if (origAddr == null || message == null) {
+ return null;
+ }
+
+ CdmaSmsAddress addr = CdmaSmsAddress.parse(origAddr);
+ if (addr == null) return null;
+
+ BearerData bearerData = new BearerData();
+ bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER;
+
+ bearerData.messageId = 0;
+
+ bearerData.deliveryAckReq = false;
+ bearerData.userAckReq = false;
+ bearerData.readAckReq = false;
+ bearerData.reportReq = false;
+
+ bearerData.userData = new UserData();
+ bearerData.userData.payloadStr = message;
+
+ bearerData.msgCenterTimeStamp = BearerData.TimeStamp.fromMillis(date);
+
+ byte[] encodedBearerData = BearerData.encode(bearerData);
+ if (encodedBearerData == null) return null;
+
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
+ DataOutputStream dos = new DataOutputStream(baos);
+ dos.writeInt(SmsEnvelope.TELESERVICE_WMT);
+ dos.writeInt(0); // servicePresent
+ dos.writeInt(0); // serviceCategory
+ dos.write(addr.digitMode);
+ dos.write(addr.numberMode);
+ dos.write(addr.ton); // number_type
+ dos.write(addr.numberPlan);
+ dos.write(addr.numberOfDigits);
+ dos.write(addr.origBytes, 0, addr.origBytes.length); // digits
+ // Subaddress is not supported.
+ dos.write(0); // subaddressType
+ dos.write(0); // subaddr_odd
+ dos.write(0); // subaddr_nbr_of_digits
+ dos.write(encodedBearerData.length);
+ dos.write(encodedBearerData, 0, encodedBearerData.length);
+ dos.close();
+
+ SubmitPdu pdu = new SubmitPdu();
+ pdu.encodedMessage = baos.toByteArray();
+ pdu.encodedScAddress = null;
+ return pdu;
+ } catch (IOException ex) {
+ Rlog.e(LOG_TAG, "creating Deliver PDU failed: " + ex);
+ }
+ return null;
+ }
+
+ /**
* Creates byte array (pseudo pdu) from SMS object.
* Note: Do not call this method more than once per object!
* @hide
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index ca03333b99aa..f4a96a67c3b2 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -32,6 +32,7 @@ import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.util.BitwiseInputStream;
import com.android.internal.util.BitwiseOutputStream;
+import java.io.ByteArrayOutputStream;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
@@ -284,6 +285,33 @@ public final class BearerData {
return ts;
}
+ public static TimeStamp fromMillis(long timeInMillis) {
+ TimeStamp ts = new TimeStamp();
+ LocalDateTime localDateTime =
+ Instant.ofEpochMilli(timeInMillis).atZone(ts.mZoneId).toLocalDateTime();
+ int year = localDateTime.getYear();
+ if (year < 1996 || year > 2095) return null;
+ ts.year = year;
+ ts.month = localDateTime.getMonthValue();
+ ts.monthDay = localDateTime.getDayOfMonth();
+ ts.hour = localDateTime.getHour();
+ ts.minute = localDateTime.getMinute();
+ ts.second = localDateTime.getSecond();
+ return ts;
+ }
+
+ public byte[] toByteArray() {
+ int year = this.year % 100; // 00 - 99
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream(6);
+ outStream.write((((year / 10) & 0x0F) << 4) | ((year % 10) & 0x0F));
+ outStream.write((((month / 10) << 4) & 0xF0) | ((month % 10) & 0x0F));
+ outStream.write((((monthDay / 10) << 4) & 0xF0) | ((monthDay % 10) & 0x0F));
+ outStream.write((((hour / 10) << 4) & 0xF0) | ((hour % 10) & 0x0F));
+ outStream.write((((minute / 10) << 4) & 0xF0) | ((minute % 10) & 0x0F));
+ outStream.write((((second / 10) << 4) & 0xF0) | ((second % 10) & 0x0F));
+ return outStream.toByteArray();
+ }
+
public long toMillis() {
LocalDateTime localDateTime =
LocalDateTime.of(year, month + 1, monthDay, hour, minute, second);
@@ -957,6 +985,12 @@ public final class BearerData {
}
}
+ private static void encodeMsgCenterTimeStamp(BearerData bData, BitwiseOutputStream outStream)
+ throws BitwiseOutputStream.AccessException {
+ outStream.write(8, 6);
+ outStream.writeByteArray(8 * 6, bData.msgCenterTimeStamp.toByteArray());
+ };
+
/**
* Create serialized representation for BearerData object.
* (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
@@ -1021,6 +1055,10 @@ public final class BearerData {
outStream.write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS);
encodeScpResults(bData, outStream);
}
+ if (bData.msgCenterTimeStamp != null) {
+ outStream.write(8, SUBPARAM_MESSAGE_CENTER_TIME_STAMP);
+ encodeMsgCenterTimeStamp(bData, outStream);
+ }
return outStream.toByteArray();
} catch (BitwiseOutputStream.AccessException ex) {
Rlog.e(LOG_TAG, "BearerData encode failed: " + ex);
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index f54da3bf6c6b..4538193818c1 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -42,8 +42,11 @@ import com.android.internal.telephony.uicc.IccUtils;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
+import java.time.Instant;
import java.time.LocalDateTime;
+import java.time.ZoneId;
import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
/**
* A Short Message Service message.
@@ -168,10 +171,9 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Create an SmsMessage from an SMS EF record.
+ * Creates an SmsMessage from an SMS EF record.
*
- * @param index Index of SMS record. This should be index in ArrayList
- * returned by SmsManager.getAllMessagesFromSim + 1.
+ * @param index Index of SMS EF record.
* @param data Record data.
* @return An SmsMessage representing the record.
*
@@ -260,12 +262,15 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Get an SMS-SUBMIT PDU for a destination address and a message
+ * Gets an SMS-SUBMIT PDU for a destination address and a message.
*
- * @param scAddress Service Centre address. Null means use default.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param message string representation of the message payload.
+ * @param statusReportRequested indicates whether a report is reuested for this message.
+ * @param header a byte array containing the data for the User Data Header.
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
* @hide
*/
@UnsupportedAppUsage
@@ -278,17 +283,19 @@ public class SmsMessage extends SmsMessageBase {
/**
- * Get an SMS-SUBMIT PDU for a destination address and a message using the
- * specified encoding.
+ * Gets an SMS-SUBMIT PDU for a destination address and a message using the specified encoding.
*
- * @param scAddress Service Centre address. Null means use default.
- * @param encoding Encoding defined by constants in
- * com.android.internal.telephony.SmsConstants.ENCODING_*
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param message string representation of the message payload.
+ * @param statusReportRequested indicates whether a report is reuested for this message.
+ * @param header a byte array containing the data for the User Data Header.
+ * @param encoding encoding defined by constants in
+ * com.android.internal.telephony.SmsConstants.ENCODING_*
* @param languageTable
* @param languageShiftTable
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
* @hide
*/
@UnsupportedAppUsage
@@ -301,18 +308,20 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Get an SMS-SUBMIT PDU for a destination address and a message using the
- * specified encoding.
+ * Gets an SMS-SUBMIT PDU for a destination address and a message using the specified encoding.
*
- * @param scAddress Service Centre address. Null means use default.
- * @param encoding Encoding defined by constants in
- * com.android.internal.telephony.SmsConstants.ENCODING_*
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param message string representation of the message payload.
+ * @param statusReportRequested indicates whether a report is reuested for this message.
+ * @param header a byte array containing the data for the User Data Header.
+ * @param encoding encoding defined by constants in
+ * com.android.internal.telephony.SmsConstants.ENCODING_*
* @param languageTable
* @param languageShiftTable
* @param validityPeriod Validity Period of the message in Minutes.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
* @hide
*/
@UnsupportedAppUsage
@@ -484,12 +493,14 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Get an SMS-SUBMIT PDU for a destination address and a message
+ * Gets an SMS-SUBMIT PDU for a destination address and a message.
*
- * @param scAddress Service Centre address. Null means use default.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param message string representation of the message payload.
+ * @param statusReportRequested indicates whether a report is reuested for this message.
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
*/
@UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddress,
@@ -500,15 +511,15 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Get an SMS-SUBMIT PDU for a destination address and a message
+ * Gets an SMS-SUBMIT PDU for a destination address and a message.
*
- * @param scAddress Service Centre address. Null means use default.
- * @param destinationAddress the address of the destination for the message
- * @param statusReportRequested staus report of the message Requested
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param message string representation of the message payload.
+ * @param statusReportRequested indicates whether a report is reuested for this message.
* @param validityPeriod Validity Period of the message in Minutes.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
*/
@UnsupportedAppUsage
public static SubmitPdu getSubmitPdu(String scAddress,
@@ -519,16 +530,15 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
+ * Gets an SMS-SUBMIT PDU for a data message to a destination address &amp; port.
*
- * @param scAddress Service Centre address. null == use default
- * @param destinationAddress the address of the destination for the message
- * @param destinationPort the port to deliver the message to at the
- * destination
- * @param data the data for the message
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
+ * @param destinationPort the port to deliver the message to at the destination.
+ * @param data the data for the message.
+ * @param statusReportRequested indicates whether a report is reuested for this message.
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
*/
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, int destinationPort, byte[] data,
@@ -552,8 +562,7 @@ public class SmsMessage extends SmsMessageBase {
SubmitPdu ret = new SubmitPdu();
ByteArrayOutputStream bo = getSubmitPduHead(
- scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT,
- // TP-UDHI = true
+ scAddress, destinationAddress, (byte) 0x41, /* TP-MTI=SMS-SUBMIT, TP-UDHI=true */
statusReportRequested, ret);
// Skip encoding pdu if error occurs when create pdu head and the error will be handled
// properly later on encodedMessage sanity check.
@@ -580,16 +589,18 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Create the beginning of a SUBMIT PDU. This is the part of the
- * SUBMIT PDU that is common to the two versions of {@link #getSubmitPdu},
- * one of which takes a byte array and the other of which takes a
+ * Creates the beginning of a SUBMIT PDU.
+ *
+ * This is the part of the SUBMIT PDU that is common to the two versions of
+ * {@link #getSubmitPdu}, one of which takes a byte array and the other of which takes a
* <code>String</code>.
*
- * @param scAddress Service Centre address. null == use default
- * @param destinationAddress the address of the destination for the message
+ * @param scAddress Service Centre address. Null means use default.
+ * @param destinationAddress the address of the destination for the message.
* @param mtiByte
- * @param ret <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message. Returns null on encode error.
+ * @param statusReportRequested indicates whether a report is reuested for this message.
+ * @param ret <code>SubmitPdu</code>.
+ * @return a byte array of the beginning of a SUBMIT PDU. Null for invalid destinationAddress.
*/
@UnsupportedAppUsage
private static ByteArrayOutputStream getSubmitPduHead(
@@ -637,6 +648,161 @@ public class SmsMessage extends SmsMessageBase {
return bo;
}
+ /**
+ * Gets an SMS-DELIVER PDU for an originating address and a message.
+ *
+ * @param scAddress Service Centre address. Null means use default.
+ * @param originatingAddress the address of the originating for the message.
+ * @param message string representation of the message payload.
+ * @param date the time stamp the message was received.
+ * @return a <code>SubmitPdu</code> containing the encoded SC address if applicable and the
+ * encoded message. Returns null on encode error.
+ * @hide
+ */
+ public static SubmitPdu getDeliverPdu(
+ String scAddress, String originatingAddress, String message, long date) {
+ if (originatingAddress == null || message == null) {
+ return null;
+ }
+
+ // Find the best encoding to use
+ TextEncodingDetails ted = calculateLength(message, false);
+ int encoding = ted.codeUnitSize;
+ int languageTable = ted.languageTable;
+ int languageShiftTable = ted.languageShiftTable;
+ byte[] header = null;
+
+ if (encoding == ENCODING_7BIT && (languageTable != 0 || languageShiftTable != 0)) {
+ SmsHeader smsHeader = new SmsHeader();
+ smsHeader.languageTable = languageTable;
+ smsHeader.languageShiftTable = languageShiftTable;
+ header = SmsHeader.toByteArray(smsHeader);
+ }
+
+ SubmitPdu ret = new SubmitPdu();
+
+ ByteArrayOutputStream bo = new ByteArrayOutputStream(MAX_USER_DATA_BYTES + 40);
+
+ // SMSC address with length octet, or 0
+ if (scAddress == null) {
+ ret.encodedScAddress = null;
+ } else {
+ ret.encodedScAddress =
+ PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(scAddress);
+ }
+
+ // TP-Message-Type-Indicator
+ bo.write(0); // SMS-DELIVER
+
+ byte[] oaBytes;
+
+ oaBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(originatingAddress);
+
+ // Return null for invalid originating address
+ if (oaBytes == null) return null;
+
+ // Originating address length in BCD digits, ignoring TON byte and pad
+ // TODO Should be better.
+ bo.write((oaBytes.length - 1) * 2 - ((oaBytes[oaBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0));
+
+ // Originating Address
+ bo.write(oaBytes, 0, oaBytes.length);
+
+ // TP-Protocol-Identifier
+ bo.write(0);
+
+ // User Data (and length)
+ byte[] userData;
+ try {
+ if (encoding == ENCODING_7BIT) {
+ userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header,
+ languageTable, languageShiftTable);
+ } else { // Assume UCS-2
+ try {
+ userData = encodeUCS2(message, header);
+ } catch (UnsupportedEncodingException uex) {
+ Rlog.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex);
+ return null;
+ }
+ }
+ } catch (EncodeException ex) {
+ if (ex.getError() == EncodeException.ERROR_EXCEED_SIZE) {
+ Rlog.e(LOG_TAG, "Exceed size limitation EncodeException", ex);
+ return null;
+ } else {
+ // Encoding to the 7-bit alphabet failed. Let's see if we can send it as a UCS-2
+ // encoded message
+ try {
+ userData = encodeUCS2(message, header);
+ encoding = ENCODING_16BIT;
+ } catch (EncodeException ex1) {
+ Rlog.e(LOG_TAG, "Exceed size limitation EncodeException", ex1);
+ return null;
+ } catch (UnsupportedEncodingException uex) {
+ Rlog.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex);
+ return null;
+ }
+ }
+ }
+
+ if (encoding == ENCODING_7BIT) {
+ if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) {
+ // Message too long
+ Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " septets)");
+ return null;
+ }
+ // TP-Data-Coding-Scheme
+ // Default encoding, uncompressed
+ bo.write(0x00);
+ } else { // Assume UCS-2
+ if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) {
+ // Message too long
+ Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " bytes)");
+ return null;
+ }
+ // TP-Data-Coding-Scheme
+ // UCS-2 encoding, uncompressed
+ bo.write(0x08);
+ }
+
+ // TP-Service-Centre-Time-Stamp
+ byte[] scts = new byte[7];
+
+ ZonedDateTime zoneDateTime = Instant.ofEpochMilli(date).atZone(ZoneId.systemDefault());
+ LocalDateTime localDateTime = zoneDateTime.toLocalDateTime();
+
+ // It indicates the difference, expressed in quarters of an hour, between the local time and
+ // GMT.
+ int timezoneOffset = zoneDateTime.getOffset().getTotalSeconds() / 60 / 15;
+ boolean negativeOffset = timezoneOffset < 0;
+ if (negativeOffset) {
+ timezoneOffset = -timezoneOffset;
+ }
+ int year = localDateTime.getYear();
+ int month = localDateTime.getMonthValue();
+ int day = localDateTime.getDayOfMonth();
+ int hour = localDateTime.getHour();
+ int minute = localDateTime.getMinute();
+ int second = localDateTime.getSecond();
+
+ year = year > 2000 ? year - 2000 : year - 1900;
+ scts[0] = (byte) ((((year % 10) & 0x0F) << 4) | ((year / 10) & 0x0F));
+ scts[1] = (byte) ((((month % 10) & 0x0F) << 4) | ((month / 10) & 0x0F));
+ scts[2] = (byte) ((((day % 10) & 0x0F) << 4) | ((day / 10) & 0x0F));
+ scts[3] = (byte) ((((hour % 10) & 0x0F) << 4) | ((hour / 10) & 0x0F));
+ scts[4] = (byte) ((((minute % 10) & 0x0F) << 4) | ((minute / 10) & 0x0F));
+ scts[5] = (byte) ((((second % 10) & 0x0F) << 4) | ((second / 10) & 0x0F));
+ scts[6] = (byte) ((((timezoneOffset % 10) & 0x0F) << 4) | ((timezoneOffset / 10) & 0x0F));
+ if (negativeOffset) {
+ scts[0] |= 0x08; // Negative offset
+ }
+ bo.write(scts, 0, scts.length);
+
+ bo.write(userData, 0, userData.length);
+ ret.encodedMessage = bo.toByteArray();
+ return ret;
+ }
+
private static class PduParser {
@UnsupportedAppUsage
byte mPdu[];
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index a7328acb73b5..3f311c951c7e 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -75,6 +75,9 @@ public class LinkPropertiesTest {
private static final LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
private static final LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
private static final LinkAddress LINKADDRV6LINKLOCAL = new LinkAddress("fe80::1/64");
+ private static final Uri CAPPORT_API_URL = Uri.parse("https://test.example.com/capportapi");
+ private static final CaptivePortalData CAPPORT_DATA = new CaptivePortalData.Builder()
+ .setVenueInfoUrl(Uri.parse("https://test.example.com/venue")).build();
private static InetAddress address(String addrString) {
return InetAddresses.parseNumericAddress(addrString);
@@ -101,6 +104,8 @@ public class LinkPropertiesTest {
assertFalse(lp.isIpv6Provisioned());
assertFalse(lp.isPrivateDnsActive());
assertFalse(lp.isWakeOnLanSupported());
+ assertNull(lp.getCaptivePortalApiUrl());
+ assertNull(lp.getCaptivePortalData());
}
private LinkProperties makeTestObject() {
@@ -124,6 +129,8 @@ public class LinkPropertiesTest {
lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
lp.setDhcpServerAddress(DHCPSERVER);
lp.setWakeOnLanSupported(true);
+ lp.setCaptivePortalApiUrl(CAPPORT_API_URL);
+ lp.setCaptivePortalData(CAPPORT_DATA);
return lp;
}
@@ -165,6 +172,12 @@ public class LinkPropertiesTest {
assertTrue(source.isIdenticalWakeOnLan(target));
assertTrue(target.isIdenticalWakeOnLan(source));
+ assertTrue(source.isIdenticalCaptivePortalApiUrl(target));
+ assertTrue(target.isIdenticalCaptivePortalApiUrl(source));
+
+ assertTrue(source.isIdenticalCaptivePortalData(target));
+ assertTrue(target.isIdenticalCaptivePortalData(source));
+
// Check result of equals().
assertTrue(source.equals(target));
assertTrue(target.equals(source));
@@ -963,6 +976,8 @@ public class LinkPropertiesTest {
source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
source.setWakeOnLanSupported(true);
+ source.setCaptivePortalApiUrl(CAPPORT_API_URL);
+ source.setCaptivePortalData(CAPPORT_DATA);
source.setDhcpServerAddress((Inet4Address) GATEWAY1);
@@ -970,7 +985,13 @@ public class LinkPropertiesTest {
stacked.setInterfaceName("test-stacked");
source.addStackedLink(stacked);
- assertParcelSane(source, 16 /* fieldCount */);
+ assertParcelSane(source.makeSensitiveFieldsParcelingCopy(), 18 /* fieldCount */);
+
+ // Verify that without using a sensitiveFieldsParcelingCopy, sensitive fields are cleared.
+ final LinkProperties sanitized = new LinkProperties(source);
+ sanitized.setCaptivePortalApiUrl(null);
+ sanitized.setCaptivePortalData(null);
+ assertEquals(sanitized, parcelingRoundTrip(source));
}
@Test
@@ -1113,4 +1134,22 @@ public class LinkPropertiesTest {
lp.clear();
assertFalse(lp.isWakeOnLanSupported());
}
+
+ @Test
+ public void testCaptivePortalApiUrl() {
+ final LinkProperties lp = makeTestObject();
+ assertEquals(CAPPORT_API_URL, lp.getCaptivePortalApiUrl());
+
+ lp.clear();
+ assertNull(lp.getCaptivePortalApiUrl());
+ }
+
+ @Test
+ public void testCaptivePortalData() {
+ final LinkProperties lp = makeTestObject();
+ assertEquals(CAPPORT_DATA, lp.getCaptivePortalData());
+
+ lp.clear();
+ assertNull(lp.getCaptivePortalData());
+ }
}
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index 18474a83b368..1c6920986318 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -35,9 +36,9 @@ import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkAgent;
+import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
-import android.net.NetworkMisc;
import android.net.NetworkProvider;
import android.net.NetworkSpecifier;
import android.net.SocketKeepalive;
@@ -74,6 +75,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
final String typeName = ConnectivityManager.getNetworkTypeName(type);
mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
mNetworkCapabilities = new NetworkCapabilities();
+ mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
mNetworkCapabilities.addTransportType(transport);
switch (transport) {
case TRANSPORT_ETHERNET:
@@ -114,7 +116,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
public InstrumentedNetworkAgent(NetworkAgentWrapper wrapper, LinkProperties lp) {
super(wrapper.mHandlerThread.getLooper(), wrapper.mContext, wrapper.mLogTag,
wrapper.mNetworkInfo, wrapper.mNetworkCapabilities, lp, wrapper.mScore,
- new NetworkMisc(), NetworkProvider.ID_NONE);
+ new NetworkAgentConfig(), NetworkProvider.ID_NONE);
mWrapper = wrapper;
}
@@ -206,13 +208,11 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
}
public void suspend() {
- mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, null, null);
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
}
public void resume() {
- mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ addCapability(NET_CAPABILITY_NOT_SUSPENDED);
}
public void disconnect() {
@@ -222,7 +222,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
@Override
public Network getNetwork() {
- return new Network(mNetworkAgent.netId);
+ return mNetworkAgent.network;
}
public void expectPreventReconnectReceived(long timeoutMs) {
diff --git a/tests/net/java/android/net/CaptivePortalDataTest.kt b/tests/net/java/android/net/CaptivePortalDataTest.kt
new file mode 100644
index 000000000000..00714382684f
--- /dev/null
+++ b/tests/net/java/android/net/CaptivePortalDataTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net
+
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.assertParcelSane
+import com.android.testutils.assertParcelingIsLossless
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+import kotlin.test.assertNotEquals
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CaptivePortalDataTest {
+ private val data = CaptivePortalData.Builder()
+ .setRefreshTime(123L)
+ .setUserPortalUrl(Uri.parse("https://portal.example.com/test"))
+ .setVenueInfoUrl(Uri.parse("https://venue.example.com/test"))
+ .setSessionExtendable(true)
+ .setBytesRemaining(456L)
+ .setExpiryTime(789L)
+ .setCaptive(true)
+ .build()
+
+ private fun makeBuilder() = CaptivePortalData.Builder(data)
+
+ @Test
+ fun testParcelUnparcel() {
+ assertParcelSane(data, fieldCount = 7)
+
+ assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build())
+ assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build())
+ }
+
+ @Test
+ fun testEquals() {
+ assertEquals(data, makeBuilder().build())
+
+ assertNotEqualsAfterChange { it.setRefreshTime(456L) }
+ assertNotEqualsAfterChange { it.setUserPortalUrl(Uri.parse("https://example.com/")) }
+ assertNotEqualsAfterChange { it.setUserPortalUrl(null) }
+ assertNotEqualsAfterChange { it.setVenueInfoUrl(Uri.parse("https://example.com/")) }
+ assertNotEqualsAfterChange { it.setVenueInfoUrl(null) }
+ assertNotEqualsAfterChange { it.setSessionExtendable(false) }
+ assertNotEqualsAfterChange { it.setBytesRemaining(789L) }
+ assertNotEqualsAfterChange { it.setExpiryTime(12L) }
+ assertNotEqualsAfterChange { it.setCaptive(false) }
+ }
+
+ private fun CaptivePortalData.mutate(mutator: (CaptivePortalData.Builder) -> Unit) =
+ CaptivePortalData.Builder(this).apply { mutator(this) }.build()
+
+ private fun assertNotEqualsAfterChange(mutator: (CaptivePortalData.Builder) -> Unit) {
+ assertNotEquals(data, data.mutate(mutator))
+ }
+} \ No newline at end of file
diff --git a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java
new file mode 100644
index 000000000000..065add4fc253
--- /dev/null
+++ b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java
@@ -0,0 +1,196 @@
+/*
+ * 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.net;
+
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
+import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
+
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.PersistableBundle;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ConnectivityDiagnosticsManagerTest {
+ private static final int NET_ID = 1;
+ private static final int DETECTION_METHOD = 2;
+ private static final long TIMESTAMP = 10L;
+ private static final String INTERFACE_NAME = "interface";
+ private static final String BUNDLE_KEY = "key";
+ private static final String BUNDLE_VALUE = "value";
+
+ private ConnectivityReport createSampleConnectivityReport() {
+ final LinkProperties linkProperties = new LinkProperties();
+ linkProperties.setInterfaceName(INTERFACE_NAME);
+
+ final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+ networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+
+ final PersistableBundle bundle = new PersistableBundle();
+ bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+ return new ConnectivityReport(
+ new Network(NET_ID), TIMESTAMP, linkProperties, networkCapabilities, bundle);
+ }
+
+ private ConnectivityReport createDefaultConnectivityReport() {
+ return new ConnectivityReport(
+ new Network(0),
+ 0L,
+ new LinkProperties(),
+ new NetworkCapabilities(),
+ PersistableBundle.EMPTY);
+ }
+
+ @Test
+ public void testPersistableBundleEquals() {
+ assertFalse(
+ ConnectivityDiagnosticsManager.persistableBundleEquals(
+ null, PersistableBundle.EMPTY));
+ assertFalse(
+ ConnectivityDiagnosticsManager.persistableBundleEquals(
+ PersistableBundle.EMPTY, null));
+ assertTrue(
+ ConnectivityDiagnosticsManager.persistableBundleEquals(
+ PersistableBundle.EMPTY, PersistableBundle.EMPTY));
+
+ final PersistableBundle a = new PersistableBundle();
+ a.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+ final PersistableBundle b = new PersistableBundle();
+ b.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+ final PersistableBundle c = new PersistableBundle();
+ c.putString(BUNDLE_KEY, null);
+
+ assertFalse(
+ ConnectivityDiagnosticsManager.persistableBundleEquals(PersistableBundle.EMPTY, a));
+ assertFalse(
+ ConnectivityDiagnosticsManager.persistableBundleEquals(a, PersistableBundle.EMPTY));
+
+ assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(a, b));
+ assertTrue(ConnectivityDiagnosticsManager.persistableBundleEquals(b, a));
+
+ assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(a, c));
+ assertFalse(ConnectivityDiagnosticsManager.persistableBundleEquals(c, a));
+ }
+
+ @Test
+ public void testConnectivityReportEquals() {
+ assertEquals(createSampleConnectivityReport(), createSampleConnectivityReport());
+ assertEquals(createDefaultConnectivityReport(), createDefaultConnectivityReport());
+
+ final LinkProperties linkProperties = new LinkProperties();
+ linkProperties.setInterfaceName(INTERFACE_NAME);
+
+ final NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+ networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
+
+ final PersistableBundle bundle = new PersistableBundle();
+ bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+ assertNotEquals(
+ createDefaultConnectivityReport(),
+ new ConnectivityReport(
+ new Network(NET_ID),
+ 0L,
+ new LinkProperties(),
+ new NetworkCapabilities(),
+ PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultConnectivityReport(),
+ new ConnectivityReport(
+ new Network(0),
+ TIMESTAMP,
+ new LinkProperties(),
+ new NetworkCapabilities(),
+ PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultConnectivityReport(),
+ new ConnectivityReport(
+ new Network(0),
+ 0L,
+ linkProperties,
+ new NetworkCapabilities(),
+ PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultConnectivityReport(),
+ new ConnectivityReport(
+ new Network(0),
+ TIMESTAMP,
+ new LinkProperties(),
+ networkCapabilities,
+ PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultConnectivityReport(),
+ new ConnectivityReport(
+ new Network(0),
+ TIMESTAMP,
+ new LinkProperties(),
+ new NetworkCapabilities(),
+ bundle));
+ }
+
+ @Test
+ public void testConnectivityReportParcelUnparcel() {
+ assertParcelSane(createSampleConnectivityReport(), 5);
+ }
+
+ private DataStallReport createSampleDataStallReport() {
+ final PersistableBundle bundle = new PersistableBundle();
+ bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
+ return new DataStallReport(new Network(NET_ID), TIMESTAMP, DETECTION_METHOD, bundle);
+ }
+
+ private DataStallReport createDefaultDataStallReport() {
+ return new DataStallReport(new Network(0), 0L, 0, PersistableBundle.EMPTY);
+ }
+
+ @Test
+ public void testDataStallReportEquals() {
+ assertEquals(createSampleDataStallReport(), createSampleDataStallReport());
+ assertEquals(createDefaultDataStallReport(), createDefaultDataStallReport());
+
+ final PersistableBundle bundle = new PersistableBundle();
+ bundle.putString(BUNDLE_KEY, BUNDLE_VALUE);
+
+ assertNotEquals(
+ createDefaultDataStallReport(),
+ new DataStallReport(new Network(NET_ID), 0L, 0, PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultDataStallReport(),
+ new DataStallReport(new Network(0), TIMESTAMP, 0, PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultDataStallReport(),
+ new DataStallReport(new Network(0), 0L, DETECTION_METHOD, PersistableBundle.EMPTY));
+ assertNotEquals(
+ createDefaultDataStallReport(), new DataStallReport(new Network(0), 0L, 0, bundle));
+ }
+
+ @Test
+ public void testDataStallReportParcelUnparcel() {
+ assertParcelSane(createSampleDataStallReport(), 4);
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b2d363e27839..783f8d177f4a 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -21,6 +21,8 @@ import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_SUPL;
@@ -114,6 +116,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import android.Manifest;
import android.annotation.NonNull;
import android.app.AlarmManager;
import android.app.NotificationManager;
@@ -129,6 +132,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources;
+import android.net.CaptivePortalData;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.ConnectivityManager.PacketKeepalive;
@@ -165,6 +169,7 @@ import android.net.ResolverParamsParcel;
import android.net.RouteInfo;
import android.net.SocketKeepalive;
import android.net.UidRange;
+import android.net.Uri;
import android.net.metrics.IpConnectivityLog;
import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
@@ -243,8 +248,10 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
@@ -347,6 +354,8 @@ public class ConnectivityServiceTest {
@Spy private Resources mResources;
private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
+ // Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant
+ private final HashMap<String, Integer> mMockedPermissions = new HashMap<>();
MockContext(Context base, ContentProvider settingsProvider) {
super(base);
@@ -417,13 +426,39 @@ public class ConnectivityServiceTest {
}
@Override
+ public int checkPermission(String permission, int pid, int uid) {
+ final Integer granted = mMockedPermissions.get(permission);
+ if (granted == null) {
+ // All non-mocked permissions should be held by the test or unnecessary: check as
+ // normal to make sure the code does not rely on unexpected permissions.
+ return super.checkPermission(permission, pid, uid);
+ }
+ return granted;
+ }
+
+ @Override
public void enforceCallingOrSelfPermission(String permission, String message) {
- // The mainline permission can only be held if signed with the network stack certificate
- // Skip testing for this permission.
- if (NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK.equals(permission)) return;
- // All other permissions should be held by the test or unnecessary: check as normal to
- // make sure the code does not rely on unexpected permissions.
- super.enforceCallingOrSelfPermission(permission, message);
+ final Integer granted = mMockedPermissions.get(permission);
+ if (granted == null) {
+ super.enforceCallingOrSelfPermission(permission, message);
+ return;
+ }
+
+ if (!granted.equals(PERMISSION_GRANTED)) {
+ throw new SecurityException("[Test] permission denied: " + permission);
+ }
+ }
+
+ /**
+ * Mock checks for the specified permission, and have them behave as per {@code granted}.
+ *
+ * <p>Passing null reverts to default behavior, which does a real permission check on the
+ * test package.
+ * @param granted One of {@link PackageManager#PERMISSION_GRANTED} or
+ * {@link PackageManager#PERMISSION_DENIED}.
+ */
+ public void setPermission(String permission, Integer granted) {
+ mMockedPermissions.put(permission, granted);
}
@Override
@@ -575,7 +610,7 @@ public class ConnectivityServiceTest {
}
};
- assertEquals(na.netId, nmNetworkCaptor.getValue().netId);
+ assertEquals(na.network.netId, nmNetworkCaptor.getValue().netId);
mNmCallbacks = nmCbCaptor.getValue();
mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor);
@@ -1750,6 +1785,66 @@ public class ConnectivityServiceTest {
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
}
+ private void doNetworkCallbacksSanitizationTest(boolean sanitized) throws Exception {
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ final TestNetworkCallback defaultCallback = new TestNetworkCallback();
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ mCm.registerNetworkCallback(wifiRequest, callback);
+ mCm.registerDefaultNetworkCallback(defaultCallback);
+
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+
+ final LinkProperties newLp = new LinkProperties();
+ final Uri capportUrl = Uri.parse("https://capport.example.com/api");
+ final CaptivePortalData capportData = new CaptivePortalData.Builder()
+ .setCaptive(true).build();
+ newLp.setCaptivePortalApiUrl(capportUrl);
+ newLp.setCaptivePortalData(capportData);
+ mWiFiNetworkAgent.sendLinkProperties(newLp);
+
+ final Uri expectedCapportUrl = sanitized ? null : capportUrl;
+ final CaptivePortalData expectedCapportData = sanitized ? null : capportData;
+ callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
+ Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl())
+ && Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
+ defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
+ Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl())
+ && Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
+
+ final LinkProperties lp = mCm.getLinkProperties(mWiFiNetworkAgent.getNetwork());
+ assertEquals(expectedCapportUrl, lp.getCaptivePortalApiUrl());
+ assertEquals(expectedCapportData, lp.getCaptivePortalData());
+ }
+
+ @Test
+ public void networkCallbacksSanitizationTest_Sanitize() throws Exception {
+ mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ PERMISSION_DENIED);
+ mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
+ PERMISSION_DENIED);
+ doNetworkCallbacksSanitizationTest(true /* sanitized */);
+ }
+
+ @Test
+ public void networkCallbacksSanitizationTest_NoSanitize_NetworkStack() throws Exception {
+ mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ PERMISSION_GRANTED);
+ mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED);
+ doNetworkCallbacksSanitizationTest(false /* sanitized */);
+ }
+
+ @Test
+ public void networkCallbacksSanitizationTest_NoSanitize_Settings() throws Exception {
+ mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ PERMISSION_DENIED);
+ mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ doNetworkCallbacksSanitizationTest(false /* sanitized */);
+ }
+
@Test
public void testMultipleLingering() throws Exception {
// This test would be flaky with the default 120ms timer: that is short enough that
@@ -2628,6 +2723,8 @@ public class ConnectivityServiceTest {
final String testKey = "testkey";
final String testValue = "testvalue";
testBundle.putString(testKey, testValue);
+ mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ PERMISSION_GRANTED);
mCm.startCaptivePortalApp(wifiNetwork, testBundle);
final Intent signInIntent = mServiceContext.expectStartActivityIntent(TIMEOUT_MS);
assertEquals(ACTION_CAPTIVE_PORTAL_SIGN_IN, signInIntent.getAction());
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 82cb1932d2c1..e863266c4b49 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -37,7 +37,6 @@ import android.net.INetd;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
-import android.net.NetworkMisc;
import android.net.NetworkProvider;
import android.net.NetworkScore;
import android.os.INetworkManagementService;
@@ -75,7 +74,6 @@ public class LingerMonitorTest {
@Mock INetd mNetd;
@Mock INetworkManagementService mNMS;
@Mock Context mCtx;
- @Mock NetworkMisc mMisc;
@Mock NetworkNotificationManager mNotifier;
@Mock Resources mResources;
@@ -358,7 +356,7 @@ public class LingerMonitorTest {
NetworkScore ns = new NetworkScore();
ns.putIntExtension(NetworkScore.LEGACY_SCORE, 50);
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
- caps, ns, mCtx, null, mMisc, mConnService, mNetd, mDnsResolver, mNMS,
+ caps, ns, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
NetworkProvider.ID_NONE);
nai.everValidated = true;
return nai;
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index b709af1a02f1..9b248878fe96 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -33,8 +33,8 @@ import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NetworkAgentConfig;
import android.net.NetworkInfo;
-import android.net.NetworkMisc;
import android.os.Handler;
import android.os.INetworkManagementService;
import android.os.test.TestLooper;
@@ -63,7 +63,6 @@ public class Nat464XlatTest {
static final int NETID = 42;
@Mock ConnectivityService mConnectivity;
- @Mock NetworkMisc mMisc;
@Mock IDnsResolver mDnsResolver;
@Mock INetd mNetd;
@Mock INetworkManagementService mNms;
@@ -72,6 +71,7 @@ public class Nat464XlatTest {
TestLooper mLooper;
Handler mHandler;
+ NetworkAgentConfig mAgentConfig = new NetworkAgentConfig();
Nat464Xlat makeNat464Xlat() {
return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) {
@@ -93,7 +93,7 @@ public class Nat464XlatTest {
mNai.networkInfo = new NetworkInfo(null);
mNai.networkInfo.setType(ConnectivityManager.TYPE_WIFI);
when(mNai.connService()).thenReturn(mConnectivity);
- when(mNai.netMisc()).thenReturn(mMisc);
+ when(mNai.netAgentConfig()).thenReturn(mAgentConfig);
when(mNai.handler()).thenReturn(mHandler);
when(mNms.getInterfaceConfig(eq(STACKED_IFACE))).thenReturn(mConfig);
@@ -104,7 +104,7 @@ public class Nat464XlatTest {
String msg = String.format("requiresClat expected %b for type=%d state=%s skip=%b "
+ "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
nai.networkInfo.getDetailedState(),
- mMisc.skip464xlat, nai.linkProperties.getNat64Prefix(),
+ mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(),
nai.linkProperties.getLinkAddresses());
assertEquals(msg, expected, Nat464Xlat.requiresClat(nai));
}
@@ -113,7 +113,7 @@ public class Nat464XlatTest {
String msg = String.format("shouldStartClat expected %b for type=%d state=%s skip=%b "
+ "nat64Prefix=%s addresses=%s", expected, nai.networkInfo.getType(),
nai.networkInfo.getDetailedState(),
- mMisc.skip464xlat, nai.linkProperties.getNat64Prefix(),
+ mAgentConfig.skip464xlat, nai.linkProperties.getNat64Prefix(),
nai.linkProperties.getLinkAddresses());
assertEquals(msg, expected, Nat464Xlat.shouldStartClat(nai));
}
@@ -151,11 +151,11 @@ public class Nat464XlatTest {
assertRequiresClat(true, mNai);
assertShouldStartClat(true, mNai);
- mMisc.skip464xlat = true;
+ mAgentConfig.skip464xlat = true;
assertRequiresClat(false, mNai);
assertShouldStartClat(false, mNai);
- mMisc.skip464xlat = false;
+ mAgentConfig.skip464xlat = false;
assertRequiresClat(true, mNai);
assertShouldStartClat(true, mNai);