Merge "Add tests to services/tests/net test mapping"
diff --git a/Android.bp b/Android.bp
index 3f1fc4d..feaafa3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -53,6 +53,7 @@
"core/java/android/view/DisplayAdjustments.java",
],
path: "core/java",
+ visibility: ["//frameworks/base/test-mock"],
}
filegroup {
@@ -73,6 +74,14 @@
}
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 @@
":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 @@
":platform-compat-native-aidl",
// AIDL sources from external directories
+ ":credstore_aidl",
":dumpstate_aidl",
":framework_native_aidl",
":gatekeeper_aidl",
@@ -289,6 +300,7 @@
"core/java",
"drm/java",
"graphics/java",
+ "identity/java",
"keystore/java",
"location/java",
"lowpan/java",
@@ -514,7 +526,6 @@
host_supported: true,
srcs: [
"core/java/android/annotation/IntDef.java",
- "core/java/android/annotation/UnsupportedAppUsage.java",
],
static_libs: [
"art.module.api.annotations",
@@ -540,7 +551,7 @@
genrule {
name: "framework-statslog-gen",
tools: ["stats-log-api-gen"],
- cmd: "$(location stats-log-api-gen) --java $(out)",
+ cmd: "$(location stats-log-api-gen) --java $(out) --worksource",
out: ["android/util/StatsLogInternal.java"],
}
@@ -579,7 +590,6 @@
"core/java/android/annotation/IntDef.java",
"core/java/android/annotation/IntRange.java",
"core/java/android/annotation/SystemApi.java",
- "core/java/android/annotation/UnsupportedAppUsage.java",
"core/java/com/android/internal/annotations/GuardedBy.java",
"core/java/com/android/internal/annotations/VisibleForTesting.java",
],
@@ -595,6 +605,7 @@
name: "framework-ike-shared-srcs",
visibility: ["//frameworks/opt/net/ike"],
srcs: [
+ "core/java/android/annotation/StringDef.java",
"core/java/android/net/annotations/PolicyDirection.java",
"core/java/com/android/internal/util/IState.java",
"core/java/com/android/internal/util/State.java",
@@ -645,7 +656,11 @@
name: "framework-tethering-annotations",
srcs: [
"core/java/android/annotation/NonNull.java",
+ "core/java/android/annotation/Nullable.java",
+ "core/java/android/annotation/RequiresPermission.java",
"core/java/android/annotation/SystemApi.java",
+ "core/java/android/annotation/TestApi.java",
+ "core/java/com/android/internal/annotations/GuardedBy.java",
],
}
// Build ext.jar
@@ -911,7 +926,6 @@
"core/java/android/annotation/Nullable.java",
"core/java/android/annotation/SystemApi.java",
"core/java/android/annotation/TestApi.java",
- "core/java/android/annotation/UnsupportedAppUsage.java",
"core/java/android/os/HidlMemory.java",
"core/java/android/os/HwBinder.java",
"core/java/android/os/HwBlob.java",
@@ -978,7 +992,6 @@
"core/java/android/annotation/StringDef.java",
"core/java/android/annotation/SystemApi.java",
"core/java/android/annotation/TestApi.java",
- "core/java/android/annotation/UnsupportedAppUsage.java",
"core/java/com/android/internal/annotations/GuardedBy.java",
],
}
@@ -1025,6 +1038,7 @@
"core/java/android/util/TimeUtils.java",
"core/java/com/android/internal/os/SomeArgs.java",
"core/java/com/android/internal/util/AsyncChannel.java",
+ "core/java/com/android/internal/util/AsyncService.java",
"core/java/com/android/internal/util/BitwiseInputStream.java",
"core/java/com/android/internal/util/FastXmlSerializer.java",
"core/java/com/android/internal/util/HexDump.java",
@@ -1047,7 +1061,11 @@
"--hide MissingPermission --hide BroadcastBehavior " +
"--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
"--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " +
- "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.*"
+ "--force-convert-to-warning-nullability-annotations +*:-android.*:+android.icu.*:-dalvik.* " +
+ "--api-lint-ignore-prefix android.icu. " +
+ "--api-lint-ignore-prefix java. " +
+ "--api-lint-ignore-prefix junit. " +
+ "--api-lint-ignore-prefix org. "
build = [
"StubLibraries.bp",
diff --git a/apex/sdkextensions/OWNERS b/apex/sdkextensions/OWNERS
index feb2742..a6e5522 100644
--- a/apex/sdkextensions/OWNERS
+++ b/apex/sdkextensions/OWNERS
@@ -1 +1,2 @@
+dariofreni@google.com
hansson@google.com
diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index dd17473..245a96b 100644
--- a/apex/sdkextensions/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -32,6 +32,7 @@
libs: [ "framework-annotations-lib" ],
permitted_packages: [ "android.os.ext" ],
installable: true,
+ plugins: ["java_api_finder"],
visibility: [
"//frameworks/base/apex/sdkextensions",
"//frameworks/base/apex/sdkextensions/testing",
diff --git a/api/current.txt b/api/current.txt
index bdb0c8a..ce28b95 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9824,6 +9824,7 @@
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
@@ -9872,6 +9873,7 @@
field public static final String STORAGE_STATS_SERVICE = "storagestats";
field public static final String SYSTEM_HEALTH_SERVICE = "systemhealth";
field public static final String TELECOM_SERVICE = "telecom";
+ field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
field public static final String TELEPHONY_SERVICE = "phone";
field public static final String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service";
field public static final String TEXT_CLASSIFICATION_SERVICE = "textclassification";
@@ -9882,6 +9884,7 @@
field public static final String USB_SERVICE = "usb";
field public static final String USER_SERVICE = "user";
field public static final String VIBRATOR_SERVICE = "vibrator";
+ field public static final String VPN_MANAGEMENT_SERVICE = "vpn_management";
field public static final String WALLPAPER_SERVICE = "wallpaper";
field public static final String WIFI_AWARE_SERVICE = "wifiaware";
field public static final String WIFI_P2P_SERVICE = "wifip2p";
@@ -16637,7 +16640,9 @@
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 +17580,9 @@
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();
}
@@ -17964,6 +17971,7 @@
field public static final int RIGHT = 7; // 0x7
field public static final int TOP = 8; // 0x8
field public static final int TOP_AND_BOTTOM = 9; // 0x9
+ field public static final int TOP_AND_BOTTOM_AND_LEFT = 15; // 0xf
field public static final int TOP_AND_BOTTOM_AND_RIGHT = 10; // 0xa
field public static final int TOP_AND_LEFT = 11; // 0xb
field public static final int TOP_AND_LEFT_AND_RIGHT = 12; // 0xc
@@ -18286,6 +18294,8 @@
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;
field public static final int CJK_COMPATIBILITY_FORMS_ID = 83; // 0x53
@@ -18313,6 +18323,8 @@
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;
field public static final android.icu.lang.UCharacter.UnicodeBlock COMBINING_DIACRITICAL_MARKS_EXTENDED;
@@ -18362,6 +18374,8 @@
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
field public static final android.icu.lang.UCharacter.UnicodeBlock DOMINO_TILES;
@@ -18490,6 +18504,8 @@
field public static final int KAYAH_LI_ID = 162; // 0xa2
field public static final android.icu.lang.UCharacter.UnicodeBlock KHAROSHTHI;
field public static final int KHAROSHTHI_ID = 137; // 0x89
+ field public static final android.icu.lang.UCharacter.UnicodeBlock KHITAN_SMALL_SCRIPT;
+ field public static final int KHITAN_SMALL_SCRIPT_ID = 304; // 0x130
field public static final android.icu.lang.UCharacter.UnicodeBlock KHMER;
field public static final int KHMER_ID = 36; // 0x24
field public static final android.icu.lang.UCharacter.UnicodeBlock KHMER_SYMBOLS;
@@ -18528,6 +18544,8 @@
field public static final int LINEAR_B_SYLLABARY_ID = 117; // 0x75
field public static final android.icu.lang.UCharacter.UnicodeBlock LISU;
field public static final int LISU_ID = 176; // 0xb0
+ field public static final android.icu.lang.UCharacter.UnicodeBlock LISU_SUPPLEMENT;
+ field public static final int LISU_SUPPLEMENT_ID = 305; // 0x131
field public static final android.icu.lang.UCharacter.UnicodeBlock LOW_SURROGATES;
field public static final int LOW_SURROGATES_ID = 77; // 0x4d
field public static final android.icu.lang.UCharacter.UnicodeBlock LYCIAN;
@@ -18739,6 +18757,8 @@
field public static final int SYLOTI_NAGRI_ID = 143; // 0x8f
field public static final android.icu.lang.UCharacter.UnicodeBlock SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A;
field public static final int SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A_ID = 298; // 0x12a
+ field public static final android.icu.lang.UCharacter.UnicodeBlock SYMBOLS_FOR_LEGACY_COMPUTING;
+ field public static final int SYMBOLS_FOR_LEGACY_COMPUTING_ID = 306; // 0x132
field public static final android.icu.lang.UCharacter.UnicodeBlock SYRIAC;
field public static final int SYRIAC_ID = 13; // 0xd
field public static final android.icu.lang.UCharacter.UnicodeBlock SYRIAC_SUPPLEMENT;
@@ -18767,6 +18787,8 @@
field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT_COMPONENTS;
field public static final int TANGUT_COMPONENTS_ID = 273; // 0x111
field public static final int TANGUT_ID = 272; // 0x110
+ field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT_SUPPLEMENT;
+ field public static final int TANGUT_SUPPLEMENT_ID = 307; // 0x133
field public static final android.icu.lang.UCharacter.UnicodeBlock TELUGU;
field public static final int TELUGU_ID = 21; // 0x15
field public static final android.icu.lang.UCharacter.UnicodeBlock THAANA;
@@ -18801,6 +18823,8 @@
field public static final int WANCHO_ID = 300; // 0x12c
field public static final android.icu.lang.UCharacter.UnicodeBlock WARANG_CITI;
field public static final int WARANG_CITI_ID = 252; // 0xfc
+ field public static final android.icu.lang.UCharacter.UnicodeBlock YEZIDI;
+ field public static final int YEZIDI_ID = 308; // 0x134
field public static final android.icu.lang.UCharacter.UnicodeBlock YIJING_HEXAGRAM_SYMBOLS;
field public static final int YIJING_HEXAGRAM_SYMBOLS_ID = 116; // 0x74
field public static final android.icu.lang.UCharacter.UnicodeBlock YI_RADICALS;
@@ -19097,6 +19121,7 @@
field public static final int CHAKMA = 118; // 0x76
field public static final int CHAM = 66; // 0x42
field public static final int CHEROKEE = 6; // 0x6
+ field public static final int CHORASMIAN = 189; // 0xbd
field public static final int CIRTH = 67; // 0x43
field public static final int COMMON = 0; // 0x0
field public static final int COPTIC = 7; // 0x7
@@ -19106,6 +19131,7 @@
field public static final int DEMOTIC_EGYPTIAN = 69; // 0x45
field public static final int DESERET = 9; // 0x9
field public static final int DEVANAGARI = 10; // 0xa
+ field public static final int DIVES_AKURU = 190; // 0xbe
field public static final int DOGRA = 178; // 0xb2
field public static final int DUPLOYAN = 135; // 0x87
field public static final int EASTERN_SYRIAC = 97; // 0x61
@@ -19147,6 +19173,7 @@
field public static final int KATAKANA_OR_HIRAGANA = 54; // 0x36
field public static final int KAYAH_LI = 79; // 0x4f
field public static final int KHAROSHTHI = 57; // 0x39
+ field public static final int KHITAN_SMALL_SCRIPT = 191; // 0xbf
field public static final int KHMER = 23; // 0x17
field public static final int KHOJKI = 157; // 0x9d
field public static final int KHUDAWADI = 145; // 0x91
@@ -19264,6 +19291,7 @@
field public static final int WARANG_CITI = 146; // 0x92
field public static final int WESTERN_SYRIAC = 96; // 0x60
field public static final int WOLEAI = 155; // 0x9b
+ field public static final int YEZIDI = 192; // 0xc0
field public static final int YI = 41; // 0x29
field public static final int ZANABAZAR_SQUARE = 177; // 0xb1
}
@@ -22519,6 +22547,7 @@
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;
@@ -28665,8 +28694,6 @@
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 {
@@ -28676,21 +28703,44 @@
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;
+ field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttemped";
+ field public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded";
+ field public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
+ field public static final int NETWORK_PROBE_DNS = 4; // 0x4
+ field public static final int NETWORK_PROBE_FALLBACK = 32; // 0x20
+ field public static final int NETWORK_PROBE_HTTP = 8; // 0x8
+ field public static final int NETWORK_PROBE_HTTPS = 16; // 0x10
+ field public static final int NETWORK_PROBE_PRIVATE_DNS = 64; // 0x40
+ field public static final int NETWORK_VALIDATION_RESULT_INVALID = 0; // 0x0
+ field public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2; // 0x2
+ field public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3; // 0x3
+ field public static final int NETWORK_VALIDATION_RESULT_VALID = 1; // 0x1
}
- 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
+ field public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
+ field public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS = "tcpMetricsCollectionPeriodMillis";
+ field public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
}
public class ConnectivityManager {
@@ -28833,6 +28883,35 @@
field public final int code;
}
+ public final class Ikev2VpnProfile extends android.net.PlatformVpnProfile {
+ method @NonNull public java.util.List<java.lang.String> getAllowedAlgorithms();
+ method public int getMaxMtu();
+ method @Nullable public String getPassword();
+ method @Nullable public byte[] getPresharedKey();
+ method @Nullable public android.net.ProxyInfo getProxyInfo();
+ method @Nullable public java.security.PrivateKey getRsaPrivateKey();
+ method @NonNull public String getServerAddr();
+ method @Nullable public java.security.cert.X509Certificate getServerRootCaCert();
+ method @Nullable public java.security.cert.X509Certificate getUserCert();
+ method @NonNull public String getUserIdentity();
+ method @Nullable public String getUsername();
+ method public boolean isBypassable();
+ method public boolean isMetered();
+ }
+
+ public static final class Ikev2VpnProfile.Builder {
+ ctor public Ikev2VpnProfile.Builder(@NonNull String, @NonNull String);
+ method @NonNull public android.net.Ikev2VpnProfile build();
+ method @NonNull public android.net.Ikev2VpnProfile.Builder setAllowedAlgorithms(@NonNull java.util.List<java.lang.String>);
+ method @NonNull public android.net.Ikev2VpnProfile.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey, @Nullable java.security.cert.X509Certificate);
+ method @NonNull public android.net.Ikev2VpnProfile.Builder setAuthPsk(@NonNull byte[]);
+ method @NonNull public android.net.Ikev2VpnProfile.Builder setAuthUsernamePassword(@NonNull String, @NonNull String, @Nullable java.security.cert.X509Certificate);
+ method @NonNull public android.net.Ikev2VpnProfile.Builder setBypassable(boolean);
+ method @NonNull public android.net.Ikev2VpnProfile.Builder setMaxMtu(int);
+ method @NonNull public android.net.Ikev2VpnProfile.Builder setMetered(boolean);
+ method @NonNull public android.net.Ikev2VpnProfile.Builder setProxy(@Nullable android.net.ProxyInfo);
+ }
+
public class InetAddresses {
method public static boolean isNumericAddress(@NonNull String);
method @NonNull public static java.net.InetAddress parseNumericAddress(@NonNull String);
@@ -29061,6 +29140,7 @@
method public int getLinkDownstreamBandwidthKbps();
method public int getLinkUpstreamBandwidthKbps();
method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
+ method public int getOwnerUid();
method public int getSignalStrength();
method @Nullable public android.net.TransportInfo getTransportInfo();
method public boolean hasCapability(int);
@@ -29070,6 +29150,7 @@
method @NonNull public android.net.NetworkCapabilities setLinkDownstreamBandwidthKbps(int);
method @NonNull public android.net.NetworkCapabilities setLinkUpstreamBandwidthKbps(int);
method @NonNull public android.net.NetworkCapabilities setNetworkSpecifier(@NonNull android.net.NetworkSpecifier);
+ method public void setOwnerUid(int);
method @NonNull public android.net.NetworkCapabilities setSignalStrength(int);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR;
@@ -29167,7 +29248,7 @@
method @NonNull public android.net.NetworkRequest.Builder clearCapabilities();
method public android.net.NetworkRequest.Builder removeCapability(int);
method public android.net.NetworkRequest.Builder removeTransportType(int);
- method public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
+ method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
}
@@ -29179,6 +29260,14 @@
field public String response;
}
+ public abstract class PlatformVpnProfile {
+ method public final int getType();
+ method @NonNull public final String getTypeString();
+ field public static final int TYPE_IKEV2_IPSEC_PSK = 7; // 0x7
+ field public static final int TYPE_IKEV2_IPSEC_RSA = 8; // 0x8
+ field public static final int TYPE_IKEV2_IPSEC_USER_PASS = 6; // 0x6
+ }
+
public final class Proxy {
ctor public Proxy();
method @Deprecated public static String getDefaultHost();
@@ -29266,6 +29355,19 @@
method public void onStopped();
}
+ public final class TelephonyNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getSubscriptionId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TelephonyNetworkSpecifier> CREATOR;
+ }
+
+ public static final class TelephonyNetworkSpecifier.Builder {
+ ctor public TelephonyNetworkSpecifier.Builder();
+ method @NonNull public android.net.TelephonyNetworkSpecifier build();
+ method @NonNull public android.net.TelephonyNetworkSpecifier.Builder setSubscriptionId(int);
+ }
+
public class TrafficStats {
ctor public TrafficStats();
method public static void clearThreadStatsTag();
@@ -29446,6 +29548,13 @@
method public String sanitize(String);
}
+ public class VpnManager {
+ method public void deleteProvisionedVpnProfile();
+ method @Nullable public android.content.Intent provisionVpnProfile(@NonNull android.net.PlatformVpnProfile);
+ method public void startProvisionedVpnProfile();
+ method public void stopProvisionedVpnProfile();
+ }
+
public class VpnService extends android.app.Service {
ctor public VpnService();
method public final boolean isAlwaysOn();
@@ -29679,6 +29788,7 @@
method public void close();
method public void continueCall(int) throws android.net.sip.SipException;
method public void endCall() throws android.net.sip.SipException;
+ method @Nullable public android.net.rtp.AudioGroup getAudioGroup();
method public android.net.sip.SipProfile getLocalProfile();
method public android.net.sip.SipProfile getPeerProfile();
method public int getState();
@@ -29689,6 +29799,7 @@
method public void makeCall(android.net.sip.SipProfile, android.net.sip.SipSession, int) throws android.net.sip.SipException;
method public void sendDtmf(int);
method public void sendDtmf(int, android.os.Message);
+ method public void setAudioGroup(@NonNull android.net.rtp.AudioGroup);
method public void setListener(android.net.sip.SipAudioCall.Listener);
method public void setListener(android.net.sip.SipAudioCall.Listener, boolean);
method public void setSpeakerMode(boolean);
@@ -29737,6 +29848,7 @@
method public void close(String) throws android.net.sip.SipException;
method public android.net.sip.SipSession createSipSession(android.net.sip.SipProfile, android.net.sip.SipSession.Listener) throws android.net.sip.SipException;
method public static String getCallId(android.content.Intent);
+ method @NonNull public java.util.List<android.net.sip.SipProfile> getListOfProfiles() throws android.net.sip.SipException;
method public static String getOfferSessionDescription(android.content.Intent);
method public android.net.sip.SipSession getSessionFor(android.content.Intent) throws android.net.sip.SipException;
method public static boolean isApiSupported(android.content.Context);
@@ -29754,6 +29866,11 @@
method public void setRegistrationListener(String, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
method public android.net.sip.SipAudioCall takeAudioCall(android.content.Intent, android.net.sip.SipAudioCall.Listener) throws android.net.sip.SipException;
method public void unregister(android.net.sip.SipProfile, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException;
+ field public static final String ACTION_SIP_CALL_OPTION_CHANGED = "android.net.sip.action.SIP_CALL_OPTION_CHANGED";
+ field public static final String ACTION_SIP_INCOMING_CALL = "android.net.sip.action.SIP_INCOMING_CALL";
+ field public static final String ACTION_SIP_REMOVE_PROFILE = "android.net.sip.action.SIP_REMOVE_PROFILE";
+ field public static final String ACTION_SIP_SERVICE_UP = "android.net.sip.action.SIP_SERVICE_UP";
+ field public static final String ACTION_START_SIP = "android.net.sip.action.START_SIP";
field public static final String EXTRA_CALL_ID = "android:sipCallID";
field public static final String EXTRA_OFFER_SD = "android:sipOfferSD";
field public static final int INCOMING_CALL_RESULT_CODE = 101; // 0x65
@@ -29763,6 +29880,7 @@
method public int describeContents();
method public String getAuthUserName();
method public boolean getAutoRegistration();
+ method public int getCallingUid();
method public String getDisplayName();
method public String getPassword();
method public int getPort();
@@ -29773,6 +29891,7 @@
method public String getSipDomain();
method public String getUriString();
method public String getUserName();
+ method public void setCallingUid(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.sip.SipProfile> CREATOR;
}
@@ -29865,7 +29984,9 @@
package android.net.wifi {
public class ScanResult implements android.os.Parcelable {
+ ctor public ScanResult(@NonNull android.net.wifi.ScanResult);
method public int describeContents();
+ method @NonNull public java.util.List<android.net.wifi.ScanResult.InformationElement> getInformationElements();
method public boolean is80211mcResponder();
method public boolean isPasspointNetwork();
method public void writeToParcel(android.os.Parcel, int);
@@ -29875,6 +29996,7 @@
field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1
field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2
field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.ScanResult> CREATOR;
field public String SSID;
field public String capabilities;
field public int centerFreq0;
@@ -29887,6 +30009,12 @@
field public CharSequence venueName;
}
+ public static class ScanResult.InformationElement {
+ ctor public ScanResult.InformationElement(@NonNull android.net.wifi.ScanResult.InformationElement);
+ method @NonNull public java.nio.ByteBuffer getBytes();
+ method public int getId();
+ }
+
public enum SupplicantState implements android.os.Parcelable {
method public int describeContents();
method public static boolean isValidState(android.net.wifi.SupplicantState);
@@ -35281,7 +35409,7 @@
method public boolean isSustainedPerformanceModeSupported();
method public boolean isWakeLockLevelSupported(int);
method public android.os.PowerManager.WakeLock newWakeLock(int, String);
- method public void reboot(@Nullable String);
+ method @RequiresPermission(android.Manifest.permission.REBOOT) public void reboot(@Nullable String);
method public void removeThermalStatusListener(@NonNull android.os.PowerManager.OnThermalStatusChangedListener);
field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
field public static final String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
@@ -37191,6 +37319,7 @@
field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
field public static final int FEATURES_RTT = 32; // 0x20
field public static final int FEATURES_VIDEO = 1; // 0x1
+ field public static final int FEATURES_VOLTE = 64; // 0x40
field public static final int FEATURES_WIFI = 8; // 0x8
field public static final String GEOCODED_LOCATION = "geocoded_location";
field public static final int INCOMING_TYPE = 1; // 0x1
@@ -40880,6 +41009,7 @@
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();
@@ -41017,6 +41147,138 @@
}
+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 {
@@ -43300,6 +43562,7 @@
method public java.util.List<android.telecom.Call> getChildren();
method public java.util.List<android.telecom.Call> getConferenceableCalls();
method public android.telecom.Call.Details getDetails();
+ method @Nullable public android.telecom.Call getGenericConferenceActiveChildCall();
method public android.telecom.Call getParent();
method public String getRemainingPostDialSequence();
method @Nullable public android.telecom.Call.RttCall getRttCall();
@@ -43317,6 +43580,7 @@
method public void registerCallback(android.telecom.Call.Callback);
method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
method public void reject(boolean, String);
+ method public void reject(int);
method public void removeExtras(java.util.List<java.lang.String>);
method public void removeExtras(java.lang.String...);
method public void respondToRttRequest(int, boolean);
@@ -43332,6 +43596,8 @@
field public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
field public static final String EXTRA_SILENT_RINGING_REQUESTED = "android.telecom.extra.SILENT_RINGING_REQUESTED";
field public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS = "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS";
+ field public static final int REJECT_REASON_DECLINED = 1; // 0x1
+ field public static final int REJECT_REASON_UNWANTED = 2; // 0x2
field public static final int STATE_ACTIVE = 4; // 0x4
field public static final int STATE_AUDIO_PROCESSING = 12; // 0xc
field public static final int STATE_CONNECTING = 9; // 0x9
@@ -43383,6 +43649,7 @@
method public int getCallerDisplayNamePresentation();
method public int getCallerNumberVerificationStatus();
method public final long getConnectTimeMillis();
+ method @Nullable public String getContactDisplayName();
method public long getCreationTimeMillis();
method public android.telecom.DisconnectCause getDisconnectCause();
method public android.os.Bundle getExtras();
@@ -43424,6 +43691,7 @@
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
@@ -43501,6 +43769,7 @@
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();
@@ -43515,6 +43784,8 @@
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();
@@ -43523,6 +43794,7 @@
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();
@@ -43542,6 +43814,8 @@
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);
@@ -43591,6 +43865,7 @@
method public void onPostDialContinue(boolean);
method public void onPullExternalCall();
method public void onReject();
+ method public void onReject(int);
method public void onReject(String);
method public void onSeparate();
method public void onShowIncomingCallUi();
@@ -43699,6 +43974,7 @@
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
@@ -43771,8 +44047,10 @@
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;
@@ -43792,9 +44070,13 @@
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);
@@ -43909,6 +44191,7 @@
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
@@ -44104,6 +44387,7 @@
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();
@@ -44131,6 +44415,7 @@
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";
@@ -44229,6 +44514,8 @@
package android.telephony {
public final class AccessNetworkConstants {
+ field public static final int TRANSPORT_TYPE_WLAN = 2; // 0x2
+ field public static final int TRANSPORT_TYPE_WWAN = 1; // 0x1
}
public static final class AccessNetworkConstants.AccessNetworkType {
@@ -44376,6 +44663,12 @@
field public static final int BAND_7 = 7; // 0x7
field public static final int BAND_8 = 8; // 0x8
field public static final int BAND_9 = 9; // 0x9
+ field public static final int BAND_A = 101; // 0x65
+ field public static final int BAND_B = 102; // 0x66
+ field public static final int BAND_C = 103; // 0x67
+ field public static final int BAND_D = 104; // 0x68
+ field public static final int BAND_E = 105; // 0x69
+ field public static final int BAND_F = 106; // 0x6a
}
public final class AvailableNetworkInfo implements android.os.Parcelable {
@@ -44403,9 +44696,13 @@
field public static final int DATA_CYCLE_USE_PLATFORM_DEFAULT = -1; // 0xffffffff
field public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
+ field public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int";
+ field public static final String KEY_5G_ICON_CONFIGURATION_STRING = "5g_icon_configuration_string";
+ field public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT = "5g_icon_display_grace_period_sec_int";
field public static final String KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrp_thresholds_int_array";
field public static final String KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrq_thresholds_int_array";
field public static final String KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY = "5g_nr_sssinr_thresholds_int_array";
+ field public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = "5g_watchdog_time_long";
field public static final String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
field public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
field public static final String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
@@ -44416,18 +44713,32 @@
field public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool";
field public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool";
field public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool";
+ field public static final String KEY_ALLOW_VIDEO_CALLING_FALLBACK_BOOL = "allow_video_calling_fallback_bool";
+ field public static final String KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL = "always_show_data_rat_icon_bool";
field @Deprecated public static final String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool";
+ field public static final String KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN = "always_show_primary_signal_bar_in_opportunistic_network_boolean";
field public static final String KEY_APN_EXPAND_BOOL = "apn_expand_bool";
+ field public static final String KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY = "apn_settings_default_apn_types_string_array";
field public static final String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool";
field public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool";
field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool";
field public static final String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array";
+ field public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING = "call_redirection_service_component_name_string";
+ field public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL = "carrier_allow_deflect_ims_call_bool";
field public static final String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
field public static final String KEY_CARRIER_APP_REQUIRED_DURING_SIM_SETUP_BOOL = "carrier_app_required_during_setup_bool";
field public static final String KEY_CARRIER_CALL_SCREENING_APP_STRING = "call_screening_app";
+ field public static final String KEY_CARRIER_CERTIFICATE_STRING_ARRAY = "carrier_certificate_string_array";
+ field public static final String KEY_CARRIER_CONFIG_APPLIED_BOOL = "carrier_config_applied_bool";
field public static final String KEY_CARRIER_CONFIG_VERSION_STRING = "carrier_config_version_string";
field public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings";
+ field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY = "carrier_default_actions_on_dcfailure_string_array";
+ field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE = "carrier_default_actions_on_default_network_available_string_array";
+ field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY = "carrier_default_actions_on_redirection_string_array";
+ field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET = "carrier_default_actions_on_reset_string_array";
+ field public static final String KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY = "carrier_default_redirection_url_string_array";
+ field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL = "carrier_default_wfc_ims_enabled_bool";
field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT = "carrier_default_wfc_ims_mode_int";
field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT = "carrier_default_wfc_ims_roaming_mode_int";
field @Deprecated public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL = "carrier_force_disable_etws_cmas_test_bool";
@@ -44440,11 +44751,13 @@
field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool";
field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool";
+ field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string";
field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool";
field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
field public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool";
field public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
+ field public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL = "carrier_volte_override_wfc_provisioning_bool";
field public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
field public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
field public static final String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
@@ -44458,6 +44771,7 @@
field public static final String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
field public static final String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int";
field public static final String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
+ field public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL = "check_pricing_with_carrier_data_roaming_bool";
field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool";
field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string";
@@ -44467,10 +44781,12 @@
field public static final String KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING = "config_ims_rcs_package_override_string";
field public static final String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string";
field public static final String KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL = "config_telephony_use_own_number_for_voicemail_bool";
+ field public static final String KEY_CONFIG_WIFI_DISABLE_IN_ECBM = "config_wifi_disable_in_ecbm";
field public static final String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool";
field public static final String KEY_DATA_LIMIT_NOTIFICATION_BOOL = "data_limit_notification_bool";
field public static final String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long";
field public static final String KEY_DATA_RAPID_NOTIFICATION_BOOL = "data_rapid_notification_bool";
+ field public static final String KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG = "data_switch_validation_timeout_long";
field public static final String KEY_DATA_WARNING_NOTIFICATION_BOOL = "data_warning_notification_bool";
field public static final String KEY_DATA_WARNING_THRESHOLD_BYTES_LONG = "data_warning_threshold_bytes_long";
field public static final String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
@@ -44478,6 +44794,7 @@
field public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
field public static final String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
field public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+ field public static final String KEY_DISABLE_CHARGE_INDICATION_BOOL = "disable_charge_indication_bool";
field public static final String KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL = "disable_supplementary_services_in_airplane_mode_bool";
field public static final String KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY = "disconnect_cause_play_busytone_int_array";
field public static final String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool";
@@ -44487,9 +44804,13 @@
field public static final String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
+ field public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool";
+ field public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL = "editable_wfc_roaming_mode_bool";
+ field public static final String KEY_EMERGENCY_NOTIFICATION_DELAY_INT = "emergency_notification_delay_int";
field public static final String KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY = "emergency_number_prefix_string_array";
field public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool";
+ field public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT = "enhanced_4g_lte_title_variant_int";
field public static final String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
field public static final String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
field public static final String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
@@ -44498,13 +44819,17 @@
field public static final String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
field public static final String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
field public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
+ field public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL = "hide_lte_plus_data_icon_bool";
field public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
field public static final String KEY_HIDE_PRESET_APN_DETAILS_BOOL = "hide_preset_apn_details_bool";
field public static final String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
+ field public static final String KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS = "ignore_data_enabled_changed_for_video_calls";
+ field public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL = "ignore_rtt_mode_setting_bool";
field public static final String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
field public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int";
field public static final String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
field public static final String KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL = "is_ims_conference_size_enforced_bool";
+ field public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool";
field public static final String KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY = "lte_rsrq_thresholds_int_array";
field public static final String KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY = "lte_rssnr_thresholds_int_array";
field public static final String KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL = "mdn_is_additional_voicemail_number_bool";
@@ -44513,6 +44838,7 @@
field public static final String KEY_MMS_ALIAS_MIN_CHARS_INT = "aliasMinChars";
field public static final String KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL = "allowAttachAudio";
field public static final String KEY_MMS_APPEND_TRANSACTION_ID_BOOL = "enabledTransID";
+ field public static final String KEY_MMS_CLOSE_CONNECTION_BOOL = "mmsCloseConnection";
field public static final String KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING = "emailGatewayNumber";
field public static final String KEY_MMS_GROUP_MMS_ENABLED_BOOL = "enableGroupMms";
field public static final String KEY_MMS_HTTP_PARAMS_STRING = "httpParams";
@@ -44540,8 +44866,11 @@
field public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl";
field public static final String KEY_MMS_USER_AGENT_STRING = "userAgent";
field public static final String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int";
+ field public static final String KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = "only_auto_select_in_home_network";
field public static final String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array";
field public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool";
+ field public static final String KEY_OPPORTUNISTIC_NETWORK_BACKOFF_TIME_LONG = "opportunistic_network_backoff_time_long";
+ field public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG = "opportunistic_network_data_switch_exit_hysteresis_time_long";
field public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG = "opportunistic_network_data_switch_hysteresis_time_long";
field public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_OR_EXIT_HYSTERESIS_TIME_LONG = "opportunistic_network_entry_or_exit_hysteresis_time_long";
field public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_BANDWIDTH_INT = "opportunistic_network_entry_threshold_bandwidth_int";
@@ -44549,34 +44878,54 @@
field public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT = "opportunistic_network_entry_threshold_rssnr_int";
field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int";
field public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int";
+ field public static final String KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG = "opportunistic_network_max_backoff_time_long";
+ field public static final String KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG = "opportunistic_network_ping_pong_time_long";
+ field public static final String KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL = "ping_test_before_data_switch_bool";
field public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
field public static final String KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL = "prevent_clir_activation_and_deactivation_code_bool";
field public static final String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array";
field public static final String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string";
+ field public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY = "read_only_apn_fields_string_array";
+ field public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY = "read_only_apn_types_string_array";
field public static final String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
field @Deprecated public static final String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool";
field public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
+ field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool";
+ field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool";
field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
+ field public static final String KEY_SHOW_BLOCKING_PAY_PHONE_OPTION_BOOL = "show_blocking_pay_phone_option_bool";
field public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool";
+ field public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING = "show_carrier_data_icon_pattern_string";
field public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
field public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
+ field public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL = "show_ims_registration_status_bool";
field public static final String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
field public static final String KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL = "show_signal_strength_in_sim_status_bool";
+ field public static final String KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL = "show_video_call_charges_alert_dialog_bool";
+ field public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL = "show_wfc_location_privacy_policy_bool";
field public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
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";
+ field public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL = "support_enhanced_call_blocking_bool";
+ field public static final String KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL = "support_ims_conference_event_package_bool";
field public static final String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
field public static final String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
+ field public static final String KEY_SUPPORT_TDSCDMA_BOOL = "support_tdscdma_bool";
+ field public static final String KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY = "support_tdscdma_roaming_networks_string_array";
+ field public static final String KEY_SWITCH_DATA_TO_PRIMARY_IF_PRIMARY_IS_OOS_BOOL = "switch_data_to_primary_if_primary_is_oos_bool";
field public static final String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL = "treat_downgraded_video_calls_as_video_calls_bool";
field public static final String KEY_TTY_SUPPORTED_BOOL = "tty_supported_bool";
+ field public static final String KEY_UNLOGGABLE_NUMBERS_STRING_ARRAY = "unloggable_numbers_string_array";
field public static final String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
field public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
field public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
field public static final String KEY_USE_RCS_SIP_OPTIONS_BOOL = "use_rcs_sip_options_bool";
+ field public static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL = "use_wfc_home_network_mode_in_roaming_network_bool";
field public static final String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
field public static final String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
field public static final String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
@@ -44589,6 +44938,8 @@
field public static final String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
field public static final String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
field public static final String KEY_VVM_TYPE_STRING = "vvm_type_string";
+ field public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string";
+ field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -44620,6 +44971,7 @@
}
public final class CellIdentityGsm extends android.telephony.CellIdentity {
+ method @NonNull public java.util.List<java.lang.String> getAdditionalPlmns();
method public int getArfcn();
method public int getBsic();
method public int getCid();
@@ -44635,8 +44987,11 @@
}
public final class CellIdentityLte extends android.telephony.CellIdentity {
+ method @NonNull public java.util.List<java.lang.String> getAdditionalPlmns();
+ method @NonNull public java.util.List<java.lang.Integer> getBands();
method public int getBandwidth();
method public int getCi();
+ method @Nullable public android.telephony.ClosedSubscriberGroupInfo getClosedSubscriberGroupInfo();
method public int getEarfcn();
method @Deprecated public int getMcc();
method @Nullable public String getMccString();
@@ -44650,6 +45005,8 @@
}
public final class CellIdentityNr extends android.telephony.CellIdentity {
+ method @NonNull public java.util.List<java.lang.String> getAdditionalPlmns();
+ method @NonNull public java.util.List<java.lang.Integer> getBands();
method @Nullable public String getMccString();
method @Nullable public String getMncString();
method public long getNci();
@@ -44661,7 +45018,9 @@
}
public final class CellIdentityTdscdma extends android.telephony.CellIdentity {
+ method @NonNull public java.util.List<java.lang.String> getAdditionalPlmns();
method public int getCid();
+ method @Nullable public android.telephony.ClosedSubscriberGroupInfo getClosedSubscriberGroupInfo();
method public int getCpid();
method public int getLac();
method @Nullable public String getMccString();
@@ -44673,7 +45032,9 @@
}
public final class CellIdentityWcdma extends android.telephony.CellIdentity {
+ method @NonNull public java.util.List<java.lang.String> getAdditionalPlmns();
method public int getCid();
+ method @Nullable public android.telephony.ClosedSubscriberGroupInfo getClosedSubscriberGroupInfo();
method public int getLac();
method @Deprecated public int getMcc();
method @Nullable public String getMccString();
@@ -44691,7 +45052,8 @@
method public int getCellConnectionStatus();
method @NonNull public abstract android.telephony.CellIdentity getCellIdentity();
method @NonNull public abstract android.telephony.CellSignalStrength getCellSignalStrength();
- method public long getTimeStamp();
+ method @Deprecated public long getTimeStamp();
+ method public long getTimestampNanos();
method public boolean isRegistered();
field public static final int CONNECTION_NONE = 0; // 0x0
field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1
@@ -44842,6 +45204,15 @@
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthWcdma> CREATOR;
}
+ public final class ClosedSubscriberGroupInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @IntRange(from=0, to=134217727) public int getCsgIdentity();
+ method public boolean getCsgIndicator();
+ method @NonNull public String getHomeNodebName();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ClosedSubscriberGroupInfo> CREATOR;
+ }
+
public class IccOpenLogicalChannelResponse implements android.os.Parcelable {
method public int describeContents();
method public int getChannel();
@@ -44926,6 +45297,35 @@
field @Deprecated public static final int UNKNOWN_RSSI = 99; // 0x63
}
+ public final class NetworkRegistrationInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getAccessNetworkTechnology();
+ method @NonNull public java.util.List<java.lang.Integer> getAvailableServices();
+ method @Nullable public android.telephony.CellIdentity getCellIdentity();
+ method public int getDomain();
+ method public int getNrState();
+ method public int getTransportType();
+ method public boolean isRegistered();
+ method public boolean isRoaming();
+ method public boolean isSearching();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR;
+ field public static final int DOMAIN_CS = 1; // 0x1
+ field public static final int DOMAIN_CS_PS = 3; // 0x3
+ field public static final int DOMAIN_PS = 2; // 0x2
+ field public static final int DOMAIN_UNKNOWN = 0; // 0x0
+ field public static final int NR_STATE_CONNECTED = 3; // 0x3
+ field public static final int NR_STATE_NONE = 0; // 0x0
+ field public static final int NR_STATE_NOT_RESTRICTED = 2; // 0x2
+ field public static final int NR_STATE_RESTRICTED = 1; // 0x1
+ field public static final int SERVICE_TYPE_DATA = 2; // 0x2
+ field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5
+ field public static final int SERVICE_TYPE_SMS = 3; // 0x3
+ field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0
+ field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4
+ field public static final int SERVICE_TYPE_VOICE = 1; // 0x1
+ }
+
public class NetworkScan {
method public void stopScan();
field public static final int ERROR_INTERRUPTED = 10002; // 0x2712
@@ -44956,8 +45356,32 @@
public final class PhoneCapability implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public java.util.List<java.lang.Integer> getBands(int);
+ method @NonNull public java.util.List<java.util.List<java.lang.Long>> getConcurrentFeaturesSupport();
+ method @NonNull public java.util.List<java.lang.String> getLogicalModemUuids();
+ method public int getMaxActiveDedicatedBearers();
+ method public int getMaxActiveInternetData();
+ method public int getMaxActivePsVoice();
+ method public long getPsDataConnectionLingerTimeMillis();
+ method @NonNull public java.util.List<android.telephony.SimSlotCapability> getSimSlotCapabilities();
+ method public long getSupportedRats();
+ method public int getUeCategory(boolean, int);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhoneCapability> CREATOR;
+ field public static final long MODEM_FEATURE_3GPP2_REG = 1L; // 0x1L
+ field public static final long MODEM_FEATURE_3GPP_REG = 2L; // 0x2L
+ field public static final long MODEM_FEATURE_CDMA2000_EHRPD_REG = 4L; // 0x4L
+ field public static final long MODEM_FEATURE_CSIM = 8192L; // 0x2000L
+ field public static final long MODEM_FEATURE_CS_VOICE_SESSION = 512L; // 0x200L
+ field public static final long MODEM_FEATURE_DEDICATED_BEARER = 2048L; // 0x800L
+ field public static final long MODEM_FEATURE_EUTRAN_REG = 32L; // 0x20L
+ field public static final long MODEM_FEATURE_EUTRA_NR_DUAL_CONNECTIVITY_REG = 128L; // 0x80L
+ field public static final long MODEM_FEATURE_GERAN_REG = 8L; // 0x8L
+ field public static final long MODEM_FEATURE_INTERACTIVE_DATA_SESSION = 1024L; // 0x400L
+ field public static final long MODEM_FEATURE_NETWORK_SCAN = 4096L; // 0x1000L
+ field public static final long MODEM_FEATURE_NGRAN_REG = 64L; // 0x40L
+ field public static final long MODEM_FEATURE_PS_VOICE_REG = 256L; // 0x100L
+ field public static final long MODEM_FEATURE_UTRAN_REG = 16L; // 0x10L
}
public class PhoneNumberFormattingTextWatcher implements android.text.TextWatcher {
@@ -45058,7 +45482,7 @@
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
@@ -45098,6 +45522,7 @@
method public int getChannelNumber();
method public int getDuplexMode();
method public boolean getIsManualSelection();
+ method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList();
method public String getOperatorAlphaLong();
method public String getOperatorAlphaShort();
method public String getOperatorNumeric();
@@ -45134,12 +45559,25 @@
method @Deprecated public int getGsmBitErrorRate();
method @Deprecated public int getGsmSignalStrength();
method public int getLevel();
+ method public long getTimestampNanos();
method @Deprecated public boolean isGsm();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalStrength> CREATOR;
field public static final int INVALID = 2147483647; // 0x7fffffff
}
+ public final class SimSlotCapability implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getPhysicalSlotIndex();
+ method public int getSlotType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SimSlotCapability> CREATOR;
+ field public static final int SLOT_TYPE_EUICC = 3; // 0x3
+ field public static final int SLOT_TYPE_IUICC = 2; // 0x2
+ field public static final int SLOT_TYPE_SOFT_SIM = 4; // 0x4
+ field public static final int SLOT_TYPE_UICC = 1; // 0x1
+ }
+
public final class SmsManager {
method public String createAppSpecificSmsToken(android.app.PendingIntent);
method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
@@ -45483,8 +45921,10 @@
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 @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.PhoneCapability getPhoneCapability();
method @Deprecated public int getPhoneCount();
method public int getPhoneType();
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription();
@@ -45615,6 +46055,9 @@
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
@@ -45637,6 +46080,7 @@
field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0
field public static final int PHONE_TYPE_CDMA = 2; // 0x2
field public static final int PHONE_TYPE_GSM = 1; // 0x1
+ field public static final int PHONE_TYPE_IMS = 5; // 0x5
field public static final int PHONE_TYPE_NONE = 0; // 0x0
field public static final int PHONE_TYPE_SIP = 3; // 0x3
field public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; // 0x2
@@ -46025,6 +46469,44 @@
package android.telephony.ims {
+ public final class ImsException extends java.lang.Exception {
+ method public int getCode();
+ field public static final int CODE_ERROR_INVALID_SUBSCRIPTION = 3; // 0x3
+ 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 ImsManager {
+ method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int);
+ 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 @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();
@@ -46208,6 +46690,38 @@
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 {
@@ -49233,6 +49747,71 @@
}
+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 {
@@ -70726,6 +71305,18 @@
method public int lastIndexOf(@Nullable Object);
method @NonNull public java.util.ListIterator<E> listIterator();
method @NonNull public java.util.ListIterator<E> listIterator(int);
+ method @NonNull public static <E> java.util.List<E> of();
+ method @NonNull public static <E> java.util.List<E> of(@NonNull E);
+ method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull @java.lang.SafeVarargs public static <E> java.util.List<E> of(@NonNull E...);
method public E remove(int);
method public default void replaceAll(@NonNull java.util.function.UnaryOperator<E>);
method public E set(int, E);
@@ -70880,6 +71471,7 @@
method @Nullable public default V computeIfPresent(K, @NonNull java.util.function.BiFunction<? super K,? super V,? extends V>);
method public boolean containsKey(@Nullable Object);
method public boolean containsValue(@Nullable Object);
+ method @NonNull public static <K, V> java.util.Map.Entry<K,V> entry(@NonNull K, @NonNull V);
method @NonNull public java.util.Set<java.util.Map.Entry<K,V>> entrySet();
method public boolean equals(@Nullable Object);
method public default void forEach(@NonNull java.util.function.BiConsumer<? super K,? super V>);
@@ -70889,6 +71481,18 @@
method public boolean isEmpty();
method @NonNull public java.util.Set<K> keySet();
method @Nullable public default V merge(K, @NonNull V, @NonNull java.util.function.BiFunction<? super V,? super V,? extends V>);
+ method @NonNull public static <K, V> java.util.Map<K,V> of();
+ method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V);
+ method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V);
+ method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V);
+ method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V);
+ method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V);
+ method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V);
+ method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V);
+ method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V);
+ method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V);
+ method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V);
+ method @NonNull @java.lang.SafeVarargs public static <K, V> java.util.Map<K,V> ofEntries(@NonNull java.util.Map.Entry<? extends K,? extends V>...);
method @Nullable public V put(K, V);
method public void putAll(@NonNull java.util.Map<? extends K,? extends V>);
method @Nullable public default V putIfAbsent(K, V);
@@ -70970,6 +71574,9 @@
}
public final class Objects {
+ method public static int checkFromIndexSize(int, int, int);
+ method public static int checkFromToIndex(int, int, int);
+ method public static int checkIndex(int, int);
method public static <T> int compare(T, T, @NonNull java.util.Comparator<? super T>);
method public static boolean deepEquals(@Nullable Object, @Nullable Object);
method public static boolean equals(@Nullable Object, @Nullable Object);
@@ -70980,6 +71587,8 @@
method @NonNull public static <T> T requireNonNull(@Nullable T);
method @NonNull public static <T> T requireNonNull(@Nullable T, @NonNull String);
method @NonNull public static <T> T requireNonNull(@Nullable T, @NonNull java.util.function.Supplier<java.lang.String>);
+ method @NonNull public static <T> T requireNonNullElse(@Nullable T, @NonNull T);
+ method @NonNull public static <T> T requireNonNullElseGet(@Nullable T, @NonNull java.util.function.Supplier<? extends T>);
method @NonNull public static String toString(@Nullable Object);
method @NonNull public static String toString(@Nullable Object, @NonNull String);
}
@@ -71284,6 +71893,18 @@
}
public interface Set<E> extends java.util.Collection<E> {
+ method @NonNull public static <E> java.util.Set<E> of();
+ method @NonNull public static <E> java.util.Set<E> of(@NonNull E);
+ method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E);
+ method @NonNull @java.lang.SafeVarargs public static <E> java.util.Set<E> of(@NonNull E...);
}
public class SimpleTimeZone extends java.util.TimeZone {
@@ -72222,6 +72843,29 @@
method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService);
}
+ public final class Flow {
+ method public static int defaultBufferSize();
+ }
+
+ public static interface Flow.Processor<T, R> extends java.util.concurrent.Flow.Subscriber<T> java.util.concurrent.Flow.Publisher<R> {
+ }
+
+ @java.lang.FunctionalInterface public static interface Flow.Publisher<T> {
+ method public void subscribe(java.util.concurrent.Flow.Subscriber<? super T>);
+ }
+
+ public static interface Flow.Subscriber<T> {
+ method public void onComplete();
+ method public void onError(Throwable);
+ method public void onNext(T);
+ method public void onSubscribe(java.util.concurrent.Flow.Subscription);
+ }
+
+ public static interface Flow.Subscription {
+ method public void cancel();
+ method public void request(long);
+ }
+
public class ForkJoinPool extends java.util.concurrent.AbstractExecutorService {
ctor public ForkJoinPool();
ctor public ForkJoinPool(int);
diff --git a/api/lint-baseline.txt b/api/lint-baseline.txt
index 2720498..5c31f41 100644
--- a/api/lint-baseline.txt
+++ b/api/lint-baseline.txt
@@ -485,10 +485,20 @@
+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:
+MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#KHITAN_SMALL_SCRIPT:
+
+MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#LISU_SUPPLEMENT:
+
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#NANDINAGARI:
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#NYIAKENG_PUACHUE_HMONG:
@@ -499,26 +509,34 @@
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A:
+MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#SYMBOLS_FOR_LEGACY_COMPUTING:
+
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#TAMIL_SUPPLEMENT:
+MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#TANGUT_SUPPLEMENT:
+
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#WANCHO:
+MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#YEZIDI:
+
MissingNullability: android.icu.text.DateTimePatternGenerator#getFieldDisplayName(int, android.icu.text.DateTimePatternGenerator.DisplayWidth):
MissingNullability: android.icu.text.DateTimePatternGenerator#getFieldDisplayName(int, android.icu.text.DateTimePatternGenerator.DisplayWidth) parameter #1:
MissingNullability: android.icu.util.MeasureUnit#ATMOSPHERE:
- Missing nullability on field `ATMOSPHERE` in class `class android.icu.util.MeasureUnit`
+
MissingNullability: android.icu.util.MeasureUnit#PERCENT:
- Missing nullability on field `PERCENT` in class `class android.icu.util.MeasureUnit`
+
MissingNullability: android.icu.util.MeasureUnit#PERMILLE:
- Missing nullability on field `PERMILLE` in class `class android.icu.util.MeasureUnit`
+
MissingNullability: android.icu.util.MeasureUnit#PETABYTE:
- Missing nullability on field `PETABYTE` in class `class android.icu.util.MeasureUnit`
+
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-app-current.txt b/api/module-app-current.txt
index d802177..4307e67 100644
--- a/api/module-app-current.txt
+++ b/api/module-app-current.txt
@@ -1 +1,9 @@
// Signature format: 2.0
+package android.app {
+
+ public final class NotificationChannel implements android.os.Parcelable {
+ method public void setBlockableSystem(boolean);
+ }
+
+}
+
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index d802177..eeef074 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -1 +1,148 @@
// Signature format: 2.0
+package android.app.timedetector {
+
+ public final class PhoneTimeSuggestion implements android.os.Parcelable {
+ method public void addDebugInfo(@NonNull String);
+ method public void addDebugInfo(@NonNull java.util.List<java.lang.String>);
+ method public int describeContents();
+ method @NonNull public java.util.List<java.lang.String> getDebugInfo();
+ method public int getPhoneId();
+ method @Nullable public android.os.TimestampedValue<java.lang.Long> getUtcTime();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.timedetector.PhoneTimeSuggestion> CREATOR;
+ }
+
+ public static final class PhoneTimeSuggestion.Builder {
+ ctor public PhoneTimeSuggestion.Builder(int);
+ method @NonNull public android.app.timedetector.PhoneTimeSuggestion.Builder addDebugInfo(@NonNull String);
+ method @NonNull public android.app.timedetector.PhoneTimeSuggestion build();
+ method @NonNull public android.app.timedetector.PhoneTimeSuggestion.Builder setUtcTime(@Nullable android.os.TimestampedValue<java.lang.Long>);
+ }
+
+ public interface TimeDetector {
+ method @RequiresPermission("android.permission.SUGGEST_PHONE_TIME_AND_ZONE") public void suggestPhoneTime(@NonNull android.app.timedetector.PhoneTimeSuggestion);
+ }
+
+}
+
+package android.app.timezonedetector {
+
+ public final class PhoneTimeZoneSuggestion implements android.os.Parcelable {
+ method public void addDebugInfo(@NonNull String);
+ method public void addDebugInfo(@NonNull java.util.List<java.lang.String>);
+ method @NonNull public static android.app.timezonedetector.PhoneTimeZoneSuggestion createEmptySuggestion(int, @NonNull String);
+ method public int describeContents();
+ method @NonNull public java.util.List<java.lang.String> getDebugInfo();
+ method public int getMatchType();
+ method public int getPhoneId();
+ method public int getQuality();
+ method @Nullable public String getZoneId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.timezonedetector.PhoneTimeZoneSuggestion> CREATOR;
+ field public static final int MATCH_TYPE_EMULATOR_ZONE_ID = 4; // 0x4
+ field public static final int MATCH_TYPE_NA = 0; // 0x0
+ field public static final int MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET = 3; // 0x3
+ field public static final int MATCH_TYPE_NETWORK_COUNTRY_ONLY = 2; // 0x2
+ field public static final int MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY = 5; // 0x5
+ field public static final int QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS = 3; // 0x3
+ field public static final int QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET = 2; // 0x2
+ field public static final int QUALITY_NA = 0; // 0x0
+ field public static final int QUALITY_SINGLE_ZONE = 1; // 0x1
+ }
+
+ public static final class PhoneTimeZoneSuggestion.Builder {
+ ctor public PhoneTimeZoneSuggestion.Builder(int);
+ method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder addDebugInfo(@NonNull String);
+ method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion build();
+ method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setMatchType(int);
+ method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setQuality(int);
+ method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setZoneId(@Nullable String);
+ }
+
+ public interface TimeZoneDetector {
+ method @RequiresPermission("android.permission.SUGGEST_PHONE_TIME_AND_ZONE") public void suggestPhoneTimeZone(@NonNull android.app.timezonedetector.PhoneTimeZoneSuggestion);
+ }
+
+}
+
+package android.os {
+
+ public final class TimestampedValue<T> implements android.os.Parcelable {
+ ctor public TimestampedValue(long, @Nullable T);
+ method public int describeContents();
+ method public long getReferenceTimeMillis();
+ method @Nullable public T getValue();
+ method public static long referenceTimeDifference(@NonNull android.os.TimestampedValue<?>, @NonNull android.os.TimestampedValue<?>);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.os.TimestampedValue<?>> CREATOR;
+ }
+
+}
+
+package android.timezone {
+
+ public final class CountryTimeZones {
+ method @Nullable public android.icu.util.TimeZone getDefaultTimeZone();
+ method @Nullable public String getDefaultTimeZoneId();
+ method @NonNull public java.util.List<android.timezone.CountryTimeZones.TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long);
+ method public boolean hasUtcZone(long);
+ method public boolean isDefaultTimeZoneBoosted();
+ method public boolean isForCountryCode(@NonNull String);
+ method @Nullable public android.timezone.CountryTimeZones.OffsetResult lookupByOffsetWithBias(int, @Nullable Boolean, @Nullable Integer, long, @Nullable android.icu.util.TimeZone);
+ }
+
+ public static final class CountryTimeZones.OffsetResult {
+ ctor public CountryTimeZones.OffsetResult(@NonNull android.icu.util.TimeZone, boolean);
+ method @NonNull public android.icu.util.TimeZone getTimeZone();
+ method public boolean isOnlyMatch();
+ }
+
+ public static final class CountryTimeZones.TimeZoneMapping {
+ method @Nullable public android.icu.util.TimeZone getTimeZone();
+ method @NonNull public String getTimeZoneId();
+ }
+
+ public final class TelephonyLookup {
+ method @NonNull public static android.timezone.TelephonyLookup getInstance();
+ method @Nullable public android.timezone.TelephonyNetworkFinder getTelephonyNetworkFinder();
+ }
+
+ public final class TelephonyNetwork {
+ method @NonNull public String getCountryIsoCode();
+ method @NonNull public String getMcc();
+ method @NonNull public String getMnc();
+ }
+
+ public final class TelephonyNetworkFinder {
+ method @Nullable public android.timezone.TelephonyNetwork findNetworkByMccMnc(@NonNull String, @NonNull String);
+ }
+
+ 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 final 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 ee62edc..305d571 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -93,6 +93,7 @@
field public static final String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
field public static final String INVOKE_CARRIER_SETUP = "android.permission.INVOKE_CARRIER_SETUP";
field public static final String KILL_UID = "android.permission.KILL_UID";
+ field public static final String LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = "android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH";
field public static final String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS";
field public static final String LOCK_DEVICE = "android.permission.LOCK_DEVICE";
field public static final String LOOP_RADIO = "android.permission.LOOP_RADIO";
@@ -200,6 +201,7 @@
field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON";
+ field public static final String SUGGEST_PHONE_TIME_AND_ZONE = "android.permission.SUGGEST_PHONE_TIME_AND_ZONE";
field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
@@ -224,6 +226,7 @@
public static final class R.array {
field public static final int config_keySystemUuidMapping = 17235973; // 0x1070005
+ field public static final int simColors = 17235974; // 0x1070006
}
public static final class R.attr {
@@ -1439,12 +1442,13 @@
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";
@@ -1462,10 +1466,14 @@
}
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
}
@@ -1570,6 +1578,7 @@
field public static final String BUGREPORT_SERVICE = "bugreport";
field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
field public static final String CONTEXTHUB_SERVICE = "contexthub";
+ field public static final String ETHERNET_SERVICE = "ethernet";
field public static final String EUICC_CARD_SERVICE = "euicc_card";
field public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
field public static final String NETD_SERVICE = "netd";
@@ -1584,7 +1593,6 @@
field public static final String STATS_MANAGER = "stats";
field public static final String STATUS_BAR_SERVICE = "statusbar";
field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
- field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
field public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry";
field public static final String TETHERING_SERVICE = "tethering";
field public static final String VR_SERVICE = "vrmanager";
@@ -1635,6 +1643,7 @@
field public static final String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
field public static final String ACTION_USER_ADDED = "android.intent.action.USER_ADDED";
field public static final String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
+ field @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public static final String ACTION_USER_SWITCHED = "android.intent.action.USER_SWITCHED";
field public static final String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
field public static final String CATEGORY_LEANBACK_SETTINGS = "android.intent.category.LEANBACK_SETTINGS";
field public static final String EXTRA_CALLING_PACKAGE = "android.intent.extra.CALLING_PACKAGE";
@@ -1652,6 +1661,7 @@
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";
@@ -1938,6 +1948,7 @@
field @Deprecated public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
field public static final int MATCH_ANY_USER = 4194304; // 0x400000
field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
+ field public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 536870912; // 0x20000000
field public static final int MATCH_INSTANT = 8388608; // 0x800000
field public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 1; // 0x1
field public static final int RESTRICTION_HIDE_NOTIFICATIONS = 2; // 0x2
@@ -2086,6 +2097,15 @@
}
+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 {
@@ -3267,10 +3287,12 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long);
field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED";
field public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE";
+ field public static final long FUNCTION_NCM = 1024L; // 0x400L
field public static final long FUNCTION_NONE = 0L; // 0x0L
field public static final long FUNCTION_RNDIS = 32L; // 0x20L
field public static final String USB_CONFIGURED = "configured";
field public static final String USB_CONNECTED = "connected";
+ field public static final String USB_FUNCTION_NCM = "ncm";
field public static final String USB_FUNCTION_RNDIS = "rndis";
}
@@ -4036,8 +4058,8 @@
public final class DvbDeviceInfo implements android.os.Parcelable {
ctor public DvbDeviceInfo(int, int);
method public int describeContents();
- method public int getAdapterId();
- method public int getDeviceId();
+ method @IntRange(from=0) public int getAdapterId();
+ method @IntRange(from=0) public int getDeviceId();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.DvbDeviceInfo> CREATOR;
}
@@ -4292,47 +4314,87 @@
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);
method @Deprecated @RequiresPermission("android.permission.NETWORK_SETTINGS") public String getCaptivePortalServerUrl();
- method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
- method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
method @Deprecated public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int, int, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, "android.permission.NETWORK_STACK"}) public boolean shouldAvoidBadWifi();
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
- method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
- method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
- method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
field public static final int TETHERING_BLUETOOTH = 2; // 0x2
field public static final int TETHERING_USB = 1; // 0x1
field public static final int TETHERING_WIFI = 0; // 0x0
- field public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
- field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+ field @Deprecated public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
+ field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+ field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
field public static final int TYPE_NONE = -1; // 0xffffffff
+ field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
}
- public abstract static class ConnectivityManager.OnStartTetheringCallback {
- ctor public ConnectivityManager.OnStartTetheringCallback();
- method public void onTetheringFailed();
- method public void onTetheringStarted();
+ @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
+ ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
+ method @Deprecated public void onTetheringFailed();
+ method @Deprecated public void onTetheringStarted();
}
- public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
- method public void onTetheringEntitlementResult(int);
+ @Deprecated public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
+ method @Deprecated public void onTetheringEntitlementResult(int);
}
- public abstract static class ConnectivityManager.OnTetheringEventCallback {
- ctor public ConnectivityManager.OnTetheringEventCallback();
- method public void onUpstreamChanged(@Nullable android.net.Network);
+ @Deprecated public abstract static class ConnectivityManager.OnTetheringEventCallback {
+ ctor @Deprecated public ConnectivityManager.OnTetheringEventCallback();
+ method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network);
+ }
+
+ public class EthernetManager {
+ method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback);
+ }
+
+ public static interface EthernetManager.TetheredInterfaceCallback {
+ method public void onAvailable(@NonNull String);
+ method public void onUnavailable();
+ }
+
+ public static class EthernetManager.TetheredInterfaceRequest {
+ method public void release();
}
public class InvalidPacketException extends java.lang.Exception {
@@ -4404,13 +4466,18 @@
public class LinkAddress implements android.os.Parcelable {
ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
ctor public LinkAddress(@NonNull String);
ctor public LinkAddress(@NonNull String, int, int);
+ method public long getDeprecationTime();
+ method public long getExpirationTime();
method public boolean isGlobalPreferred();
method public boolean isIpv4();
method public boolean isIpv6();
method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
+ field public static final long LIFETIME_PERMANENT = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final long LIFETIME_UNKNOWN = -1L; // 0xffffffffffffffffL
}
public final class LinkProperties implements android.os.Parcelable {
@@ -4422,6 +4489,8 @@
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();
@@ -4435,9 +4504,12 @@
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);
@@ -4466,10 +4538,51 @@
field public final int netId;
}
+ public abstract class NetworkAgent {
+ method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
+ method public void onAutomaticReconnectDisabled();
+ method public void onBandwidthUpdateRequested();
+ method public void onNetworkUnwanted();
+ method public void onRemoveKeepalivePacketFilter(int);
+ method public void onSaveAcceptUnvalidated(boolean);
+ method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
+ method public void onStartSocketKeepalive(int, int, @NonNull android.net.KeepalivePacketData);
+ method public void onStopSocketKeepalive(int);
+ method public void onValidationStatus(int, @Nullable String);
+ method public void sendLinkProperties(@NonNull android.net.LinkProperties);
+ method public void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
+ method public void sendNetworkScore(int);
+ method public void sendSocketKeepaliveEvent(int, int);
+ field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
+ field public static final int VALIDATION_STATUS_VALID = 1; // 0x1
+ field @NonNull public final android.net.Network network;
+ field public final int providerId;
+ }
+
+ 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 @NonNull public java.util.List<java.lang.Integer> getAdministratorUids();
+ method @Nullable public String getSSID();
method @NonNull public int[] getTransportTypes();
method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
+ method public void setAdministratorUids(@NonNull java.util.List<java.lang.Integer>);
method @NonNull public android.net.NetworkCapabilities setSSID(@Nullable String);
method @NonNull public android.net.NetworkCapabilities setTransportInfo(@NonNull android.net.TransportInfo);
field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
@@ -4504,6 +4617,10 @@
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);
}
@@ -4524,6 +4641,9 @@
field @Deprecated public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
field public static final String EXTRA_NEW_SCORER = "newScorer";
field @Deprecated public static final String EXTRA_PACKAGE_NAME = "packageName";
+ field public static final int SCORE_FILTER_CURRENT_NETWORK = 1; // 0x1
+ field public static final int SCORE_FILTER_NONE = 0; // 0x0
+ field public static final int SCORE_FILTER_SCAN_RESULTS = 2; // 0x2
}
public static interface NetworkScoreManager.NetworkScoreCallback {
@@ -4570,6 +4690,8 @@
public final class RouteInfo implements android.os.Parcelable {
ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
+ ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
+ method public int getMtu();
method public int getType();
field public static final int RTN_THROW = 9; // 0x9
field public static final int RTN_UNICAST = 1; // 0x1
@@ -4635,13 +4757,103 @@
method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@Nullable android.net.LinkAddress);
}
- public final class StringNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
- ctor public StringNetworkSpecifier(@NonNull String);
- method public int describeContents();
+ public final class TelephonyNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
method public boolean satisfiedBy(android.net.NetworkSpecifier);
+ }
+
+ public final class TetheredClient implements android.os.Parcelable {
+ ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int);
+ method public int describeContents();
+ method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses();
+ method @NonNull public android.net.MacAddress getMacAddress();
+ method public int getTetheringType();
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;
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR;
+ }
+
+ public static final class TetheredClient.AddressInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.net.LinkAddress getAddress();
+ method @Nullable public String getHostname();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
+ }
+
+ public class TetheringManager {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
+ field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
+ field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
+ field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
+ field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
+ field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
+ field public static final int TETHERING_BLUETOOTH = 2; // 0x2
+ field public static final int TETHERING_ETHERNET = 5; // 0x5
+ field public static final int TETHERING_INVALID = -1; // 0xffffffff
+ field public static final int TETHERING_NCM = 4; // 0x4
+ field public static final int TETHERING_USB = 1; // 0x1
+ field public static final int TETHERING_WIFI = 0; // 0x0
+ field public static final int TETHERING_WIFI_P2P = 3; // 0x3
+ field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
+ field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9
+ field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8
+ field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
+ field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
+ field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5
+ field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
+ field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
+ field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+ field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+ field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
+ field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
+ field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
+ field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
+ field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
+ field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
+ }
+
+ public static interface TetheringManager.OnTetheringEntitlementResultListener {
+ method public void onTetheringEntitlementResult(int);
+ }
+
+ public abstract static class TetheringManager.StartTetheringCallback {
+ ctor public TetheringManager.StartTetheringCallback();
+ method public void onTetheringFailed(int);
+ method public void onTetheringStarted();
+ }
+
+ public abstract static class TetheringManager.TetheringEventCallback {
+ ctor public TetheringManager.TetheringEventCallback();
+ method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
+ method public void onError(@NonNull String, int);
+ method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
+ method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+ method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+ method public void onTetheringSupported(boolean);
+ method public void onUpstreamChanged(@Nullable android.net.Network);
+ }
+
+ @Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
+ ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]);
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
+ }
+
+ public static class TetheringManager.TetheringRequest {
+ }
+
+ public static class TetheringManager.TetheringRequest.Builder {
+ ctor public TetheringManager.TetheringRequest.Builder(int);
+ method @NonNull public android.net.TetheringManager.TetheringRequest build();
+ method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress);
}
public class TrafficStats {
@@ -4769,9 +4981,11 @@
}
public abstract class ChildSessionParams {
+ method public long getHardLifetime();
method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getLocalTrafficSelectors();
method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getRemoteTrafficSelectors();
method @NonNull public java.util.List<android.net.ipsec.ike.ChildSaProposal> getSaProposals();
+ method public long getSoftLifetime();
}
public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification {
@@ -4831,7 +5045,7 @@
}
public final class IkeSessionConfiguration {
- ctor public IkeSessionConfiguration();
+ method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
method @NonNull public String getRemoteApplicationVersion();
method @NonNull public java.util.List<byte[]> getRemoteVendorIDs();
method public boolean isIkeExtensionEnabled(int);
@@ -4840,29 +5054,43 @@
}
public final class IkeSessionParams {
+ method @NonNull public java.util.List<android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest> getConfigurationRequests();
+ method public long getHardLifetime();
method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getLocalAuthConfig();
method @NonNull public android.net.ipsec.ike.IkeIdentification getLocalIdentification();
method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getRemoteAuthConfig();
method @NonNull public android.net.ipsec.ike.IkeIdentification getRemoteIdentification();
method @NonNull public java.util.List<android.net.ipsec.ike.IkeSaProposal> getSaProposals();
method @NonNull public java.net.InetAddress getServerAddress();
+ method public long getSoftLifetime();
method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket getUdpEncapsulationSocket();
}
public static final class IkeSessionParams.Builder {
ctor public IkeSessionParams.Builder();
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addPcscfServerRequest(@NonNull java.net.InetAddress);
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addPcscfServerRequest(int);
method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal);
method @NonNull public android.net.ipsec.ike.IkeSessionParams build();
method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey);
method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey);
method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthEap(@Nullable java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig);
method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthPsk(@NonNull byte[]);
+ method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLifetime(long, long);
method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification);
method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setServerAddress(@NonNull java.net.InetAddress);
method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket);
}
+ public static interface IkeSessionParams.ConfigRequestIpv4PcscfServer extends android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest {
+ method @Nullable public java.net.Inet4Address getAddress();
+ }
+
+ public static interface IkeSessionParams.ConfigRequestIpv6PcscfServer extends android.net.ipsec.ike.IkeSessionParams.IkeConfigRequest {
+ method @Nullable public java.net.Inet6Address getAddress();
+ }
+
public abstract static class IkeSessionParams.IkeAuthConfig {
}
@@ -4884,6 +5112,9 @@
method @NonNull public byte[] getPsk();
}
+ public static interface IkeSessionParams.IkeConfigRequest {
+ }
+
public final class IkeTrafficSelector {
ctor public IkeTrafficSelector(int, int, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress);
field public final int endPort;
@@ -4927,10 +5158,11 @@
method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams build();
+ method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder setLifetime(long, long);
}
public final class TunnelModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams {
- method @NonNull public java.util.List<android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest> getConfigurationRequests();
+ method @NonNull public java.util.List<android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest> getConfigurationRequests();
}
public static final class TunnelModeChildSessionParams.Builder {
@@ -4944,35 +5176,36 @@
method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector);
method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal);
method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams build();
+ method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder setLifetime(long, long);
}
- public static interface TunnelModeChildSessionParams.ConfigRequest {
- }
-
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
method @Nullable public java.net.Inet4Address getAddress();
}
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
method @Nullable public java.net.Inet4Address getAddress();
}
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
method @Nullable public java.net.Inet4Address getAddress();
}
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Netmask extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv4Netmask extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
}
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv6Address extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
method @Nullable public java.net.Inet6Address getAddress();
method public int getPrefixLength();
}
- public static interface TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequest {
+ public static interface TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer extends android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
method @Nullable public java.net.Inet6Address getAddress();
}
+ public static interface TunnelModeChildSessionParams.TunnelModeChildConfigRequest {
+ }
+
}
package android.net.ipsec.ike.exceptions {
@@ -5456,7 +5689,7 @@
method public boolean isPortableHotspotSupported();
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
method public boolean isWifiScannerSupported();
- method @RequiresPermission("android.permission.NETWORK_SETTINGS") public void registerSoftApCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
+ method @RequiresPermission("android.permission.NETWORK_SETTINGS") public void registerSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission("android.permission.WIFI_SET_DEVICE_MOBILITY_STATE") public void setDeviceMobilityState(int);
@@ -6873,6 +7106,7 @@
field public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
field public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
field public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
+ field public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled";
field public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
field public static final String DOZE_ALWAYS_ON = "doze_always_on";
field public static final String HUSH_GESTURE_USED = "hush_gesture_used";
@@ -6992,7 +7226,73 @@
}
public static final class Telephony.SimInfo {
+ field public static final String ACCESS_RULES = "access_rules";
+ field public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS = "access_rules_from_carrier_configs";
+ field public static final String ALLOWED_NETWORK_TYPES = "allowed_network_types";
+ field public static final String CARD_ID = "card_id";
+ field public static final String CARRIER_ID = "carrier_id";
+ field public static final String CARRIER_NAME = "carrier_name";
+ field public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+ field public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+ field public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+ field public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+ field public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+ field public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+ field public static final String CB_CMAS_TEST_ALERT = "enable_cmas_test_alerts";
+ field public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+ field public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+ field public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+ field public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+ field public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+ field public static final String COLOR = "color";
field @NonNull public static final android.net.Uri CONTENT_URI;
+ field public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+ field public static final String DATA_ROAMING = "data_roaming";
+ field public static final int DATA_ROAMING_DEFAULT = 0; // 0x0
+ field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
+ field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+ field public static final String DISPLAY_NAME = "display_name";
+ field public static final String EHPLMNS = "ehplmns";
+ field public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+ field public static final String GROUP_OWNER = "group_owner";
+ field public static final String GROUP_UUID = "group_uuid";
+ field public static final String HPLMNS = "hplmns";
+ field public static final String ICC_ID = "icc_id";
+ field public static final String IMSI = "imsi";
+ field public static final String IMS_RCS_UCE_ENABLED = "ims_rcs_uce_enabled";
+ field public static final String ISO_COUNTRY_CODE = "iso_country_code";
+ field public static final String IS_EMBEDDED = "is_embedded";
+ field public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+ field public static final String IS_REMOVABLE = "is_removable";
+ field public static final String MCC = "mcc";
+ field public static final String MCC_STRING = "mcc_string";
+ field public static final String MNC = "mnc";
+ field public static final String MNC_STRING = "mnc_string";
+ field public static final String NAME_SOURCE = "name_source";
+ field public static final int NAME_SOURCE_CARRIER = 3; // 0x3
+ field public static final int NAME_SOURCE_DEFAULT = 0; // 0x0
+ field public static final int NAME_SOURCE_SIM_PNN = 4; // 0x4
+ field public static final int NAME_SOURCE_SIM_SPN = 1; // 0x1
+ field public static final int NAME_SOURCE_USER_INPUT = 2; // 0x2
+ field public static final String NUMBER = "number";
+ field public static final String PROFILE_CLASS = "profile_class";
+ field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff
+ field public static final int PROFILE_CLASS_OPERATIONAL = 2; // 0x2
+ field public static final int PROFILE_CLASS_PROVISIONING = 1; // 0x1
+ field public static final int PROFILE_CLASS_TESTING = 0; // 0x0
+ field public static final int PROFILE_CLASS_UNSET = -1; // 0xffffffff
+ field public static final int SIM_NOT_INSERTED = -1; // 0xffffffff
+ field public static final String SIM_SLOT_INDEX = "sim_id";
+ field public static final String SUBSCRIPTION_TYPE = "subscription_type";
+ field public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0; // 0x0
+ field public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1; // 0x1
+ field public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+ field public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+ field public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+ field public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+ field public static final String WFC_IMS_MODE = "wfc_ims_mode";
+ field public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+ field public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
}
public static final class Telephony.Sms.Intents {
@@ -7017,6 +7317,14 @@
}
+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 {
@@ -8105,8 +8413,13 @@
public final class AccessNetworkConstants {
field public static final int TRANSPORT_TYPE_INVALID = -1; // 0xffffffff
- field public static final int TRANSPORT_TYPE_WLAN = 2; // 0x2
- field public static final int TRANSPORT_TYPE_WWAN = 1; // 0x1
+ }
+
+ public static final class AccessNetworkConstants.NgranBands {
+ method public static int getFrequencyRangeGroup(int);
+ field public static final int FREQUENCY_RANGE_GROUP_1 = 1; // 0x1
+ field public static final int FREQUENCY_RANGE_GROUP_2 = 2; // 0x2
+ field public static final int FREQUENCY_RANGE_GROUP_UNKNOWN = 0; // 0x0
}
public final class CallAttributes implements android.os.Parcelable {
@@ -8119,6 +8432,27 @@
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR;
}
+ public final class CallForwardingInfo implements android.os.Parcelable {
+ ctor public CallForwardingInfo(int, int, @Nullable String, int);
+ method public int describeContents();
+ method @Nullable public String getNumber();
+ method public int getReason();
+ method public int getStatus();
+ method public int getTimeoutSeconds();
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallForwardingInfo> CREATOR;
+ field public static final int REASON_ALL = 4; // 0x4
+ field public static final int REASON_ALL_CONDITIONAL = 5; // 0x5
+ field public static final int REASON_BUSY = 1; // 0x1
+ field public static final int REASON_NOT_REACHABLE = 3; // 0x3
+ field public static final int REASON_NO_REPLY = 2; // 0x2
+ field public static final int REASON_UNCONDITIONAL = 0; // 0x0
+ field public static final int STATUS_ACTIVE = 1; // 0x1
+ field public static final int STATUS_FDN_CHECK_FAILURE = 2; // 0x2
+ field public static final int STATUS_INACTIVE = 0; // 0x0
+ field public static final int STATUS_NOT_SUPPORTED = 4; // 0x4
+ field public static final int STATUS_UNKNOWN_ERROR = 3; // 0x3
+ }
+
public final class CallQuality implements android.os.Parcelable {
ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int);
method public int describeContents();
@@ -8206,7 +8540,7 @@
}
public class CellBroadcastIntents {
- method public static void sendOrderedBroadcastForBackgroundReceivers(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+ method public static void sendSmsCbReceivedBroadcast(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.telephony.SmsCbMessage, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, int);
}
public abstract class CellBroadcastService extends android.app.Service {
@@ -8723,6 +9057,7 @@
method public int getSleepTimeMillis();
method public long getTimestamp();
method @NonNull public java.util.List<android.telephony.ModemActivityInfo.TransmitPower> getTransmitPowerInfo();
+ method public boolean isValid();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ModemActivityInfo> CREATOR;
field public static final int TX_POWER_LEVELS = 5; // 0x5
@@ -8734,37 +9069,18 @@
}
public final class NetworkRegistrationInfo implements android.os.Parcelable {
- method public int describeContents();
- method public int getAccessNetworkTechnology();
- method @NonNull public java.util.List<java.lang.Integer> getAvailableServices();
- method @Nullable public android.telephony.CellIdentity getCellIdentity();
method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
- method public int getDomain();
- method public int getNrState();
method public int getRegistrationState();
method public int getRejectCause();
method public int getRoamingType();
- method public int getTransportType();
method public boolean isEmergencyEnabled();
- method public boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR;
- field public static final int DOMAIN_CS = 1; // 0x1
- field public static final int DOMAIN_CS_PS = 3; // 0x3
- field public static final int DOMAIN_PS = 2; // 0x2
- field public static final int DOMAIN_UNKNOWN = 0; // 0x0
field public static final int REGISTRATION_STATE_DENIED = 3; // 0x3
field public static final int REGISTRATION_STATE_HOME = 1; // 0x1
field public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; // 0x0
field public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; // 0x2
field public static final int REGISTRATION_STATE_ROAMING = 5; // 0x5
field public static final int REGISTRATION_STATE_UNKNOWN = 4; // 0x4
- field public static final int SERVICE_TYPE_DATA = 2; // 0x2
- field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5
- field public static final int SERVICE_TYPE_SMS = 3; // 0x3
- field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0
- field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4
- field public static final int SERVICE_TYPE_VOICE = 1; // 0x1
}
public static final class NetworkRegistrationInfo.Builder {
@@ -8839,13 +9155,14 @@
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.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = 512; // 0x200
+ 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
- field public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
+ field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 8388608; // 0x800000
field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_SRVCC_STATE_CHANGED = 16384; // 0x4000
- field public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
+ field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
}
public final class PreciseCallState implements android.os.Parcelable {
@@ -8869,6 +9186,7 @@
}
public final class PreciseDataConnectionState implements android.os.Parcelable {
+ ctor public PreciseDataConnectionState(int, int, int, @NonNull String, @Nullable android.net.LinkProperties, int, @Nullable android.telephony.data.ApnSetting);
method @Deprecated @NonNull public String getDataConnectionApn();
method @Deprecated public int getDataConnectionApnTypeBitMask();
method @Deprecated public int getDataConnectionFailCause();
@@ -8977,9 +9295,9 @@
public class ServiceState implements android.os.Parcelable {
method @NonNull public android.telephony.ServiceState createLocationInfoSanitizedCopy(boolean);
method public void fillInNotifierBundle(@NonNull android.os.Bundle);
+ method public int getDataNetworkType();
method public int getDataRegistrationState();
method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int);
- method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList();
method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int);
method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForTransportType(int);
method public int getNrFrequencyRange();
@@ -8992,6 +9310,10 @@
field public static final int ROAMING_TYPE_UNKNOWN = 1; // 0x1
}
+ public class SignalStrength implements android.os.Parcelable {
+ ctor public SignalStrength(@NonNull android.telephony.SignalStrength);
+ }
+
public final class SmsCbCmasInfo implements android.os.Parcelable {
ctor public SmsCbCmasInfo(int, int, int, int, int, int);
method public int describeContents();
@@ -9115,6 +9437,7 @@
}
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);
@@ -9125,6 +9448,8 @@
}
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);
}
@@ -9203,9 +9528,13 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean);
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int);
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypes();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CallForwardingInfo getCallForwarding(int);
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCallWaitingStatus();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int);
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn();
@@ -9272,18 +9601,25 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback);
+ method public void requestModemActivityInfo(@NonNull android.os.ResultReceiver);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void resetIms(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings();
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAlwaysReportSignalStrength(boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCallForwarding(@NonNull android.telephony.CallForwardingInfo);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCallWaitingStatus(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setNetworkSelectionModeManual(@NonNull String, int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean);
@@ -9304,16 +9640,29 @@
method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String);
field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED";
field public static final String ACTION_EMERGENCY_ASSISTANCE = "android.telephony.action.EMERGENCY_ASSISTANCE";
+ field public static final String ACTION_SERVICE_PROVIDERS_UPDATED = "android.telephony.action.SERVICE_PROVIDERS_UPDATED";
field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED";
field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED";
field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
+ field public static final int CALL_WAITING_STATUS_ACTIVE = 1; // 0x1
+ field public static final int CALL_WAITING_STATUS_INACTIVE = 2; // 0x2
+ field public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4; // 0x4
+ field public static final int CALL_WAITING_STATUS_UNKNOWN_ERROR = 3; // 0x3
+ field public static final int CARD_POWER_DOWN = 0; // 0x0
+ field public static final int CARD_POWER_UP = 1; // 0x1
+ field public static final int CARD_POWER_UP_PASS_THROUGH = 2; // 0x2
field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
field public static final String EXTRA_ANOMALY_DESCRIPTION = "android.telephony.extra.ANOMALY_DESCRIPTION";
field public static final String EXTRA_ANOMALY_ID = "android.telephony.extra.ANOMALY_ID";
+ field public static final String EXTRA_DATA_SPN = "android.telephony.extra.DATA_SPN";
+ field public static final String EXTRA_PLMN = "android.telephony.extra.PLMN";
+ field public static final String EXTRA_SHOW_PLMN = "android.telephony.extra.SHOW_PLMN";
+ field public static final String EXTRA_SHOW_SPN = "android.telephony.extra.SHOW_SPN";
field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE";
+ field public static final String EXTRA_SPN = "android.telephony.extra.SPN";
field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
field public static final int INVALID_EMERGENCY_NUMBER_DB_VERSION = -1; // 0xffffffff
@@ -9339,6 +9688,7 @@
field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L
field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L
field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L
+ field public static final int PHONE_TYPE_THIRD_PARTY = 4; // 0x4
field public static final int RADIO_POWER_OFF = 0; // 0x0
field public static final int RADIO_POWER_ON = 1; // 0x1
field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2
@@ -9437,7 +9787,9 @@
method public int getId();
method @NonNull public String getInterfaceName();
method public int getLinkStatus();
- method public int getMtu();
+ method @Deprecated public int getMtu();
+ method public int getMtuV4();
+ method public int getMtuV6();
method @NonNull public java.util.List<java.net.InetAddress> getPcscfAddresses();
method public int getProtocolType();
method public int getSuggestedRetryTime();
@@ -9459,7 +9811,9 @@
method @NonNull public android.telephony.data.DataCallResponse.Builder setId(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setInterfaceName(@NonNull String);
method @NonNull public android.telephony.data.DataCallResponse.Builder setLinkStatus(int);
- method @NonNull public android.telephony.data.DataCallResponse.Builder setMtu(int);
+ method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setMtu(int);
+ method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV4(int);
+ method @NonNull public android.telephony.data.DataCallResponse.Builder setMtuV6(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setPcscfAddresses(@NonNull java.util.List<java.net.InetAddress>);
method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
method @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int);
@@ -9470,7 +9824,9 @@
method @NonNull public String getApn();
method public int getAuthType();
method public int getBearerBitmask();
- method public int getMtu();
+ method @Deprecated public int getMtu();
+ method public int getMtuV4();
+ method public int getMtuV6();
method @Nullable public String getPassword();
method public int getProfileId();
method public int getProtocolType();
@@ -9495,7 +9851,9 @@
method @NonNull public android.telephony.data.DataProfile.Builder setApn(@NonNull String);
method @NonNull public android.telephony.data.DataProfile.Builder setAuthType(int);
method @NonNull public android.telephony.data.DataProfile.Builder setBearerBitmask(int);
- method @NonNull public android.telephony.data.DataProfile.Builder setMtu(int);
+ method @Deprecated @NonNull public android.telephony.data.DataProfile.Builder setMtu(int);
+ method @NonNull public android.telephony.data.DataProfile.Builder setMtuV4(int);
+ method @NonNull public android.telephony.data.DataProfile.Builder setMtuV6(int);
method @NonNull public android.telephony.data.DataProfile.Builder setPassword(@NonNull String);
method @NonNull public android.telephony.data.DataProfile.Builder setPersistent(boolean);
method @NonNull public android.telephony.data.DataProfile.Builder setPreferred(boolean);
@@ -9740,6 +10098,7 @@
method public int getEmergencyServiceCategories();
method @NonNull public java.util.List<java.lang.String> getEmergencyUrns();
method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
+ method @Nullable public android.os.Bundle getProprietaryCallExtras();
method public int getRestrictCause();
method public int getServiceType();
method public static int getVideoStateFromCallType(int);
@@ -9783,7 +10142,8 @@
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";
@@ -9815,8 +10175,8 @@
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);
@@ -9824,7 +10184,7 @@
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);
@@ -9846,6 +10206,9 @@
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 {
@@ -9877,10 +10240,6 @@
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 {
@@ -9900,29 +10259,19 @@
}
public class ImsManager {
- 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";
}
public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
- method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
+ method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) 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);
@@ -9932,16 +10281,6 @@
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 {
@@ -10205,7 +10544,27 @@
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
@@ -10215,16 +10574,52 @@
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 {
@@ -10237,10 +10632,13 @@
method public int describeContents();
method @NonNull public java.util.List<java.lang.String> getCapableExtensionTags();
method @NonNull public android.net.Uri getContactUri();
- method @Nullable public android.net.Uri getServiceUri(int);
- method public boolean isCapable(int);
+ method @Nullable public android.net.Uri getServiceUri(long);
+ method public boolean isCapable(long);
method public boolean isCapable(@NonNull String);
method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000
+ field public static final int CAPABILITY_CHAT_BOT = 67108864; // 0x4000000
+ field public static final int CAPABILITY_CHAT_BOT_ROLE = 134217728; // 0x8000000
field public static final int CAPABILITY_CHAT_SESSION = 2; // 0x2
field public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = 4; // 0x4
field public static final int CAPABILITY_CHAT_STANDALONE = 1; // 0x1
@@ -10257,10 +10655,16 @@
field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100
field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000
field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000
+ field public static final int CAPABILITY_MMTEL_CALL_COMPOSER = 1073741824; // 0x40000000
+ field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000
+ field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000
field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000
field public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = 2097152; // 0x200000
field public static final int CAPABILITY_RCS_VOICE_CALL = 524288; // 0x80000
+ field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000
+ field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000
field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800
+ field public static final int CAPABILITY_STANDALONE_CHAT_BOT = 536870912; // 0x20000000
field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400
field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR;
@@ -10268,28 +10672,41 @@
public static class RcsContactUceCapability.Builder {
ctor public RcsContactUceCapability.Builder(@NonNull android.net.Uri);
- method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(int, @NonNull android.net.Uri);
- method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(int);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long, @NonNull android.net.Uri);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long);
method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(@NonNull String);
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 class RcsUceAdapter {
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getUcePublishState() throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void requestCapabilities(@NonNull java.util.concurrent.Executor, @NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
+ field public static final int ERROR_ALREADY_IN_QUEUE = 13; // 0xd
+ field public static final int ERROR_FORBIDDEN = 6; // 0x6
+ field public static final int ERROR_GENERIC_FAILURE = 1; // 0x1
+ field public static final int ERROR_INSUFFICIENT_MEMORY = 11; // 0xb
+ field public static final int ERROR_LOST_NETWORK = 12; // 0xc
+ field public static final int ERROR_NOT_AUTHORIZED = 5; // 0x5
+ field public static final int ERROR_NOT_AVAILABLE = 3; // 0x3
+ field public static final int ERROR_NOT_ENABLED = 2; // 0x2
+ field public static final int ERROR_NOT_FOUND = 7; // 0x7
+ field public static final int ERROR_NOT_REGISTERED = 4; // 0x4
+ field public static final int ERROR_REQUEST_TIMEOUT = 10; // 0xa
+ field public static final int ERROR_REQUEST_TOO_LARGE = 8; // 0x8
+ field public static final int PUBLISH_STATE_200_OK = 1; // 0x1
+ field public static final int PUBLISH_STATE_NOT_PUBLISHED = 2; // 0x2
+ field public static final int PUBLISH_STATE_OTHER_ERROR = 6; // 0x6
+ field public static final int PUBLISH_STATE_RCS_PROVISION_ERROR = 4; // 0x4
+ field public static final int PUBLISH_STATE_REQUEST_TIMEOUT = 5; // 0x5
+ field public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; // 0x3
}
- 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);
+ public static class RcsUceAdapter.CapabilitiesCallback {
+ ctor public RcsUceAdapter.CapabilitiesCallback();
+ method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>);
+ method public void onError(int);
}
}
@@ -10315,6 +10732,7 @@
public abstract class ImsFeature {
ctor public ImsFeature();
method public abstract void changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
+ method public int getFeatureState();
method public final int getSlotIndex();
method public abstract void onFeatureReady();
method public abstract void onFeatureRemoved();
@@ -10353,7 +10771,7 @@
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";
@@ -10369,10 +10787,6 @@
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 {
@@ -10384,6 +10798,8 @@
public class RcsFeature extends android.telephony.ims.feature.ImsFeature {
ctor public RcsFeature();
method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
+ method @NonNull public android.telephony.ims.stub.RcsSipOptionsImplBase getOptionsExchangeImpl();
+ method @NonNull public android.telephony.ims.stub.RcsPresenceExchangeImplBase getPresenceExchangeImpl();
method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities);
method public void onFeatureReady();
method public void onFeatureRemoved();
@@ -10556,12 +10972,89 @@
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);
method public int updateClir(int);
method public int updateColp(boolean);
method public int updateColr(int);
+ field public static final int CALL_BARRING_ALL = 7; // 0x7
+ field public static final int CALL_BARRING_ALL_INCOMING = 1; // 0x1
+ field public static final int CALL_BARRING_ALL_OUTGOING = 2; // 0x2
+ field public static final int CALL_BARRING_ANONYMOUS_INCOMING = 6; // 0x6
+ field public static final int CALL_BARRING_INCOMING_ALL_SERVICES = 9; // 0x9
+ field public static final int CALL_BARRING_OUTGOING_ALL_SERVICES = 8; // 0x8
+ field public static final int CALL_BARRING_OUTGOING_INTL = 3; // 0x3
+ field public static final int CALL_BARRING_OUTGOING_INTL_EXCL_HOME = 4; // 0x4
+ field public static final int CALL_BARRING_SPECIFIC_INCOMING_CALLS = 10; // 0xa
+ field public static final int CALL_BLOCKING_INCOMING_WHEN_ROAMING = 5; // 0x5
+ field public static final int INVALID_RESULT = -1; // 0xffffffff
+ }
+
+ public class RcsCapabilityExchange {
+ ctor public RcsCapabilityExchange();
+ method public final void onCommandUpdate(int, int) throws android.telephony.ims.ImsException;
+ field public static final int COMMAND_CODE_FETCH_ERROR = 4; // 0x4
+ field public static final int COMMAND_CODE_GENERIC_FAILURE = 2; // 0x2
+ field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6; // 0x6
+ field public static final int COMMAND_CODE_INVALID_PARAM = 3; // 0x3
+ field public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7; // 0x7
+ field public static final int COMMAND_CODE_NOT_FOUND = 9; // 0x9
+ field public static final int COMMAND_CODE_NOT_SUPPORTED = 8; // 0x8
+ field public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11; // 0xb
+ field public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5; // 0x5
+ field public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10; // 0xa
+ field public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; // 0x0
+ field public static final int COMMAND_CODE_SUCCESS = 1; // 0x1
+ }
+
+ public class RcsPresenceExchangeImplBase extends android.telephony.ims.stub.RcsCapabilityExchange {
+ ctor public RcsPresenceExchangeImplBase();
+ method public final void onCapabilityRequestResponse(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>, int) throws android.telephony.ims.ImsException;
+ method public final void onNetworkResponse(int, @NonNull String, int) throws android.telephony.ims.ImsException;
+ method public final void onNotifyUpdateCapabilites(int) throws android.telephony.ims.ImsException;
+ method public final void onUnpublish() throws android.telephony.ims.ImsException;
+ method public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, int);
+ method public void updateCapabilities(@NonNull android.telephony.ims.RcsContactUceCapability, int);
+ field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; // 0x0
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; // 0x6
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; // 0x5
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; // 0x3
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; // 0x4
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; // 0x8
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; // 0x1
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; // 0x2
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; // 0xa
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; // 0x7
+ field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; // 0x9
+ field public static final int RESPONSE_FORBIDDEN = 3; // 0x3
+ field public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2; // 0x2
+ field public static final int RESPONSE_NOT_FOUND = 4; // 0x4
+ field public static final int RESPONSE_NOT_REGISTERED = 1; // 0x1
+ field public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7; // 0x7
+ field public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5; // 0x5
+ field public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8; // 0x8
+ field public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1; // 0xffffffff
+ field public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6; // 0x6
+ field public static final int RESPONSE_SUCCESS = 0; // 0x0
+ }
+
+ public class RcsSipOptionsImplBase extends android.telephony.ims.stub.RcsCapabilityExchange {
+ ctor public RcsSipOptionsImplBase();
+ method public final void onCapabilityRequestResponse(int, @NonNull String, @Nullable android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException;
+ method public final void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException;
+ method public void respondToCapabilityRequest(@NonNull String, @NonNull android.telephony.ims.RcsContactUceCapability, int);
+ method public void respondToCapabilityRequestWithError(@NonNull android.net.Uri, int, @NonNull String, int);
+ method public void sendCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int);
+ field public static final int RESPONSE_BAD_REQUEST = 5; // 0x5
+ field public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4; // 0x4
+ field public static final int RESPONSE_GENERIC_FAILURE = -1; // 0xffffffff
+ field public static final int RESPONSE_NOT_FOUND = 3; // 0x3
+ field public static final int RESPONSE_REQUEST_TIMEOUT = 2; // 0x2
+ field public static final int RESPONSE_SUCCESS = 0; // 0x0
+ field public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1; // 0x1
}
}
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index 432a5fd..306b8af 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -1,4 +1,14 @@
// Baseline format: 1.0
+// Tethering broadcast action / extras cannot change name for backwards compatibility
+ActionValue: android.net.TetheringManager#ACTION_TETHER_STATE_CHANGED:
+ Inconsistent action value; expected `android.net.action.TETHER_STATE_CHANGED`, was `android.net.conn.TETHER_STATE_CHANGED`
+ActionValue: android.net.TetheringManager#EXTRA_ACTIVE_TETHER:
+ Inconsistent extra value; expected `android.net.extra.ACTIVE_TETHER`, was `tetherArray`
+ActionValue: android.net.TetheringManager#EXTRA_AVAILABLE_TETHER:
+ Inconsistent extra value; expected `android.net.extra.AVAILABLE_TETHER`, was `availableArray`
+ActionValue: android.net.TetheringManager#EXTRA_ERRORED_TETHER:
+ Inconsistent extra value; expected `android.net.extra.ERRORED_TETHER`, was `erroredArray`
+
ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
diff --git a/api/test-current.txt b/api/test-current.txt
index c1b997a..9a331a2 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -320,8 +320,10 @@
}
public final class NotificationChannel implements android.os.Parcelable {
+ method public boolean isBlockableSystem();
method public boolean isImportanceLockedByCriticalDeviceFunction();
method public boolean isImportanceLockedByOEM();
+ method public void setBlockableSystem(boolean);
method public void setImportanceLockedByCriticalDeviceFunction(boolean);
method public void setImportanceLockedByOEM(boolean);
}
@@ -651,11 +653,11 @@
method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions);
field public static final String BUGREPORT_SERVICE = "bugreport";
field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
+ field public static final String ETHERNET_SERVICE = "ethernet";
field public static final String NETWORK_STACK_SERVICE = "network_stack";
field public static final String PERMISSION_SERVICE = "permission";
field public static final String ROLLBACK_SERVICE = "rollback";
field public static final String STATUS_BAR_SERVICE = "statusbar";
- field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
field public static final String TEST_NETWORK_SERVICE = "test_network";
}
@@ -1359,12 +1361,51 @@
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";
field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
}
+ public class EthernetManager {
+ method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback);
+ }
+
+ public static interface EthernetManager.TetheredInterfaceCallback {
+ method public void onAvailable(@NonNull String);
+ method public void onUnavailable();
+ }
+
+ public static class EthernetManager.TetheredInterfaceRequest {
+ method public void release();
+ }
+
public final class IpPrefix implements android.os.Parcelable {
ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
ctor public IpPrefix(@NonNull String);
@@ -1376,9 +1417,12 @@
public class LinkAddress implements android.os.Parcelable {
ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
ctor public LinkAddress(@NonNull String);
ctor public LinkAddress(@NonNull String, int, int);
+ method public long getDeprecationTime();
+ method public long getExpirationTime();
method public boolean isGlobalPreferred();
method public boolean isIpv4();
method public boolean isIpv6();
@@ -1389,6 +1433,8 @@
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();
@@ -1399,9 +1445,12 @@
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);
@@ -1473,6 +1522,101 @@
method public void teardownTestNetwork(@NonNull android.net.Network);
}
+ public final class TetheredClient implements android.os.Parcelable {
+ ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int);
+ method public int describeContents();
+ method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses();
+ method @NonNull public android.net.MacAddress getMacAddress();
+ method public int getTetheringType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR;
+ }
+
+ public static final class TetheredClient.AddressInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.net.LinkAddress getAddress();
+ method @Nullable public String getHostname();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
+ }
+
+ public class TetheringManager {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
+ method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
+ field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
+ field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
+ field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
+ field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
+ field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
+ field public static final int TETHERING_BLUETOOTH = 2; // 0x2
+ field public static final int TETHERING_ETHERNET = 5; // 0x5
+ field public static final int TETHERING_INVALID = -1; // 0xffffffff
+ field public static final int TETHERING_NCM = 4; // 0x4
+ field public static final int TETHERING_USB = 1; // 0x1
+ field public static final int TETHERING_WIFI = 0; // 0x0
+ field public static final int TETHERING_WIFI_P2P = 3; // 0x3
+ field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
+ field public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; // 0x9
+ field public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; // 0x8
+ field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
+ field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
+ field public static final int TETHER_ERROR_MASTER_ERROR = 5; // 0x5
+ field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
+ field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
+ field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+ field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+ field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
+ field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
+ field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
+ field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
+ field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
+ field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
+ }
+
+ public static interface TetheringManager.OnTetheringEntitlementResultListener {
+ method public void onTetheringEntitlementResult(int);
+ }
+
+ public abstract static class TetheringManager.StartTetheringCallback {
+ ctor public TetheringManager.StartTetheringCallback();
+ method public void onTetheringFailed(int);
+ method public void onTetheringStarted();
+ }
+
+ public abstract static class TetheringManager.TetheringEventCallback {
+ ctor public TetheringManager.TetheringEventCallback();
+ method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
+ method public void onError(@NonNull String, int);
+ method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
+ method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+ method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
+ method public void onTetheringSupported(boolean);
+ method public void onUpstreamChanged(@Nullable android.net.Network);
+ }
+
+ @Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
+ ctor @Deprecated public TetheringManager.TetheringInterfaceRegexps(@NonNull String[], @NonNull String[], @NonNull String[]);
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
+ method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
+ }
+
+ public static class TetheringManager.TetheringRequest {
+ }
+
+ public static class TetheringManager.TetheringRequest.Builder {
+ ctor public TetheringManager.TetheringRequest.Builder(int);
+ method @NonNull public android.net.TetheringManager.TetheringRequest build();
+ method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
+ method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setSilentProvisioning(boolean);
+ method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder useStaticIpv4Addresses(@NonNull android.net.LinkAddress);
+ }
+
public class TrafficStats {
method public static long getLoopbackRxBytes();
method public static long getLoopbackRxPackets();
@@ -2851,6 +2995,8 @@
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);
@@ -2888,8 +3034,13 @@
public final class AccessNetworkConstants {
field public static final int TRANSPORT_TYPE_INVALID = -1; // 0xffffffff
- field public static final int TRANSPORT_TYPE_WLAN = 2; // 0x2
- field public static final int TRANSPORT_TYPE_WWAN = 1; // 0x1
+ }
+
+ public static final class AccessNetworkConstants.NgranBands {
+ method public static int getFrequencyRangeGroup(int);
+ field public static final int FREQUENCY_RANGE_GROUP_1 = 1; // 0x1
+ field public static final int FREQUENCY_RANGE_GROUP_2 = 2; // 0x2
+ field public static final int FREQUENCY_RANGE_GROUP_UNKNOWN = 0; // 0x0
}
public final class CallQuality implements android.os.Parcelable {
@@ -2952,36 +3103,18 @@
}
public final class NetworkRegistrationInfo implements android.os.Parcelable {
- method public int describeContents();
- method public int getAccessNetworkTechnology();
- method @NonNull public java.util.List<java.lang.Integer> getAvailableServices();
- method @Nullable public android.telephony.CellIdentity getCellIdentity();
method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
- method public int getDomain();
method public int getRegistrationState();
method public int getRejectCause();
method public int getRoamingType();
- method public int getTransportType();
method public boolean isEmergencyEnabled();
- method public boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR;
- field public static final int DOMAIN_CS = 1; // 0x1
- field public static final int DOMAIN_CS_PS = 3; // 0x3
- field public static final int DOMAIN_PS = 2; // 0x2
- field public static final int DOMAIN_UNKNOWN = 0; // 0x0
field public static final int REGISTRATION_STATE_DENIED = 3; // 0x3
field public static final int REGISTRATION_STATE_HOME = 1; // 0x1
field public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; // 0x0
field public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; // 0x2
field public static final int REGISTRATION_STATE_ROAMING = 5; // 0x5
field public static final int REGISTRATION_STATE_UNKNOWN = 4; // 0x4
- field public static final int SERVICE_TYPE_DATA = 2; // 0x2
- field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5
- field public static final int SERVICE_TYPE_SMS = 3; // 0x3
- field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0
- field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4
- field public static final int SERVICE_TYPE_VOICE = 1; // 0x1
}
public static final class NetworkRegistrationInfo.Builder {
@@ -3018,6 +3151,7 @@
public class ServiceState implements android.os.Parcelable {
method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo);
+ method public int getDataNetworkType();
method public void setCdmaSystemAndNetworkId(int, int);
method public void setCellBandwidths(int[]);
method public void setChannelNumber(int);
@@ -3126,6 +3260,7 @@
method public int getEmergencyServiceCategories();
method @NonNull public java.util.List<java.lang.String> getEmergencyUrns();
method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
+ method @Nullable public android.os.Bundle getProprietaryCallExtras();
method public int getRestrictCause();
method public int getServiceType();
method public static int getVideoStateFromCallType(int);
@@ -3169,7 +3304,8 @@
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";
@@ -3178,6 +3314,7 @@
field public static final String EXTRA_DISPLAY_TEXT = "DisplayText";
field public static final String EXTRA_EMERGENCY_CALL = "e_call";
field public static final String EXTRA_IS_CALL_PULL = "CallPull";
+ field public static final String EXTRA_OEM_EXTRAS = "android.telephony.ims.extra.OEM_EXTRAS";
field public static final String EXTRA_OI = "oi";
field public static final String EXTRA_OIR = "oir";
field public static final String EXTRA_REMOTE_URI = "remote_uri";
@@ -3201,8 +3338,8 @@
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);
@@ -3210,7 +3347,7 @@
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);
@@ -3232,6 +3369,9 @@
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 {
@@ -3263,10 +3403,6 @@
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 {
@@ -3286,29 +3422,19 @@
}
public class ImsManager {
- 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";
}
public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
- method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
+ method @Deprecated @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 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);
@@ -3318,16 +3444,6 @@
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 {
@@ -3587,7 +3703,27 @@
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
@@ -3597,16 +3733,52 @@
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 {
@@ -3615,22 +3787,85 @@
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 final class RcsContactUceCapability implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<java.lang.String> getCapableExtensionTags();
+ method @NonNull public android.net.Uri getContactUri();
+ method @Nullable public android.net.Uri getServiceUri(long);
+ method public boolean isCapable(long);
+ method public boolean isCapable(@NonNull String);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000
+ field public static final int CAPABILITY_CHAT_BOT = 67108864; // 0x4000000
+ field public static final int CAPABILITY_CHAT_BOT_ROLE = 134217728; // 0x8000000
+ field public static final int CAPABILITY_CHAT_SESSION = 2; // 0x2
+ field public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = 4; // 0x4
+ field public static final int CAPABILITY_CHAT_STANDALONE = 1; // 0x1
+ field public static final int CAPABILITY_DISCOVERY_VIA_PRESENCE = 4096; // 0x1000
+ field public static final int CAPABILITY_FILE_TRANSFER = 8; // 0x8
+ field public static final int CAPABILITY_FILE_TRANSFER_HTTP = 64; // 0x40
+ field public static final int CAPABILITY_FILE_TRANSFER_SMS = 128; // 0x80
+ field public static final int CAPABILITY_FILE_TRANSFER_STORE_FORWARD = 32; // 0x20
+ field public static final int CAPABILITY_FILE_TRANSFER_THUMBNAIL = 16; // 0x10
+ field public static final int CAPABILITY_GEOLOCATION_PULL = 131072; // 0x20000
+ field public static final int CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER = 262144; // 0x40000
+ field public static final int CAPABILITY_GEOLOCATION_PUSH = 32768; // 0x8000
+ field public static final int CAPABILITY_GEOLOCATION_PUSH_SMS = 65536; // 0x10000
+ field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100
+ field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000
+ field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000
+ field public static final int CAPABILITY_MMTEL_CALL_COMPOSER = 1073741824; // 0x40000000
+ field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000
+ field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000
+ field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000
+ field public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = 2097152; // 0x200000
+ field public static final int CAPABILITY_RCS_VOICE_CALL = 524288; // 0x80000
+ field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000
+ field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000
+ field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800
+ field public static final int CAPABILITY_STANDALONE_CHAT_BOT = 536870912; // 0x20000000
+ field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400
+ field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR;
}
- 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);
+ public static class RcsContactUceCapability.Builder {
+ ctor public RcsContactUceCapability.Builder(@NonNull android.net.Uri);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long, @NonNull android.net.Uri);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(@NonNull String);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability build();
+ }
+
+ public class RcsUceAdapter {
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getUcePublishState() throws android.telephony.ims.ImsException;
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException;
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void requestCapabilities(@NonNull java.util.concurrent.Executor, @NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
+ field public static final int ERROR_ALREADY_IN_QUEUE = 13; // 0xd
+ field public static final int ERROR_FORBIDDEN = 6; // 0x6
+ field public static final int ERROR_GENERIC_FAILURE = 1; // 0x1
+ field public static final int ERROR_INSUFFICIENT_MEMORY = 11; // 0xb
+ field public static final int ERROR_LOST_NETWORK = 12; // 0xc
+ field public static final int ERROR_NOT_AUTHORIZED = 5; // 0x5
+ field public static final int ERROR_NOT_AVAILABLE = 3; // 0x3
+ field public static final int ERROR_NOT_ENABLED = 2; // 0x2
+ field public static final int ERROR_NOT_FOUND = 7; // 0x7
+ field public static final int ERROR_NOT_REGISTERED = 4; // 0x4
+ field public static final int ERROR_REQUEST_TIMEOUT = 10; // 0xa
+ field public static final int ERROR_REQUEST_TOO_LARGE = 8; // 0x8
+ field public static final int PUBLISH_STATE_200_OK = 1; // 0x1
+ field public static final int PUBLISH_STATE_NOT_PUBLISHED = 2; // 0x2
+ field public static final int PUBLISH_STATE_OTHER_ERROR = 6; // 0x6
+ field public static final int PUBLISH_STATE_RCS_PROVISION_ERROR = 4; // 0x4
+ field public static final int PUBLISH_STATE_REQUEST_TIMEOUT = 5; // 0x5
+ field public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; // 0x3
+ }
+
+ public static class RcsUceAdapter.CapabilitiesCallback {
+ ctor public RcsUceAdapter.CapabilitiesCallback();
+ method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>);
+ method public void onError(int);
}
}
@@ -3656,6 +3891,7 @@
public abstract class ImsFeature {
ctor public ImsFeature();
method public abstract void changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
+ method public int getFeatureState();
method public final int getSlotIndex();
method public abstract void onFeatureReady();
method public abstract void onFeatureRemoved();
@@ -3694,7 +3930,7 @@
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";
@@ -3710,10 +3946,6 @@
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 {
@@ -3725,6 +3957,8 @@
public class RcsFeature extends android.telephony.ims.feature.ImsFeature {
ctor public RcsFeature();
method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
+ method @NonNull public android.telephony.ims.stub.RcsSipOptionsImplBase getOptionsExchangeImpl();
+ method @NonNull public android.telephony.ims.stub.RcsPresenceExchangeImplBase getPresenceExchangeImpl();
method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities);
method public void onFeatureReady();
method public void onFeatureRemoved();
@@ -3897,12 +4131,89 @@
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);
method public int updateClir(int);
method public int updateColp(boolean);
method public int updateColr(int);
+ field public static final int CALL_BARRING_ALL = 7; // 0x7
+ field public static final int CALL_BARRING_ALL_INCOMING = 1; // 0x1
+ field public static final int CALL_BARRING_ALL_OUTGOING = 2; // 0x2
+ field public static final int CALL_BARRING_ANONYMOUS_INCOMING = 6; // 0x6
+ field public static final int CALL_BARRING_INCOMING_ALL_SERVICES = 9; // 0x9
+ field public static final int CALL_BARRING_OUTGOING_ALL_SERVICES = 8; // 0x8
+ field public static final int CALL_BARRING_OUTGOING_INTL = 3; // 0x3
+ field public static final int CALL_BARRING_OUTGOING_INTL_EXCL_HOME = 4; // 0x4
+ field public static final int CALL_BARRING_SPECIFIC_INCOMING_CALLS = 10; // 0xa
+ field public static final int CALL_BLOCKING_INCOMING_WHEN_ROAMING = 5; // 0x5
+ field public static final int INVALID_RESULT = -1; // 0xffffffff
+ }
+
+ public class RcsCapabilityExchange {
+ ctor public RcsCapabilityExchange();
+ method public final void onCommandUpdate(int, int) throws android.telephony.ims.ImsException;
+ field public static final int COMMAND_CODE_FETCH_ERROR = 4; // 0x4
+ field public static final int COMMAND_CODE_GENERIC_FAILURE = 2; // 0x2
+ field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6; // 0x6
+ field public static final int COMMAND_CODE_INVALID_PARAM = 3; // 0x3
+ field public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7; // 0x7
+ field public static final int COMMAND_CODE_NOT_FOUND = 9; // 0x9
+ field public static final int COMMAND_CODE_NOT_SUPPORTED = 8; // 0x8
+ field public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11; // 0xb
+ field public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5; // 0x5
+ field public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10; // 0xa
+ field public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; // 0x0
+ field public static final int COMMAND_CODE_SUCCESS = 1; // 0x1
+ }
+
+ public class RcsPresenceExchangeImplBase extends android.telephony.ims.stub.RcsCapabilityExchange {
+ ctor public RcsPresenceExchangeImplBase();
+ method public final void onCapabilityRequestResponse(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>, int) throws android.telephony.ims.ImsException;
+ method public final void onNetworkResponse(int, @NonNull String, int) throws android.telephony.ims.ImsException;
+ method public final void onNotifyUpdateCapabilites(int) throws android.telephony.ims.ImsException;
+ method public final void onUnpublish() throws android.telephony.ims.ImsException;
+ method public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, int);
+ method public void updateCapabilities(@NonNull android.telephony.ims.RcsContactUceCapability, int);
+ field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; // 0x0
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; // 0x6
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; // 0x5
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; // 0x3
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; // 0x4
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; // 0x8
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; // 0x1
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; // 0x2
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; // 0xa
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb
+ field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; // 0x7
+ field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; // 0x9
+ field public static final int RESPONSE_FORBIDDEN = 3; // 0x3
+ field public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2; // 0x2
+ field public static final int RESPONSE_NOT_FOUND = 4; // 0x4
+ field public static final int RESPONSE_NOT_REGISTERED = 1; // 0x1
+ field public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7; // 0x7
+ field public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5; // 0x5
+ field public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8; // 0x8
+ field public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1; // 0xffffffff
+ field public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6; // 0x6
+ field public static final int RESPONSE_SUCCESS = 0; // 0x0
+ }
+
+ public class RcsSipOptionsImplBase extends android.telephony.ims.stub.RcsCapabilityExchange {
+ ctor public RcsSipOptionsImplBase();
+ method public final void onCapabilityRequestResponse(int, @NonNull String, @Nullable android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException;
+ method public final void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException;
+ method public void respondToCapabilityRequest(@NonNull String, @NonNull android.telephony.ims.RcsContactUceCapability, int);
+ method public void respondToCapabilityRequestWithError(@NonNull android.net.Uri, int, @NonNull String, int);
+ method public void sendCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int);
+ field public static final int RESPONSE_BAD_REQUEST = 5; // 0x5
+ field public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4; // 0x4
+ field public static final int RESPONSE_GENERIC_FAILURE = -1; // 0xffffffff
+ field public static final int RESPONSE_NOT_FOUND = 3; // 0x3
+ field public static final int RESPONSE_REQUEST_TIMEOUT = 2; // 0x2
+ field public static final int RESPONSE_SUCCESS = 0; // 0x0
+ field public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1; // 0x1
}
}
@@ -4087,138 +4398,10 @@
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/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
index 3af392c..46f3aeb 100644
--- a/api/test-lint-baseline.txt
+++ b/api/test-lint-baseline.txt
@@ -5,6 +5,16 @@
+// Tethering broadcast action / extras cannot change name for backwards compatibility
+ActionValue: android.net.TetheringManager#ACTION_TETHER_STATE_CHANGED:
+ Inconsistent action value; expected `android.net.action.TETHER_STATE_CHANGED`, was `android.net.conn.TETHER_STATE_CHANGED`
+ActionValue: android.net.TetheringManager#EXTRA_ACTIVE_TETHER:
+ Inconsistent extra value; expected `android.net.extra.ACTIVE_TETHER`, was `tetherArray`
+ActionValue: android.net.TetheringManager#EXTRA_AVAILABLE_TETHER:
+ Inconsistent extra value; expected `android.net.extra.AVAILABLE_TETHER`, was `availableArray`
+ActionValue: android.net.TetheringManager#EXTRA_ERRORED_TETHER:
+ Inconsistent extra value; expected `android.net.extra.ERRORED_TETHER`, was `erroredArray`
+
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_ADDITIONAL_CALL_INFO:
Inconsistent extra value; expected `android.telephony.ims.extra.ADDITIONAL_CALL_INFO`, was `AdditionalCallInfo`
ActionValue: android.telephony.ims.ImsCallProfile#EXTRA_CALL_RAT_TYPE:
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index db384ba..85db4b9 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -17,6 +17,8 @@
#define LOG_NDEBUG 0
#define LOG_TAG "BootAnimation"
+#include <vector>
+
#include <stdint.h>
#include <inttypes.h>
#include <sys/inotify.h>
@@ -80,6 +82,10 @@
static const char PRODUCT_SHUTDOWNANIMATION_FILE[] = "/product/media/shutdownanimation.zip";
static const char SYSTEM_SHUTDOWNANIMATION_FILE[] = "/system/media/shutdownanimation.zip";
+static constexpr const char* PRODUCT_USERSPACE_REBOOT_ANIMATION_FILE = "/product/media/userspace-reboot.zip";
+static constexpr const char* OEM_USERSPACE_REBOOT_ANIMATION_FILE = "/oem/media/userspace-reboot.zip";
+static constexpr const char* SYSTEM_USERSPACE_REBOOT_ANIMATION_FILE = "/system/media/userspace-reboot.zip";
+
static const char SYSTEM_DATA_DIR_PATH[] = "/data/system";
static const char SYSTEM_TIME_DIR_NAME[] = "time";
static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time";
@@ -341,6 +347,16 @@
return false;
}
+bool BootAnimation::findBootAnimationFileInternal(const std::vector<std::string> &files) {
+ for (const std::string& f : files) {
+ if (access(f.c_str(), R_OK) == 0) {
+ mZipFileName = f.c_str();
+ return true;
+ }
+ }
+ return false;
+}
+
void BootAnimation::findBootAnimationFile() {
// If the device has encryption turned on or is in process
// of being encrypted we show the encrypted boot animation.
@@ -351,28 +367,33 @@
!strcmp("trigger_restart_min_framework", decrypt);
if (!mShuttingDown && encryptedAnimation) {
- static const char* encryptedBootFiles[] =
- {PRODUCT_ENCRYPTED_BOOTANIMATION_FILE, SYSTEM_ENCRYPTED_BOOTANIMATION_FILE};
- for (const char* f : encryptedBootFiles) {
- if (access(f, R_OK) == 0) {
- mZipFileName = f;
- return;
- }
+ static const std::vector<std::string> encryptedBootFiles = {
+ PRODUCT_ENCRYPTED_BOOTANIMATION_FILE, SYSTEM_ENCRYPTED_BOOTANIMATION_FILE,
+ };
+ if (findBootAnimationFileInternal(encryptedBootFiles)) {
+ return;
}
}
const bool playDarkAnim = android::base::GetIntProperty("ro.boot.theme", 0) == 1;
- static const char* bootFiles[] =
- {APEX_BOOTANIMATION_FILE, playDarkAnim ? PRODUCT_BOOTANIMATION_DARK_FILE : PRODUCT_BOOTANIMATION_FILE,
- OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE};
- static const char* shutdownFiles[] =
- {PRODUCT_SHUTDOWNANIMATION_FILE, OEM_SHUTDOWNANIMATION_FILE, SYSTEM_SHUTDOWNANIMATION_FILE, ""};
+ static const std::vector<std::string> bootFiles = {
+ APEX_BOOTANIMATION_FILE, playDarkAnim ? PRODUCT_BOOTANIMATION_DARK_FILE : PRODUCT_BOOTANIMATION_FILE,
+ OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE
+ };
+ static const std::vector<std::string> shutdownFiles = {
+ PRODUCT_SHUTDOWNANIMATION_FILE, OEM_SHUTDOWNANIMATION_FILE, SYSTEM_SHUTDOWNANIMATION_FILE, ""
+ };
+ static const std::vector<std::string> userspaceRebootFiles = {
+ PRODUCT_USERSPACE_REBOOT_ANIMATION_FILE, OEM_USERSPACE_REBOOT_ANIMATION_FILE,
+ SYSTEM_USERSPACE_REBOOT_ANIMATION_FILE,
+ };
- for (const char* f : (!mShuttingDown ? bootFiles : shutdownFiles)) {
- if (access(f, R_OK) == 0) {
- mZipFileName = f;
- return;
- }
+ if (android::base::GetBoolProperty("sys.init.userspace_reboot.in_progress", false)) {
+ findBootAnimationFileInternal(userspaceRebootFiles);
+ } else if (mShuttingDown) {
+ findBootAnimationFileInternal(shutdownFiles);
+ } else {
+ findBootAnimationFileInternal(bootFiles);
}
}
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index dc19fb0..574d65e 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_BOOTANIMATION_H
#define ANDROID_BOOTANIMATION_H
+#include <vector>
+
#include <stdint.h>
#include <sys/types.h>
@@ -157,6 +159,7 @@
bool parseAnimationDesc(Animation&);
bool preloadZip(Animation &animation);
void findBootAnimationFile();
+ bool findBootAnimationFileInternal(const std::vector<std::string>& files);
bool preloadAnimation();
void checkExit();
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index 6033655..c2ee6dc 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -103,6 +103,10 @@
runSetVirtualDisk();
} else if ("set-isolated-storage".equals(op)) {
runIsolatedStorage();
+ } else if ("start-checkpoint".equals(op)) {
+ runStartCheckpoint();
+ } else if ("supports-checkpoint".equals(op)) {
+ runSupportsCheckpoint();
} else {
throw new IllegalArgumentException();
}
@@ -313,6 +317,27 @@
}
}
+ private void runStartCheckpoint() throws RemoteException {
+ final String numRetriesString = nextArg();
+ if (numRetriesString == null) {
+ throw new IllegalArgumentException("Expected <num-retries>");
+ }
+ int numRetries;
+ try {
+ numRetries = Integer.parseInt(numRetriesString);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("<num-retries> must be a positive integer");
+ }
+ if (numRetries <= 0) {
+ throw new IllegalArgumentException("<num-retries> must be a positive integer");
+ }
+ mSm.startCheckpoint(numRetries);
+ }
+
+ private void runSupportsCheckpoint() throws RemoteException {
+ System.out.println(mSm.supportsCheckpoint());
+ }
+
private String nextArg() {
if (mNextArg >= mArgs.length) {
return null;
@@ -344,6 +369,10 @@
System.err.println("");
System.err.println(" sm set-isolated-storage [on|off|default]");
System.err.println("");
+ System.err.println(" sm start-checkpoint <num-retries>");
+ System.err.println("");
+ System.err.println(" sm supports-checkpoint");
+ System.err.println("");
return 1;
}
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index c923156..88d94cc 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -50,6 +50,7 @@
import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
import "frameworks/base/core/proto/android/stats/location/location_enums.proto";
import "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.proto";
+import "frameworks/base/core/proto/android/stats/otaupdate/updateengine_enums.proto";
import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto";
import "frameworks/base/core/proto/android/stats/style/style_enums.proto";
import "frameworks/base/core/proto/android/telecomm/enums.proto";
@@ -74,9 +75,9 @@
// Pushed atoms start at 2.
oneof pushed {
// For StatsLog reasons, 1 is illegal and will not work. Must start at 2.
- BleScanStateChanged ble_scan_state_changed = 2;
+ BleScanStateChanged ble_scan_state_changed = 2 [(log_from_module) = "bluetooth"];
ProcessStateChanged process_state_changed = 3;
- BleScanResultReceived ble_scan_result_received = 4;
+ BleScanResultReceived ble_scan_result_received = 4 [(log_from_module) = "bluetooth"];
SensorStateChanged sensor_state_changed = 5;
GpsScanStateChanged gps_scan_state_changed = 6;
SyncStateChanged sync_state_changed = 7;
@@ -123,10 +124,10 @@
AppStartOccurred app_start_occurred = 48;
AppStartCanceled app_start_canceled = 49;
AppStartFullyDrawn app_start_fully_drawn = 50;
- LmkKillOccurred lmk_kill_occurred = 51;
+ LmkKillOccurred lmk_kill_occurred = 51 [(log_from_module) = "lmkd"];
PictureInPictureStateChanged picture_in_picture_state_changed = 52;
WifiMulticastLockStateChanged wifi_multicast_lock_state_changed = 53;
- LmkStateChanged lmk_state_changed = 54;
+ LmkStateChanged lmk_state_changed = 54 [(log_from_module) = "lmkd"];
AppStartMemoryStateCaptured app_start_memory_state_captured = 55;
ShutdownSequenceReported shutdown_sequence_reported = 56;
BootSequenceReported boot_sequence_reported = 57;
@@ -140,7 +141,8 @@
AppDied app_died = 65;
ResourceConfigurationChanged resource_configuration_changed = 66;
BluetoothEnabledStateChanged bluetooth_enabled_state_changed = 67;
- BluetoothConnectionStateChanged bluetooth_connection_state_changed = 68;
+ BluetoothConnectionStateChanged bluetooth_connection_state_changed =
+ 68 [(log_from_module) = "bluetooth"];
GpsSignalQualityChanged gps_signal_quality_changed = 69;
UsbConnectorStateChanged usb_connector_state_changed = 70;
SpeakerImpedanceReported speaker_impedance_reported = 71;
@@ -215,9 +217,12 @@
RescuePartyResetReported rescue_party_reset_reported = 122;
SignedConfigReported signed_config_reported = 123;
GnssNiEventReported gnss_ni_event_reported = 124;
- BluetoothLinkLayerConnectionEvent bluetooth_link_layer_connection_event = 125;
- BluetoothAclConnectionStateChanged bluetooth_acl_connection_state_changed = 126;
- BluetoothScoConnectionStateChanged bluetooth_sco_connection_state_changed = 127;
+ BluetoothLinkLayerConnectionEvent bluetooth_link_layer_connection_event =
+ 125 [(log_from_module) = "bluetooth"];
+ BluetoothAclConnectionStateChanged bluetooth_acl_connection_state_changed =
+ 126 [(log_from_module) = "bluetooth"];
+ BluetoothScoConnectionStateChanged bluetooth_sco_connection_state_changed =
+ 127 [(log_from_module) = "bluetooth"];
AppDowngraded app_downgraded = 128;
AppOptimizedAfterDowngraded app_optimized_after_downgraded = 129;
LowStorageStateChanged low_storage_state_changed = 130;
@@ -241,23 +246,40 @@
BiometricSystemHealthIssueDetected biometric_system_health_issue_detected = 148;
BubbleUIChanged bubble_ui_changed = 149;
ScheduledJobConstraintChanged scheduled_job_constraint_changed = 150;
- BluetoothActiveDeviceChanged bluetooth_active_device_changed = 151;
- BluetoothA2dpPlaybackStateChanged bluetooth_a2dp_playback_state_changed = 152;
- BluetoothA2dpCodecConfigChanged bluetooth_a2dp_codec_config_changed = 153;
- BluetoothA2dpCodecCapabilityChanged bluetooth_a2dp_codec_capability_changed = 154;
- BluetoothA2dpAudioUnderrunReported bluetooth_a2dp_audio_underrun_reported = 155;
- BluetoothA2dpAudioOverrunReported bluetooth_a2dp_audio_overrun_reported = 156;
- BluetoothDeviceRssiReported bluetooth_device_rssi_reported = 157;
- BluetoothDeviceFailedContactCounterReported bluetooth_device_failed_contact_counter_reported = 158;
- BluetoothDeviceTxPowerLevelReported bluetooth_device_tx_power_level_reported = 159;
- BluetoothHciTimeoutReported bluetooth_hci_timeout_reported = 160;
- BluetoothQualityReportReported bluetooth_quality_report_reported = 161;
- BluetoothDeviceInfoReported bluetooth_device_info_reported = 162;
- BluetoothRemoteVersionInfoReported bluetooth_remote_version_info_reported = 163;
- BluetoothSdpAttributeReported bluetooth_sdp_attribute_reported = 164;
- BluetoothBondStateChanged bluetooth_bond_state_changed = 165;
- BluetoothClassicPairingEventReported bluetooth_classic_pairing_event_reported = 166;
- BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported = 167;
+ BluetoothActiveDeviceChanged bluetooth_active_device_changed =
+ 151 [(log_from_module) = "bluetooth"];
+ BluetoothA2dpPlaybackStateChanged bluetooth_a2dp_playback_state_changed =
+ 152 [(log_from_module) = "bluetooth"];
+ BluetoothA2dpCodecConfigChanged bluetooth_a2dp_codec_config_changed =
+ 153 [(log_from_module) = "bluetooth"];
+ BluetoothA2dpCodecCapabilityChanged bluetooth_a2dp_codec_capability_changed =
+ 154 [(log_from_module) = "bluetooth"];
+ BluetoothA2dpAudioUnderrunReported bluetooth_a2dp_audio_underrun_reported =
+ 155 [(log_from_module) = "bluetooth"];
+ BluetoothA2dpAudioOverrunReported bluetooth_a2dp_audio_overrun_reported =
+ 156 [(log_from_module) = "bluetooth"];
+ BluetoothDeviceRssiReported bluetooth_device_rssi_reported =
+ 157 [(log_from_module) = "bluetooth"];
+ BluetoothDeviceFailedContactCounterReported
+ bluetooth_device_failed_contact_counter_reported = 158 [(log_from_module) = "bluetooth"];
+ BluetoothDeviceTxPowerLevelReported bluetooth_device_tx_power_level_reported =
+ 159 [(log_from_module) = "bluetooth"];
+ BluetoothHciTimeoutReported bluetooth_hci_timeout_reported =
+ 160 [(log_from_module) = "bluetooth"];
+ BluetoothQualityReportReported bluetooth_quality_report_reported =
+ 161 [(log_from_module) = "bluetooth"];
+ BluetoothDeviceInfoReported bluetooth_device_info_reported =
+ 162 [(log_from_module) = "bluetooth"];
+ BluetoothRemoteVersionInfoReported bluetooth_remote_version_info_reported =
+ 163 [(log_from_module) = "bluetooth"];
+ BluetoothSdpAttributeReported bluetooth_sdp_attribute_reported =
+ 164 [(log_from_module) = "bluetooth"];
+ BluetoothBondStateChanged bluetooth_bond_state_changed =
+ 165 [(log_from_module) = "bluetooth"];
+ BluetoothClassicPairingEventReported bluetooth_classic_pairing_event_reported =
+ 166 [(log_from_module) = "bluetooth"];
+ BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported =
+ 167 [(log_from_module) = "bluetooth"];
ScreenTimeoutExtensionReported screen_timeout_extension_reported = 168;
ProcessStartTime process_start_time = 169;
PermissionGrantRequestResultReported permission_grant_request_result_reported =
@@ -279,7 +301,8 @@
BiometricEnrolled biometric_enrolled = 184;
SystemServerWatchdogOccurred system_server_watchdog_occurred = 185;
TombStoneOccurred tomb_stone_occurred = 186;
- BluetoothClassOfDeviceReported bluetooth_class_of_device_reported = 187;
+ BluetoothClassOfDeviceReported bluetooth_class_of_device_reported =
+ 187 [(log_from_module) = "bluetooth"];
IntelligenceEventReported intelligence_event_reported =
188 [(log_from_module) = "intelligence"];
ThermalThrottlingSeverityStateChanged thermal_throttling_severity_state_changed = 189;
@@ -322,6 +345,8 @@
ExclusionRectStateChanged exclusion_rect_state_changed = 223;
BackGesture back_gesture_reported_reported = 224;
+ UpdateEngineUpdateAttemptReported update_engine_update_attempt_reported = 225;
+ UpdateEngineSuccessfulUpdateReported update_engine_successful_update_reported = 226;
AppCompatibilityChangeReported app_compatibility_change_reported =
228 [(allow_from_any_uid) = true];
PerfettoUploaded perfetto_uploaded =
@@ -6234,7 +6259,8 @@
optional bool is_preinstalled = 3;
// True if the package is privileged.
- optional bool is_priv_app = 4;
+ // Starting from Android 11, this boolean is not set and will always be false.
+ optional bool is_priv_app = 4 [deprecated = true];
}
/**
@@ -6894,3 +6920,70 @@
optional int64 trace_uuid_lsb = 2;
optional int64 trace_uuid_msb = 3;
}
+
+/**
+ * Information about an OTA update attempt by update_engine.
+ * Logged from platform/system/update_engine/metrics_reporter_android.cc
+ */
+message UpdateEngineUpdateAttemptReported {
+ // The number of attempts for the update engine to apply a given payload.
+ optional int32 attempt_number = 1;
+
+ optional android.stats.otaupdate.PayloadType payload_type = 2;
+
+ // The total time in minutes for the update engine to apply a given payload.
+ // The time is calculated by calling clock_gettime() / CLOCK_BOOTTIME; and
+ // it's increased when the system is sleeping.
+ optional int32 duration_boottime_in_minutes = 3;
+
+ // The total time in minutes for the update engine to apply a given payload.
+ // The time is calculated by calling clock_gettime() / CLOCK_MONOTONIC_RAW;
+ // and it's not increased when the system is sleeping.
+ optional int32 duration_monotonic_in_minutes = 4;
+
+ // The size of the payload in MiBs.
+ optional int32 payload_size_mib = 5;
+
+ // The attempt result reported by the update engine for an OTA update.
+ optional android.stats.otaupdate.AttemptResult attempt_result = 6;
+
+ // The error code reported by the update engine after an OTA update attempt
+ // on A/B devices.
+ optional android.stats.otaupdate.ErrorCode error_code = 7;
+
+ // The build fingerprint of the source system. The value is read from a
+ // system property when the device takes the update. e.g.
+ // Android/aosp_sailfish/sailfish:10/QP1A.190425.004/5507117:userdebug/test-keys
+ optional string source_fingerprint = 8;
+}
+
+/**
+ * Information about all the attempts the device make before finishing the
+ * successful update.
+ * Logged from platform/system/update_engine/metrics_reporter_android.cc
+ */
+message UpdateEngineSuccessfulUpdateReported {
+ // The number of attempts for the update engine to apply the payload for a
+ // successful update.
+ optional int32 attempt_count = 1;
+
+ optional android.stats.otaupdate.PayloadType payload_type = 2;
+
+ optional int32 payload_size_mib = 3;
+
+ // The total number of bytes downloaded by update_engine since the last
+ // successful update.
+ optional int32 total_bytes_downloaded_mib = 4;
+
+ // The ratio in percentage of the over-downloaded bytes compared to the
+ // total bytes needed to successfully install the update. e.g. 200 if we
+ // download 200MiB in total for a 100MiB package.
+ optional int32 download_overhead_percentage = 5;
+
+ // The total time in minutes for the update engine to apply the payload for a
+ // successful update.
+ optional int32 total_duration_minutes = 6;
+
+ // The number of reboot of the device during a successful update.
+ optional int32 reboot_count = 7;
+}
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 1987440..9707405 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -366,12 +366,8 @@
}
private void runGetMaxPhones() throws RemoteException {
- // This assumes the max number of SIMs is 2, which it currently is
- if (TelephonyManager.MULTISIM_ALLOWED == mTelephonyManager.isMultiSimSupported()) {
- System.out.println("2");
- } else {
- System.out.println("1");
- }
+ // how many logical modems can be potentially active simultaneously
+ System.out.println(mTelephonyManager.getSupportedModemCount());
}
private void runSetEmergencyPhoneAccountPackageFilter() throws RemoteException {
diff --git a/core/java/android/annotation/SystemApi.java b/core/java/android/annotation/SystemApi.java
index 2cb93e4..ecbfed9 100644
--- a/core/java/android/annotation/SystemApi.java
+++ b/core/java/android/annotation/SystemApi.java
@@ -23,6 +23,7 @@
import static java.lang.annotation.ElementType.PACKAGE;
import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -40,39 +41,48 @@
*/
@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
+@Repeatable(SystemApi.Container.class) // TODO(b/146727827): make this non-repeatable
public @interface SystemApi {
enum Client {
/**
* Specifies that the intended clients of a SystemApi are privileged apps.
- * This is the default value for {@link #client}. This implies
- * MODULE_APPS and MODULE_LIBRARIES as well, which means that APIs will also
- * be available to module apps and jars.
+ * This is the default value for {@link #client}.
+ * TODO Update the javadoc according to the final spec
*/
PRIVILEGED_APPS,
/**
- * Specifies that the intended clients of a SystemApi are modules implemented
- * as apps, like the NetworkStack app. This implies MODULE_LIBRARIES as well,
- * which means that APIs will also be available to module jars.
+ * DO NOT USE. Use PRIVILEGED_APPS instead.
+ * (This would provide no further protection over PRIVILEGED_APPS; do not rely on it)
+ * @deprecated Use #PRIVILEGED_APPS instead
*/
+ @Deprecated
MODULE_APPS,
/**
* Specifies that the intended clients of a SystemApi are modules implemented
* as libraries, like the conscrypt.jar in the conscrypt APEX.
+ * TODO Update the javadoc according to the final spec
*/
- MODULE_LIBRARIES
+ MODULE_LIBRARIES,
+
+ /**
+ * Specifies that the system API is available only in the system server process.
+ * Use this to expose APIs from code loaded by the system server process <em>but</em>
+ * not in <pre>BOOTCLASSPATH</pre>.
+ * TODO(b/148177503) Update "services-stubs" and actually use it.
+ */
+ SYSTEM_SERVER
}
+ /** @deprecated do not use */
+ @Deprecated
enum Process {
- /**
- * Specifies that the SystemAPI is available in every Java processes.
- * This is the default value for {@link #process}.
- */
+ /** @deprecated do not use */
ALL,
/**
- * Specifies that the SystemAPI is available only in the system server process.
+ * @deprecated use Client#SYSTEM_SERVER instead
*/
SYSTEM_SERVER
}
@@ -83,7 +93,18 @@
Client client() default android.annotation.SystemApi.Client.PRIVILEGED_APPS;
/**
- * The process(es) that this SystemAPI is available
+ * @deprecated use Client#SYSTEM_SERVER instead for system_server APIs
*/
+ @Deprecated
Process process() default android.annotation.SystemApi.Process.ALL;
+
+
+ /**
+ * Container for {@link SystemApi} that allows it to be applied repeatedly to types.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(TYPE)
+ @interface Container {
+ SystemApi[] value();
+ }
}
diff --git a/core/java/android/annotation/UnsupportedAppUsage.java b/core/java/android/annotation/UnsupportedAppUsage.java
deleted file mode 100644
index 1af48cb..0000000
--- a/core/java/android/annotation/UnsupportedAppUsage.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.annotation;
-
-import static java.lang.annotation.ElementType.CONSTRUCTOR;
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.CLASS;
-
-import java.lang.annotation.Repeatable;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Indicates that this non-SDK interface is used by apps. A non-SDK interface is a
- * class member (field or method) that is not part of the public SDK. Since the
- * member is not part of the SDK, usage by apps is not supported.
- *
- * <h2>If you are an Android App developer</h2>
- *
- * This annotation indicates that you may be able to access the member, but that
- * this access is discouraged and not supported by Android. If there is a value
- * for {@link #maxTargetSdk()} on the annotation, access will be restricted based
- * on the {@code targetSdkVersion} value set in your manifest.
- *
- * <p>Fields and methods annotated with this are likely to be restricted, changed
- * or removed in future Android releases. If you rely on these members for
- * functionality that is not otherwise supported by Android, consider filing a
- * <a href="http://g.co/dev/appcompat">feature request</a>.
- *
- * <h2>If you are an Android OS developer</h2>
- *
- * This annotation acts as a heads up that changing a given method or field
- * may affect apps, potentially breaking them when the next Android version is
- * released. In some cases, for members that are heavily used, this annotation
- * may imply restrictions on changes to the member.
- *
- * <p>This annotation also results in access to the member being permitted by the
- * runtime, with a warning being generated in debug builds. Which apps can access
- * the member is determined by the value of {@link #maxTargetSdk()}.
- *
- * <p>For more details, see go/UnsupportedAppUsage.
- *
- * {@hide}
- */
-@Retention(CLASS)
-@Target({CONSTRUCTOR, METHOD, FIELD, TYPE})
-@Repeatable(UnsupportedAppUsage.Container.class)
-public @interface UnsupportedAppUsage {
-
- /**
- * Associates a bug tracking the work to add a public alternative to this API. Optional.
- *
- * @return ID of the associated tracking bug
- */
- long trackingBug() default 0;
-
- /**
- * Indicates that usage of this API is limited to apps based on their target SDK version.
- *
- * <p>Access to the API is allowed if the targetSdkVersion in the apps manifest is no greater
- * than this value. Access checks are performed at runtime.
- *
- * <p>This is used to give app developers a grace period to migrate off a non-SDK interface.
- * When making Android version N, existing APIs can have a maxTargetSdk of N-1 added to them.
- * Developers must then migrate off the API when their app is updated in future, but it will
- * continue working in the meantime.
- *
- * <p>Possible values are:
- * <ul>
- * <li>
- * An API level like {@link android.os.Build.VERSION_CODES#O} - in which case the API is
- * available up to and including the specified release. Or, in other words, the API is
- * blacklisted (unavailable) from the next API level from the one specified.
- * </li>
- * <li>
- * absent (default value) - All apps can access this API, but doing so may result in
- * warnings in the log, UI warnings (on developer builds) and/or strictmode violations.
- * The API is likely to be further restricted in future.
- * </li>
- *
- * </ul>
- *
- * @return The maximum value for an apps targetSdkVersion in order to access this API.
- */
- int maxTargetSdk() default Integer.MAX_VALUE;
-
- /**
- * For debug use only. The expected dex signature to be generated for this API, used to verify
- * parts of the build process.
- *
- * @return A dex API signature.
- */
- String expectedSignature() default "";
-
- /**
- * The signature of an implicit (not present in the source) member that forms part of the
- * hiddenapi.
- *
- * <p>Allows access to non-SDK API elements that are not represented in the input source to be
- * managed.
- *
- * <p>This must only be used when applying the annotation to a type, using it in any other
- * situation is an error.
- *
- * @return A dex API signature.
- */
- String implicitMember() default "";
-
- /**
- * Public API alternatives to this API.
- *
- * <p>If non-empty, the string must be a description of the public API alternative(s) to this
- * API. The explanation must contain at least one Javadoc link tag to public API methods or
- * fields. e.g.:
- * {@literal @UnsupportedAppUsage(publicAlternatives="Use {@link foo.bar.Baz#bat()} instead.")}
- *
- * <p>Any elements that can be deduced can be omitted, e.g.:
- * <ul>
- * <li>
- * the class, if it's the same as for the annotated element.
- * </li>
- * <li>
- * the package name, if it's the same as for the annotated element.
- * </li>
- * <li>
- * the method parameters, if there is only one method with that name in the given
- * package and class.
- * </li>
- * </ul>
- * @return A Javadoc-formatted string.
- */
- @SuppressWarnings("JavadocReference")
- String publicAlternatives() default "";
-
- /**
- * Override the default source position when generating an index of the annotations.
- *
- * <p>This is intended for use by tools that generate java source code, to point to the
- * original source position of the annotation, rather than the position within the generated
- * code. It should never be set manually.
- *
- * <p>The format of the value is "path/to/file:startline:startcol:endline:endcol" indicating
- * the position of the annotation itself.
- */
- String overrideSourcePosition() default "";
-
- /**
- * Container for {@link UnsupportedAppUsage} that allows it to be applied repeatedly to types.
- */
- @Retention(CLASS)
- @Target(TYPE)
- @interface Container {
- UnsupportedAppUsage[] value();
- }
-}
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index a0040ff..b669d77 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -35,7 +35,7 @@
import android.util.Log;
import android.util.proto.ProtoOutputStream;
-import libcore.timezone.ZoneInfoDB;
+import libcore.timezone.ZoneInfoDb;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -1000,7 +1000,7 @@
if (mTargetSdkVersion >= Build.VERSION_CODES.M) {
boolean hasTimeZone = false;
try {
- hasTimeZone = ZoneInfoDB.getInstance().hasTimeZone(timeZone);
+ hasTimeZone = ZoneInfoDb.getInstance().hasTimeZone(timeZone);
} catch (IOException ignored) {
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 7d3cd28..6ff48ea 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -720,7 +720,18 @@
/** @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 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 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 @@
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 @@
OPSTR_ACCESS_ACCESSIBILITY,
OPSTR_READ_DEVICE_IDENTIFIERS,
OPSTR_ACCESS_MEDIA_LOCATION,
+ OPSTR_ACTIVATE_PLATFORM_VPN,
};
/**
@@ -1480,6 +1506,7 @@
"ACCESS_ACCESSIBILITY",
"READ_DEVICE_IDENTIFIERS",
"ACCESS_MEDIA_LOCATION",
+ "ACTIVATE_PLATFORM_VPN"
};
/**
@@ -1579,6 +1606,7 @@
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 @@
null, // ACCESS_ACCESSIBILITY
null, // READ_DEVICE_IDENTIFIERS
null, // ACCESS_MEDIA_LOCATION
+ null, // ACTIVATE_PLATFORM_VPN
};
/**
@@ -1776,6 +1805,7 @@
false, // ACCESS_ACCESSIBILITY
false, // READ_DEVICE_IDENTIFIERS
false, // ACCESS_MEDIA_LOCATION
+ false, // ACTIVATE_PLATFORM_VPN
};
/**
@@ -1873,6 +1903,7 @@
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 @@
false, // ACCESS_ACCESSIBILITY
false, // READ_DEVICE_IDENTIFIERS
false, // ACCESS_MEDIA_LOCATION
+ false, // ACTIVATE_PLATFORM_VPN
};
/**
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index 08cad04..996939e 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -16,7 +16,6 @@
package android.app;
-import android.annotation.NonNull;
import android.util.SparseIntArray;
import com.android.internal.util.function.QuadFunction;
@@ -77,38 +76,10 @@
public abstract void setDeviceAndProfileOwners(SparseIntArray owners);
/**
- * Sets the app-ops mode for a certain app-op and uid.
- *
- * <p>Similar as {@link AppOpsManager#setUidMode} but does not require the package manager to be
- * working. Hence this can be used very early during boot.
- *
- * <p>Only for internal callers. Does <u>not</u> verify that package name belongs to uid.
- *
- * @param code The op code to set.
- * @param uid The UID for which to set.
- * @param mode The new mode to set.
- */
- public abstract void setUidMode(int code, int uid, int mode);
-
- /**
* Set all {@link #setMode (package) modes} for this uid to the default value.
*
* @param code The app-op
* @param uid The uid
*/
public abstract void setAllPkgModesToDefault(int code, int uid);
-
- /**
- * Get the (raw) mode of an app-op.
- *
- * <p>Does <u>not</u> verify that package belongs to uid. The caller needs to do that.
- *
- * @param code The code of the op
- * @param uid The uid of the package the op belongs to
- * @param packageName The package the op belongs to
- *
- * @return The mode of the op
- */
- public abstract @AppOpsManager.Mode int checkOperationUnchecked(int code, int uid,
- @NonNull String packageName);
}
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index b1d791b..8ad2b36 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -15,6 +15,8 @@
*/
package android.app;
+import static android.annotation.SystemApi.Client.MODULE_APPS;
+
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -317,9 +319,14 @@
}
/**
+ * Allows users to block notifications sent through this channel, if this channel belongs to
+ * a package that is signed with the system signature. If the channel does not belong to a
+ * package that is signed with the system signature, this method does nothing.
+ * @param blockableSystem if {@code true}, allows users to block notifications on this channel.
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi(client = MODULE_APPS)
+ @TestApi
public void setBlockableSystem(boolean blockableSystem) {
mBlockableSystem = blockableSystem;
}
@@ -639,6 +646,7 @@
/**
* @hide
*/
+ @TestApi
public boolean isBlockableSystem() {
return mBlockableSystem;
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 88976e1..86b2c06 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -30,8 +30,10 @@
import android.app.role.RoleManager;
import android.app.slice.SliceManager;
import android.app.timedetector.TimeDetector;
+import android.app.timedetector.TimeDetectorImpl;
import android.app.timezone.RulesManager;
import android.app.timezonedetector.TimeZoneDetector;
+import android.app.timezonedetector.TimeZoneDetectorImpl;
import android.app.trust.TrustManager;
import android.app.usage.IStorageStatsManager;
import android.app.usage.IUsageStatsManager;
@@ -98,6 +100,7 @@
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;
@@ -112,6 +115,7 @@
import android.net.NetworkWatchlistManager;
import android.net.TestNetworkManager;
import android.net.TetheringManager;
+import android.net.VpnManager;
import android.net.lowpan.ILowpanManager;
import android.net.lowpan.LowpanManager;
import android.net.nsd.INsdManager;
@@ -352,11 +356,9 @@
registerService(Context.TETHERING_SERVICE, TetheringManager.class,
new CachedServiceFetcher<TetheringManager>() {
@Override
- public TetheringManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder b = ServiceManager.getService(Context.TETHERING_SERVICE);
- if (b == null) return null;
-
- return new TetheringManager(ctx, b);
+ public TetheringManager createService(ContextImpl ctx) {
+ return new TetheringManager(
+ ctx, () -> ServiceManager.getService(Context.TETHERING_SERVICE));
}});
@@ -369,6 +371,27 @@
return new IpSecManager(ctx, service);
}});
+ registerService(Context.VPN_MANAGEMENT_SERVICE, VpnManager.class,
+ new CachedServiceFetcher<VpnManager>() {
+ @Override
+ public VpnManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+ IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
+ return new VpnManager(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,
@@ -1254,7 +1277,7 @@
@Override
public TimeDetector createService(ContextImpl ctx)
throws ServiceNotFoundException {
- return new TimeDetector();
+ return new TimeDetectorImpl();
}});
registerService(Context.TIME_ZONE_DETECTOR_SERVICE, TimeZoneDetector.class,
@@ -1262,7 +1285,7 @@
@Override
public TimeZoneDetector createService(ContextImpl ctx)
throws ServiceNotFoundException {
- return new TimeZoneDetector();
+ return new TimeZoneDetectorImpl();
}});
registerService(Context.TELEPHONY_IMS_SERVICE, android.telephony.ims.ImsManager.class,
diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
index 479e4b4..bd649f8 100644
--- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.TimestampedValue;
@@ -28,17 +29,23 @@
import java.util.Objects;
/**
- * A time signal from a telephony source. The value can be {@code null} to indicate that the
- * telephony source has entered an "un-opinionated" state and any previously sent suggestions are
- * being withdrawn. When not {@code null}, the value consists of the number of milliseconds elapsed
- * since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number
- * was established. The elapsed realtime clock is considered accurate but volatile, so time signals
- * must not be persisted across device resets.
+ * A time suggestion from an identified telephony source. e.g. from NITZ information from a specific
+ * radio.
+ *
+ * <p>The time value can be {@code null} to indicate that the telephony source has entered an
+ * "un-opinionated" state and any previous suggestions from the source are being withdrawn. When not
+ * {@code null}, the value consists of the number of milliseconds elapsed since 1/1/1970 00:00:00
+ * UTC and the time according to the elapsed realtime clock when that number was established. The
+ * elapsed realtime clock is considered accurate but volatile, so time suggestions must not be
+ * persisted across device resets.
*
* @hide
*/
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class PhoneTimeSuggestion implements Parcelable {
+ /** @hide */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final @NonNull Parcelable.Creator<PhoneTimeSuggestion> CREATOR =
new Parcelable.Creator<PhoneTimeSuggestion>() {
public PhoneTimeSuggestion createFromParcel(Parcel in) {
@@ -85,15 +92,27 @@
dest.writeList(mDebugInfo);
}
+ /**
+ * Returns an identifier for the source of this suggestion. When a device has several "phones",
+ * i.e. sim slots or equivalent, it is used to identify which one.
+ */
public int getPhoneId() {
return mPhoneId;
}
+ /**
+ * Returns the suggestion. {@code null} means that the caller is no longer sure what time it
+ * is.
+ */
@Nullable
public TimestampedValue<Long> getUtcTime() {
return mUtcTime;
}
+ /**
+ * Returns debug metadata for the suggestion. The information is present in {@link #toString()}
+ * but is not considered for {@link #equals(Object)} and {@link #hashCode()}.
+ */
@NonNull
public List<String> getDebugInfo() {
return mDebugInfo == null
@@ -105,7 +124,7 @@
* information is present in {@link #toString()} but is not considered for
* {@link #equals(Object)} and {@link #hashCode()}.
*/
- public void addDebugInfo(String debugInfo) {
+ public void addDebugInfo(@NonNull String debugInfo) {
if (mDebugInfo == null) {
mDebugInfo = new ArrayList<>();
}
@@ -156,16 +175,19 @@
*
* @hide
*/
- public static class Builder {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final class Builder {
private final int mPhoneId;
- private TimestampedValue<Long> mUtcTime;
- private List<String> mDebugInfo;
+ @Nullable private TimestampedValue<Long> mUtcTime;
+ @Nullable private List<String> mDebugInfo;
+ /** Creates a builder with the specified {@code phoneId}. */
public Builder(int phoneId) {
mPhoneId = phoneId;
}
/** Returns the builder for call chaining. */
+ @NonNull
public Builder setUtcTime(@Nullable TimestampedValue<Long> utcTime) {
if (utcTime != null) {
// utcTime can be null, but the value it holds cannot.
@@ -177,6 +199,7 @@
}
/** Returns the builder for call chaining. */
+ @NonNull
public Builder addDebugInfo(@NonNull String debugInfo) {
if (mDebugInfo == null) {
mDebugInfo = new ArrayList<>();
@@ -186,6 +209,7 @@
}
/** Returns the {@link PhoneTimeSuggestion}. */
+ @NonNull
public PhoneTimeSuggestion build() {
return new PhoneTimeSuggestion(this);
}
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index 54dd1be..2412fb3 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -18,67 +18,27 @@
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.ServiceManager.ServiceNotFoundException;
import android.os.SystemClock;
import android.os.TimestampedValue;
-import android.util.Log;
/**
* The interface through which system components can send signals to the TimeDetectorService.
+ *
* @hide
*/
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@SystemService(Context.TIME_DETECTOR_SERVICE)
-public class TimeDetector {
- private static final String TAG = "timedetector.TimeDetector";
- private static final boolean DEBUG = false;
-
- private final ITimeDetectorService mITimeDetectorService;
-
- public TimeDetector() throws ServiceNotFoundException {
- mITimeDetectorService = ITimeDetectorService.Stub.asInterface(
- ServiceManager.getServiceOrThrow(Context.TIME_DETECTOR_SERVICE));
- }
-
- /**
- * Suggests the current phone-signal derived time to the detector. The detector may ignore the
- * signal if better signals are available such as those that come from more reliable sources or
- * were determined more recently.
- */
- @RequiresPermission(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE)
- public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
- if (DEBUG) {
- Log.d(TAG, "suggestPhoneTime called: " + timeSuggestion);
- }
- try {
- mITimeDetectorService.suggestPhoneTime(timeSuggestion);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Suggests the user's manually entered current time to the detector.
- */
- @RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE)
- public void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion) {
- if (DEBUG) {
- Log.d(TAG, "suggestManualTime called: " + timeSuggestion);
- }
- try {
- mITimeDetectorService.suggestManualTime(timeSuggestion);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+public interface TimeDetector {
/**
* A shared utility method to create a {@link ManualTimeSuggestion}.
+ *
+ * @hide
*/
- public static ManualTimeSuggestion createManualTimeSuggestion(long when, String why) {
+ static ManualTimeSuggestion createManualTimeSuggestion(long when, String why) {
TimestampedValue<Long> utcTime =
new TimestampedValue<>(SystemClock.elapsedRealtime(), when);
ManualTimeSuggestion manualTimeSuggestion = new ManualTimeSuggestion(utcTime);
@@ -87,17 +47,26 @@
}
/**
+ * Suggests the current phone-signal derived time to the detector. The detector may ignore the
+ * signal if better signals are available such as those that come from more reliable sources or
+ * were determined more recently.
+ */
+ @RequiresPermission(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE)
+ void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion);
+
+ /**
+ * Suggests the user's manually entered current time to the detector.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE)
+ void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
+
+ /**
* Suggests the time according to a network time source like NTP.
+ *
+ * @hide
*/
@RequiresPermission(android.Manifest.permission.SET_TIME)
- public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
- if (DEBUG) {
- Log.d(TAG, "suggestNetworkTime called: " + timeSuggestion);
- }
- try {
- mITimeDetectorService.suggestNetworkTime(timeSuggestion);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion);
}
diff --git a/core/java/android/app/timedetector/TimeDetectorImpl.java b/core/java/android/app/timedetector/TimeDetectorImpl.java
new file mode 100644
index 0000000..1683817
--- /dev/null
+++ b/core/java/android/app/timedetector/TimeDetectorImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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.app.timedetector;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.Log;
+
+/**
+ * The real implementation of {@link TimeDetector}.
+ *
+ * @hide
+ */
+public final class TimeDetectorImpl implements TimeDetector {
+ private static final String TAG = "timedetector.TimeDetector";
+ private static final boolean DEBUG = false;
+
+ private final ITimeDetectorService mITimeDetectorService;
+
+ public TimeDetectorImpl() throws ServiceNotFoundException {
+ mITimeDetectorService = ITimeDetectorService.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.TIME_DETECTOR_SERVICE));
+ }
+
+ @Override
+ public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
+ if (DEBUG) {
+ Log.d(TAG, "suggestPhoneTime called: " + timeSuggestion);
+ }
+ try {
+ mITimeDetectorService.suggestPhoneTime(timeSuggestion);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion) {
+ if (DEBUG) {
+ Log.d(TAG, "suggestManualTime called: " + timeSuggestion);
+ }
+ try {
+ mITimeDetectorService.suggestManualTime(timeSuggestion);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
+ if (DEBUG) {
+ Log.d(TAG, "suggestNetworkTime called: " + timeSuggestion);
+ }
+ try {
+ mITimeDetectorService.suggestNetworkTime(timeSuggestion);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
index e8162488..d71ffcb 100644
--- a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
+++ b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,12 +31,27 @@
import java.util.Objects;
/**
- * A suggested time zone from a Phone-based signal, e.g. from MCC and NITZ information.
+ * A time zone suggestion from an identified telephony source, e.g. from MCC and NITZ information
+ * associated with a specific radio.
+ *
+ * <p>The time zone ID can be {@code null} to indicate that the telephony source has entered an
+ * "un-opinionated" state and any previous suggestions from that source are being withdrawn.
+ * When not {@code null}, the value consists of a suggested time zone ID and metadata that can be
+ * used to judge quality / certainty of the suggestion.
+ *
+ * <p>{@code matchType} must be set to {@link #MATCH_TYPE_NA} when {@code zoneId} is {@code null},
+ * and one of the other {@code MATCH_TYPE_} values when it is not {@code null}.
+ *
+ * <p>{@code quality} must be set to {@link #QUALITY_NA} when {@code zoneId} is {@code null},
+ * and one of the other {@code QUALITY_} values when it is not {@code null}.
*
* @hide
*/
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class PhoneTimeZoneSuggestion implements Parcelable {
+ /** @hide */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@NonNull
public static final Creator<PhoneTimeZoneSuggestion> CREATOR =
new Creator<PhoneTimeZoneSuggestion>() {
@@ -58,6 +74,7 @@
return new Builder(phoneId).addDebugInfo(debugInfo).build();
}
+ /** @hide */
@IntDef({ MATCH_TYPE_NA, MATCH_TYPE_NETWORK_COUNTRY_ONLY, MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET,
MATCH_TYPE_EMULATOR_ZONE_ID, MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY })
@Retention(RetentionPolicy.SOURCE)
@@ -90,6 +107,7 @@
*/
public static final int MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY = 5;
+ /** @hide */
@IntDef({ QUALITY_NA, QUALITY_SINGLE_ZONE, QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET,
QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS })
@Retention(RetentionPolicy.SOURCE)
@@ -115,7 +133,7 @@
/**
* The ID of the phone this suggestion is associated with. For multiple-sim devices this
- * helps to establish origin so filtering / stickiness can be implemented.
+ * helps to establish source so filtering / stickiness can be implemented.
*/
private final int mPhoneId;
@@ -123,6 +141,7 @@
* The suggestion. {@code null} means there is no current suggestion and any previous suggestion
* should be forgotten.
*/
+ @Nullable
private final String mZoneId;
/**
@@ -139,9 +158,10 @@
private final int mQuality;
/**
- * Free-form debug information about how the signal was derived. Used for debug only,
+ * Free-form debug information about how the suggestion was derived. Used for debug only,
* intentionally not used in equals(), etc.
*/
+ @Nullable
private List<String> mDebugInfo;
private PhoneTimeZoneSuggestion(Builder builder) {
@@ -182,25 +202,47 @@
return 0;
}
+ /**
+ * Returns an identifier for the source of this suggestion. When a device has several "phones",
+ * i.e. sim slots or equivalent, it is used to identify which one.
+ */
public int getPhoneId() {
return mPhoneId;
}
+ /**
+ * Returns the suggested time zone Olson ID, e.g. "America/Los_Angeles". {@code null} means that
+ * the caller is no longer sure what the current time zone is. See
+ * {@link PhoneTimeZoneSuggestion} for the associated {@code matchType} / {@code quality} rules.
+ */
@Nullable
public String getZoneId() {
return mZoneId;
}
+ /**
+ * Returns information about how the suggestion was determined which could be used to rank
+ * suggestions when several are available from different sources. See
+ * {@link PhoneTimeZoneSuggestion} for the associated rules.
+ */
@MatchType
public int getMatchType() {
return mMatchType;
}
+ /**
+ * Returns information about the likelihood of the suggested zone being correct. See
+ * {@link PhoneTimeZoneSuggestion} for the associated rules.
+ */
@Quality
public int getQuality() {
return mQuality;
}
+ /**
+ * Returns debug metadata for the suggestion. The information is present in {@link #toString()}
+ * but is not considered for {@link #equals(Object)} and {@link #hashCode()}.
+ */
@NonNull
public List<String> getDebugInfo() {
return mDebugInfo == null
@@ -267,36 +309,43 @@
*
* @hide
*/
- public static class Builder {
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final class Builder {
private final int mPhoneId;
- private String mZoneId;
+ @Nullable private String mZoneId;
@MatchType private int mMatchType;
@Quality private int mQuality;
- private List<String> mDebugInfo;
+ @Nullable private List<String> mDebugInfo;
public Builder(int phoneId) {
mPhoneId = phoneId;
}
- /** Returns the builder for call chaining. */
- public Builder setZoneId(String zoneId) {
+ /**
+ * Returns the builder for call chaining.
+ */
+ @NonNull
+ public Builder setZoneId(@Nullable String zoneId) {
mZoneId = zoneId;
return this;
}
/** Returns the builder for call chaining. */
+ @NonNull
public Builder setMatchType(@MatchType int matchType) {
mMatchType = matchType;
return this;
}
/** Returns the builder for call chaining. */
+ @NonNull
public Builder setQuality(@Quality int quality) {
mQuality = quality;
return this;
}
/** Returns the builder for call chaining. */
+ @NonNull
public Builder addDebugInfo(@NonNull String debugInfo) {
if (mDebugInfo == null) {
mDebugInfo = new ArrayList<>();
@@ -333,6 +382,7 @@
}
/** Returns the {@link PhoneTimeZoneSuggestion}. */
+ @NonNull
public PhoneTimeZoneSuggestion build() {
validate();
return new PhoneTimeZoneSuggestion(this);
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
index e165d8a..b4f6087 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetector.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -18,69 +18,47 @@
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.ServiceManager.ServiceNotFoundException;
-import android.util.Log;
/**
* The interface through which system components can send signals to the TimeZoneDetectorService.
*
* @hide
*/
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@SystemService(Context.TIME_ZONE_DETECTOR_SERVICE)
-public class TimeZoneDetector {
- private static final String TAG = "timezonedetector.TimeZoneDetector";
- private static final boolean DEBUG = false;
+public interface TimeZoneDetector {
- private final ITimeZoneDetectorService mITimeZoneDetectorService;
-
- public TimeZoneDetector() throws ServiceNotFoundException {
- mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface(
- ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE));
+ /**
+ * A shared utility method to create a {@link ManualTimeZoneSuggestion}.
+ *
+ * @hide
+ */
+ static ManualTimeZoneSuggestion createManualTimeZoneSuggestion(String tzId, String debugInfo) {
+ ManualTimeZoneSuggestion suggestion = new ManualTimeZoneSuggestion(tzId);
+ suggestion.addDebugInfo(debugInfo);
+ return suggestion;
}
/**
* Suggests the current time zone, determined using telephony signals, to the detector. The
* detector may ignore the signal based on system settings, whether better information is
* available, and so on.
+ *
+ * @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE)
- public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) {
- if (DEBUG) {
- Log.d(TAG, "suggestPhoneTimeZone called: " + timeZoneSuggestion);
- }
- try {
- mITimeZoneDetectorService.suggestPhoneTimeZone(timeZoneSuggestion);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
+ void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion);
/**
* Suggests the current time zone, determined for the user's manually information, to the
* detector. The detector may ignore the signal based on system settings.
+ *
+ * @hide
*/
@RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE)
- public void suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
- if (DEBUG) {
- Log.d(TAG, "suggestManualTimeZone called: " + timeZoneSuggestion);
- }
- try {
- mITimeZoneDetectorService.suggestManualTimeZone(timeZoneSuggestion);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * A shared utility method to create a {@link ManualTimeZoneSuggestion}.
- */
- public static ManualTimeZoneSuggestion createManualTimeZoneSuggestion(String tzId, String why) {
- ManualTimeZoneSuggestion suggestion = new ManualTimeZoneSuggestion(tzId);
- suggestion.addDebugInfo(why);
- return suggestion;
- }
+ void suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion);
}
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
new file mode 100644
index 0000000..27b8374
--- /dev/null
+++ b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
@@ -0,0 +1,65 @@
+/*
+ * 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.app.timezonedetector;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.Log;
+
+/**
+ * The real implementation of {@link TimeZoneDetector}.
+ *
+ * @hide
+ */
+public final class TimeZoneDetectorImpl implements TimeZoneDetector {
+ private static final String TAG = "timezonedetector.TimeZoneDetector";
+ private static final boolean DEBUG = false;
+
+ private final ITimeZoneDetectorService mITimeZoneDetectorService;
+
+ public TimeZoneDetectorImpl() throws ServiceNotFoundException {
+ mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE));
+ }
+
+ @Override
+ public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) {
+ if (DEBUG) {
+ Log.d(TAG, "suggestPhoneTimeZone called: " + timeZoneSuggestion);
+ }
+ try {
+ mITimeZoneDetectorService.suggestPhoneTimeZone(timeZoneSuggestion);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public void suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
+ if (DEBUG) {
+ Log.d(TAG, "suggestManualTimeZone called: " + timeZoneSuggestion);
+ }
+ try {
+ mITimeZoneDetectorService.suggestManualTimeZone(timeZoneSuggestion);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+}
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
index 8993de0..ee2cc6d 100755
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ b/core/java/android/bluetooth/BluetoothA2dpSink.java
@@ -297,7 +297,8 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- public boolean setConnectionPolicy(@Nullable BluetoothDevice device, int connectionPolicy) {
+ public boolean setConnectionPolicy(@Nullable BluetoothDevice device,
+ @ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
@@ -345,7 +346,7 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public int getConnectionPolicy(@Nullable BluetoothDevice device) {
+ public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
final IBluetoothA2dpSink service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 1869c6f..b6d096c 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1222,6 +1222,7 @@
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 @@
*/
@UnsupportedAppUsage
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public @NonNull ParcelUuid[] getUuids() {
+ public @Nullable ParcelUuid[] getUuids() {
if (getState() != STATE_ON) {
return null;
}
@@ -2161,6 +2162,33 @@
}
/**
+ * Fetches a list of the most recently connected bluetooth devices ordered by how recently they
+ * were connected with most recently first and least recently last
+ *
+ * @return {@link List} of bonded {@link BluetoothDevice} ordered by how recently they were
+ * connected
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ public @NonNull List<BluetoothDevice> getMostRecentlyConnectedDevices() {
+ if (getState() != STATE_ON) {
+ return new ArrayList<>();
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) {
+ return mService.getMostRecentlyConnectedDevices();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return new ArrayList<>();
+ }
+
+ /**
* Return the set of {@link BluetoothDevice} objects that are bonded
* (paired) to the local adapter.
* <p>If Bluetooth state is not {@link #STATE_ON}, this API
@@ -3235,18 +3263,6 @@
}
/**
- * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
- * API name, listenUsingL2capChannel.
- * @hide
- */
- @RequiresPermission(Manifest.permission.BLUETOOTH)
- public BluetoothServerSocket listenUsingL2capCoc(int transport)
- throws IOException {
- Log.e(TAG, "listenUsingL2capCoc: PLEASE USE THE OFFICIAL API, listenUsingL2capChannel");
- return listenUsingL2capChannel();
- }
-
- /**
* Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
* assign a dynamic PSM value. This socket can be used to listen for incoming connections. The
* supported Bluetooth transport is LE only.
@@ -3293,19 +3309,6 @@
}
/**
- * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
- * API name, listenUsingInsecureL2capChannel.
- * @hide
- */
- @RequiresPermission(Manifest.permission.BLUETOOTH)
- public BluetoothServerSocket listenUsingInsecureL2capCoc(int transport)
- throws IOException {
- Log.e(TAG, "listenUsingInsecureL2capCoc: PLEASE USE THE OFFICIAL API, "
- + "listenUsingInsecureL2capChannel");
- return listenUsingInsecureL2capChannel();
- }
-
- /**
* Register a {@link #OnMetadataChangedListener} to receive update about metadata
* changes for this {@link BluetoothDevice}.
* Registration must be done when Bluetooth is ON and will last until
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 9fe4dd6..12dc814c 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -2172,17 +2172,6 @@
}
/**
- * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
- * API name, createL2capChannel.
- * @hide
- */
- @RequiresPermission(Manifest.permission.BLUETOOTH)
- public BluetoothSocket createL2capCocSocket(int transport, int psm) throws IOException {
- Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createL2capChannel");
- return createL2capChannel(psm);
- }
-
- /**
* Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
* be used to start a secure outgoing connection to the remote device with the same dynamic
* protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
@@ -2213,17 +2202,6 @@
}
/**
- * TODO: Remove this hidden method once all the SL4A and other tests are updated to use the new
- * API name, createInsecureL2capChannel.
- * @hide
- */
- @RequiresPermission(Manifest.permission.BLUETOOTH)
- public BluetoothSocket createInsecureL2capCocSocket(int transport, int psm) throws IOException {
- Log.e(TAG, "createL2capCocSocket: PLEASE USE THE OFFICIAL API, createInsecureL2capChannel");
- return createInsecureL2capChannel(psm);
- }
-
- /**
* Set a keyed metadata of this {@link BluetoothDevice} to a
* {@link String} value.
* Only bonded devices's metadata will be persisted across Bluetooth
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index 6de1ffb..fbda9e9 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -584,7 +584,8 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+ public boolean setConnectionPolicy(BluetoothDevice device,
+ @ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
final IBluetoothHeadsetClient service =
getService();
@@ -633,7 +634,7 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public int getConnectionPolicy(BluetoothDevice device) {
+ public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
final IBluetoothHeadsetClient service =
getService();
diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java
index c1233b8..26e3e27 100644
--- a/core/java/android/bluetooth/BluetoothHidHost.java
+++ b/core/java/android/bluetooth/BluetoothHidHost.java
@@ -416,7 +416,8 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- public boolean setConnectionPolicy(@Nullable BluetoothDevice device, int connectionPolicy) {
+ public boolean setConnectionPolicy(@Nullable BluetoothDevice device,
+ @ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
@@ -464,7 +465,7 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public int getConnectionPolicy(@Nullable BluetoothDevice device) {
+ public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
final IBluetoothHidHost service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
index 4674706..1c62faa 100644
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ b/core/java/android/bluetooth/BluetoothMap.java
@@ -340,7 +340,8 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- public boolean setConnectionPolicy(@Nullable BluetoothDevice device, int connectionPolicy) {
+ public boolean setConnectionPolicy(@Nullable BluetoothDevice device,
+ @ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
final IBluetoothMap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
@@ -388,7 +389,7 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public int getConnectionPolicy(@Nullable BluetoothDevice device) {
+ public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
final IBluetoothMap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index 0aa5aac..8d2aadd 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -271,7 +271,8 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+ public boolean setConnectionPolicy(BluetoothDevice device,
+ @ConnectionPolicy int connectionPolicy) {
if (DBG) Log.d(TAG, "setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
@@ -319,7 +320,7 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public int getConnectionPolicy(BluetoothDevice device) {
+ public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) {
if (VDBG) Log.d(TAG, "getConnectionPolicy(" + device + ")");
final IBluetoothMapClient service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 024bb06..ec63fd0 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -30,6 +30,7 @@
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 @@
* @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 @@
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 @@
return mProfileConnector.getService();
}
-
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
protected void finalize() {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
close();
}
@@ -316,6 +326,7 @@
* @hide
*/
@Override
+ @RequiresPermission(Manifest.permission.BLUETOOTH)
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
final IBluetoothPan service = getService();
@@ -335,6 +346,7 @@
* {@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 @@
*
* @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 @@
*
* @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/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
index 9618ba0..9563c68 100644
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ b/core/java/android/bluetooth/BluetoothPbapClient.java
@@ -271,7 +271,8 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+ public boolean setConnectionPolicy(BluetoothDevice device,
+ @ConnectionPolicy int connectionPolicy) {
if (DBG) {
log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
}
@@ -323,7 +324,7 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public int getConnectionPolicy(BluetoothDevice device) {
+ public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) {
if (VDBG) {
log("getConnectionPolicy(" + device + ")");
}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index 638e6de..7538df8 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -146,7 +146,7 @@
*
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
int A2DP_SINK = 11;
/**
@@ -154,7 +154,7 @@
*
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
int AVRCP_CONTROLLER = 12;
/**
@@ -169,6 +169,7 @@
*
* @hide
*/
+ @SystemApi
int HEADSET_CLIENT = 16;
/**
@@ -176,6 +177,7 @@
*
* @hide
*/
+ @SystemApi
int PBAP_CLIENT = 17;
/**
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
index 8bf1b58..bfc3a4d 100644
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ b/core/java/android/bluetooth/BluetoothSap.java
@@ -330,7 +330,8 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
+ public boolean setConnectionPolicy(BluetoothDevice device,
+ @ConnectionPolicy int connectionPolicy) {
if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
final IBluetoothSap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
@@ -378,7 +379,7 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public int getConnectionPolicy(BluetoothDevice device) {
+ public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) {
if (VDBG) log("getConnectionPolicy(" + device + ")");
final IBluetoothSap service = getService();
if (service != null && isEnabled() && isValidDevice(device)) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index f2f9051..c3c7f97 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -30,6 +30,7 @@
import android.annotation.StringRes;
import android.annotation.StyleRes;
import android.annotation.StyleableRes;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
@@ -3295,6 +3296,7 @@
CONNECTIVITY_SERVICE,
//@hide: IP_MEMORY_STORE_SERVICE,
IPSEC_SERVICE,
+ VPN_MANAGEMENT_SERVICE,
TEST_NETWORK_SERVICE,
//@hide: UPDATE_LOCK_SERVICE,
//@hide: NETWORKMANAGEMENT_SERVICE,
@@ -3827,6 +3829,7 @@
*/
@SystemApi
@TestApi
+ @SuppressLint("ServiceName")
public static final String STATUS_BAR_SERVICE = "statusbar";
/**
@@ -3878,6 +3881,24 @@
public static final String IPSEC_SERVICE = "ipsec";
/**
+ * Use with {@link #getSystemService(String)} to retrieve a {@link android.net.VpnManager} to
+ * manage profiles for the platform built-in VPN.
+ *
+ * @see #getSystemService(String)
+ */
+ public static final String VPN_MANAGEMENT_SERVICE = "vpn_management";
+
+ /**
+ * 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
*
@@ -3921,6 +3942,7 @@
public static final String NETWORK_STATS_SERVICE = "netstats";
/** {@hide} */
@SystemApi
+ @SuppressLint("ServiceName")
public static final String NETWORK_POLICY_SERVICE = "netpolicy";
/** {@hide} */
public static final String NETWORK_WATCHLIST_SERVICE = "network_watchlist";
@@ -4000,16 +4022,16 @@
public static final String LOWPAN_SERVICE = "lowpan";
/**
- * Use with {@link #getSystemService(String)} to retrieve a {@link
- * android.net.EthernetManager} for handling management of
- * Ethernet access.
+ * Use with {@link #getSystemService(String)} to retrieve a {@link android.net.EthernetManager}
+ * for handling management of Ethernet access.
*
* @see #getSystemService(String)
* @see android.net.EthernetManager
*
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
+ @TestApi
public static final String ETHERNET_SERVICE = "ethernet";
/**
@@ -4230,6 +4252,7 @@
* @see #getSystemService(String)
*/
@TestApi
+ @SuppressLint("ServiceName") // TODO: This should be renamed to CONTENT_CAPTURE_SERVICE
public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
/**
@@ -4831,10 +4854,7 @@
/**
* Use with {@link #getSystemService(String)} to retrieve an
* {@link android.telephony.ims.ImsManager}.
- * @hide
*/
- @SystemApi
- @TestApi
public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9c7bf1f..d859a3af 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3619,7 +3619,9 @@
* {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
* @hide
*/
- @UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @SystemApi
public static final String ACTION_USER_SWITCHED =
"android.intent.action.USER_SWITCHED";
@@ -4011,6 +4013,7 @@
* <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 +4190,18 @@
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/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0ae00fb..93b90b4 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -545,9 +545,10 @@
public static final int MATCH_DEBUG_TRIAGED_MISSING = MATCH_DIRECT_BOOT_AUTO;
/**
- * Internal flag used to indicate that a package is a hidden system app.
+ * Internal {@link PackageInfo} flag used to indicate that a package is a hidden system app.
* @hide
*/
+ @SystemApi
public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS = 0x20000000;
/**
diff --git a/core/java/android/debug/AdbManager.java b/core/java/android/debug/AdbManager.java
index ae3d794..0a76bed 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 @@
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 79e0794..c48fc07 100644
--- a/core/java/android/debug/IAdbManager.aidl
+++ b/core/java/android/debug/IAdbManager.aidl
@@ -41,4 +41,15 @@
* 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 1142a07..2497ea9 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -32,6 +32,7 @@
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 @@
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 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 787dc66..0af18df 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 @@
/**
* 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 @@
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 @@
}
/**
+ * 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 315af32..16f9688 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -44,6 +44,7 @@
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 @@
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 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/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 67fdda3..b0d0b4c 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -262,6 +262,15 @@
public static final String USB_FUNCTION_ACCESSORY = "accessory";
/**
+ * Name of the NCM USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
+ */
+ @SystemApi
+ public static final String USB_FUNCTION_NCM = "ncm";
+
+ /**
* Name of extra for {@link #ACTION_USB_PORT_CHANGED}
* containing the {@link UsbPort} object for the port.
*
@@ -367,8 +376,15 @@
*/
public static final long FUNCTION_ADB = GadgetFunction.ADB;
+ /**
+ * Code for the ncm source usb function.
+ * {@hide}
+ */
+ @SystemApi
+ public static final long FUNCTION_NCM = 1 << 10;
+
private static final long SETTABLE_FUNCTIONS = FUNCTION_MTP | FUNCTION_PTP | FUNCTION_RNDIS
- | FUNCTION_MIDI;
+ | FUNCTION_MIDI | FUNCTION_NCM;
private static final Map<String, Long> FUNCTION_NAME_TO_CODE = new HashMap<>();
@@ -380,6 +396,7 @@
FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_ACCESSORY, FUNCTION_ACCESSORY);
FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_AUDIO_SOURCE, FUNCTION_AUDIO_SOURCE);
FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_ADB, FUNCTION_ADB);
+ FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_NCM, FUNCTION_NCM);
}
private final Context mContext;
@@ -935,6 +952,9 @@
if ((functions & FUNCTION_AUDIO_SOURCE) != 0) {
joiner.add(UsbManager.USB_FUNCTION_AUDIO_SOURCE);
}
+ if ((functions & FUNCTION_NCM) != 0) {
+ joiner.add(UsbManager.USB_FUNCTION_NCM);
+ }
if ((functions & FUNCTION_ADB) != 0) {
joiner.add(UsbManager.USB_FUNCTION_ADB);
}
diff --git a/core/java/android/net/NetworkMisc.aidl b/core/java/android/net/CaptivePortalData.aidl
similarity index 84%
copy from core/java/android/net/NetworkMisc.aidl
copy to core/java/android/net/CaptivePortalData.aidl
index c65583f..1d57ee7 100644
--- a/core/java/android/net/NetworkMisc.aidl
+++ b/core/java/android/net/CaptivePortalData.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,4 +16,4 @@
package android.net;
-parcelable NetworkMisc;
+@JavaOnlyStableParcelable parcelable CaptivePortalData;
diff --git a/core/java/android/net/CaptivePortalData.java b/core/java/android/net/CaptivePortalData.java
new file mode 100644
index 0000000..1357803
--- /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/NetworkMisc.aidl b/core/java/android/net/ConnectivityDiagnosticsManager.aidl
similarity index 69%
copy from core/java/android/net/NetworkMisc.aidl
copy to core/java/android/net/ConnectivityDiagnosticsManager.aidl
index c65583f..82ba0ca 100644
--- a/core/java/android/net/NetworkMisc.aidl
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.aidl
@@ -1,11 +1,12 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
+/**
+ *
+ * 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
+ * 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,
@@ -16,4 +17,5 @@
package android.net;
-parcelable NetworkMisc;
+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 6afdb5e..b13e4b7 100644
--- a/core/java/android/net/ConnectivityDiagnosticsManager.java
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -18,10 +18,20 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.content.Context;
+import android.os.Binder;
+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 +57,169 @@
* </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 overall status of the network is that it is invalid; it neither provides
+ * connectivity nor has been exempted from validation.
+ */
+ public static final int NETWORK_VALIDATION_RESULT_INVALID = 0;
+
+ /**
+ * The overall status of the network is that it is valid, this may be because it provides
+ * full Internet access (all probes succeeded), or because other properties of the network
+ * caused probes not to be run.
+ */
+ // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID
+ public static final int NETWORK_VALIDATION_RESULT_VALID = 1;
+
+ /**
+ * The overall status of the network is that it provides partial connectivity; some
+ * probed services succeeded but others failed.
+ */
+ // TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
+ public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2;
+
+ /**
+ * Due to the properties of the network, validation was not performed.
+ */
+ public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3;
+
+ /** @hide */
+ @IntDef(
+ prefix = {"NETWORK_VALIDATION_RESULT_"},
+ value = {
+ NETWORK_VALIDATION_RESULT_INVALID,
+ NETWORK_VALIDATION_RESULT_VALID,
+ NETWORK_VALIDATION_RESULT_PARTIALLY_VALID,
+ NETWORK_VALIDATION_RESULT_SKIPPED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NetworkValidationResult {}
+
+ /**
+ * The overall validation result for the Network being reported on.
+ *
+ * <p>The possible values for this key are:
+ * {@link #NETWORK_VALIDATION_RESULT_INVALID},
+ * {@link #NETWORK_VALIDATION_RESULT_VALID},
+ * {@link #NETWORK_VALIDATION_RESULT_PARTIALLY_VALID},
+ * {@link #NETWORK_VALIDATION_RESULT_SKIPPED}.
+ *
+ * @see android.net.NetworkCapabilities#CAPABILITY_VALIDATED
+ */
+ @NetworkValidationResult
+ public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
+
+ /** DNS probe. */
+ // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS
+ public static final int NETWORK_PROBE_DNS = 0x04;
+
+ /** HTTP probe. */
+ // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP
+ public static final int NETWORK_PROBE_HTTP = 0x08;
+
+ /** HTTPS probe. */
+ // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
+ public static final int NETWORK_PROBE_HTTPS = 0x10;
+
+ /** Captive portal fallback probe. */
+ // TODO: link to INetworkMonitor.NETWORK_VALIDATION_FALLBACK
+ public static final int NETWORK_PROBE_FALLBACK = 0x20;
+
+ /** Private DNS (DNS over TLS) probd. */
+ // TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS
+ public static final int NETWORK_PROBE_PRIVATE_DNS = 0x40;
+
+ /** @hide */
+ @IntDef(
+ prefix = {"NETWORK_PROBE_"},
+ value = {
+ NETWORK_PROBE_DNS,
+ NETWORK_PROBE_HTTP,
+ NETWORK_PROBE_HTTPS,
+ NETWORK_PROBE_FALLBACK,
+ NETWORK_PROBE_PRIVATE_DNS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface NetworkProbe {}
+
+ /**
+ * A bitmask of network validation probes that succeeded.
+ *
+ * <p>The possible bits values reported by this key are:
+ * {@link #NETWORK_PROBE_DNS},
+ * {@link #NETWORK_PROBE_HTTP},
+ * {@link #NETWORK_PROBE_HTTPS},
+ * {@link #NETWORK_PROBE_FALLBACK},
+ * {@link #NETWORK_PROBE_PRIVATE_DNS}.
+ */
+ @NetworkProbe
+ public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK =
+ "networkProbesSucceeded";
+
+ /**
+ * A bitmask of network validation probes that were attempted.
+ *
+ * <p>These probes may have failed or may be incomplete at the time of this report.
+ *
+ * <p>The possible bits values reported by this key are:
+ * {@link #NETWORK_PROBE_DNS},
+ * {@link #NETWORK_PROBE_HTTP},
+ * {@link #NETWORK_PROBE_HTTPS},
+ * {@link #NETWORK_PROBE_FALLBACK},
+ * {@link #NETWORK_PROBE_PRIVATE_DNS}.
+ */
+ @NetworkProbe
+ public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK =
+ "networkProbesAttemped";
+
+ /** @hide */
+ @StringDef(prefix = {"KEY_"}, value = {
+ KEY_NETWORK_VALIDATION_RESULT, KEY_NETWORK_PROBES_SUCCEEDED_BITMASK,
+ KEY_NETWORK_PROBES_ATTEMPTED_BITMASK})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ConnectivityReportBundleKeys {}
+
/** 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 +242,191 @@
@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<ConnectivityReport>() {
+ 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 {}
+
+ /**
+ * This key represents the period in milliseconds over which other included TCP metrics
+ * were measured.
+ *
+ * <p>This key will be included if the data stall detection method is
+ * {@link #DETECTION_METHOD_TCP_METRICS}.
+ *
+ * <p>This value is an int.
+ */
+ public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS =
+ "tcpMetricsCollectionPeriodMillis";
+
+ /**
+ * This key represents the fail rate of TCP packets when the suspected data stall was
+ * detected.
+ *
+ * <p>This key will be included if the data stall detection method is
+ * {@link #DETECTION_METHOD_TCP_METRICS}.
+ *
+ * <p>This value is an int percentage between 0 and 100.
+ */
+ public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
+
+ /**
+ * This key represents the consecutive number of DNS timeouts that have occurred.
+ *
+ * <p>The consecutive count will be reset any time a DNS response is received.
+ *
+ * <p>This key will be included if the data stall detection method is
+ * {@link #DETECTION_METHOD_DNS_EVENTS}.
+ *
+ * <p>This value is an int.
+ */
+ public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef(prefix = {"KEY_"}, value = {
+ KEY_TCP_PACKET_FAIL_RATE,
+ KEY_DNS_CONSECUTIVE_TIMEOUTS
+ })
+ public @interface DataStallReportBundleKeys {}
+
/** 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,10 +445,150 @@
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.
+ *
+ * <p>Gets a bundle with details about the suspected data stall including information
+ * specific to the monitoring method that detected the data stall.
+ *
+ * @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];
+ }
+ };
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public static class ConnectivityDiagnosticsBinder
+ extends IConnectivityDiagnosticsCallback.Stub {
+ @NonNull private final ConnectivityDiagnosticsCallback mCb;
+ @NonNull private final Executor mExecutor;
+
+ /** @hide */
+ @VisibleForTesting
+ public ConnectivityDiagnosticsBinder(
+ @NonNull ConnectivityDiagnosticsCallback cb, @NonNull Executor executor) {
+ this.mCb = cb;
+ this.mExecutor = executor;
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public void onConnectivityReport(@NonNull ConnectivityReport report) {
+ Binder.withCleanCallingIdentity(() -> {
+ mExecutor.execute(() -> {
+ mCb.onConnectivityReport(report);
+ });
+ });
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public void onDataStallSuspected(@NonNull DataStallReport report) {
+ Binder.withCleanCallingIdentity(() -> {
+ mExecutor.execute(() -> {
+ mCb.onDataStallSuspected(report);
+ });
+ });
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public void onNetworkConnectivityReported(
+ @NonNull Network network, boolean hasConnectivity) {
+ Binder.withCleanCallingIdentity(() -> {
+ mExecutor.execute(() -> {
+ mCb.onNetworkConnectivityReported(network, hasConnectivity);
+ });
+ });
}
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 67d4eb1..94eda01 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -33,6 +33,9 @@
import android.content.Intent;
import android.net.IpSecManager.UdpEncapsulationSocket;
import android.net.SocketKeepalive.Callback;
+import android.net.TetheringManager.StartTetheringCallback;
+import android.net.TetheringManager.TetheringEventCallback;
+import android.net.TetheringManager.TetheringRequest;
import android.os.Binder;
import android.os.Build;
import android.os.Build.VERSION_CODES;
@@ -58,6 +61,7 @@
import android.util.Log;
import android.util.SparseIntArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Protocol;
@@ -75,6 +79,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -484,34 +489,35 @@
* enable if any.
* @hide
*/
- public static final String EXTRA_ADD_TETHER_TYPE = TetheringManager.EXTRA_ADD_TETHER_TYPE;
+ public static final String EXTRA_ADD_TETHER_TYPE = TetheringConstants.EXTRA_ADD_TETHER_TYPE;
/**
* Extra used for communicating with the TetherService. Includes the type of tethering for
* which to cancel provisioning.
* @hide
*/
- public static final String EXTRA_REM_TETHER_TYPE = TetheringManager.EXTRA_REM_TETHER_TYPE;
+ public static final String EXTRA_REM_TETHER_TYPE = TetheringConstants.EXTRA_REM_TETHER_TYPE;
/**
* Extra used for communicating with the TetherService. True to schedule a recheck of tether
* provisioning.
* @hide
*/
- public static final String EXTRA_SET_ALARM = TetheringManager.EXTRA_SET_ALARM;
+ public static final String EXTRA_SET_ALARM = TetheringConstants.EXTRA_SET_ALARM;
/**
* Tells the TetherService to run a provision check now.
* @hide
*/
- public static final String EXTRA_RUN_PROVISION = TetheringManager.EXTRA_RUN_PROVISION;
+ public static final String EXTRA_RUN_PROVISION = TetheringConstants.EXTRA_RUN_PROVISION;
/**
* Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
* which will receive provisioning results. Can be left empty.
* @hide
*/
- public static final String EXTRA_PROVISION_CALLBACK = TetheringManager.EXTRA_PROVISION_CALLBACK;
+ public static final String EXTRA_PROVISION_CALLBACK =
+ TetheringConstants.EXTRA_PROVISION_CALLBACK;
/**
* The absence of a connection type.
@@ -662,7 +668,7 @@
* {@hide}
*/
@Deprecated
- @UnsupportedAppUsage
+ @SystemApi
public static final int TYPE_WIFI_P2P = 13;
/**
@@ -2369,10 +2375,12 @@
*
* @return an array of 0 or more Strings of tetherable interface names.
*
+ * @deprecated Use {@link TetheringEventCallback#onTetherableInterfacesChanged(List)} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public String[] getTetherableIfaces() {
return getTetheringManager().getTetherableIfaces();
}
@@ -2382,10 +2390,12 @@
*
* @return an array of 0 or more String of currently tethered interface names.
*
+ * @deprecated Use {@link TetheringEventCallback#onTetherableInterfacesChanged(List)} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public String[] getTetheredIfaces() {
return getTetheringManager().getTetheredIfaces();
}
@@ -2401,10 +2411,12 @@
* @return an array of 0 or more String indicating the interface names
* which failed to tether.
*
+ * @deprecated Use {@link TetheringEventCallback#onError(String, int)} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public String[] getTetheringErroredIfaces() {
return getTetheringManager().getTetheringErroredIfaces();
}
@@ -2413,9 +2425,11 @@
* Get the set of tethered dhcp ranges.
*
* @return an array of 0 or more {@code String} of tethered dhcp ranges.
+ * @deprecated This API just return the default value which is not used in DhcpServer.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ @Deprecated
public String[] getTetheredDhcpRanges() {
return getTetheringManager().getTetheredDhcpRanges();
}
@@ -2441,10 +2455,12 @@
*
* @param iface the interface name to tether.
* @return error a {@code TETHER_ERROR} value indicating success or failure type
+ * @deprecated Use {@link TetheringManager#startTethering} instead
*
* {@hide}
*/
@UnsupportedAppUsage
+ @Deprecated
public int tether(String iface) {
return getTetheringManager().tether(iface);
}
@@ -2468,6 +2484,7 @@
* {@hide}
*/
@UnsupportedAppUsage
+ @Deprecated
public int untether(String iface) {
return getTetheringManager().untether(iface);
}
@@ -2488,6 +2505,7 @@
*
* @return a boolean - {@code true} indicating Tethering is supported.
*
+ * @deprecated Use {@link TetheringEventCallback#onTetheringSupported(boolean)} instead.
* {@hide}
*/
@SystemApi
@@ -2499,9 +2517,12 @@
/**
* Callback for use with {@link #startTethering} to find out whether tethering succeeded.
+ *
+ * @deprecated Use {@link TetheringManager.StartTetheringCallback} instead.
* @hide
*/
@SystemApi
+ @Deprecated
public static abstract class OnStartTetheringCallback {
/**
* Called when tethering has been successfully started.
@@ -2518,9 +2539,12 @@
* Convenient overload for
* {@link #startTethering(int, boolean, OnStartTetheringCallback, Handler)} which passes a null
* handler to run on the current thread's {@link Looper}.
+ *
+ * @deprecated Use {@link TetheringManager#startTethering} instead.
* @hide
*/
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void startTethering(int type, boolean showProvisioningUi,
final OnStartTetheringCallback callback) {
@@ -2544,26 +2568,44 @@
* @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller
* of the result of trying to tether.
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ *
+ * @deprecated Use {@link TetheringManager#startTethering} instead.
* @hide
*/
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void startTethering(int type, boolean showProvisioningUi,
final OnStartTetheringCallback callback, Handler handler) {
Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
- ResultReceiver wrappedCallback = new ResultReceiver(handler) {
+ final Executor executor = new Executor() {
@Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- if (resultCode == TETHER_ERROR_NO_ERROR) {
- callback.onTetheringStarted();
+ public void execute(Runnable command) {
+ if (handler == null) {
+ command.run();
} else {
- callback.onTetheringFailed();
+ handler.post(command);
}
}
};
- getTetheringManager().startTethering(type, wrappedCallback, showProvisioningUi);
+ final StartTetheringCallback tetheringCallback = new StartTetheringCallback() {
+ @Override
+ public void onTetheringStarted() {
+ callback.onTetheringStarted();
+ }
+
+ @Override
+ public void onTetheringFailed(final int resultCode) {
+ callback.onTetheringFailed();
+ }
+ };
+
+ final TetheringRequest request = new TetheringRequest.Builder(type)
+ .setSilentProvisioning(!showProvisioningUi).build();
+
+ getTetheringManager().startTethering(request, executor, tetheringCallback);
}
/**
@@ -2574,9 +2616,12 @@
* {@link ConnectivityManager.TETHERING_WIFI},
* {@link ConnectivityManager.TETHERING_USB}, or
* {@link ConnectivityManager.TETHERING_BLUETOOTH}.
+ *
+ * @deprecated Use {@link TetheringManager#stopTethering} instead.
* @hide
*/
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void stopTethering(int type) {
getTetheringManager().stopTethering(type);
@@ -2586,9 +2631,11 @@
* Callback for use with {@link registerTetheringEventCallback} to find out tethering
* upstream status.
*
- *@hide
+ * @deprecated Use {@link TetheringManager#OnTetheringEventCallback} instead.
+ * @hide
*/
@SystemApi
+ @Deprecated
public abstract static class OnTetheringEventCallback {
/**
@@ -2601,6 +2648,10 @@
public void onUpstreamChanged(@Nullable Network network) {}
}
+ @GuardedBy("mTetheringEventCallbacks")
+ private final ArrayMap<OnTetheringEventCallback, TetheringEventCallback>
+ mTetheringEventCallbacks = new ArrayMap<>();
+
/**
* Start listening to tethering change events. Any new added callback will receive the last
* tethering status right away. If callback is registered when tethering has no upstream or
@@ -2609,16 +2660,30 @@
*
* @param executor the executor on which callback will be invoked.
* @param callback the callback to be called when tethering has change events.
+ *
+ * @deprecated Use {@link TetheringManager#registerTetheringEventCallback} instead.
* @hide
*/
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void registerTetheringEventCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull final OnTetheringEventCallback callback) {
Preconditions.checkNotNull(callback, "OnTetheringEventCallback cannot be null.");
- getTetheringManager().registerTetheringEventCallback(executor, callback);
+ final TetheringEventCallback tetherCallback =
+ new TetheringEventCallback() {
+ @Override
+ public void onUpstreamChanged(@Nullable Network network) {
+ callback.onUpstreamChanged(network);
+ }
+ };
+
+ synchronized (mTetheringEventCallbacks) {
+ mTetheringEventCallbacks.put(callback, tetherCallback);
+ getTetheringManager().registerTetheringEventCallback(executor, tetherCallback);
+ }
}
/**
@@ -2626,13 +2691,21 @@
* {@link #registerTetheringEventCallback}.
*
* @param callback previously registered callback.
+ *
+ * @deprecated Use {@link TetheringManager#unregisterTetheringEventCallback} instead.
* @hide
*/
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void unregisterTetheringEventCallback(
@NonNull final OnTetheringEventCallback callback) {
- getTetheringManager().unregisterTetheringEventCallback(callback);
+ Objects.requireNonNull(callback, "The callback must be non-null");
+ synchronized (mTetheringEventCallbacks) {
+ final TetheringEventCallback tetherCallback =
+ mTetheringEventCallbacks.remove(callback);
+ getTetheringManager().unregisterTetheringEventCallback(tetherCallback);
+ }
}
@@ -2644,10 +2717,12 @@
* @return an array of 0 or more regular expression Strings defining
* what interfaces are considered tetherable usb interfaces.
*
+ * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public String[] getTetherableUsbRegexs() {
return getTetheringManager().getTetherableUsbRegexs();
}
@@ -2660,10 +2735,12 @@
* @return an array of 0 or more regular expression Strings defining
* what interfaces are considered tetherable wifi interfaces.
*
+ * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public String[] getTetherableWifiRegexs() {
return getTetheringManager().getTetherableWifiRegexs();
}
@@ -2676,10 +2753,13 @@
* @return an array of 0 or more regular expression Strings defining
* what interfaces are considered tetherable bluetooth interfaces.
*
+ * @deprecated Use {@link TetheringEventCallback#onTetherableInterfaceRegexpsChanged(
+ *TetheringManager.TetheringInterfaceRegexps)} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public String[] getTetherableBluetoothRegexs() {
return getTetheringManager().getTetherableBluetoothRegexs();
}
@@ -2698,45 +2778,114 @@
*
* @param enable a boolean - {@code true} to enable tethering
* @return error a {@code TETHER_ERROR} value indicating success or failure type
+ * @deprecated Use {@link TetheringManager#startTethering} instead
*
* {@hide}
*/
@UnsupportedAppUsage
+ @Deprecated
public int setUsbTethering(boolean enable) {
return getTetheringManager().setUsbTethering(enable);
}
- /** {@hide} */
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_NO_ERROR}.
+ * {@hide}
+ */
@SystemApi
- public static final int TETHER_ERROR_NO_ERROR = 0;
- /** {@hide} */
- public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
- /** {@hide} */
- public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
- /** {@hide} */
- public static final int TETHER_ERROR_UNSUPPORTED = 3;
- /** {@hide} */
- public static final int TETHER_ERROR_UNAVAIL_IFACE = 4;
- /** {@hide} */
- public static final int TETHER_ERROR_MASTER_ERROR = 5;
- /** {@hide} */
- public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6;
- /** {@hide} */
- public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7;
- /** {@hide} */
- public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8;
- /** {@hide} */
- public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9;
- /** {@hide} */
- public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10;
- /** {@hide} */
+ @Deprecated
+ public static final int TETHER_ERROR_NO_ERROR = TetheringManager.TETHER_ERROR_NO_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNKNOWN_IFACE}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_UNKNOWN_IFACE =
+ TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_SERVICE_UNAVAIL}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_SERVICE_UNAVAIL =
+ TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNSUPPORTED}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_UNSUPPORTED = TetheringManager.TETHER_ERROR_UNSUPPORTED;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNAVAIL_IFACE}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_UNAVAIL_IFACE =
+ TetheringManager.TETHER_ERROR_UNAVAIL_IFACE;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_MASTER_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_MASTER_ERROR = TetheringManager.TETHER_ERROR_MASTER_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_TETHER_IFACE_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_TETHER_IFACE_ERROR =
+ TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_UNTETHER_IFACE_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR =
+ TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENABLE_NAT_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_ENABLE_NAT_ERROR =
+ TetheringManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_DISABLE_NAT_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_DISABLE_NAT_ERROR =
+ TetheringManager.TETHER_ERROR_DISABLE_NAT_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_IFACE_CFG_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_IFACE_CFG_ERROR =
+ TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_PROVISION_FAILED}.
+ * {@hide}
+ */
@SystemApi
- public static final int TETHER_ERROR_PROVISION_FAILED = 11;
- /** {@hide} */
- public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12;
- /** {@hide} */
+ @Deprecated
+ public static final int TETHER_ERROR_PROVISION_FAILED =
+ TetheringManager.TETHER_ERROR_PROVISION_FAILED;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_DHCPSERVER_ERROR}.
+ * {@hide}
+ */
+ @Deprecated
+ public static final int TETHER_ERROR_DHCPSERVER_ERROR =
+ TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR;
+ /**
+ * @deprecated Use {@link TetheringManager#TETHER_ERROR_ENTITLEMENT_UNKNOWN}.
+ * {@hide}
+ */
@SystemApi
- public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13;
+ @Deprecated
+ public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN =
+ TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
/**
* Get a more detailed error code after a Tethering or Untethering
@@ -2746,10 +2895,12 @@
* @return error The error code of the last error tethering or untethering the named
* interface
*
+ * @deprecated Use {@link TetheringEventCallback#onError(String, int)} instead.
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
@UnsupportedAppUsage
+ @Deprecated
public int getLastTetherError(String iface) {
return getTetheringManager().getLastTetherError(iface);
}
@@ -2767,9 +2918,12 @@
/**
* Callback for use with {@link #getLatestTetheringEntitlementResult} to find out whether
* entitlement succeeded.
+ *
+ * @deprecated Use {@link TetheringManager#OnTetheringEntitlementResultListener} instead.
* @hide
*/
@SystemApi
+ @Deprecated
public interface OnTetheringEntitlementResultListener {
/**
* Called to notify entitlement result.
@@ -2799,9 +2953,11 @@
* @param listener an {@link OnTetheringEntitlementResultListener} which will be called to
* notify the caller of the result of entitlement check. The listener may be called zero
* or one time.
+ * @deprecated Use {@link TetheringManager#requestLatestTetheringEntitlementResult} instead.
* {@hide}
*/
@SystemApi
+ @Deprecated
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void getLatestTetheringEntitlementResult(int type, boolean showEntitlementUi,
@NonNull @CallbackExecutor Executor executor,
@@ -3169,24 +3325,25 @@
/**
* @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/EthernetManager.java b/core/java/android/net/EthernetManager.java
index fd015b4..a3899b7 100644
--- a/core/java/android/net/EthernetManager.java
+++ b/core/java/android/net/EthernetManager.java
@@ -16,7 +16,10 @@
package android.net;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Handler;
@@ -24,12 +27,15 @@
import android.os.RemoteException;
import java.util.ArrayList;
+import java.util.Objects;
/**
* A class representing the IP configuration of the Ethernet network.
*
* @hide
*/
+@SystemApi
+@TestApi
@SystemService(Context.ETHERNET_SERVICE)
public class EthernetManager {
private static final String TAG = "EthernetManager";
@@ -37,7 +43,7 @@
private final Context mContext;
private final IEthernetManager mService;
- private final Handler mHandler = new Handler() {
+ private final Handler mHandler = new Handler(ConnectivityThread.getInstanceLooper()) {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_AVAILABILITY_CHANGED) {
@@ -60,12 +66,14 @@
/**
* A listener interface to receive notification on changes in Ethernet.
+ * @hide
*/
public interface Listener {
/**
* Called when Ethernet port's availability is changed.
* @param iface Ethernet interface name
* @param isAvailable {@code true} if Ethernet port exists.
+ * @hide
*/
@UnsupportedAppUsage
void onAvailabilityChanged(String iface, boolean isAvailable);
@@ -76,6 +84,7 @@
* Applications will almost always want to use
* {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
* the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}.
+ * @hide
*/
public EthernetManager(Context context, IEthernetManager service) {
mContext = context;
@@ -85,6 +94,7 @@
/**
* Get Ethernet configuration.
* @return the Ethernet Configuration, contained in {@link IpConfiguration}.
+ * @hide
*/
@UnsupportedAppUsage
public IpConfiguration getConfiguration(String iface) {
@@ -97,6 +107,7 @@
/**
* Set Ethernet configuration.
+ * @hide
*/
@UnsupportedAppUsage
public void setConfiguration(String iface, IpConfiguration config) {
@@ -109,6 +120,7 @@
/**
* Indicates whether the system currently has one or more Ethernet interfaces.
+ * @hide
*/
@UnsupportedAppUsage
public boolean isAvailable() {
@@ -119,6 +131,7 @@
* Indicates whether the system has given interface.
*
* @param iface Ethernet interface name
+ * @hide
*/
@UnsupportedAppUsage
public boolean isAvailable(String iface) {
@@ -133,6 +146,7 @@
* Adds a listener.
* @param listener A {@link Listener} to add.
* @throws IllegalArgumentException If the listener is null.
+ * @hide
*/
@UnsupportedAppUsage
public void addListener(Listener listener) {
@@ -151,6 +165,7 @@
/**
* Returns an array of available Ethernet interface names.
+ * @hide
*/
@UnsupportedAppUsage
public String[] getAvailableInterfaces() {
@@ -165,6 +180,7 @@
* Removes a listener.
* @param listener A {@link Listener} to remove.
* @throws IllegalArgumentException If the listener is null.
+ * @hide
*/
@UnsupportedAppUsage
public void removeListener(Listener listener) {
@@ -180,4 +196,78 @@
}
}
}
+
+ /**
+ * A request for a tethered interface.
+ */
+ public static class TetheredInterfaceRequest {
+ private final IEthernetManager mService;
+ private final ITetheredInterfaceCallback mCb;
+
+ private TetheredInterfaceRequest(@NonNull IEthernetManager service,
+ @NonNull ITetheredInterfaceCallback cb) {
+ this.mService = service;
+ this.mCb = cb;
+ }
+
+ /**
+ * Release the request, causing the interface to revert back from tethering mode if there
+ * is no other requestor.
+ */
+ public void release() {
+ try {
+ mService.releaseTetheredInterface(mCb);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Callback for {@link #requestTetheredInterface(TetheredInterfaceCallback)}.
+ */
+ public interface TetheredInterfaceCallback {
+ /**
+ * Called when the tethered interface is available.
+ * @param iface The name of the interface.
+ */
+ void onAvailable(@NonNull String iface);
+
+ /**
+ * Called when the tethered interface is now unavailable.
+ */
+ void onUnavailable();
+ }
+
+ /**
+ * Request a tethered interface in tethering mode.
+ *
+ * <p>When this method is called and there is at least one ethernet interface available, the
+ * system will designate one to act as a tethered interface. If there is already a tethered
+ * interface, the existing interface will be used.
+ * @param callback A callback to be called once the request has been fulfilled.
+ */
+ @NonNull
+ public TetheredInterfaceRequest requestTetheredInterface(
+ @NonNull TetheredInterfaceCallback callback) {
+ Objects.requireNonNull(callback, "Callback must be non-null");
+ final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() {
+ @Override
+ public void onAvailable(String iface) {
+ callback.onAvailable(iface);
+ }
+
+ @Override
+ public void onUnavailable() {
+ callback.onUnavailable();
+ }
+ };
+
+ try {
+ mService.requestTetheredInterface(cbInternal);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return new TetheredInterfaceRequest(mService, cbInternal);
+ }
}
diff --git a/core/java/android/net/IConnectivityDiagnosticsCallback.aidl b/core/java/android/net/IConnectivityDiagnosticsCallback.aidl
new file mode 100644
index 0000000..3a161bf
--- /dev/null
+++ b/core/java/android/net/IConnectivityDiagnosticsCallback.aidl
@@ -0,0 +1,28 @@
+/**
+ *
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.ConnectivityDiagnosticsManager;
+import android.net.Network;
+
+/** @hide */
+oneway interface IConnectivityDiagnosticsCallback {
+ void onConnectivityReport(in ConnectivityDiagnosticsManager.ConnectivityReport report);
+ void onDataStallSuspected(in ConnectivityDiagnosticsManager.DataStallReport report);
+ void onNetworkConnectivityReported(in Network n, boolean hasConnectivity);
+}
\ No newline at end of file
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index e6a0379..3e9e7fa 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -18,11 +18,12 @@
import android.app.PendingIntent;
import android.net.ConnectionInfo;
+import android.net.IConnectivityDiagnosticsCallback;
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 +153,9 @@
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);
@@ -210,5 +212,9 @@
boolean isCallerCurrentAlwaysOnVpnApp();
boolean isCallerCurrentAlwaysOnVpnLockdownApp();
+ void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback,
+ in NetworkRequest request);
+ void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback);
+
IBinder startOrGetTestNetworkService();
}
diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl
index 94960b5..ccc6e35 100644
--- a/core/java/android/net/IEthernetManager.aidl
+++ b/core/java/android/net/IEthernetManager.aidl
@@ -18,6 +18,7 @@
import android.net.IpConfiguration;
import android.net.IEthernetServiceListener;
+import android.net.ITetheredInterfaceCallback;
/**
* Interface that answers queries about, and allows changing
@@ -32,4 +33,6 @@
boolean isAvailable(String iface);
void addListener(in IEthernetServiceListener listener);
void removeListener(in IEthernetServiceListener listener);
+ void requestTetheredInterface(in ITetheredInterfaceCallback callback);
+ void releaseTetheredInterface(in ITetheredInterfaceCallback callback);
}
diff --git a/core/java/android/net/NetworkMisc.aidl b/core/java/android/net/ITetheredInterfaceCallback.aidl
similarity index 77%
copy from core/java/android/net/NetworkMisc.aidl
copy to core/java/android/net/ITetheredInterfaceCallback.aidl
index c65583f..e3d0759 100644
--- a/core/java/android/net/NetworkMisc.aidl
+++ b/core/java/android/net/ITetheredInterfaceCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -16,4 +16,8 @@
package android.net;
-parcelable NetworkMisc;
+/** @hide */
+interface ITetheredInterfaceCallback {
+ void onAvailable(in String iface);
+ void onUnavailable();
+}
\ No newline at end of file
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
new file mode 100644
index 0000000..42b4da1
--- /dev/null
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -0,0 +1,728 @@
+/*
+ * 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 static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_PSK;
+import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_RSA;
+import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+import static com.android.internal.util.Preconditions.checkStringNotEmpty;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.security.Credentials;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.net.VpnProfile;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The Ikev2VpnProfile is a configuration for the platform setup of IKEv2/IPsec VPNs.
+ *
+ * <p>Together with VpnManager, this allows apps to provision IKEv2/IPsec VPNs that do not require
+ * the VPN app to constantly run in the background.
+ *
+ * @see VpnManager
+ * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296 - Internet Key
+ * Exchange, Version 2 (IKEv2)</a>
+ */
+public final class Ikev2VpnProfile extends PlatformVpnProfile {
+ private static final String MISSING_PARAM_MSG_TMPL = "Required parameter was not provided: %s";
+ private static final String EMPTY_CERT = "";
+
+ @NonNull private final String mServerAddr;
+ @NonNull private final String mUserIdentity;
+
+ // PSK authentication
+ @Nullable private final byte[] mPresharedKey;
+
+ // Username/Password, RSA authentication
+ @Nullable private final X509Certificate mServerRootCaCert;
+
+ // Username/Password authentication
+ @Nullable private final String mUsername;
+ @Nullable private final String mPassword;
+
+ // RSA Certificate authentication
+ @Nullable private final PrivateKey mRsaPrivateKey;
+ @Nullable private final X509Certificate mUserCert;
+
+ @Nullable private final ProxyInfo mProxyInfo;
+ @NonNull private final List<String> mAllowedAlgorithms;
+ private final boolean mIsBypassable; // Defaults in builder
+ private final boolean mIsMetered; // Defaults in builder
+ private final int mMaxMtu; // Defaults in builder
+
+ private Ikev2VpnProfile(
+ int type,
+ @NonNull String serverAddr,
+ @NonNull String userIdentity,
+ @Nullable byte[] presharedKey,
+ @Nullable X509Certificate serverRootCaCert,
+ @Nullable String username,
+ @Nullable String password,
+ @Nullable PrivateKey rsaPrivateKey,
+ @Nullable X509Certificate userCert,
+ @Nullable ProxyInfo proxyInfo,
+ @NonNull List<String> allowedAlgorithms,
+ boolean isBypassable,
+ boolean isMetered,
+ int maxMtu) {
+ super(type);
+
+ checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address");
+ checkNotNull(userIdentity, MISSING_PARAM_MSG_TMPL, "User Identity");
+ checkNotNull(allowedAlgorithms, MISSING_PARAM_MSG_TMPL, "Allowed Algorithms");
+
+ mServerAddr = serverAddr;
+ mUserIdentity = userIdentity;
+ mPresharedKey =
+ presharedKey == null ? null : Arrays.copyOf(presharedKey, presharedKey.length);
+ mServerRootCaCert = serverRootCaCert;
+ mUsername = username;
+ mPassword = password;
+ mRsaPrivateKey = rsaPrivateKey;
+ mUserCert = userCert;
+ mProxyInfo = new ProxyInfo(proxyInfo);
+
+ // UnmodifiableList doesn't make a defensive copy by default.
+ mAllowedAlgorithms = Collections.unmodifiableList(new ArrayList<>(allowedAlgorithms));
+
+ mIsBypassable = isBypassable;
+ mIsMetered = isMetered;
+ mMaxMtu = maxMtu;
+
+ validate();
+ }
+
+ private void validate() {
+ // Server Address not validated except to check an address was provided. This allows for
+ // dual-stack servers and hostname based addresses.
+ checkStringNotEmpty(mServerAddr, MISSING_PARAM_MSG_TMPL, "Server Address");
+ checkStringNotEmpty(mUserIdentity, MISSING_PARAM_MSG_TMPL, "User Identity");
+
+ // IPv6 MTU is greater; since profiles may be started by the system on IPv4 and IPv6
+ // networks, the VPN must provide a link fulfilling the stricter of the two conditions
+ // (at least that of the IPv6 MTU).
+ if (mMaxMtu < LinkProperties.MIN_MTU_V6) {
+ throw new IllegalArgumentException(
+ "Max MTU must be at least" + LinkProperties.MIN_MTU_V6);
+ }
+
+ switch (mType) {
+ case TYPE_IKEV2_IPSEC_USER_PASS:
+ checkNotNull(mUsername, MISSING_PARAM_MSG_TMPL, "Username");
+ checkNotNull(mPassword, MISSING_PARAM_MSG_TMPL, "Password");
+
+ if (mServerRootCaCert != null) checkCert(mServerRootCaCert);
+
+ break;
+ case TYPE_IKEV2_IPSEC_PSK:
+ checkNotNull(mPresharedKey, MISSING_PARAM_MSG_TMPL, "Preshared Key");
+ break;
+ case TYPE_IKEV2_IPSEC_RSA:
+ checkNotNull(mUserCert, MISSING_PARAM_MSG_TMPL, "User cert");
+ checkNotNull(mRsaPrivateKey, MISSING_PARAM_MSG_TMPL, "RSA Private key");
+
+ checkCert(mUserCert);
+ if (mServerRootCaCert != null) checkCert(mServerRootCaCert);
+
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid auth method set");
+ }
+
+ VpnProfile.validateAllowedAlgorithms(mAllowedAlgorithms);
+ }
+
+ /** Retrieves the server address string. */
+ @NonNull
+ public String getServerAddr() {
+ return mServerAddr;
+ }
+
+ /** Retrieves the user identity. */
+ @NonNull
+ public String getUserIdentity() {
+ return mUserIdentity;
+ }
+
+ /**
+ * Retrieves the pre-shared key.
+ *
+ * <p>May be null if the profile is not using Pre-shared key authentication.
+ */
+ @Nullable
+ public byte[] getPresharedKey() {
+ return mPresharedKey == null ? null : Arrays.copyOf(mPresharedKey, mPresharedKey.length);
+ }
+
+ /**
+ * Retrieves the certificate for the server's root CA.
+ *
+ * <p>May be null if the profile is not using RSA Digital Signature Authentication or
+ * Username/Password authentication
+ */
+ @Nullable
+ public X509Certificate getServerRootCaCert() {
+ return mServerRootCaCert;
+ }
+
+ /**
+ * Retrieves the username.
+ *
+ * <p>May be null if the profile is not using Username/Password authentication
+ */
+ @Nullable
+ public String getUsername() {
+ return mUsername;
+ }
+
+ /**
+ * Retrieves the password.
+ *
+ * <p>May be null if the profile is not using Username/Password authentication
+ */
+ @Nullable
+ public String getPassword() {
+ return mPassword;
+ }
+
+ /**
+ * Retrieves the RSA private key.
+ *
+ * <p>May be null if the profile is not using RSA Digital Signature authentication
+ */
+ @Nullable
+ public PrivateKey getRsaPrivateKey() {
+ return mRsaPrivateKey;
+ }
+
+ /** Retrieves the user certificate, if any was set. */
+ @Nullable
+ public X509Certificate getUserCert() {
+ return mUserCert;
+ }
+
+ /** Retrieves the proxy information if any was set */
+ @Nullable
+ public ProxyInfo getProxyInfo() {
+ return mProxyInfo;
+ }
+
+ /** Returns all the algorithms allowed by this VPN profile. */
+ @NonNull
+ public List<String> getAllowedAlgorithms() {
+ return mAllowedAlgorithms;
+ }
+
+ /** Returns whether or not the VPN profile should be bypassable. */
+ public boolean isBypassable() {
+ return mIsBypassable;
+ }
+
+ /** Returns whether or not the VPN profile should be always considered metered. */
+ public boolean isMetered() {
+ return mIsMetered;
+ }
+
+ /** Retrieves the maximum MTU set for this VPN profile. */
+ public int getMaxMtu() {
+ return mMaxMtu;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mType,
+ mServerAddr,
+ mUserIdentity,
+ Arrays.hashCode(mPresharedKey),
+ mServerRootCaCert,
+ mUsername,
+ mPassword,
+ mRsaPrivateKey,
+ mUserCert,
+ mProxyInfo,
+ mAllowedAlgorithms,
+ mIsBypassable,
+ mIsMetered,
+ mMaxMtu);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Ikev2VpnProfile)) {
+ return false;
+ }
+
+ final Ikev2VpnProfile other = (Ikev2VpnProfile) obj;
+ return mType == other.mType
+ && Objects.equals(mServerAddr, other.mServerAddr)
+ && Objects.equals(mUserIdentity, other.mUserIdentity)
+ && Arrays.equals(mPresharedKey, other.mPresharedKey)
+ && Objects.equals(mServerRootCaCert, other.mServerRootCaCert)
+ && Objects.equals(mUsername, other.mUsername)
+ && Objects.equals(mPassword, other.mPassword)
+ && Objects.equals(mRsaPrivateKey, other.mRsaPrivateKey)
+ && Objects.equals(mUserCert, other.mUserCert)
+ && Objects.equals(mProxyInfo, other.mProxyInfo)
+ && Objects.equals(mAllowedAlgorithms, other.mAllowedAlgorithms)
+ && mIsBypassable == other.mIsBypassable
+ && mIsMetered == other.mIsMetered
+ && mMaxMtu == other.mMaxMtu;
+ }
+
+ /**
+ * Builds a VpnProfile instance for internal use, based on the stored IKEv2/IPsec parameters.
+ *
+ * <p>Redundant authentication information (from previous calls to other setAuth* methods) will
+ * be discarded.
+ *
+ * @hide
+ */
+ @NonNull
+ public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException {
+ final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */);
+ profile.type = mType;
+ profile.server = mServerAddr;
+ profile.ipsecIdentifier = mUserIdentity;
+ profile.proxy = mProxyInfo;
+ profile.setAllowedAlgorithms(mAllowedAlgorithms);
+ profile.isBypassable = mIsBypassable;
+ profile.isMetered = mIsMetered;
+ profile.maxMtu = mMaxMtu;
+ profile.areAuthParamsInline = true;
+ profile.saveLogin = true;
+
+ switch (mType) {
+ case TYPE_IKEV2_IPSEC_USER_PASS:
+ profile.username = mUsername;
+ profile.password = mPassword;
+ profile.ipsecCaCert =
+ mServerRootCaCert == null ? "" : certificateToPemString(mServerRootCaCert);
+ break;
+ case TYPE_IKEV2_IPSEC_PSK:
+ profile.ipsecSecret = encodeForIpsecSecret(mPresharedKey);
+ break;
+ case TYPE_IKEV2_IPSEC_RSA:
+ profile.ipsecUserCert = certificateToPemString(mUserCert);
+ profile.ipsecSecret = encodeForIpsecSecret(mRsaPrivateKey.getEncoded());
+ profile.ipsecCaCert =
+ mServerRootCaCert == null ? "" : certificateToPemString(mServerRootCaCert);
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid auth method set");
+ }
+
+ return profile;
+ }
+
+ /**
+ * Constructs a Ikev2VpnProfile from an internal-use VpnProfile instance.
+ *
+ * <p>Redundant authentication information (not related to profile type) will be discarded.
+ *
+ * @hide
+ */
+ @NonNull
+ public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile)
+ throws IOException, GeneralSecurityException {
+ final Builder builder = new Builder(profile.server, profile.ipsecIdentifier);
+ builder.setProxy(profile.proxy);
+ builder.setAllowedAlgorithms(profile.getAllowedAlgorithms());
+ builder.setBypassable(profile.isBypassable);
+ builder.setMetered(profile.isMetered);
+ builder.setMaxMtu(profile.maxMtu);
+
+ switch (profile.type) {
+ case TYPE_IKEV2_IPSEC_USER_PASS:
+ builder.setAuthUsernamePassword(
+ profile.username,
+ profile.password,
+ certificateFromPemString(profile.ipsecCaCert));
+ break;
+ case TYPE_IKEV2_IPSEC_PSK:
+ builder.setAuthPsk(decodeFromIpsecSecret(profile.ipsecSecret));
+ break;
+ case TYPE_IKEV2_IPSEC_RSA:
+ final X509Certificate userCert = certificateFromPemString(profile.ipsecUserCert);
+ final PrivateKey key = getPrivateKey(profile.ipsecSecret);
+ final X509Certificate serverRootCa = certificateFromPemString(profile.ipsecCaCert);
+ builder.setAuthDigitalSignature(userCert, key, serverRootCa);
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid auth method set");
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Converts a X509 Certificate to a PEM-formatted string.
+ *
+ * <p>Must be public due to runtime-package restrictions.
+ *
+ * @hide
+ */
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static String certificateToPemString(@Nullable X509Certificate cert)
+ throws IOException, CertificateEncodingException {
+ if (cert == null) {
+ return EMPTY_CERT;
+ }
+
+ // Credentials.convertToPem outputs ASCII bytes.
+ return new String(Credentials.convertToPem(cert), StandardCharsets.US_ASCII);
+ }
+
+ /**
+ * Decodes the provided Certificate(s).
+ *
+ * <p>Will use the first one if the certStr encodes more than one certificate.
+ */
+ @Nullable
+ private static X509Certificate certificateFromPemString(@Nullable String certStr)
+ throws CertificateException {
+ if (certStr == null || EMPTY_CERT.equals(certStr)) {
+ return null;
+ }
+
+ try {
+ final List<X509Certificate> certs =
+ Credentials.convertFromPem(certStr.getBytes(StandardCharsets.US_ASCII));
+ return certs.isEmpty() ? null : certs.get(0);
+ } catch (IOException e) {
+ throw new CertificateException(e);
+ }
+ }
+
+ /** @hide */
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static String encodeForIpsecSecret(@NonNull byte[] secret) {
+ checkNotNull(secret, MISSING_PARAM_MSG_TMPL, "secret");
+
+ return Base64.getEncoder().encodeToString(secret);
+ }
+
+ @NonNull
+ private static byte[] decodeFromIpsecSecret(@NonNull String encoded) {
+ checkNotNull(encoded, MISSING_PARAM_MSG_TMPL, "encoded");
+
+ return Base64.getDecoder().decode(encoded);
+ }
+
+ @NonNull
+ private static PrivateKey getPrivateKey(@NonNull String keyStr)
+ throws InvalidKeySpecException, NoSuchAlgorithmException {
+ final PKCS8EncodedKeySpec privateKeySpec =
+ new PKCS8EncodedKeySpec(decodeFromIpsecSecret(keyStr));
+ final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ return keyFactory.generatePrivate(privateKeySpec);
+ }
+
+ private static void checkCert(@NonNull X509Certificate cert) {
+ try {
+ certificateToPemString(cert);
+ } catch (GeneralSecurityException | IOException e) {
+ throw new IllegalArgumentException("Certificate could not be encoded");
+ }
+ }
+
+ private static @NonNull <T> T checkNotNull(
+ final T reference, final String messageTemplate, final Object... messageArgs) {
+ return Objects.requireNonNull(reference, String.format(messageTemplate, messageArgs));
+ }
+
+ /** A incremental builder for IKEv2 VPN profiles */
+ public static final class Builder {
+ private int mType = -1;
+ @NonNull private final String mServerAddr;
+ @NonNull private final String mUserIdentity;
+
+ // PSK authentication
+ @Nullable private byte[] mPresharedKey;
+
+ // Username/Password, RSA authentication
+ @Nullable private X509Certificate mServerRootCaCert;
+
+ // Username/Password authentication
+ @Nullable private String mUsername;
+ @Nullable private String mPassword;
+
+ // RSA Certificate authentication
+ @Nullable private PrivateKey mRsaPrivateKey;
+ @Nullable private X509Certificate mUserCert;
+
+ @Nullable private ProxyInfo mProxyInfo;
+ @NonNull private List<String> mAllowedAlgorithms = new ArrayList<>();
+ private boolean mIsBypassable = false;
+ private boolean mIsMetered = true;
+ private int mMaxMtu = 1360;
+
+ /**
+ * Creates a new builder with the basic parameters of an IKEv2/IPsec VPN.
+ *
+ * @param serverAddr the server that the VPN should connect to
+ * @param identity the identity string to be used for IKEv2 authentication
+ */
+ public Builder(@NonNull String serverAddr, @NonNull String identity) {
+ checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "serverAddr");
+ checkNotNull(identity, MISSING_PARAM_MSG_TMPL, "identity");
+
+ mServerAddr = serverAddr;
+ mUserIdentity = identity;
+ }
+
+ private void resetAuthParams() {
+ mPresharedKey = null;
+ mServerRootCaCert = null;
+ mUsername = null;
+ mPassword = null;
+ mRsaPrivateKey = null;
+ mUserCert = null;
+ }
+
+ /**
+ * Set the IKEv2 authentication to use the provided username/password.
+ *
+ * <p>Setting this will configure IKEv2 authentication using EAP-MSCHAPv2. Only one
+ * authentication method may be set. This method will overwrite any previously set
+ * authentication method.
+ *
+ * @param user the username to be used for EAP-MSCHAPv2 authentication
+ * @param pass the password to be used for EAP-MSCHAPv2 authentication
+ * @param serverRootCa the root certificate to be used for verifying the identity of the
+ * server
+ * @return this {@link Builder} object to facilitate chaining of method calls
+ * @throws IllegalArgumentException if any of the certificates were invalid or of an
+ * unrecognized format
+ */
+ @NonNull
+ public Builder setAuthUsernamePassword(
+ @NonNull String user,
+ @NonNull String pass,
+ @Nullable X509Certificate serverRootCa) {
+ checkNotNull(user, MISSING_PARAM_MSG_TMPL, "user");
+ checkNotNull(pass, MISSING_PARAM_MSG_TMPL, "pass");
+
+ // Test to make sure all auth params can be encoded safely.
+ if (serverRootCa != null) checkCert(serverRootCa);
+
+ resetAuthParams();
+ mUsername = user;
+ mPassword = pass;
+ mServerRootCaCert = serverRootCa;
+ mType = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
+ return this;
+ }
+
+ /**
+ * Set the IKEv2 authentication to use Digital Signature Authentication with the given key.
+ *
+ * <p>Setting this will configure IKEv2 authentication using a Digital Signature scheme.
+ * Only one authentication method may be set. This method will overwrite any previously set
+ * authentication method.
+ *
+ * @param userCert the username to be used for RSA Digital signiture authentication
+ * @param key the PrivateKey instance associated with the user ceritificate, used for
+ * constructing the signature
+ * @param serverRootCa the root certificate to be used for verifying the identity of the
+ * server
+ * @return this {@link Builder} object to facilitate chaining of method calls
+ * @throws IllegalArgumentException if any of the certificates were invalid or of an
+ * unrecognized format
+ */
+ @NonNull
+ public Builder setAuthDigitalSignature(
+ @NonNull X509Certificate userCert,
+ @NonNull PrivateKey key,
+ @Nullable X509Certificate serverRootCa) {
+ checkNotNull(userCert, MISSING_PARAM_MSG_TMPL, "userCert");
+ checkNotNull(key, MISSING_PARAM_MSG_TMPL, "key");
+
+ // Test to make sure all auth params can be encoded safely.
+ checkCert(userCert);
+ if (serverRootCa != null) checkCert(serverRootCa);
+
+ resetAuthParams();
+ mUserCert = userCert;
+ mRsaPrivateKey = key;
+ mServerRootCaCert = serverRootCa;
+ mType = VpnProfile.TYPE_IKEV2_IPSEC_RSA;
+ return this;
+ }
+
+ /**
+ * Set the IKEv2 authentication to use Preshared keys.
+ *
+ * <p>Setting this will configure IKEv2 authentication using a Preshared Key. Only one
+ * authentication method may be set. This method will overwrite any previously set
+ * authentication method.
+ *
+ * @param psk the key to be used for Pre-Shared Key authentication
+ * @return this {@link Builder} object to facilitate chaining of method calls
+ */
+ @NonNull
+ public Builder setAuthPsk(@NonNull byte[] psk) {
+ checkNotNull(psk, MISSING_PARAM_MSG_TMPL, "psk");
+
+ resetAuthParams();
+ mPresharedKey = psk;
+ mType = VpnProfile.TYPE_IKEV2_IPSEC_PSK;
+ return this;
+ }
+
+ /**
+ * Sets whether apps can bypass this VPN connection.
+ *
+ * <p>By default, all traffic from apps are forwarded through the VPN interface and it is
+ * not possible for unprivileged apps to side-step the VPN. If a VPN is set to bypassable,
+ * apps may use methods such as {@link Network#getSocketFactory} or {@link
+ * Network#openConnection} to instead send/receive directly over the underlying network or
+ * any other network they have permissions for.
+ *
+ * @param isBypassable Whether or not the VPN should be considered bypassable. Defaults to
+ * {@code false}.
+ * @return this {@link Builder} object to facilitate chaining of method calls
+ */
+ @NonNull
+ public Builder setBypassable(boolean isBypassable) {
+ mIsBypassable = isBypassable;
+ return this;
+ }
+
+ /**
+ * Sets a proxy for the VPN network.
+ *
+ * <p>Note that this proxy is only a recommendation and it may be ignored by apps.
+ *
+ * @param proxy the ProxyInfo to be set for the VPN network
+ * @return this {@link Builder} object to facilitate chaining of method calls
+ */
+ @NonNull
+ public Builder setProxy(@Nullable ProxyInfo proxy) {
+ mProxyInfo = proxy;
+ return this;
+ }
+
+ /**
+ * Set the upper bound of the maximum transmission unit (MTU) of the VPN interface.
+ *
+ * <p>If it is not set, a safe value will be used. Additionally, the actual link MTU will be
+ * dynamically calculated/updated based on the underlying link's mtu.
+ *
+ * @param mtu the MTU (in bytes) of the VPN interface
+ * @return this {@link Builder} object to facilitate chaining of method calls
+ * @throws IllegalArgumentException if the value is not at least the minimum IPv6 MTU (1280)
+ */
+ @NonNull
+ public Builder setMaxMtu(int mtu) {
+ // IPv6 MTU is greater; since profiles may be started by the system on IPv4 and IPv6
+ // networks, the VPN must provide a link fulfilling the stricter of the two conditions
+ // (at least that of the IPv6 MTU).
+ if (mtu < LinkProperties.MIN_MTU_V6) {
+ throw new IllegalArgumentException(
+ "Max MTU must be at least " + LinkProperties.MIN_MTU_V6);
+ }
+ mMaxMtu = mtu;
+ return this;
+ }
+
+ /**
+ * Marks the VPN network as metered.
+ *
+ * <p>A VPN network is classified as metered when the user is sensitive to heavy data usage
+ * due to monetary costs and/or data limitations. In such cases, you should set this to
+ * {@code true} so that apps on the system can avoid doing large data transfers. Otherwise,
+ * set this to {@code false}. Doing so would cause VPN network to inherit its meteredness
+ * from the underlying network.
+ *
+ * @param isMetered {@code true} if the VPN network should be treated as metered regardless
+ * of underlying network meteredness. Defaults to {@code true}.
+ * @return this {@link Builder} object to facilitate chaining of method calls
+ * @see NetworkCapabilities.NET_CAPABILITY_NOT_METERED
+ */
+ @NonNull
+ public Builder setMetered(boolean isMetered) {
+ mIsMetered = isMetered;
+ return this;
+ }
+
+ /**
+ * Sets the allowable set of IPsec algorithms
+ *
+ * <p>A list of allowed IPsec algorithms as defined in {@link IpSecAlgorithm}
+ *
+ * @param algorithmNames the list of supported IPsec algorithms
+ * @return this {@link Builder} object to facilitate chaining of method calls
+ * @see IpSecAlgorithm
+ */
+ @NonNull
+ public Builder setAllowedAlgorithms(@NonNull List<String> algorithmNames) {
+ checkNotNull(algorithmNames, MISSING_PARAM_MSG_TMPL, "algorithmNames");
+ VpnProfile.validateAllowedAlgorithms(algorithmNames);
+
+ mAllowedAlgorithms = algorithmNames;
+ return this;
+ }
+
+ /**
+ * Validates, builds and provisions the VpnProfile.
+ *
+ * @throws IllegalArgumentException if any of the required keys or values were invalid
+ */
+ @NonNull
+ public Ikev2VpnProfile build() {
+ return new Ikev2VpnProfile(
+ mType,
+ mServerAddr,
+ mUserIdentity,
+ mPresharedKey,
+ mServerRootCaCert,
+ mUsername,
+ mPassword,
+ mRsaPrivateKey,
+ mUserCert,
+ mProxyInfo,
+ mAllowedAlgorithms,
+ mIsBypassable,
+ mIsMetered,
+ mMaxMtu);
+ }
+ }
+}
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index bf8b38f..a9d7f17 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -19,6 +19,7 @@
import static android.system.OsConstants.IFA_F_DADFAILED;
import static android.system.OsConstants.IFA_F_DEPRECATED;
import static android.system.OsConstants.IFA_F_OPTIMISTIC;
+import static android.system.OsConstants.IFA_F_PERMANENT;
import static android.system.OsConstants.IFA_F_TENTATIVE;
import static android.system.OsConstants.RT_SCOPE_HOST;
import static android.system.OsConstants.RT_SCOPE_LINK;
@@ -34,6 +35,7 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
import android.util.Pair;
import java.net.Inet4Address;
@@ -41,6 +43,7 @@
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.UnknownHostException;
+import java.util.Objects;
/**
* Identifies an IP address on a network link.
@@ -58,6 +61,21 @@
* </ul>
*/
public class LinkAddress implements Parcelable {
+
+ /**
+ * Indicates the deprecation or expiration time is unknown
+ * @hide
+ */
+ @SystemApi
+ public static final long LIFETIME_UNKNOWN = -1;
+
+ /**
+ * Indicates this address is permanent.
+ * @hide
+ */
+ @SystemApi
+ public static final long LIFETIME_PERMANENT = Long.MAX_VALUE;
+
/**
* IPv4 or IPv6 address.
*/
@@ -71,7 +89,9 @@
private int prefixLength;
/**
- * Address flags. A bitmask of IFA_F_* values.
+ * Address flags. A bitmask of {@code IFA_F_*} values. Note that {@link #getFlags()} may not
+ * return these exact values. For example, it may set or clear the {@code IFA_F_DEPRECATED}
+ * flag depending on the current preferred lifetime.
*/
private int flags;
@@ -81,6 +101,23 @@
private int scope;
/**
+ * The time, as reported by {@link SystemClock#elapsedRealtime}, when this LinkAddress will be
+ * or was deprecated. At the time existing connections can still use this address until it
+ * expires, but new connections should use the new address. {@link #LIFETIME_UNKNOWN} indicates
+ * this information is not available. {@link #LIFETIME_PERMANENT} indicates this
+ * {@link LinkAddress} will never be deprecated.
+ */
+ private long deprecationTime;
+
+ /**
+ * The time, as reported by {@link SystemClock#elapsedRealtime}, when this {@link LinkAddress}
+ * will expire and be removed from the interface. {@link #LIFETIME_UNKNOWN} indicates this
+ * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
+ * will never expire.
+ */
+ private long expirationTime;
+
+ /**
* Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and
* RFC 6724 section 3.2.
* @hide
@@ -152,7 +189,8 @@
/**
* Utility function for the constructors.
*/
- private void init(InetAddress address, int prefixLength, int flags, int scope) {
+ private void init(InetAddress address, int prefixLength, int flags, int scope,
+ long deprecationTime, long expirationTime) {
if (address == null ||
address.isMulticastAddress() ||
prefixLength < 0 ||
@@ -161,15 +199,42 @@
throw new IllegalArgumentException("Bad LinkAddress params " + address +
"/" + prefixLength);
}
+
+ // deprecation time and expiration time must be both provided, or neither.
+ if ((deprecationTime == LIFETIME_UNKNOWN) != (expirationTime == LIFETIME_UNKNOWN)) {
+ throw new IllegalArgumentException(
+ "Must not specify only one of deprecation time and expiration time");
+ }
+
+ // deprecation time needs to be a positive value.
+ if (deprecationTime != LIFETIME_UNKNOWN && deprecationTime < 0) {
+ throw new IllegalArgumentException("invalid deprecation time " + deprecationTime);
+ }
+
+ // expiration time needs to be a positive value.
+ if (expirationTime != LIFETIME_UNKNOWN && expirationTime < 0) {
+ throw new IllegalArgumentException("invalid expiration time " + expirationTime);
+ }
+
+ // expiration time can't be earlier than deprecation time
+ if (deprecationTime != LIFETIME_UNKNOWN && expirationTime != LIFETIME_UNKNOWN
+ && expirationTime < deprecationTime) {
+ throw new IllegalArgumentException("expiration earlier than deprecation ("
+ + deprecationTime + ", " + expirationTime + ")");
+ }
+
this.address = address;
this.prefixLength = prefixLength;
this.flags = flags;
this.scope = scope;
+ this.deprecationTime = deprecationTime;
+ this.expirationTime = expirationTime;
}
/**
* Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with
* the specified flags and scope. Flags and scope are not checked for validity.
+ *
* @param address The IP address.
* @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
* @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
@@ -181,7 +246,39 @@
@TestApi
public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
int flags, int scope) {
- init(address, prefixLength, flags, scope);
+ init(address, prefixLength, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
+ }
+
+ /**
+ * Constructs a new {@code LinkAddress} from an {@code InetAddress}, prefix length, with
+ * the specified flags, scope, deprecation time, and expiration time. Flags and scope are not
+ * checked for validity. The value of the {@code IFA_F_DEPRECATED} and {@code IFA_F_PERMANENT}
+ * flag will be adjusted based on the passed-in lifetimes.
+ *
+ * @param address The IP address.
+ * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
+ * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
+ * @param scope An integer defining the scope in which the address is unique (e.g.,
+ * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
+ * @param deprecationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when
+ * this {@link LinkAddress} will be or was deprecated. At the time
+ * existing connections can still use this address until it expires, but
+ * new connections should use the new address. {@link #LIFETIME_UNKNOWN}
+ * indicates this information is not available.
+ * {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
+ * never be deprecated.
+ * @param expirationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when this
+ * {@link LinkAddress} will expire and be removed from the interface.
+ * {@link #LIFETIME_UNKNOWN} indicates this information is not available.
+ * {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
+ * never expire.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
+ int flags, int scope, long deprecationTime, long expirationTime) {
+ init(address, prefixLength, flags, scope, deprecationTime, expirationTime);
}
/**
@@ -237,7 +334,7 @@
// This may throw an IllegalArgumentException; catching it is the caller's responsibility.
// TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address);
- init(ipAndMask.first, ipAndMask.second, flags, scope);
+ init(ipAndMask.first, ipAndMask.second, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
}
/**
@@ -265,10 +362,12 @@
return false;
}
LinkAddress linkAddress = (LinkAddress) obj;
- return this.address.equals(linkAddress.address) &&
- this.prefixLength == linkAddress.prefixLength &&
- this.flags == linkAddress.flags &&
- this.scope == linkAddress.scope;
+ return this.address.equals(linkAddress.address)
+ && this.prefixLength == linkAddress.prefixLength
+ && this.flags == linkAddress.flags
+ && this.scope == linkAddress.scope
+ && this.deprecationTime == linkAddress.deprecationTime
+ && this.expirationTime == linkAddress.expirationTime;
}
/**
@@ -276,7 +375,7 @@
*/
@Override
public int hashCode() {
- return address.hashCode() + 11 * prefixLength + 19 * flags + 43 * scope;
+ return Objects.hash(address, prefixLength, flags, scope, deprecationTime, expirationTime);
}
/**
@@ -329,6 +428,25 @@
* Returns the flags of this {@code LinkAddress}.
*/
public int getFlags() {
+ int flags = this.flags;
+ if (deprecationTime != LIFETIME_UNKNOWN) {
+ if (SystemClock.elapsedRealtime() >= deprecationTime) {
+ flags |= IFA_F_DEPRECATED;
+ } else {
+ // If deprecation time is in the future, or permanent.
+ flags &= ~IFA_F_DEPRECATED;
+ }
+ }
+
+ if (expirationTime == LIFETIME_PERMANENT) {
+ flags |= IFA_F_PERMANENT;
+ } else if (expirationTime != LIFETIME_UNKNOWN) {
+ // If we know this address expired or will expire in the future, then this address
+ // should not be permanent.
+ flags &= ~IFA_F_PERMANENT;
+ }
+
+ // Do no touch the original flags. Return the adjusted flags here.
return flags;
}
@@ -340,7 +458,42 @@
}
/**
- * Returns true if this {@code LinkAddress} is global scope and preferred.
+ * Get the deprecation time, as reported by {@link SystemClock#elapsedRealtime}, when this
+ * {@link LinkAddress} will be or was deprecated. At the time existing connections can still use
+ * this address until it expires, but new connections should use the new address.
+ *
+ * @return The deprecation time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this
+ * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
+ * will never be deprecated.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public long getDeprecationTime() {
+ return deprecationTime;
+ }
+
+ /**
+ * Get the expiration time, as reported by {@link SystemClock#elapsedRealtime}, when this
+ * {@link LinkAddress} will expire and be removed from the interface.
+ *
+ * @return The expiration time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this
+ * information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
+ * will never expire.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public long getExpirationTime() {
+ return expirationTime;
+ }
+
+ /**
+ * Returns true if this {@code LinkAddress} is global scope and preferred (i.e., not currently
+ * deprecated).
+ *
* @hide
*/
@TestApi
@@ -352,6 +505,7 @@
* state has cleared either DAD has succeeded or failed, and both
* flags are cleared regardless).
*/
+ int flags = getFlags();
return (scope == RT_SCOPE_UNIVERSE
&& !isIpv6ULA()
&& (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L
@@ -373,6 +527,8 @@
dest.writeInt(prefixLength);
dest.writeInt(this.flags);
dest.writeInt(scope);
+ dest.writeLong(deprecationTime);
+ dest.writeLong(expirationTime);
}
/**
@@ -392,7 +548,10 @@
int prefixLength = in.readInt();
int flags = in.readInt();
int scope = in.readInt();
- return new LinkAddress(address, prefixLength, flags, scope);
+ long deprecationTime = in.readLong();
+ long expirationTime = in.readLong();
+ return new LinkAddress(address, prefixLength, flags, scope, deprecationTime,
+ expirationTime);
}
public LinkAddress[] newArray(int size) {
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 2792c56..d25ee0e 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -70,9 +70,18 @@
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;
+ /* package-visibility - Used in other files (such as Ikev2VpnProfile) as minimum iface MTU. */
+ static final int MIN_MTU_V6 = 1280;
private static final int MAX_MTU = 10000;
private static final int INET6_ADDR_LENGTH = 16;
@@ -174,6 +183,7 @@
* Constructs a new {@code LinkProperties} with default values.
*/
public LinkProperties() {
+ mParcelSensitiveFields = false;
}
/**
@@ -182,26 +192,32 @@
@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 +876,11 @@
* 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 +896,8 @@
mTcpBufferSizes = null;
mNat64Prefix = null;
mWakeOnLanSupported = false;
+ mCaptivePortalApiUrl = null;
+ mCaptivePortalData = null;
}
/**
@@ -945,6 +968,14 @@
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 +1510,28 @@
}
/**
+ * 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 +1552,73 @@
}
/**
+ * 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 +1657,9 @@
&& isIdenticalMtu(target)
&& isIdenticalTcpBufferSizes(target)
&& isIdenticalNat64Prefix(target)
- && isIdenticalWakeOnLan(target);
+ && isIdenticalWakeOnLan(target)
+ && isIdenticalCaptivePortalApiUrl(target)
+ && isIdenticalCaptivePortalData(target);
}
/**
@@ -1655,7 +1777,8 @@
+ mPcscfs.size() * 67
+ ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode())
+ Objects.hash(mNat64Prefix)
- + (mWakeOnLanSupported ? 71 : 0);
+ + (mWakeOnLanSupported ? 71 : 0)
+ + Objects.hash(mCaptivePortalApiUrl, mCaptivePortalData);
}
/**
@@ -1694,6 +1817,8 @@
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 +1910,9 @@
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 5f6cc6e..aae9fd4 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -17,6 +17,8 @@
package android.net;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Build;
@@ -43,11 +45,15 @@
*
* @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;
+@SystemApi
+public abstract class NetworkAgent {
+ /**
+ * The {@link Network} corresponding to this object.
+ */
+ @NonNull
+ public final Network network;
+ private final Handler mHandler;
private volatile AsyncChannel mAsyncChannel;
private final String LOG_TAG;
private static final boolean DBG = true;
@@ -56,9 +62,14 @@
private final ArrayList<Message>mPreConnectedQueue = new ArrayList<Message>();
private volatile long mLastBwRefreshTime = 0;
private static final long BW_REFRESH_MIN_WIN_MS = 500;
- private boolean mPollLceScheduled = false;
- private AtomicBoolean mPollLcePending = new AtomicBoolean(false);
- public final int mProviderId;
+ private boolean mBandwidthUpdateScheduled = false;
+ private AtomicBoolean mBandwidthUpdatePending = new AtomicBoolean(false);
+
+ /**
+ * The ID of the {@link NetworkProvider} that created this object, or
+ * {@link NetworkProvider#ID_NONE} if unknown.
+ */
+ public final int providerId;
private static final int BASE = Protocol.BASE_NETWORK_AGENT;
@@ -66,6 +77,7 @@
* Sent by ConnectivityService to the NetworkAgent to inform it of
* suspected connectivity problems on its network. The NetworkAgent
* should take steps to verify and correct connectivity.
+ * @hide
*/
public static final int CMD_SUSPECT_BAD = BASE;
@@ -74,6 +86,7 @@
* ConnectivityService to pass the current NetworkInfo (connection state).
* Sent when the NetworkInfo changes, mainly due to change of state.
* obj = NetworkInfo
+ * @hide
*/
public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1;
@@ -81,6 +94,7 @@
* Sent by the NetworkAgent to ConnectivityService to pass the current
* NetworkCapabilties.
* obj = NetworkCapabilities
+ * @hide
*/
public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 2;
@@ -88,11 +102,14 @@
* Sent by the NetworkAgent to ConnectivityService to pass the current
* NetworkProperties.
* obj = NetworkProperties
+ * @hide
*/
public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3;
- /* centralize place where base network score, and network score scaling, will be
+ /**
+ * Centralize the place where base network score, and network score scaling, will be
* stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE
+ * @hide
*/
public static final int WIFI_BASE_SCORE = 60;
@@ -100,6 +117,7 @@
* Sent by the NetworkAgent to ConnectivityService to pass the current
* network score.
* obj = network score Integer
+ * @hide
*/
public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
@@ -112,12 +130,33 @@
* obj = Bundle containing map from {@code REDIRECT_URL_KEY} to {@code String}
* representing URL that Internet probe was redirect to, if it was redirected,
* or mapping to {@code null} otherwise.
+ * @hide
*/
public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7;
+
+ /**
+ * Network validation suceeded.
+ * Corresponds to {@link NetworkCapabilities.NET_CAPABILITY_VALIDATED}.
+ */
+ public static final int VALIDATION_STATUS_VALID = 1;
+
+ /**
+ * Network validation was attempted and failed. This may be received more than once as
+ * subsequent validation attempts are made.
+ */
+ public static final int VALIDATION_STATUS_NOT_VALID = 2;
+
+ // TODO: remove.
+ /** @hide */
public static final int VALID_NETWORK = 1;
+ /** @hide */
public static final int INVALID_NETWORK = 2;
+ /**
+ * The key for the redirect URL in the Bundle argument of {@code CMD_REPORT_NETWORK_STATUS}.
+ * @hide
+ */
public static String REDIRECT_URL_KEY = "redirect URL";
/**
@@ -126,6 +165,7 @@
* CONNECTED so it can be given special treatment at that time.
*
* obj = boolean indicating whether to use this network even if unvalidated
+ * @hide
*/
public static final int EVENT_SET_EXPLICITLY_SELECTED = BASE + 8;
@@ -136,12 +176,14 @@
* responsibility to remember it.
*
* arg1 = 1 if true, 0 if false
+ * @hide
*/
public static final int CMD_SAVE_ACCEPT_UNVALIDATED = BASE + 9;
/**
* Sent by ConnectivityService to the NetworkAgent to inform the agent to pull
* the underlying network connection for updated bandwidth information.
+ * @hide
*/
public static final int CMD_REQUEST_BANDWIDTH_UPDATE = BASE + 10;
@@ -154,6 +196,7 @@
* obj = KeepalivePacketData object describing the data to be sent
*
* Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
+ * @hide
*/
public static final int CMD_START_SOCKET_KEEPALIVE = BASE + 11;
@@ -163,6 +206,7 @@
* arg1 = slot number of the keepalive to stop.
*
* Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
+ * @hide
*/
public static final int CMD_STOP_SOCKET_KEEPALIVE = BASE + 12;
@@ -176,6 +220,7 @@
*
* arg1 = slot number of the keepalive
* arg2 = error code
+ * @hide
*/
public static final int EVENT_SOCKET_KEEPALIVE = BASE + 13;
@@ -184,6 +229,7 @@
* that when crossed should trigger a system wakeup and a NetworkCapabilities update.
*
* obj = int[] describing signal strength thresholds.
+ * @hide
*/
public static final int CMD_SET_SIGNAL_STRENGTH_THRESHOLDS = BASE + 14;
@@ -191,6 +237,7 @@
* Sent by ConnectivityService to the NeworkAgent to inform the agent to avoid
* automatically reconnecting to this network (e.g. via autojoin). Happens
* when user selects "No" option on the "Stay connected?" dialog box.
+ * @hide
*/
public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15;
@@ -203,6 +250,7 @@
* This does not happen with UDP, so this message is TCP-specific.
* arg1 = slot number of the keepalive to filter for.
* obj = the keepalive packet to send repeatedly.
+ * @hide
*/
public static final int CMD_ADD_KEEPALIVE_PACKET_FILTER = BASE + 16;
@@ -210,6 +258,7 @@
* Sent by the KeepaliveTracker to NetworkAgent to remove a packet filter. See
* {@link #CMD_ADD_KEEPALIVE_PACKET_FILTER}.
* arg1 = slot number of the keepalive packet filter to remove.
+ * @hide
*/
public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17;
@@ -217,27 +266,32 @@
// of dependent changes that would conflict throughout the automerger graph. Having these
// temporarily helps with the process of going through with all these dependent changes across
// the entire tree.
+ /** @hide TODO: decide which of these to expose. */
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score) {
this(looper, context, logTag, ni, nc, lp, score, null, NetworkProvider.ID_NONE);
}
+
+ /** @hide TODO: decide which of these to expose. */
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);
}
+ /** @hide TODO: decide which of these to expose. */
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, int providerId) {
this(looper, context, logTag, ni, nc, lp, score, null, providerId);
}
+ /** @hide TODO: decide which of these to expose. */
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;
+ this.providerId = providerId;
if (ni == null || nc == null || lp == null) {
throw new IllegalArgumentException();
}
@@ -245,116 +299,126 @@
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);
- }
- mPreConnectedQueue.clear();
- }
- }
- 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;
- }
- 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.");
- }
- if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) {
- mPollLceScheduled = false;
- if (mPollLcePending.getAndSet(true) == false) {
- 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;
- }
- 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;
- }
+ private class NetworkAgentHandler extends Handler {
+ NetworkAgentHandler(Looper looper) {
+ super(looper);
+ }
- 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);
+ @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();
+ }
+ }
+ 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;
+ 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.
+ onNetworkUnwanted();
+ synchronized (mPreConnectedQueue) {
+ mAsyncChannel = null;
+ }
+ 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.");
+ }
+ if (currentTimeMs >= (mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS)) {
+ mBandwidthUpdateScheduled = false;
+ if (!mBandwidthUpdatePending.getAndSet(true)) {
+ onBandwidthUpdateRequested();
+ }
+ } else {
+ // deliver the request at a later time rather than discard it completely.
+ if (!mBandwidthUpdateScheduled) {
+ long waitTime = mLastBwRefreshTime + BW_REFRESH_MIN_WIN_MS
+ - currentTimeMs + 1;
+ mBandwidthUpdateScheduled = sendEmptyMessageDelayed(
+ CMD_REQUEST_BANDWIDTH_UPDATE, waitTime);
+ }
+ }
+ 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);
+ }
+ onValidationStatus(msg.arg1 /* status */, redirectUrl);
+ break;
+ }
+ case CMD_SAVE_ACCEPT_UNVALIDATED: {
+ onSaveAcceptUnvalidated(msg.arg1 != 0);
+ break;
+ }
+ case CMD_START_SOCKET_KEEPALIVE: {
+ onStartSocketKeepalive(msg.arg1 /* slot */, msg.arg2 /* interval */,
+ (KeepalivePacketData) msg.obj /* packet */);
+ break;
+ }
+ case CMD_STOP_SOCKET_KEEPALIVE: {
+ onStopSocketKeepalive(msg.arg1 /* slot */);
+ 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);
+ }
+ onSignalStrengthThresholdsUpdated(intThresholds);
+ break;
+ }
+ case CMD_PREVENT_AUTOMATIC_RECONNECT: {
+ onAutomaticReconnectDisabled();
+ break;
+ }
+ case CMD_ADD_KEEPALIVE_PACKET_FILTER: {
+ onAddKeepalivePacketFilter(msg.arg1 /* slot */,
+ (KeepalivePacketData) msg.obj /* packet */);
+ break;
+ }
+ case CMD_REMOVE_KEEPALIVE_PACKET_FILTER: {
+ onRemoveKeepalivePacketFilter(msg.arg1 /* slot */);
+ break;
+ }
}
}
}
@@ -387,14 +451,16 @@
}
/**
- * Called by the bearer code when it has new LinkProperties data.
+ * Must be called by the agent when the network's {@link LinkProperties} change.
+ * @param linkProperties the new LinkProperties.
*/
- public void sendLinkProperties(LinkProperties linkProperties) {
+ public void sendLinkProperties(@NonNull LinkProperties linkProperties) {
queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties));
}
/**
- * Called by the bearer code when it has new NetworkInfo data.
+ * Must be called by the agent when it has a new NetworkInfo object.
+ * @hide TODO: expose something better.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void sendNetworkInfo(NetworkInfo networkInfo) {
@@ -402,17 +468,19 @@
}
/**
- * Called by the bearer code when it has new NetworkCapabilities data.
+ * Must be called by the agent when the network's {@link NetworkCapabilities} change.
+ * @param networkCapabilities the new NetworkCapabilities.
*/
- public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) {
- mPollLcePending.set(false);
+ public void sendNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) {
+ mBandwidthUpdatePending.set(false);
mLastBwRefreshTime = System.currentTimeMillis();
queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED,
new NetworkCapabilities(networkCapabilities));
}
/**
- * Called by the bearer code when it has a new score for this network.
+ * Must be called by the agent to update the score of this network.
+ * @param score the new score.
*/
public void sendNetworkScore(int score) {
if (score < 0) {
@@ -424,14 +492,16 @@
}
/**
- * Called by the bearer code when it has a new NetworkScore for this network.
+ * Must be called by the agent when it has a new {@link NetworkScore} for this network.
+ * @param ns the new score.
+ * @hide TODO: unhide the NetworkScore class, and rename to sendNetworkScore.
*/
public void updateScore(@NonNull NetworkScore ns) {
queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new NetworkScore(ns));
}
/**
- * Called by the bearer to indicate this network was manually selected by the user.
+ * Must be called by the agent to indicate this network was manually selected by the user.
* This should be called before the NetworkInfo is marked CONNECTED so that this
* Network can be given special treatment at that time. If {@code acceptUnvalidated} is
* {@code true}, then the system will switch to this network. If it is {@code false} and the
@@ -440,15 +510,16 @@
* {@link #saveAcceptUnvalidated} to persist the user's choice. Thus, if the transport ever
* calls this method with {@code acceptUnvalidated} set to {@code false}, it must also implement
* {@link #saveAcceptUnvalidated} to respect the user's choice.
+ * @hide should move to NetworkAgentConfig.
*/
public void explicitlySelected(boolean acceptUnvalidated) {
explicitlySelected(true /* explicitlySelected */, acceptUnvalidated);
}
/**
- * Called by the bearer to indicate whether the network was manually selected by the user.
- * This should be called before the NetworkInfo is marked CONNECTED so that this
- * Network can be given special treatment at that time.
+ * Must be called by the agent to indicate whether the network was manually selected by the
+ * user. This should be called before the network becomes connected, so it can be given
+ * special treatment when it does.
*
* If {@code explicitlySelected} is {@code true}, and {@code acceptUnvalidated} is {@code true},
* then the system will switch to this network. If {@code explicitlySelected} is {@code true}
@@ -463,6 +534,7 @@
* {@code true}, the system will interpret this as the user having accepted partial connectivity
* on this network. Thus, the system will switch to the network and consider it validated even
* if it only provides partial connectivity, but the network is not otherwise treated specially.
+ * @hide should move to NetworkAgentConfig.
*/
public void explicitlySelected(boolean explicitlySelected, boolean acceptUnvalidated) {
queueOrSendMessage(EVENT_SET_EXPLICITLY_SELECTED,
@@ -476,73 +548,126 @@
* as well, either canceling NetworkRequests or altering their score such that this
* network won't be immediately requested again.
*/
- abstract protected void unwanted();
+ public void onNetworkUnwanted() {
+ unwanted();
+ }
+ /** @hide TODO delete once subclasses have moved to onNetworkUnwanted. */
+ protected void unwanted() {
+ }
/**
* Called when ConnectivityService request a bandwidth update. The parent factory
* shall try to overwrite this method and produce a bandwidth update if capable.
*/
+ public void onBandwidthUpdateRequested() {
+ pollLceData();
+ }
+ /** @hide TODO delete once subclasses have moved to onBandwidthUpdateRequested. */
protected void pollLceData() {
}
/**
* Called when the system determines the usefulness of this network.
*
- * Networks claiming internet connectivity will have their internet
- * connectivity verified.
+ * The system attempts to validate Internet connectivity on networks that provide the
+ * {@link NetworkCapabilities#NET_CAPABILITY_INTERNET} capability.
*
* Currently there are two possible values:
- * {@code VALID_NETWORK} if the system is happy with the connection,
- * {@code INVALID_NETWORK} if the system is not happy.
- * TODO - add indications of captive portal-ness and related success/failure,
- * ie, CAPTIVE_SUCCESS_NETWORK, CAPTIVE_NETWORK for successful login and detection
+ * {@code VALIDATION_STATUS_VALID} if Internet connectivity was validated,
+ * {@code VALIDATION_STATUS_NOT_VALID} if Internet connectivity was not validated.
*
- * This may be called multiple times as the network status changes and may
- * generate false negatives if we lose ip connectivity before the link is torn down.
+ * This may be called multiple times as network status changes, or if there are multiple
+ * subsequent attempts to validate connectivity that fail.
*
- * @param status one of {@code VALID_NETWORK} or {@code INVALID_NETWORK}.
- * @param redirectUrl If the Internet probe was redirected, this is the destination it was
- * redirected to, otherwise {@code null}.
+ * @param status one of {@code VALIDATION_STATUS_VALID} or {@code VALIDATION_STATUS_NOT_VALID}.
+ * @param redirectUrl If Internet connectivity is being redirected (e.g., on a captive portal),
+ * this is the destination the probes are being redirected to, otherwise {@code null}.
*/
+ public void onValidationStatus(int status, @Nullable String redirectUrl) {
+ networkStatus(status, redirectUrl);
+ }
+ /** @hide TODO delete once subclasses have moved to onValidationStatus */
protected void networkStatus(int status, String redirectUrl) {
}
+
/**
* Called when the user asks to remember the choice to use this network even if unvalidated.
* The transport is responsible for remembering the choice, and the next time the user connects
* to the network, should explicitlySelected with {@code acceptUnvalidated} set to {@code true}.
* This method will only be called if {@link #explicitlySelected} was called with
* {@code acceptUnvalidated} set to {@code false}.
+ * @param accept whether the user wants to use the network even if unvalidated.
*/
+ public void onSaveAcceptUnvalidated(boolean accept) {
+ saveAcceptUnvalidated(accept);
+ }
+ /** @hide TODO delete once subclasses have moved to onSaveAcceptUnvalidated */
protected void saveAcceptUnvalidated(boolean accept) {
}
/**
* Requests that the network hardware send the specified packet at the specified interval.
+ *
+ * @param slot the hardware slot on which to start the keepalive.
+ * @param intervalSeconds the interval between packets
+ * @param packet the packet to send.
*/
+ public void onStartSocketKeepalive(int slot, int intervalSeconds,
+ @NonNull KeepalivePacketData packet) {
+ Message msg = mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, slot, intervalSeconds,
+ packet);
+ startSocketKeepalive(msg);
+ msg.recycle();
+ }
+ /** @hide TODO delete once subclasses have moved to onStartSocketKeepalive */
protected void startSocketKeepalive(Message msg) {
onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED);
}
/**
- * Requests that the network hardware send the specified packet at the specified interval.
+ * Requests that the network hardware stop a previously-started keepalive.
+ *
+ * @param slot the hardware slot on which to stop the keepalive.
*/
+ public void onStopSocketKeepalive(int slot) {
+ Message msg = mHandler.obtainMessage(CMD_STOP_SOCKET_KEEPALIVE, slot, 0, null);
+ stopSocketKeepalive(msg);
+ msg.recycle();
+ }
+ /** @hide TODO delete once subclasses have moved to onStopSocketKeepalive */
protected void stopSocketKeepalive(Message msg) {
onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_UNSUPPORTED);
}
/**
- * Called by the network when a socket keepalive event occurs.
+ * Must be called by the agent when a socket keepalive event occurs.
+ *
+ * @param slot the hardware slot on which the event occurred.
+ * @param event the event that occurred.
*/
+ public void sendSocketKeepaliveEvent(int slot, int event) {
+ queueOrSendMessage(EVENT_SOCKET_KEEPALIVE, slot, event);
+ }
+ /** @hide TODO delete once callers have moved to sendSocketKeepaliveEvent */
public void onSocketKeepaliveEvent(int slot, int reason) {
- queueOrSendMessage(EVENT_SOCKET_KEEPALIVE, slot, reason);
+ sendSocketKeepaliveEvent(slot, reason);
}
/**
* Called by ConnectivityService to add specific packet filter to network hardware to block
- * ACKs matching the sent keepalive packets. Implementations that support this feature must
- * override this method.
+ * replies (e.g., TCP ACKs) matching the sent keepalive packets. Implementations that support
+ * this feature must override this method.
+ *
+ * @param slot the hardware slot on which the keepalive should be sent.
+ * @param packet the packet that is being sent.
*/
+ public void onAddKeepalivePacketFilter(int slot, @NonNull KeepalivePacketData packet) {
+ Message msg = mHandler.obtainMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0, packet);
+ addKeepalivePacketFilter(msg);
+ msg.recycle();
+ }
+ /** @hide TODO delete once subclasses have moved to onAddKeepalivePacketFilter */
protected void addKeepalivePacketFilter(Message msg) {
}
@@ -550,14 +675,28 @@
* Called by ConnectivityService to remove a packet filter installed with
* {@link #addKeepalivePacketFilter(Message)}. Implementations that support this feature
* must override this method.
+ *
+ * @param slot the hardware slot on which the keepalive is being sent.
*/
+ public void onRemoveKeepalivePacketFilter(int slot) {
+ Message msg = mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, slot, 0, null);
+ removeKeepalivePacketFilter(msg);
+ msg.recycle();
+ }
+ /** @hide TODO delete once subclasses have moved to onRemoveKeepalivePacketFilter */
protected void removeKeepalivePacketFilter(Message msg) {
}
/**
* Called by ConnectivityService to inform this network transport of signal strength thresholds
* that when crossed should trigger a system wakeup and a NetworkCapabilities update.
+ *
+ * @param thresholds the array of thresholds that should trigger wakeups.
*/
+ public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) {
+ setSignalStrengthThresholds(thresholds);
+ }
+ /** @hide TODO delete once subclasses have moved to onSetSignalStrengthThresholds */
protected void setSignalStrengthThresholds(int[] thresholds) {
}
@@ -567,9 +706,14 @@
* responsible for making sure the device does not automatically reconnect to the same network
* after the {@code unwanted} call.
*/
+ public void onAutomaticReconnectDisabled() {
+ preventAutomaticReconnect();
+ }
+ /** @hide TODO delete once subclasses have moved to onAutomaticReconnectDisabled */
protected void preventAutomaticReconnect() {
}
+ /** @hide */
protected void log(String s) {
Log.d(LOG_TAG, "NetworkAgent: " + s);
}
diff --git a/core/java/android/net/NetworkMisc.aidl b/core/java/android/net/NetworkAgentConfig.aidl
similarity index 95%
rename from core/java/android/net/NetworkMisc.aidl
rename to core/java/android/net/NetworkAgentConfig.aidl
index c65583f..cb70bdd 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 0000000..abc6b67
--- /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 f43385d..f94bdb7 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -26,6 +26,7 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;
@@ -35,6 +36,9 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;
@@ -55,7 +59,6 @@
*/
public final class NetworkCapabilities implements Parcelable {
private static final String TAG = "NetworkCapabilities";
- private static final int INVALID_UID = -1;
// Set to true when private DNS is broken.
private boolean mPrivateDnsBroken;
@@ -82,7 +85,8 @@
mTransportInfo = null;
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
mUids = null;
- mEstablishingVpnAppUid = INVALID_UID;
+ mAdministratorUids.clear();
+ mOwnerUid = Process.INVALID_UID;
mSSID = null;
mPrivateDnsBroken = false;
}
@@ -100,7 +104,8 @@
mTransportInfo = nc.mTransportInfo;
mSignalStrength = nc.mSignalStrength;
setUids(nc.mUids); // Will make the defensive copy
- mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
+ setAdministratorUids(nc.mAdministratorUids);
+ mOwnerUid = nc.mOwnerUid;
mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
mSSID = nc.mSSID;
mPrivateDnsBroken = nc.mPrivateDnsBroken;
@@ -805,31 +810,76 @@
}
/**
- * UID of the app that manages this network, or INVALID_UID if none/unknown.
+ * UID of the app that owns this network, or INVALID_UID if none/unknown.
*
- * This field keeps track of the UID of the app that created this network and is in charge
- * of managing it. In the practice, it is used to store the UID of VPN apps so it is named
- * accordingly, but it may be renamed if other mechanisms are offered for third party apps
- * to create networks.
- *
- * Because this field is only used in the services side (and to avoid apps being able to
- * set this to whatever they want), this field is not parcelled and will not be conserved
- * across the IPC boundary.
- * @hide
+ * <p>This field keeps track of the UID of the app that created this network and is in charge of
+ * its lifecycle. This could be the UID of apps such as the Wifi network suggestor, the running
+ * VPN, or Carrier Service app managing a cellular data connection.
*/
- private int mEstablishingVpnAppUid = INVALID_UID;
+ private int mOwnerUid = Process.INVALID_UID;
/**
- * Set the UID of the managing app.
- * @hide
+ * Set the UID of the owner app.
*/
- public void setEstablishingVpnAppUid(final int uid) {
- mEstablishingVpnAppUid = uid;
+ public void setOwnerUid(final int uid) {
+ mOwnerUid = uid;
}
- /** @hide */
- public int getEstablishingVpnAppUid() {
- return mEstablishingVpnAppUid;
+ /**
+ * Retrieves the UID of the owner app.
+ */
+ public int getOwnerUid() {
+ return mOwnerUid;
+ }
+
+ /**
+ * UIDs of packages that are administrators of this network, or empty if none.
+ *
+ * <p>This field tracks the UIDs of packages that have permission to manage this network.
+ *
+ * <p>Network owners will also be listed as administrators.
+ *
+ * <p>For NetworkCapability instances being sent from the System Server, this value MUST be
+ * empty unless the destination is 1) the System Server, or 2) Telephony. In either case, the
+ * receiving entity must have the ACCESS_FINE_LOCATION permission and target R+.
+ */
+ private final List<Integer> mAdministratorUids = new ArrayList<>();
+
+ /**
+ * Sets the list of UIDs that are administrators of this network.
+ *
+ * <p>UIDs included in administratorUids gain administrator privileges over this Network.
+ * Examples of UIDs that should be included in administratorUids are:
+ * <ul>
+ * <li>Carrier apps with privileges for the relevant subscription
+ * <li>Active VPN apps
+ * <li>Other application groups with a particular Network-related role
+ * </ul>
+ *
+ * <p>In general, user-supplied networks (such as WiFi networks) do not have an administrator.
+ *
+ * <p>An app is granted owner privileges over Networks that it supplies. Owner privileges
+ * implicitly include administrator privileges.
+ *
+ * @param administratorUids the UIDs to be set as administrators of this Network.
+ * @hide
+ */
+ @SystemApi
+ public void setAdministratorUids(@NonNull final List<Integer> administratorUids) {
+ mAdministratorUids.clear();
+ mAdministratorUids.addAll(administratorUids);
+ }
+
+ /**
+ * Retrieves the list of UIDs that are administrators of this Network.
+ *
+ * @return the List of UIDs that are administrators of this Network
+ * @hide
+ */
+ @NonNull
+ @SystemApi
+ public List<Integer> getAdministratorUids() {
+ return Collections.unmodifiableList(mAdministratorUids);
}
/**
@@ -1102,7 +1152,7 @@
* member is null, then the network is not restricted by app UID. If it's an empty list, then
* it means nobody can use it.
* As a special exception, the app managing this network (as identified by its UID stored in
- * mEstablishingVpnAppUid) can always see this network. This is embodied by a special check in
+ * mOwnerUid) can always see this network. This is embodied by a special check in
* satisfiedByUids. That still does not mean the network necessarily <strong>applies</strong>
* to the app that manages it as determined by #appliesToUid.
* <p>
@@ -1209,7 +1259,7 @@
* in the passed nc (representing the UIDs that this network is available to).
* <p>
* As a special exception, the UID that created the passed network (as represented by its
- * mEstablishingVpnAppUid field) always satisfies a NetworkRequest requiring it (of LISTEN
+ * mOwnerUid field) always satisfies a NetworkRequest requiring it (of LISTEN
* or REQUEST types alike), even if the network does not apply to it. That is so a VPN app
* can see its own network when it listens for it.
* <p>
@@ -1220,7 +1270,7 @@
public boolean satisfiedByUids(@NonNull NetworkCapabilities nc) {
if (null == nc.mUids || null == mUids) return true; // The network satisfies everything.
for (UidRange requiredRange : mUids) {
- if (requiredRange.contains(nc.mEstablishingVpnAppUid)) return true;
+ if (requiredRange.contains(nc.mOwnerUid)) return true;
if (!nc.appliesToUidRange(requiredRange)) {
return false;
}
@@ -1283,6 +1333,7 @@
* Gets the SSID of this network, or null if none or unknown.
* @hide
*/
+ @SystemApi
public @Nullable String getSSID() {
return mSSID;
}
@@ -1470,6 +1521,7 @@
public int describeContents() {
return 0;
}
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(mNetworkCapabilities);
@@ -1483,6 +1535,8 @@
dest.writeArraySet(mUids);
dest.writeString(mSSID);
dest.writeBoolean(mPrivateDnsBroken);
+ dest.writeList(mAdministratorUids);
+ dest.writeInt(mOwnerUid);
}
public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
@@ -1503,6 +1557,8 @@
null /* ClassLoader, null for default */);
netCap.mSSID = in.readString();
netCap.mPrivateDnsBroken = in.readBoolean();
+ netCap.setAdministratorUids(in.readArrayList(null));
+ netCap.mOwnerUid = in.readInt();
return netCap;
}
@Override
@@ -1552,8 +1608,12 @@
sb.append(" Uids: <").append(mUids).append(">");
}
}
- if (mEstablishingVpnAppUid != INVALID_UID) {
- sb.append(" EstablishingAppUid: ").append(mEstablishingVpnAppUid);
+ if (mOwnerUid != Process.INVALID_UID) {
+ sb.append(" OwnerUid: ").append(mOwnerUid);
+ }
+
+ if (!mAdministratorUids.isEmpty()) {
+ sb.append(" AdministratorUids: ").append(mAdministratorUids);
}
if (null != mSSID) {
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index 824ddb8..e271037 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -115,13 +115,6 @@
*/
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 4ad52d5..0000000
--- 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 c7b3009..ee4379a 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -300,22 +300,34 @@
* this without a single transport set will generate an exception, as will
* subsequently adding or removing transports after this is set.
* </p>
- * The interpretation of this {@code String} is bearer specific and bearers that use
- * it should document their particulars. For example, Bluetooth may use some sort of
- * device id while WiFi could used ssid and/or bssid. Cellular may use carrier spn.
+ * If the {@code networkSpecifier} is provided, it shall be interpreted as follows:
+ * <ul>
+ * <li>If the specifier can be parsed as an integer, it will be treated as a
+ * {@link android.net TelephonyNetworkSpecifier}, and the provided integer will be
+ * interpreted as a SubscriptionId.
+ * <li>If the value is an ethernet interface name, it will be treated as such.
+ * <li>For all other cases, the behavior is undefined.
+ * </ul>
*
- * @param networkSpecifier An {@code String} of opaque format used to specify the bearer
- * specific network specifier where the bearer has a choice of
- * networks.
+ * @param networkSpecifier A {@code String} of either a SubscriptionId in cellular
+ * network request or an ethernet interface name in ethernet
+ * network request.
+ *
+ * @deprecated Use {@link #setNetworkSpecifier(NetworkSpecifier)} instead.
*/
+ @Deprecated
public Builder setNetworkSpecifier(String networkSpecifier) {
- /*
- * A StringNetworkSpecifier does not accept null or empty ("") strings. When network
- * specifiers were strings a null string and an empty string were considered equivalent.
- * Hence no meaning is attached to a null or empty ("") string.
- */
- return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null
- : new StringNetworkSpecifier(networkSpecifier));
+ try {
+ int subId = Integer.parseInt(networkSpecifier);
+ return setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+ .setSubscriptionId(subId).build());
+ } catch (NumberFormatException nfe) {
+ // A StringNetworkSpecifier does not accept null or empty ("") strings. When network
+ // specifiers were strings a null string and an empty string were considered
+ // equivalent. Hence no meaning is attached to a null or empty ("") string.
+ return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null
+ : new StringNetworkSpecifier(networkSpecifier));
+ }
}
/**
@@ -455,6 +467,19 @@
}
/**
+ * 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/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index f6dc525..c233ec0 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -163,27 +163,26 @@
public static final String EXTRA_NEW_SCORER = "newScorer";
/** @hide */
- @IntDef({CACHE_FILTER_NONE, CACHE_FILTER_CURRENT_NETWORK, CACHE_FILTER_SCAN_RESULTS})
+ @IntDef({SCORE_FILTER_NONE, SCORE_FILTER_CURRENT_NETWORK, SCORE_FILTER_SCAN_RESULTS})
@Retention(RetentionPolicy.SOURCE)
- public @interface CacheUpdateFilter {}
+ public @interface ScoreUpdateFilter {}
/**
- * Do not filter updates sent to the cache.
- * @hide
+ * Do not filter updates sent to the {@link NetworkScoreCallback}].
*/
- public static final int CACHE_FILTER_NONE = 0;
+ public static final int SCORE_FILTER_NONE = 0;
/**
- * Only send cache updates when the network matches the connected network.
- * @hide
+ * Only send updates to the {@link NetworkScoreCallback} when the network matches the connected
+ * network.
*/
- public static final int CACHE_FILTER_CURRENT_NETWORK = 1;
+ public static final int SCORE_FILTER_CURRENT_NETWORK = 1;
/**
- * Only send cache updates when the network is part of the current scan result set.
- * @hide
+ * Only send updates to the {@link NetworkScoreCallback} when the network is part of the
+ * current scan result set.
*/
- public static final int CACHE_FILTER_SCAN_RESULTS = 2;
+ public static final int SCORE_FILTER_SCAN_RESULTS = 2;
/** @hide */
@IntDef({RECOMMENDATIONS_ENABLED_FORCED_OFF, RECOMMENDATIONS_ENABLED_OFF,
@@ -404,13 +403,13 @@
* @throws SecurityException if the caller does not hold the
* {@link permission#REQUEST_NETWORK_SCORES} permission.
* @throws IllegalArgumentException if a score cache is already registered for this type.
- * @deprecated equivalent to registering for cache updates with CACHE_FILTER_NONE.
+ * @deprecated equivalent to registering for cache updates with {@link #SCORE_FILTER_NONE}.
* @hide
*/
@RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
@Deprecated // migrate to registerNetworkScoreCache(int, INetworkScoreCache, int)
public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
- registerNetworkScoreCache(networkType, scoreCache, CACHE_FILTER_NONE);
+ registerNetworkScoreCache(networkType, scoreCache, SCORE_FILTER_NONE);
}
/**
@@ -418,7 +417,7 @@
*
* @param networkType the type of network this cache can handle. See {@link NetworkKey#type}
* @param scoreCache implementation of {@link INetworkScoreCache} to store the scores
- * @param filterType the {@link CacheUpdateFilter} to apply
+ * @param filterType the {@link ScoreUpdateFilter} to apply
* @throws SecurityException if the caller does not hold the
* {@link permission#REQUEST_NETWORK_SCORES} permission.
* @throws IllegalArgumentException if a score cache is already registered for this type.
@@ -426,7 +425,7 @@
*/
@RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache,
- @CacheUpdateFilter int filterType) {
+ @ScoreUpdateFilter int filterType) {
try {
mService.registerNetworkScoreCache(networkType, scoreCache, filterType);
} catch (RemoteException e) {
@@ -510,7 +509,7 @@
* Register a network score callback.
*
* @param networkType the type of network this cache can handle. See {@link NetworkKey#type}
- * @param filterType the {@link CacheUpdateFilter} to apply
+ * @param filterType the {@link ScoreUpdateFilter} to apply
* @param callback implementation of {@link NetworkScoreCallback} that will be invoked when the
* scores change.
* @param executor The executor on which to execute the callbacks.
@@ -522,7 +521,7 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
public void registerNetworkScoreCallback(@NetworkKey.NetworkType int networkType,
- @CacheUpdateFilter int filterType,
+ @ScoreUpdateFilter int filterType,
@NonNull @CallbackExecutor Executor executor,
@NonNull NetworkScoreCallback callback) throws SecurityException {
if (callback == null || executor == null) {
diff --git a/core/java/android/net/PlatformVpnProfile.java b/core/java/android/net/PlatformVpnProfile.java
new file mode 100644
index 0000000..fbae637
--- /dev/null
+++ b/core/java/android/net/PlatformVpnProfile.java
@@ -0,0 +1,107 @@
+/*
+ * 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 static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_PSK;
+import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_RSA;
+import static android.net.PlatformVpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+
+import com.android.internal.net.VpnProfile;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.GeneralSecurityException;
+
+/**
+ * PlatformVpnProfile represents a configuration for a platform-based VPN implementation.
+ *
+ * <p>Platform-based VPNs allow VPN applications to provide configuration and authentication options
+ * to leverage the Android OS' implementations of well-defined control plane (authentication, key
+ * negotiation) and data plane (per-packet encryption) protocols to simplify the creation of VPN
+ * tunnels. In contrast, {@link VpnService} based VPNs must implement both the control and data
+ * planes on a per-app basis.
+ *
+ * @see Ikev2VpnProfile
+ */
+public abstract class PlatformVpnProfile {
+ /**
+ * Alias to platform VPN related types from VpnProfile, for API use.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ TYPE_IKEV2_IPSEC_USER_PASS,
+ TYPE_IKEV2_IPSEC_PSK,
+ TYPE_IKEV2_IPSEC_RSA,
+ })
+ public static @interface PlatformVpnType {}
+
+ public static final int TYPE_IKEV2_IPSEC_USER_PASS = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
+ public static final int TYPE_IKEV2_IPSEC_PSK = VpnProfile.TYPE_IKEV2_IPSEC_PSK;
+ public static final int TYPE_IKEV2_IPSEC_RSA = VpnProfile.TYPE_IKEV2_IPSEC_RSA;
+
+ /** @hide */
+ @PlatformVpnType protected final int mType;
+
+ /** @hide */
+ PlatformVpnProfile(@PlatformVpnType int type) {
+ mType = type;
+ }
+ /** Returns the profile integer type. */
+ @PlatformVpnType
+ public final int getType() {
+ return mType;
+ }
+
+ /** Returns a type string describing the VPN profile type */
+ @NonNull
+ public final String getTypeString() {
+ switch (mType) {
+ case TYPE_IKEV2_IPSEC_USER_PASS:
+ return "IKEv2/IPsec Username/Password";
+ case TYPE_IKEV2_IPSEC_PSK:
+ return "IKEv2/IPsec Preshared key";
+ case TYPE_IKEV2_IPSEC_RSA:
+ return "IKEv2/IPsec RSA Digital Signature";
+ default:
+ return "Unknown VPN profile type";
+ }
+ }
+
+ /** @hide */
+ @NonNull
+ public abstract VpnProfile toVpnProfile() throws IOException, GeneralSecurityException;
+
+ /** @hide */
+ @NonNull
+ public static PlatformVpnProfile fromVpnProfile(@NonNull VpnProfile profile)
+ throws IOException, GeneralSecurityException {
+ switch (profile.type) {
+ case TYPE_IKEV2_IPSEC_USER_PASS: // fallthrough
+ case TYPE_IKEV2_IPSEC_PSK: // fallthrough
+ case TYPE_IKEV2_IPSEC_RSA:
+ return Ikev2VpnProfile.fromVpnProfile(profile);
+ default:
+ throw new IllegalArgumentException("Unknown VPN Profile type");
+ }
+ }
+}
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index ea6002c..67bad53 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -104,6 +104,11 @@
*/
private final int mType;
+ /**
+ * The maximum transmission unit size for this route.
+ */
+ private final int mMtu;
+
// Derived data members.
// TODO: remove these.
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -132,6 +137,31 @@
@TestApi
public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
@Nullable String iface, @RouteType int type) {
+ this(destination, gateway, iface, type, 0);
+ }
+
+ /**
+ * Constructs a RouteInfo object.
+ *
+ * If destination is null, then gateway must be specified and the
+ * constructed route is either the IPv4 default route <code>0.0.0.0</code>
+ * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
+ * route <code>::/0</code> if gateway is an instance of
+ * {@link Inet6Address}.
+ * <p>
+ * destination and gateway may not both be null.
+ *
+ * @param destination the destination prefix
+ * @param gateway the IP address to route packets through
+ * @param iface the interface name to send packets on
+ * @param type the type of this route
+ * @param mtu the maximum transmission unit size for this route
+ *
+ * @hide
+ */
+ @SystemApi
+ public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
+ @Nullable String iface, @RouteType int type, int mtu) {
switch (type) {
case RTN_UNICAST:
case RTN_UNREACHABLE:
@@ -161,7 +191,7 @@
} else {
// no destination, no gateway. invalid.
throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," +
- destination);
+ destination);
}
}
// TODO: set mGateway to null if there is no gateway. This is more correct, saves space, and
@@ -176,10 +206,10 @@
}
mHasGateway = (!gateway.isAnyLocalAddress());
- if ((destination.getAddress() instanceof Inet4Address &&
- (gateway instanceof Inet4Address == false)) ||
- (destination.getAddress() instanceof Inet6Address &&
- (gateway instanceof Inet6Address == false))) {
+ if ((destination.getAddress() instanceof Inet4Address
+ && !(gateway instanceof Inet4Address))
+ || (destination.getAddress() instanceof Inet6Address
+ && !(gateway instanceof Inet6Address))) {
throw new IllegalArgumentException("address family mismatch in RouteInfo constructor");
}
mDestination = destination; // IpPrefix objects are immutable.
@@ -187,6 +217,7 @@
mInterface = iface; // Strings are immutable.
mType = type;
mIsHost = isHost();
+ mMtu = mtu;
}
/**
@@ -373,6 +404,17 @@
}
/**
+ * Retrieves the MTU size for this route.
+ *
+ * @return The MTU size, or 0 if it has not been set.
+ * @hide
+ */
+ @SystemApi
+ public int getMtu() {
+ return mMtu;
+ }
+
+ /**
* Indicates if this route is a default route (ie, has no destination specified).
*
* @return {@code true} if the destination has a prefix length of 0.
@@ -476,6 +518,7 @@
val += " unknown type " + mType;
}
}
+ val += " mtu " + mMtu;
return val;
}
@@ -493,7 +536,7 @@
return Objects.equals(mDestination, target.getDestination()) &&
Objects.equals(mGateway, target.getGateway()) &&
Objects.equals(mInterface, target.getInterface()) &&
- mType == target.getType();
+ mType == target.getType() && mMtu == target.getMtu();
}
/**
@@ -503,7 +546,7 @@
return (mDestination.hashCode() * 41)
+ (mGateway == null ? 0 :mGateway.hashCode() * 47)
+ (mInterface == null ? 0 :mInterface.hashCode() * 67)
- + (mType * 71);
+ + (mType * 71) + (mMtu * 89);
}
/**
@@ -522,6 +565,7 @@
dest.writeByteArray(gatewayBytes);
dest.writeString(mInterface);
dest.writeInt(mType);
+ dest.writeInt(mMtu);
}
/**
@@ -540,8 +584,9 @@
String iface = in.readString();
int type = in.readInt();
+ int mtu = in.readInt();
- return new RouteInfo(dest, gateway, iface, type);
+ return new RouteInfo(dest, gateway, iface, type, mtu);
}
public RouteInfo[] newArray(int size) {
diff --git a/core/java/android/net/StringNetworkSpecifier.java b/core/java/android/net/StringNetworkSpecifier.java
index 83dbc63..6ae5971 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;
@@ -27,7 +26,6 @@
import java.util.Objects;
/** @hide */
-@SystemApi
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/TelephonyNetworkSpecifier.java b/core/java/android/net/TelephonyNetworkSpecifier.java
new file mode 100644
index 0000000..726f770
--- /dev/null
+++ b/core/java/android/net/TelephonyNetworkSpecifier.java
@@ -0,0 +1,146 @@
+/*
+ * 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 android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * NetworkSpecifier object for cellular network request. Apps should use the
+ * {@link TelephonyNetworkSpecifier.Builder} class to create an instance.
+ */
+public final class TelephonyNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+
+ private final int mSubId;
+
+ /**
+ * Return the subscription Id of current TelephonyNetworkSpecifier object.
+ *
+ * @return The subscription id.
+ */
+ public int getSubscriptionId() {
+ return mSubId;
+ }
+
+ /**
+ * @hide
+ */
+ public TelephonyNetworkSpecifier(int subId) {
+ this.mSubId = subId;
+ }
+
+ public static final @NonNull Creator<TelephonyNetworkSpecifier> CREATOR =
+ new Creator<TelephonyNetworkSpecifier>() {
+ @Override
+ public TelephonyNetworkSpecifier createFromParcel(Parcel in) {
+ int subId = in.readInt();
+ return new TelephonyNetworkSpecifier(subId);
+ }
+
+ @Override
+ public TelephonyNetworkSpecifier[] newArray(int size) {
+ return new TelephonyNetworkSpecifier[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mSubId);
+ }
+
+ @Override
+ public int hashCode() {
+ return mSubId;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof TelephonyNetworkSpecifier)) {
+ return false;
+ }
+
+ TelephonyNetworkSpecifier lhs = (TelephonyNetworkSpecifier) obj;
+ return mSubId == lhs.mSubId;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("TelephonyNetworkSpecifier [")
+ .append("mSubId = ").append(mSubId)
+ .append("]")
+ .toString();
+ }
+
+ /** @hide */
+ @Override
+ public boolean satisfiedBy(NetworkSpecifier other) {
+ // Any generic requests should be satisfied by a specific telephony network.
+ // For simplicity, we treat null same as MatchAllNetworkSpecifier
+ return equals(other) || other == null || other instanceof MatchAllNetworkSpecifier;
+ }
+
+
+ /**
+ * Builder to create {@link TelephonyNetworkSpecifier} object.
+ */
+ public static final class Builder {
+ // Integer.MIN_VALUE which is not a valid subId, services as the sentinel to check if
+ // subId was set
+ private static final int SENTINEL_SUB_ID = Integer.MIN_VALUE;
+
+ private int mSubId;
+
+ public Builder() {
+ mSubId = SENTINEL_SUB_ID;
+ }
+
+ /**
+ * Set the subscription id.
+ *
+ * @param subId The subscription Id.
+ * @return Instance of {@link Builder} to enable the chaining of the builder method.
+ */
+ public @NonNull Builder setSubscriptionId(int subId) {
+ mSubId = subId;
+ return this;
+ }
+
+ /**
+ * Create a NetworkSpecifier for the cellular network request.
+ *
+ * @return TelephonyNetworkSpecifier object.
+ * @throws IllegalArgumentException when subscription Id is not provided through
+ * {@link #setSubscriptionId(int)}.
+ */
+ public @NonNull TelephonyNetworkSpecifier build() {
+ if (mSubId == SENTINEL_SUB_ID) {
+ throw new IllegalArgumentException("Subscription Id is not provided.");
+ }
+ return new TelephonyNetworkSpecifier(mSubId);
+ }
+ }
+}
diff --git a/core/java/android/net/Uri.aidl b/core/java/android/net/Uri.aidl
index 6bd3be5..b85f63b 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/net/VpnManager.java b/core/java/android/net/VpnManager.java
new file mode 100644
index 0000000..f95807a
--- /dev/null
+++ b/core/java/android/net/VpnManager.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * This class provides an interface for apps to manage platform VPN profiles
+ *
+ * <p>Apps can use this API to provide profiles with which the platform can set up a VPN without
+ * further app intermediation. When a VPN profile is present and the app is selected as an always-on
+ * VPN, the platform will directly trigger the negotiation of the VPN without starting or waking the
+ * app (unlike VpnService).
+ *
+ * <p>VPN apps using supported protocols should preferentially use this API over the {@link
+ * VpnService} API for ease-of-development and reduced maintainance burden. This also give the user
+ * the guarantee that VPN network traffic is not subjected to on-device packet interception.
+ *
+ * @see Ikev2VpnProfile
+ */
+public class VpnManager {
+ @NonNull private final Context mContext;
+ @NonNull private final IConnectivityManager mService;
+
+ /**
+ * Create an instance of the VpnManger with the given context.
+ *
+ * <p>Internal only. Applications are expected to obtain an instance of the VpnManager via the
+ * {@link Context.getSystemService()} method call.
+ *
+ * @hide
+ */
+ public VpnManager(@NonNull Context ctx, @NonNull IConnectivityManager service) {
+ mContext = checkNotNull(ctx, "missing Context");
+ mService = checkNotNull(service, "missing IConnectivityManager");
+ }
+
+ /**
+ * Install a VpnProfile configuration keyed on the calling app's package name.
+ *
+ * @param profile the PlatformVpnProfile provided by this package. Will override any previous
+ * PlatformVpnProfile stored for this package.
+ * @return an intent to request user consent if needed (null otherwise).
+ */
+ @Nullable
+ public Intent provisionVpnProfile(@NonNull PlatformVpnProfile profile) {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+ /** Delete the VPN profile configuration that was provisioned by the calling app */
+ public void deleteProvisionedVpnProfile() {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+ /**
+ * Request the startup of a previously provisioned VPN.
+ *
+ * @throws SecurityException exception if user or device settings prevent this VPN from being
+ * setup, or if user consent has not been granted
+ */
+ public void startProvisionedVpnProfile() {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+ /** Tear down the VPN provided by the calling app (if any) */
+ public void stopProvisionedVpnProfile() {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+}
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 8bb2df0..b9e6ff4 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -455,12 +455,12 @@
*
* @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 b6b347c..ae468fe 100644
--- a/core/java/android/nfc/tech/BasicTagTechnology.java
+++ b/core/java/android/nfc/tech/BasicTagTechnology.java
@@ -75,7 +75,10 @@
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 6daa5b4..9257496 100644
--- a/core/java/android/os/AppZygote.java
+++ b/core/java/android/os/AppZygote.java
@@ -21,6 +21,8 @@
import com.android.internal.annotations.GuardedBy;
+import dalvik.system.VMRuntime;
+
/**
* AppZygote is responsible for interfacing with an application-specific zygote.
*
@@ -113,7 +115,7 @@
"app_zygote", // seInfo
abi, // abi
abi, // acceptedAbiList
- null, // instructionSet
+ VMRuntime.getInstructionSet(abi), // instructionSet
mZygoteUidGidMin,
mZygoteUidGidMax);
diff --git a/core/java/android/os/IVibratorService.aidl b/core/java/android/os/IVibratorService.aidl
index 6b881fe..264ab60 100644
--- a/core/java/android/os/IVibratorService.aidl
+++ b/core/java/android/os/IVibratorService.aidl
@@ -24,7 +24,8 @@
{
boolean hasVibrator();
boolean hasAmplitudeControl();
- boolean setAlwaysOnEffect(int id, in VibrationEffect effect, in AudioAttributes attributes);
+ boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, in VibrationEffect effect,
+ in AudioAttributes attributes);
void vibrate(int uid, String opPkg, in VibrationEffect effect, in AudioAttributes attributes,
String reason, IBinder token);
void cancelVibrate(IBinder token);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index febc36c..68c2764 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1409,6 +1409,7 @@
* @throws UnsupportedOperationException if userspace reboot was requested on a device that
* doesn't support it.
*/
+ @RequiresPermission(permission.REBOOT)
public void reboot(@Nullable String reason) {
if (REBOOT_USERSPACE.equals(reason) && !isRebootingUserspaceSupported()) {
throw new UnsupportedOperationException(
@@ -1428,6 +1429,7 @@
* </p>
* @hide
*/
+ @RequiresPermission(permission.REBOOT)
public void rebootSafeMode() {
try {
mService.rebootSafeMode(false, true);
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index f585c75..11a425d 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -70,13 +70,14 @@
}
@Override
- public boolean setAlwaysOnEffect(int id, VibrationEffect effect, AudioAttributes attributes) {
+ public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect,
+ AudioAttributes attributes) {
if (mService == null) {
Log.w(TAG, "Failed to set always-on effect; no vibrator service.");
return false;
}
try {
- return mService.setAlwaysOnEffect(id, effect, attributes);
+ return mService.setAlwaysOnEffect(uid, opPkg, alwaysOnId, effect, attributes);
} catch (RemoteException e) {
Log.w(TAG, "Failed to set always-on effect.", e);
}
diff --git a/core/java/android/os/TimestampedValue.java b/core/java/android/os/TimestampedValue.java
index 348574e..f4c87ac 100644
--- a/core/java/android/os/TimestampedValue.java
+++ b/core/java/android/os/TimestampedValue.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import java.util.Objects;
@@ -35,19 +36,27 @@
* @param <T> the type of the value with an associated timestamp
* @hide
*/
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final class TimestampedValue<T> implements Parcelable {
private final long mReferenceTimeMillis;
+ @Nullable
private final T mValue;
- public TimestampedValue(long referenceTimeMillis, T value) {
+ public TimestampedValue(long referenceTimeMillis, @Nullable T value) {
mReferenceTimeMillis = referenceTimeMillis;
mValue = value;
}
+ /** Returns the reference time value. See {@link TimestampedValue} for more information. */
public long getReferenceTimeMillis() {
return mReferenceTimeMillis;
}
+ /**
+ * Returns the value associated with the timestamp. See {@link TimestampedValue} for more
+ * information.
+ */
+ @Nullable
public T getValue() {
return mValue;
}
@@ -86,6 +95,8 @@
return one.mReferenceTimeMillis - two.mReferenceTimeMillis;
}
+ /** @hide */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final @NonNull Parcelable.Creator<TimestampedValue<?>> CREATOR =
new Parcelable.ClassLoaderCreator<TimestampedValue<?>>() {
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index ccbb0f1..ae75f3d 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -155,7 +155,7 @@
/**
* Configure an always-on haptics effect.
*
- * @param id The board-specific always-on ID to configure.
+ * @param alwaysOnId The board-specific always-on ID to configure.
* @param effect Vibration effect to assign to always-on id. Passing null will disable it.
* @param attributes {@link AudioAttributes} corresponding to the vibration. For example,
* specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
@@ -164,8 +164,17 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)
- public boolean setAlwaysOnEffect(int id, @Nullable VibrationEffect effect,
- @Nullable AudioAttributes attributes) {
+ public boolean setAlwaysOnEffect(int alwaysOnId, @Nullable VibrationEffect effect,
+ @Nullable AudioAttributes attributes) {
+ return setAlwaysOnEffect(Process.myUid(), mPackageName, alwaysOnId, effect, attributes);
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)
+ public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId,
+ @Nullable VibrationEffect effect, @Nullable AudioAttributes attributes) {
Log.w(TAG, "Always-on effects aren't supported");
return false;
}
diff --git a/core/java/android/os/image/DynamicSystemClient.java b/core/java/android/os/image/DynamicSystemClient.java
index 921f0f2..5cb3361 100644
--- a/core/java/android/os/image/DynamicSystemClient.java
+++ b/core/java/android/os/image/DynamicSystemClient.java
@@ -256,9 +256,13 @@
mService.send(msg);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to get status from installation service");
- mExecutor.execute(() -> {
+ if (mExecutor != null) {
+ mExecutor.execute(() -> {
+ mListener.onStatusChanged(STATUS_UNKNOWN, CAUSE_ERROR_IPC, 0, e);
+ });
+ } else {
mListener.onStatusChanged(STATUS_UNKNOWN, CAUSE_ERROR_IPC, 0, e);
- });
+ }
}
}
diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java
index 4c92c28..cbf531c 100644
--- a/core/java/android/os/image/DynamicSystemManager.java
+++ b/core/java/android/os/image/DynamicSystemManager.java
@@ -106,9 +106,9 @@
* @return true if the call succeeds
*/
@RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
- public boolean startInstallation() {
+ public boolean startInstallation(String dsuSlot) {
try {
- return mService.startInstallation();
+ return mService.startInstallation(dsuSlot);
} catch (RemoteException e) {
throw new RuntimeException(e.toString());
}
diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl
index 69cbab2..cc32f99 100644
--- a/core/java/android/os/image/IDynamicSystemService.aidl
+++ b/core/java/android/os/image/IDynamicSystemService.aidl
@@ -22,9 +22,10 @@
{
/**
* Start DynamicSystem installation.
+ * @param dsuSlot Name used to identify this installation
* @return true if the call succeeds
*/
- boolean startInstallation();
+ boolean startInstallation(@utf8InCpp String dsuSlot);
/**
* Create a DSU partition. This call may take 60~90 seconds. The caller
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 92fecad..bbc936d 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -193,4 +193,5 @@
void startCheckpoint(int numTries) = 85;
boolean needsCheckpoint() = 86;
void abortChanges(in String message, boolean retry) = 87;
+ void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 9ffeff9..a0e92b3 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -232,6 +232,9 @@
/** Call was on RTT at some point */
public static final int FEATURES_RTT = 1 << 5;
+ /** Call was VoLTE */
+ public static final int FEATURES_VOLTE = 1 << 6;
+
/**
* The phone number as the user entered it.
* <P>Type: TEXT</P>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1f3ae09..b22db2e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -81,7 +81,6 @@
import android.os.UserHandle;
import android.provider.SettingsValidators.Validator;
import android.speech.tts.TextToSpeech;
-import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.AndroidException;
import android.util.ArrayMap;
@@ -8571,6 +8570,7 @@
*
* @hide
*/
+ @SystemApi
public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled";
/**
@@ -13320,16 +13320,17 @@
/**
* Whether the Volte is enabled. If this setting is not set then we use the Carrier Config
- * value {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
+ * value
+ * {@link android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
* <p>
* Type: int (0 for false, 1 for true)
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#ENHANCED_4G_MODE_ENABLED}
* instead.
*/
@Deprecated
public static final String ENHANCED_4G_MODE_ENABLED =
- SubscriptionManager.ENHANCED_4G_MODE_ENABLED;
+ Telephony.SimInfo.ENHANCED_4G_MODE_ENABLED;
/**
* Whether VT (Video Telephony over IMS) is enabled
@@ -13337,10 +13338,10 @@
* Type: int (0 for false, 1 for true)
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#VT_IMS_ENABLED} instead.
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#VT_IMS_ENABLED} instead.
*/
@Deprecated
- public static final String VT_IMS_ENABLED = SubscriptionManager.VT_IMS_ENABLED;
+ public static final String VT_IMS_ENABLED = Telephony.SimInfo.VT_IMS_ENABLED;
/**
* Whether WFC is enabled
@@ -13348,10 +13349,10 @@
* Type: int (0 for false, 1 for true)
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ENABLED} instead.
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ENABLED} instead.
*/
@Deprecated
- public static final String WFC_IMS_ENABLED = SubscriptionManager.WFC_IMS_ENABLED;
+ public static final String WFC_IMS_ENABLED = Telephony.SimInfo.WFC_IMS_ENABLED;
/**
* WFC mode on home/non-roaming network.
@@ -13359,10 +13360,10 @@
* Type: int - 2=Wi-Fi preferred, 1=Cellular preferred, 0=Wi-Fi only
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_MODE} instead.
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_MODE} instead.
*/
@Deprecated
- public static final String WFC_IMS_MODE = SubscriptionManager.WFC_IMS_MODE;
+ public static final String WFC_IMS_MODE = Telephony.SimInfo.WFC_IMS_MODE;
/**
* WFC mode on roaming network.
@@ -13370,11 +13371,11 @@
* Type: int - see {@link #WFC_IMS_MODE} for values
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_MODE}
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ROAMING_MODE}
* instead.
*/
@Deprecated
- public static final String WFC_IMS_ROAMING_MODE = SubscriptionManager.WFC_IMS_ROAMING_MODE;
+ public static final String WFC_IMS_ROAMING_MODE = Telephony.SimInfo.WFC_IMS_ROAMING_MODE;
/**
* Whether WFC roaming is enabled
@@ -13382,12 +13383,12 @@
* Type: int (0 for false, 1 for true)
*
* @hide
- * @deprecated Use {@link android.telephony.SubscriptionManager#WFC_IMS_ROAMING_ENABLED}
+ * @deprecated Use {@link android.provider.Telephony.SimInfo#WFC_IMS_ROAMING_ENABLED}
* instead
*/
@Deprecated
public static final String WFC_IMS_ROAMING_ENABLED =
- SubscriptionManager.WFC_IMS_ROAMING_ENABLED;
+ Telephony.SimInfo.WFC_IMS_ROAMING_ENABLED;
/**
* Whether user can enable/disable LTE as a preferred network. A carrier might control
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 90ac821..1611d28 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -37,11 +37,13 @@
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
+import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SmsMessage;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.UiccAccessRule;
import android.text.TextUtils;
import android.util.Patterns;
@@ -4928,5 +4930,414 @@
*/
@NonNull
public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+
+ /**
+ * TelephonyProvider unique key column name is the subscription id.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+
+ /**
+ * TelephonyProvider column name for a unique identifier for the subscription within the
+ * specific subscription type. For example, it contains SIM ICC Identifier subscriptions
+ * on Local SIMs. and Mac-address for Remote-SIM Subscriptions for Bluetooth devices.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String ICC_ID = "icc_id";
+
+ /**
+ * TelephonyProvider column name for user SIM_SlOT_INDEX
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String SIM_SLOT_INDEX = "sim_id";
+
+ /**
+ * SIM is not inserted
+ */
+ public static final int SIM_NOT_INSERTED = -1;
+
+ /**
+ * TelephonyProvider column name Subscription-type.
+ * <P>Type: INTEGER (int)</P> {@link #SUBSCRIPTION_TYPE_LOCAL_SIM} for Local-SIM
+ * Subscriptions, {@link #SUBSCRIPTION_TYPE_REMOTE_SIM} for Remote-SIM Subscriptions.
+ * Default value is 0.
+ */
+ public static final String SUBSCRIPTION_TYPE = "subscription_type";
+
+ /**
+ * This constant is to designate a subscription as a Local-SIM Subscription.
+ * <p> A Local-SIM can be a physical SIM inserted into a sim-slot in the device, or eSIM on
+ * the device.
+ * </p>
+ */
+ public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0;
+
+ /**
+ * This constant is to designate a subscription as a Remote-SIM Subscription.
+ * <p>
+ * A Remote-SIM subscription is for a SIM on a phone connected to this device via some
+ * connectivity mechanism, for example bluetooth. Similar to Local SIM, this subscription
+ * can be used for SMS, Voice and data by proxying data through the connected device.
+ * Certain data of the SIM, such as IMEI, are not accessible for Remote SIMs.
+ * </p>
+ *
+ * <p>
+ * A Remote-SIM is available only as long the phone stays connected to this device.
+ * When the phone disconnects, Remote-SIM subscription is removed from this device and is
+ * no longer known. All data associated with the subscription, such as stored SMS, call
+ * logs, contacts etc, are removed from this device.
+ * </p>
+ *
+ * <p>
+ * If the phone re-connects to this device, a new Remote-SIM subscription is created for
+ * the phone. The Subscription Id associated with the new subscription is different from
+ * the Subscription Id of the previous Remote-SIM subscription created (and removed) for the
+ * phone; i.e., new Remote-SIM subscription treats the reconnected phone as a Remote-SIM
+ * that was never seen before.
+ * </p>
+ */
+ public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1;
+
+ /**
+ * TelephonyProvider column name data_enabled_override_rules.
+ * It's a list of rules for overriding data enabled settings. The syntax is
+ * For example, "mms=nonDefault" indicates enabling data for mms in non-default
+ * subscription.
+ * "default=nonDefault&inVoiceCall" indicates enabling data for internet in non-default
+ * subscription and while is in voice call.
+ *
+ * Default value is empty string.
+ */
+ public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+
+ /**
+ * TelephonyProvider column name for user displayed name.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String DISPLAY_NAME = "display_name";
+
+ /**
+ * TelephonyProvider column name for the service provider name for the SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String CARRIER_NAME = "carrier_name";
+
+ /**
+ * TelephonyProvider column name for source of the user displayed name.
+ * <P>Type: INT (int)</P> with one of the NAME_SOURCE_XXXX values below
+ */
+ public static final String NAME_SOURCE = "name_source";
+
+ /** The name_source is the default, which is from the carrier id. */
+ public static final int NAME_SOURCE_DEFAULT = 0;
+
+ /**
+ * The name_source is from SIM EF_SPN.
+ */
+ public static final int NAME_SOURCE_SIM_SPN = 1;
+
+ /**
+ * The name_source is from user input
+ */
+ public static final int NAME_SOURCE_USER_INPUT = 2;
+
+ /**
+ * The name_source is carrier (carrier app, carrier config, etc.)
+ */
+ public static final int NAME_SOURCE_CARRIER = 3;
+
+ /**
+ * The name_source is from SIM EF_PNN.
+ */
+ public static final int NAME_SOURCE_SIM_PNN = 4;
+
+ /**
+ * TelephonyProvider column name for the color of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String COLOR = "color";
+
+ /** TelephonyProvider column name for the default color of a SIM {@hide} */
+ public static final int COLOR_DEFAULT = 0;
+
+ /**
+ * TelephonyProvider column name for the phone number of a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String NUMBER = "number";
+
+ /**
+ * TelephonyProvider column name for the number display format of a SIM.
+ * <P>Type: INTEGER (int)</P>
+ * @hide
+ */
+ public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
+
+ /**
+ * TelephonyProvider column name for the default display format of a SIM
+ * @hide
+ */
+ public static final int DISPLAY_NUMBER_DEFAULT = 1;
+
+ /**
+ * TelephonyProvider column name for whether data roaming is enabled.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String DATA_ROAMING = "data_roaming";
+
+ /** Indicates that data roaming is enabled for a subscription */
+ public static final int DATA_ROAMING_ENABLE = 1;
+
+ /** Indicates that data roaming is disabled for a subscription */
+ public static final int DATA_ROAMING_DISABLE = 0;
+
+ /** TelephonyProvider column name for default data roaming setting: disable */
+ public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
+
+ /**
+ * TelephonyProvider column name for subscription carrier id.
+ * @see TelephonyManager#getSimCarrierId()
+ * <p>Type: INTEGER (int) </p>
+ */
+ public static final String CARRIER_ID = "carrier_id";
+
+ /**
+ * A comma-separated list of EHPLMNs associated with the subscription
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String EHPLMNS = "ehplmns";
+
+ /**
+ * A comma-separated list of HPLMNs associated with the subscription
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String HPLMNS = "hplmns";
+
+ /**
+ * TelephonyProvider column name for the MCC associated with a SIM, stored as a string.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String MCC_STRING = "mcc_string";
+
+ /**
+ * TelephonyProvider column name for the MNC associated with a SIM, stored as a string.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String MNC_STRING = "mnc_string";
+
+ /**
+ * TelephonyProvider column name for the MCC associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String MCC = "mcc";
+
+ /**
+ * TelephonyProvider column name for the MNC associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String MNC = "mnc";
+
+ /**
+ * TelephonyProvider column name for the iso country code associated with a SIM.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String ISO_COUNTRY_CODE = "iso_country_code";
+
+ /**
+ * TelephonyProvider column name for the sim provisioning status associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ * @hide
+ */
+ public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
+
+ /** The sim is provisioned {@hide} */
+ public static final int SIM_PROVISIONED = 0;
+
+ /**
+ * TelephonyProvider column name for whether a subscription is embedded (that is, present on
+ * an eSIM).
+ * <p>Type: INTEGER (int), 1 for embedded or 0 for non-embedded.
+ */
+ public static final String IS_EMBEDDED = "is_embedded";
+
+ /**
+ * TelephonyProvider column name for SIM card identifier. For UICC card it is the ICCID of
+ * the current enabled profile on the card, while for eUICC card it is the EID of the card.
+ * <P>Type: TEXT (String)</P>
+ */
+ public static final String CARD_ID = "card_id";
+
+ /**
+ * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
+ * {@link UiccAccessRule#encodeRules}. Only present if {@link #IS_EMBEDDED} is 1.
+ * <p>TYPE: BLOB
+ */
+ public static final String ACCESS_RULES = "access_rules";
+
+ /**
+ * TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
+ * {@link UiccAccessRule#encodeRules} but for the rules that come from CarrierConfigs.
+ * Only present if there are access rules in CarrierConfigs
+ * <p>TYPE: BLOB
+ */
+ public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS =
+ "access_rules_from_carrier_configs";
+
+ /**
+ * TelephonyProvider column name identifying whether an embedded subscription is on a
+ * removable card. Such subscriptions are marked inaccessible as soon as the current card
+ * is removed. Otherwise, they will remain accessible unless explicitly deleted. Only
+ * present if {@link #IS_EMBEDDED} is 1.
+ * <p>TYPE: INTEGER (int), 1 for removable or 0 for non-removable.
+ */
+ public static final String IS_REMOVABLE = "is_removable";
+
+ /** TelephonyProvider column name for extreme threat in CB settings */
+ public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+
+ /** TelephonyProvider column name for severe threat in CB settings */
+ public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+
+ /** TelephonyProvider column name for amber alert in CB settings */
+ public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+
+ /** TelephonyProvider column name for emergency alert in CB settings */
+ public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+
+ /** TelephonyProvider column name for alert sound duration in CB settings */
+ public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+
+ /** TelephonyProvider column name for alert reminder interval in CB settings */
+ public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+
+ /** TelephonyProvider column name for enabling vibrate in CB settings */
+ public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+
+ /** TelephonyProvider column name for enabling alert speech in CB settings */
+ public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+
+ /** TelephonyProvider column name for ETWS test alert in CB settings */
+ public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+
+ /** TelephonyProvider column name for enable channel50 alert in CB settings */
+ public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+
+ /** TelephonyProvider column name for CMAS test alert in CB settings */
+ public static final String CB_CMAS_TEST_ALERT = "enable_cmas_test_alerts";
+
+ /** TelephonyProvider column name for Opt out dialog in CB settings */
+ public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+
+ /**
+ * TelephonyProvider column name for enable Volte.
+ *
+ * If this setting is not initialized (set to -1) then we use the Carrier Config value
+ * {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
+ */
+ public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+
+ /** TelephonyProvider column name for enable VT (Video Telephony over IMS) */
+ public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+
+ /** TelephonyProvider column name for enable Wifi calling */
+ public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+
+ /** TelephonyProvider column name for Wifi calling mode */
+ public static final String WFC_IMS_MODE = "wfc_ims_mode";
+
+ /** TelephonyProvider column name for Wifi calling mode in roaming */
+ public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+
+ /** TelephonyProvider column name for enable Wifi calling in roaming */
+ public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+
+ /**
+ * Determines if the user has enabled IMS RCS User Capability Exchange (UCE) for this
+ * subscription.
+ */
+ public static final String IMS_RCS_UCE_ENABLED = "ims_rcs_uce_enabled";
+
+ /**
+ * TelephonyProvider column name for whether a subscription is opportunistic, that is,
+ * whether the network it connects to is limited in functionality or coverage.
+ * For example, CBRS.
+ * <p>Type: INTEGER (int), 1 for opportunistic or 0 for non-opportunistic.
+ */
+ public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+
+ /**
+ * TelephonyProvider column name for group ID. Subscriptions with same group ID
+ * are considered bundled together, and should behave as a single subscription at
+ * certain scenarios.
+ */
+ public static final String GROUP_UUID = "group_uuid";
+
+ /**
+ * TelephonyProvider column name for group owner. It's the package name who created
+ * the subscription group.
+ */
+ public static final String GROUP_OWNER = "group_owner";
+
+ /**
+ * TelephonyProvider column name for whether a subscription is metered or not, that is,
+ * whether the network it connects to charges for subscription or not. For example, paid
+ * CBRS or unpaid.
+ * @hide
+ */
+ public static final String IS_METERED = "is_metered";
+
+ /**
+ * TelephonyProvider column name for the profile class of a subscription
+ * Only present if {@link #IS_EMBEDDED} is 1.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String PROFILE_CLASS = "profile_class";
+
+ /**
+ * A testing profile can be pre-loaded or downloaded onto
+ * the eUICC and provides connectivity to test equipment
+ * for the purpose of testing the device and the eUICC. It
+ * is not intended to store any operator credentials.
+ */
+ public static final int PROFILE_CLASS_TESTING = 0;
+
+ /**
+ * A provisioning profile is pre-loaded onto the eUICC and
+ * provides connectivity to a mobile network solely for the
+ * purpose of provisioning profiles.
+ */
+ public static final int PROFILE_CLASS_PROVISIONING = 1;
+
+ /**
+ * An operational profile can be pre-loaded or downloaded
+ * onto the eUICC and provides services provided by the
+ * operator.
+ */
+ public static final int PROFILE_CLASS_OPERATIONAL = 2;
+
+ /**
+ * The profile class is unset. This occurs when profile class
+ * info is not available. The subscription either has no profile
+ * metadata or the profile metadata did not encode profile class.
+ */
+ public static final int PROFILE_CLASS_UNSET = -1;
+
+ /** Default profile class */
+ public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
+
+ /**
+ * IMSI (International Mobile Subscriber Identity).
+ * <P>Type: TEXT </P>
+ */
+ public static final String IMSI = "imsi";
+
+ /** Whether uicc applications is set to be enabled or disabled. By default it's enabled. */
+ public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+
+ /**
+ * TelephonyProvider column name for allowed network types. Indicate which network types
+ * are allowed. Default is -1.
+ */
+ public static final String ALLOWED_NETWORK_TYPES = "allowed_network_types";
}
}
diff --git a/core/java/android/se/omapi/ISecureElementReader.aidl b/core/java/android/se/omapi/ISecureElementReader.aidl
index a312c44..41244ab 100644
--- a/core/java/android/se/omapi/ISecureElementReader.aidl
+++ b/core/java/android/se/omapi/ISecureElementReader.aidl
@@ -48,4 +48,10 @@
*/
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 80262f7..7f68d91 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 @@
} 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 00060ab..a5c5c61 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -98,6 +98,8 @@
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 @@
* 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 @@
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/security/ConfirmationPrompt.java b/core/java/android/security/ConfirmationPrompt.java
index 5330cff..f67af85 100644
--- a/core/java/android/security/ConfirmationPrompt.java
+++ b/core/java/android/security/ConfirmationPrompt.java
@@ -212,20 +212,16 @@
private int getUiOptionsAsFlags() {
int uiOptionsAsFlags = 0;
- try {
- ContentResolver contentResolver = mContext.getContentResolver();
- int inversionEnabled = Settings.Secure.getInt(contentResolver,
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
- if (inversionEnabled == 1) {
- uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_INVERTED_FLAG;
- }
- float fontScale = Settings.System.getFloat(contentResolver,
- Settings.System.FONT_SCALE);
- if (fontScale > 1.0) {
- uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG;
- }
- } catch (SettingNotFoundException e) {
- Log.w(TAG, "Unexpected SettingNotFoundException");
+ ContentResolver contentResolver = mContext.getContentResolver();
+ int inversionEnabled = Settings.Secure.getInt(contentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0);
+ if (inversionEnabled == 1) {
+ uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_INVERTED_FLAG;
+ }
+ float fontScale = Settings.System.getFloat(contentResolver,
+ Settings.System.FONT_SCALE, (float) 1.0);
+ if (fontScale > 1.0) {
+ uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG;
}
return uiOptionsAsFlags;
}
diff --git a/core/java/android/telephony/CellBroadcastIntents.java b/core/java/android/telephony/CellBroadcastIntents.java
index 8446253..2e08108 100644
--- a/core/java/android/telephony/CellBroadcastIntents.java
+++ b/core/java/android/telephony/CellBroadcastIntents.java
@@ -16,22 +16,23 @@
package android.telephony;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
+import android.provider.Telephony;
/**
* A static helper class used to send Intents with prepopulated flags.
* <p>
- * This is intended to be used by the CellBroadcastService and will throw a security exception if
- * used from a UID besides the network stack UID.
+ * This is intended to be used by the CellBroadcastService and does nothing if the caller does not
+ * have permission to broadcast {@link Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION}.
*
* @hide
*/
@@ -39,6 +40,8 @@
public class CellBroadcastIntents {
private static final String LOG_TAG = "CellBroadcastIntents";
+ private static final String EXTRA_MESSAGE = "message";
+
/**
* @hide
*/
@@ -46,50 +49,71 @@
}
/**
- * Returns an intent which can be received by background BroadcastReceivers. This is only
- * intended to be used by the CellBroadcastService and will throw a security exception if called
- * from another UID.
+ * Broadcasts an SMS_CB_RECEIVED_ACTION intent which can be received by background
+ * BroadcastReceivers. This is only intended to be used by the CellBroadcastService and will
+ * do nothing if the caller does not have permission to broadcast
+ * {@link Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION}.
*
* @param context The context from which to send the broadcast
* @param user The user from which to send the broadcast
- * @param intent The Intent to broadcast; all receivers matching this Intent will
- * receive the broadcast.
- * @param receiverPermission String naming a permissions that a receiver must hold in order to
- * receive your broadcast. If null, no permission is required.
- * @param receiverAppOp The app op associated with the broadcast. If null, no appOp is
- * required. If both receiverAppOp and receiverPermission are
- * non-null, a receiver must have both of them to receive the
- * broadcast
+ * @param smsCbMessage The SmsCbMessage to include with the intent
* @param resultReceiver Your own BroadcastReceiver to treat as the final receiver of the
* broadcast.
* @param scheduler A custom Handler with which to schedule the resultReceiver
* callback; if null it will be scheduled in the Context's main
* thread.
* @param initialCode An initial value for the result code. Often Activity.RESULT_OK.
- * @param initialData An initial value for the result data. Often null.
- * @param initialExtras An initial value for the result extras. Often null.
+ * @param slotIndex The slot index to include in the intent
*/
- public static void sendOrderedBroadcastForBackgroundReceivers(@NonNull Context context,
- @Nullable UserHandle user, @NonNull Intent intent, @Nullable String receiverPermission,
- @Nullable String receiverAppOp, @Nullable BroadcastReceiver resultReceiver,
- @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
- @Nullable Bundle initialExtras) {
- int status = context.checkCallingOrSelfPermission(
- "android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS");
- if (status == PackageManager.PERMISSION_DENIED) {
- throw new SecurityException(
- "Caller does not have permission to send broadcast for background receivers");
- }
- Intent backgroundIntent = new Intent(intent);
+ public static void sendSmsCbReceivedBroadcast(@NonNull Context context,
+ @Nullable UserHandle user, @NonNull SmsCbMessage smsCbMessage,
+ @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler,
+ int initialCode, int slotIndex) {
+ Intent backgroundIntent = new Intent(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION);
+ backgroundIntent.putExtra(EXTRA_MESSAGE, smsCbMessage);
backgroundIntent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ putPhoneIdAndSubIdExtra(context, backgroundIntent, slotIndex);
+
+ String receiverPermission = Manifest.permission.RECEIVE_SMS;
+ String receiverAppOp = AppOpsManager.OPSTR_RECEIVE_SMS;
if (user != null) {
context.createContextAsUser(user, 0).sendOrderedBroadcast(backgroundIntent,
receiverPermission, receiverAppOp, resultReceiver, scheduler, initialCode,
- initialData, initialExtras);
+ null, null);
} else {
context.sendOrderedBroadcast(backgroundIntent, receiverPermission,
- receiverAppOp, resultReceiver, scheduler, initialCode, initialData,
- initialExtras);
+ receiverAppOp, resultReceiver, scheduler, initialCode, null, null);
+ }
+ }
+
+ /**
+ * Put the phone ID and sub ID into an intent as extras.
+ */
+ private static void putPhoneIdAndSubIdExtra(Context context, Intent intent, int phoneId) {
+ int subId = getSubIdForPhone(context, phoneId);
+ if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ intent.putExtra("subscription", subId);
+ intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
+ }
+ intent.putExtra("phone", phoneId);
+ intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId);
+ }
+
+ /**
+ * Get the subscription ID for a phone ID, or INVALID_SUBSCRIPTION_ID if the phone does not
+ * have an active sub
+ * @param phoneId the phoneId to use
+ * @return the associated sub id
+ */
+ private static int getSubIdForPhone(Context context, int phoneId) {
+ SubscriptionManager subMan =
+ (SubscriptionManager) context.getSystemService(
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+ int[] subIds = subMan.getSubscriptionIds(phoneId);
+ if (subIds != null) {
+ return subIds[0];
+ } else {
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
}
}
}
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index e08a06a..1d0b4a0 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -168,6 +168,16 @@
public static final int LISTEN_SIGNAL_STRENGTHS = 0x00000100;
/**
+ * Listen for always reported changes of the network signal strengths (cellular),
+ * even in some situations such as the screen of the device is off.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
+ @SystemApi
+ public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = 0x00000200;
+
+ /**
* Listen for changes to observed cell info.
*
* @see #onCellInfoChanged
@@ -178,6 +188,10 @@
* 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 +201,13 @@
/**
* 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;
/**
@@ -211,6 +225,9 @@
/**
* Listen for changes to the SRVCC state of the active call.
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
+ *
* @see #onServiceStateChanged(ServiceState)
* @hide
*/
@@ -239,6 +256,9 @@
/**
* Listen for changes to the sim voice activation state
+ *
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
+ *
* @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
* @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
* @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
@@ -252,6 +272,7 @@
* @hide
*/
@SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public static final int LISTEN_VOICE_ACTIVATION_STATE = 0x00020000;
/**
@@ -298,10 +319,13 @@
/**
* Listen for changes to the radio power state.
*
+ * <p>Requires permission {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
+ *
* @see #onRadioPowerStateChanged
* @hide
*/
@SystemApi
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public static final int LISTEN_RADIO_POWER_STATE_CHANGED = 0x00800000;
/**
@@ -318,26 +342,36 @@
* 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))
@@ -869,7 +903,6 @@
* Callback invoked when phone capability changes.
* Note, this callback triggers regardless of registered subscription.
*
- * Requires the READ_PRIVILEGED_PHONE_STATE permission.
* @param capability the new phone capability
* @hide
*/
@@ -899,7 +932,7 @@
* subId. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
- * Requires the READ_PRIVILEGED_PHONE_STATE permission.
+ * Requires the READ_PRECISE_PHONE_STATE permission.
* @param callAttributes the call attributes
* @hide
*/
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index bab4bc3..248e321 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -18,7 +18,7 @@
import android.util.TimeFormatException;
-import libcore.timezone.ZoneInfoDB;
+import libcore.timezone.ZoneInfoDb;
import libcore.util.ZoneInfo;
import java.io.IOException;
@@ -1107,9 +1107,9 @@
private static ZoneInfo lookupZoneInfo(String timezoneId) {
try {
- ZoneInfo zoneInfo = ZoneInfoDB.getInstance().makeTimeZone(timezoneId);
+ ZoneInfo zoneInfo = ZoneInfoDb.getInstance().makeTimeZone(timezoneId);
if (zoneInfo == null) {
- zoneInfo = ZoneInfoDB.getInstance().makeTimeZone("GMT");
+ zoneInfo = ZoneInfoDb.getInstance().makeTimeZone("GMT");
}
if (zoneInfo == null) {
throw new AssertionError("GMT not found: \"" + timezoneId + "\"");
diff --git a/core/java/android/timezone/CountryTimeZones.java b/core/java/android/timezone/CountryTimeZones.java
new file mode 100644
index 0000000..e5bbdf4
--- /dev/null
+++ b/core/java/android/timezone/CountryTimeZones.java
@@ -0,0 +1,266 @@
+/*
+ * 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.timezone;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.icu.util.TimeZone;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Information about a country's time zones.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class CountryTimeZones {
+
+ /**
+ * A mapping to a time zone ID with some associated metadata.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final class TimeZoneMapping {
+
+ @NonNull
+ private libcore.timezone.CountryTimeZones.TimeZoneMapping mDelegate;
+
+ TimeZoneMapping(libcore.timezone.CountryTimeZones.TimeZoneMapping delegate) {
+ this.mDelegate = Objects.requireNonNull(delegate);
+ }
+
+ /**
+ * Returns the ID for this mapping. See also {@link #getTimeZone()} which handles when the
+ * ID is unrecognized.
+ */
+ @NonNull
+ public String getTimeZoneId() {
+ return mDelegate.timeZoneId;
+ }
+
+ /**
+ * Returns a {@link TimeZone} object for this mapping, or {@code null} if the ID is
+ * unrecognized.
+ */
+ @Nullable
+ public TimeZone getTimeZone() {
+ return mDelegate.getTimeZone();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ TimeZoneMapping that = (TimeZoneMapping) o;
+ return this.mDelegate.equals(that.mDelegate);
+ }
+
+ @Override
+ public int hashCode() {
+ return this.mDelegate.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return mDelegate.toString();
+ }
+ }
+
+ /**
+ * The result of lookup up a time zone using offset information (and possibly more).
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final class OffsetResult {
+
+ private final TimeZone mTimeZone;
+ private final boolean mIsOnlyMatch;
+
+ /** Creates an instance with the supplied information. */
+ public OffsetResult(@NonNull TimeZone timeZone, boolean isOnlyMatch) {
+ mTimeZone = Objects.requireNonNull(timeZone);
+ mIsOnlyMatch = isOnlyMatch;
+ }
+
+ /**
+ * Returns a time zone that matches the supplied criteria.
+ */
+ @NonNull
+ public TimeZone getTimeZone() {
+ return mTimeZone;
+ }
+
+ /**
+ * Returns {@code true} if there is only one matching time zone for the supplied criteria.
+ */
+ public boolean isOnlyMatch() {
+ return mIsOnlyMatch;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ OffsetResult that = (OffsetResult) o;
+ return mIsOnlyMatch == that.mIsOnlyMatch
+ && mTimeZone.getID().equals(that.mTimeZone.getID());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTimeZone, mIsOnlyMatch);
+ }
+
+ @Override
+ public String toString() {
+ return "OffsetResult{"
+ + "mTimeZone=" + mTimeZone
+ + ", mIsOnlyMatch=" + mIsOnlyMatch
+ + '}';
+ }
+ }
+
+ @NonNull
+ private final libcore.timezone.CountryTimeZones mDelegate;
+
+ CountryTimeZones(libcore.timezone.CountryTimeZones delegate) {
+ mDelegate = delegate;
+ }
+
+ /**
+ * Returns true if the ISO code for the country is a match for the one specified.
+ */
+ public boolean isForCountryCode(@NonNull String countryIso) {
+ return mDelegate.isForCountryCode(countryIso);
+ }
+
+ /**
+ * Returns the default time zone ID for the country. Can return {@code null} in cases when no
+ * data is available or the time zone ID was not recognized.
+ */
+ @Nullable
+ public String getDefaultTimeZoneId() {
+ return mDelegate.getDefaultTimeZoneId();
+ }
+
+ /**
+ * Returns the default time zone for the country. Can return {@code null} in cases when no data
+ * is available or the time zone ID was not recognized.
+ */
+ @Nullable
+ public TimeZone getDefaultTimeZone() {
+ return mDelegate.getDefaultTimeZone();
+ }
+
+ /**
+ * Qualifier for a country's default time zone. {@code true} indicates whether the default
+ * would be a good choice <em>generally</em> when there's no other information available.
+ */
+ public boolean isDefaultTimeZoneBoosted() {
+ return mDelegate.getDefaultTimeZoneBoost();
+ }
+
+ /**
+ * Returns true if the country has at least one zone that is the same as UTC at the given time.
+ */
+ public boolean hasUtcZone(long whenMillis) {
+ return mDelegate.hasUtcZone(whenMillis);
+ }
+
+ /**
+ * Returns a time zone for the country, if there is one, that matches the desired properties. If
+ * there are multiple matches and the {@code bias} is one of them then it is returned, otherwise
+ * an arbitrary match is returned based on the {@link #getEffectiveTimeZoneMappingsAt(long)}
+ * ordering.
+ *
+ * @param totalOffsetMillis the offset from UTC at {@code whenMillis}
+ * @param isDst the Daylight Savings Time state at {@code whenMillis}. {@code true} means DST,
+ * {@code false} means not DST, {@code null} means unknown
+ * @param dstOffsetMillis the part of {@code totalOffsetMillis} contributed by DST, only used if
+ * {@code isDst} is {@code true}. The value can be {@code null} if the DST offset is
+ * unknown
+ * @param whenMillis the UTC time to match against
+ * @param bias the time zone to prefer, can be {@code null}
+ */
+ @Nullable
+ public OffsetResult lookupByOffsetWithBias(int totalOffsetMillis, @Nullable Boolean isDst,
+ @SuppressLint("AutoBoxing") @Nullable Integer dstOffsetMillis, long whenMillis,
+ @Nullable TimeZone bias) {
+ libcore.timezone.CountryTimeZones.OffsetResult delegateOffsetResult =
+ mDelegate.lookupByOffsetWithBias(
+ totalOffsetMillis, isDst, dstOffsetMillis, whenMillis, bias);
+ return delegateOffsetResult == null ? null :
+ new OffsetResult(delegateOffsetResult.mTimeZone, delegateOffsetResult.mOneMatch);
+ }
+
+ /**
+ * Returns an immutable, ordered list of time zone mappings for the country in an undefined but
+ * "priority" order, filtered so that only "effective" time zone IDs are returned. An
+ * "effective" time zone is one that differs from another time zone used in the country after
+ * {@code whenMillis}. The list can be empty if there were no zones configured or the configured
+ * zone IDs were not recognized.
+ */
+ @NonNull
+ public List<TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long whenMillis) {
+ List<libcore.timezone.CountryTimeZones.TimeZoneMapping> delegateList =
+ mDelegate.getEffectiveTimeZoneMappingsAt(whenMillis);
+
+ List<TimeZoneMapping> toReturn = new ArrayList<>(delegateList.size());
+ for (libcore.timezone.CountryTimeZones.TimeZoneMapping delegateMapping : delegateList) {
+ toReturn.add(new TimeZoneMapping(delegateMapping));
+ }
+ return Collections.unmodifiableList(toReturn);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CountryTimeZones that = (CountryTimeZones) 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/TelephonyLookup.java b/core/java/android/timezone/TelephonyLookup.java
new file mode 100644
index 0000000..8a5864e
--- /dev/null
+++ b/core/java/android/timezone/TelephonyLookup.java
@@ -0,0 +1,70 @@
+/*
+ * 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.timezone;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Objects;
+
+/**
+ * A class that can find time zone-related information about telephony networks.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class TelephonyLookup {
+
+ private static final Object sLock = new Object();
+ @GuardedBy("sLock")
+ private static TelephonyLookup sInstance;
+
+ /**
+ * Obtains an instance for use when resolving telephony time zone information.
+ */
+ @NonNull
+ public static TelephonyLookup getInstance() {
+ synchronized (sLock) {
+ if (sInstance == null) {
+ sInstance = new TelephonyLookup(libcore.timezone.TelephonyLookup.getInstance());
+ }
+ return sInstance;
+ }
+ }
+
+ @NonNull
+ private final libcore.timezone.TelephonyLookup mDelegate;
+
+ private TelephonyLookup(@NonNull libcore.timezone.TelephonyLookup delegate) {
+ mDelegate = Objects.requireNonNull(delegate);
+ }
+
+ /**
+ * Returns an object capable of querying telephony network information. This method can return
+ * {@code null} in the event of an error while reading the underlying data files.
+ */
+ @Nullable
+ public TelephonyNetworkFinder getTelephonyNetworkFinder() {
+ libcore.timezone.TelephonyNetworkFinder telephonyNetworkFinderDelegate =
+ mDelegate.getTelephonyNetworkFinder();
+ return telephonyNetworkFinderDelegate != null
+ ? new TelephonyNetworkFinder(telephonyNetworkFinderDelegate) : null;
+ }
+}
diff --git a/core/java/android/timezone/TelephonyNetwork.java b/core/java/android/timezone/TelephonyNetwork.java
new file mode 100644
index 0000000..487b3f2
--- /dev/null
+++ b/core/java/android/timezone/TelephonyNetwork.java
@@ -0,0 +1,86 @@
+/*
+ * 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.timezone;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+import java.util.Objects;
+
+/**
+ * Information about a telephony network.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class TelephonyNetwork {
+
+ @NonNull
+ private final libcore.timezone.TelephonyNetwork mDelegate;
+
+ TelephonyNetwork(@NonNull libcore.timezone.TelephonyNetwork delegate) {
+ mDelegate = Objects.requireNonNull(delegate);
+ }
+
+ /**
+ * Returns the Mobile Country Code of the network.
+ */
+ @NonNull
+ public String getMcc() {
+ return mDelegate.getMcc();
+ }
+
+ /**
+ * Returns the Mobile Network Code of the network.
+ */
+ @NonNull
+ public String getMnc() {
+ return mDelegate.getMnc();
+ }
+
+ /**
+ * Returns the country in which the network operates as an ISO 3166 alpha-2 (lower case).
+ */
+ @NonNull
+ public String getCountryIsoCode() {
+ return mDelegate.getCountryIsoCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ TelephonyNetwork that = (TelephonyNetwork) o;
+ return mDelegate.equals(that.mDelegate);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDelegate);
+ }
+
+ @Override
+ public String toString() {
+ return "TelephonyNetwork{"
+ + "mDelegate=" + mDelegate
+ + '}';
+ }
+}
diff --git a/core/java/android/timezone/TelephonyNetworkFinder.java b/core/java/android/timezone/TelephonyNetworkFinder.java
new file mode 100644
index 0000000..2ddd3d9
--- /dev/null
+++ b/core/java/android/timezone/TelephonyNetworkFinder.java
@@ -0,0 +1,55 @@
+/*
+ * 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.timezone;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+import java.util.Objects;
+
+/**
+ * A class that can find telephony network information loaded via {@link TelephonyLookup}.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class TelephonyNetworkFinder {
+
+ @NonNull
+ private final libcore.timezone.TelephonyNetworkFinder mDelegate;
+
+ TelephonyNetworkFinder(libcore.timezone.TelephonyNetworkFinder delegate) {
+ mDelegate = Objects.requireNonNull(delegate);
+ }
+
+ /**
+ * Returns information held about a specific MCC + MNC combination. It is expected for this
+ * method to return {@code null}. Only known, unusual networks will typically have information
+ * returned, e.g. if they operate in countries other than the one suggested by their MCC.
+ */
+ @Nullable
+ public TelephonyNetwork findNetworkByMccMnc(@NonNull String mcc, @NonNull String mnc) {
+ Objects.requireNonNull(mcc);
+ Objects.requireNonNull(mnc);
+
+ libcore.timezone.TelephonyNetwork telephonyNetworkDelegate =
+ mDelegate.findNetworkByMccMnc(mcc, mnc);
+ return telephonyNetworkDelegate != null
+ ? new TelephonyNetwork(telephonyNetworkDelegate) : null;
+ }
+}
diff --git a/core/java/android/timezone/TimeZoneFinder.java b/core/java/android/timezone/TimeZoneFinder.java
new file mode 100644
index 0000000..c76bb1d
--- /dev/null
+++ b/core/java/android/timezone/TimeZoneFinder.java
@@ -0,0 +1,78 @@
+/*
+ * 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.timezone;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Objects;
+
+/**
+ * A class that can be used to find time zones using information like country and offset.
+ *
+ * @hide
+ */
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+public final class TimeZoneFinder {
+
+ private static final Object sLock = new Object();
+ @GuardedBy("sLock")
+ private static TimeZoneFinder sInstance;
+
+ /**
+ * Obtains the singleton instance.
+ */
+ @NonNull
+ public static TimeZoneFinder getInstance() {
+ synchronized (sLock) {
+ if (sInstance == null) {
+ sInstance = new TimeZoneFinder(libcore.timezone.TimeZoneFinder.getInstance());
+ }
+ }
+ 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
+ * during lookup this method can return null.
+ */
+ @Nullable
+ public CountryTimeZones lookupCountryTimeZones(@NonNull String countryIso) {
+ libcore.timezone.CountryTimeZones delegate = mDelegate.lookupCountryTimeZones(countryIso);
+ return delegate == null ? null : new CountryTimeZones(delegate);
+ }
+}
diff --git a/core/java/android/timezone/TzDataSetVersion.java b/core/java/android/timezone/TzDataSetVersion.java
new file mode 100644
index 0000000..605155e
--- /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 final 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 0000000..4612a56
--- /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 final 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/CloseGuard.java b/core/java/android/util/CloseGuard.java
index 6ac7696..ba504a3 100644
--- a/core/java/android/util/CloseGuard.java
+++ b/core/java/android/util/CloseGuard.java
@@ -26,7 +26,7 @@
* A simple example: <pre> {@code
* class Foo {
*
- * private final CloseGuard guard = CloseGuard.get();
+ * private final CloseGuard guard = new CloseGuard();
*
* ...
*
@@ -64,7 +64,7 @@
* be deferred. For example: <pre> {@code
* class Bar {
*
- * private final CloseGuard guard = CloseGuard.get();
+ * private final CloseGuard guard = new CloseGuard();
*
* ...
*
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 8439f5a..a8a579c 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -26,7 +26,7 @@
import libcore.timezone.CountryTimeZones;
import libcore.timezone.CountryTimeZones.TimeZoneMapping;
import libcore.timezone.TimeZoneFinder;
-import libcore.timezone.ZoneInfoDB;
+import libcore.timezone.ZoneInfoDb;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
@@ -88,7 +88,7 @@
*
* <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()}
@@ -133,7 +133,7 @@
* during the lifetime of an activity.
*/
public static String getTimeZoneDatabaseVersion() {
- return ZoneInfoDB.getInstance().getVersion();
+ return ZoneInfoDb.getInstance().getVersion();
}
/** @hide Field length that can hold 999 days of time */
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index 6efcfbf..7b24ba9 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 @@
/**
* 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}.
*
- * TODO: Add a constructor that takes an OutputStream and write to that
+ * <p>To retrieve the encoded protobuf stream, call {@link #getBytes()}.
+ *
* stream as the top-level objects are finished.
*
- * @hide
*/
/* IMPLEMENTATION NOTES
@@ -99,7 +104,6 @@
* 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 @@
/**
* 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 @@
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 @@
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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
* 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 @@
/**
* 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 @@
* 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 @@
/**
* 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
* 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 @@
}
/**
- * 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 @@
* 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 @@
}
/**
- * 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 @@
/**
* 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 @@
/**
* 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 9e2e95a..4969d8a 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 >>> FIELD_ID_SHIFT;
+ *
+ * // Building a tag from a field number and a wire type.
+ * int tag = (fieldNumber << 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 & WIRE_TYPE_MASK;
+ *
+ * // Building a tag from a field number and a wire type.
+ * int tag = (fieldNumber << 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 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 @@
//
// 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* Get the location of the offset recorded in the token.
+ *
+ * @hide
*/
public static int getOffsetFromToken(long token) {
return (int) token;
@@ -255,8 +533,11 @@
/**
* 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 @@
/**
* 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 @@
+ ')';
}
}
+
+ /**
+ * @hide
+ */
+ protected ProtoStream() {}
}
diff --git a/core/java/android/util/proto/ProtoUtils.java b/core/java/android/util/proto/ProtoUtils.java
index 03bf590..a71561b 100644
--- a/core/java/android/util/proto/ProtoUtils.java
+++ b/core/java/android/util/proto/ProtoUtils.java
@@ -24,12 +24,12 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 a636bd4..ef1125b 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/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java b/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java
index 4b0b098..9aee879f 100644
--- a/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java
+++ b/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java
@@ -18,16 +18,9 @@
import android.content.Context;
import android.content.Intent;
-
-import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.Message;
-import android.os.ServiceManager;
import android.os.RemoteException;
-
-import java.util.HashMap;
-import android.util.Log;
+import android.os.ServiceManager;
/**
* ImsUceManager Declaration
@@ -49,55 +42,25 @@
private IUceService mUceService = null;
private UceServiceDeathRecipient mDeathReceipient = new UceServiceDeathRecipient();
private Context mContext;
- private int mPhoneId;
- /**
- * Stores the UceManager instaces of Clients identified by
- * phoneId
- * @hide
- */
- private static HashMap<Integer, ImsUceManager> sUceManagerInstances =
- new HashMap<Integer, ImsUceManager>();
+ private static final Object sLock = new Object();
+ private static ImsUceManager sUceManager;
public static final String ACTION_UCE_SERVICE_UP =
"com.android.ims.internal.uce.UCE_SERVICE_UP";
public static final String ACTION_UCE_SERVICE_DOWN =
"com.android.ims.internal.uce.UCE_SERVICE_DOWN";
- /** Uce Service status received in IUceListener.setStatus()
- * callback
- * @hide
- */
- public static final int UCE_SERVICE_STATUS_FAILURE = 0;
- /** indicate UI to call Presence/Options API. */
- public static final int UCE_SERVICE_STATUS_ON = 1;
- /** Indicate UI destroy Presence/Options */
- public static final int UCE_SERVICE_STATUS_CLOSED = 2;
- /** Service up and trying to register for network events */
- public static final int UCE_SERVICE_STATUS_READY = 3;
-
- /**
- * Part of the ACTION_UCE_SERVICE_UP or _DOWN intents. A long
- * value; the phone ID corresponding to the IMS service coming up or down.
- * Internal use only.
- * @hide
- */
- public static final String EXTRA_PHONE_ID = "android:phone_id";
-
/**
* Gets the instance of UCE Manager
* @hide
*/
- public static ImsUceManager getInstance(Context context, int phoneId) {
- //if (DBG) Log.d (LOG_TAG, "GetInstance Called");
- synchronized (sUceManagerInstances) {
- if (sUceManagerInstances.containsKey(phoneId)) {
- return sUceManagerInstances.get(phoneId);
- } else {
- ImsUceManager uceMgr = new ImsUceManager(context, phoneId);
- sUceManagerInstances.put(phoneId, uceMgr);
- return uceMgr;
+ public static ImsUceManager getInstance(Context context) {
+ synchronized (sLock) {
+ if (sUceManager == null && context != null) {
+ sUceManager = new ImsUceManager(context);
}
+ return sUceManager;
}
}
@@ -105,10 +68,9 @@
* Constructor
* @hide
*/
- private ImsUceManager(Context context, int phoneId) {
+ private ImsUceManager(Context context) {
//if (DBG) Log.d (LOG_TAG, "Constructor");
mContext = context;
- mPhoneId = phoneId;
createUceService(true);
}
@@ -129,7 +91,7 @@
* Gets the UCE service name
* @hide
*/
- private String getUceServiceName(int phoneId) {
+ private String getUceServiceName() {
return UCE_SERVICE;
}
@@ -143,14 +105,14 @@
public void createUceService(boolean checkService) {
//if (DBG) Log.d (LOG_TAG, "CreateUceService Called");
if (checkService) {
- IBinder binder = ServiceManager.checkService(getUceServiceName(mPhoneId));
+ IBinder binder = ServiceManager.checkService(getUceServiceName());
if (binder == null) {
//if (DBG)Log.d (LOG_TAG, "Unable to find IBinder");
return;
}
}
- IBinder b = ServiceManager.getService(getUceServiceName(mPhoneId));
+ IBinder b = ServiceManager.getService(getUceServiceName());
if (b != null) {
try {
@@ -174,12 +136,10 @@
private class UceServiceDeathRecipient implements IBinder.DeathRecipient {
@Override
public void binderDied() {
- //if (DBG) Log.d (LOG_TAG, "found IBinder/IUceService Service Died");
mUceService = null;
if (mContext != null) {
Intent intent = new Intent(ACTION_UCE_SERVICE_DOWN);
- intent.putExtra(EXTRA_PHONE_ID, mPhoneId);
mContext.sendBroadcast(new Intent(intent));
}
}
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 4bb012a..bbae027 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -16,6 +16,7 @@
package com.android.internal.net;
+import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.ProxyInfo;
import android.os.Build;
@@ -23,21 +24,34 @@
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
/**
- * Parcel-like entity class for VPN profiles. To keep things simple, all
- * fields are package private. Methods are provided for serialization, so
- * storage can be implemented easily. Two rules are set for this class.
- * First, all fields must be kept non-null. Second, always make a copy
- * using clone() before modifying.
+ * Profile storage class for a platform VPN.
+ *
+ * <p>This class supports both the Legacy VPN, as well as application-configurable platform VPNs
+ * (such as IKEv2/IPsec).
+ *
+ * <p>This class is serialized and deserialized via the {@link #encode()} and {@link #decode()}
+ * functions for persistent storage in the Android Keystore. The encoding is entirely custom, but
+ * must be kept for backward compatibility for devices upgrading between Android versions.
*
* @hide
*/
-public class VpnProfile implements Cloneable, Parcelable {
+public final class VpnProfile implements Cloneable, Parcelable {
private static final String TAG = "VpnProfile";
+ @VisibleForTesting static final String VALUE_DELIMITER = "\0";
+ @VisibleForTesting static final String LIST_DELIMITER = ",";
+
// Match these constants with R.array.vpn_types.
public static final int TYPE_PPTP = 0;
public static final int TYPE_L2TP_IPSEC_PSK = 1;
@@ -45,39 +59,85 @@
public static final int TYPE_IPSEC_XAUTH_PSK = 3;
public static final int TYPE_IPSEC_XAUTH_RSA = 4;
public static final int TYPE_IPSEC_HYBRID_RSA = 5;
- public static final int TYPE_MAX = 5;
+ public static final int TYPE_IKEV2_IPSEC_USER_PASS = 6;
+ public static final int TYPE_IKEV2_IPSEC_PSK = 7;
+ public static final int TYPE_IKEV2_IPSEC_RSA = 8;
+ public static final int TYPE_MAX = 8;
// Match these constants with R.array.vpn_proxy_settings.
public static final int PROXY_NONE = 0;
public static final int PROXY_MANUAL = 1;
+ private static final String ENCODED_NULL_PROXY_INFO = "\0\0\0\0";
+
// Entity fields.
@UnsupportedAppUsage
- public final String key; // -1
+ public final String key; // -1
+
@UnsupportedAppUsage
- public String name = ""; // 0
+ public String name = ""; // 0
+
@UnsupportedAppUsage
- public int type = TYPE_PPTP; // 1
+ public int type = TYPE_PPTP; // 1
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public String server = ""; // 2
+ public String server = ""; // 2
+
@UnsupportedAppUsage
- public String username = ""; // 3
- public String password = ""; // 4
- public String dnsServers = ""; // 5
- public String searchDomains = ""; // 6
- public String routes = ""; // 7
- public boolean mppe = true; // 8
- public String l2tpSecret = ""; // 9
- public String ipsecIdentifier = "";// 10
- public String ipsecSecret = ""; // 11
- public String ipsecUserCert = ""; // 12
- public String ipsecCaCert = ""; // 13
- public String ipsecServerCert = "";// 14
- public ProxyInfo proxy = null; // 15~18
+ public String username = ""; // 3
+ public String password = ""; // 4
+ public String dnsServers = ""; // 5
+ public String searchDomains = ""; // 6
+ public String routes = ""; // 7
+ public boolean mppe = true; // 8
+ public String l2tpSecret = ""; // 9
+ public String ipsecIdentifier = ""; // 10
+
+ /**
+ * The RSA private key or pre-shared key used for authentication.
+ *
+ * <p>If areAuthParamsInline is {@code true}, this String will be either:
+ *
+ * <ul>
+ * <li>If this is an IKEv2 RSA profile: a PKCS#8 encoded {@link java.security.PrivateKey}
+ * <li>If this is an IKEv2 PSK profile: a string value representing the PSK.
+ * </ul>
+ */
+ public String ipsecSecret = ""; // 11
+
+ /**
+ * The RSA certificate to be used for digital signature authentication.
+ *
+ * <p>If areAuthParamsInline is {@code true}, this String will be a pem-encoded {@link
+ * java.security.X509Certificate}
+ */
+ public String ipsecUserCert = ""; // 12
+
+ /**
+ * The RSA certificate that should be used to verify the server's end/target certificate.
+ *
+ * <p>If areAuthParamsInline is {@code true}, this String will be a pem-encoded {@link
+ * java.security.X509Certificate}
+ */
+ public String ipsecCaCert = ""; // 13
+ public String ipsecServerCert = ""; // 14
+ public ProxyInfo proxy = null; // 15~18
+
+ /**
+ * The list of allowable algorithms.
+ *
+ * <p>This list is validated in the setter to ensure that encoding characters (list, value
+ * delimiters) are not present in the algorithm names. See {@link #validateAllowedAlgorithms()}
+ */
+ private List<String> mAllowedAlgorithms = new ArrayList<>(); // 19
+ public boolean isBypassable = false; // 20
+ public boolean isMetered = false; // 21
+ public int maxMtu = 1400; // 22
+ public boolean areAuthParamsInline = false; // 23
// Helper fields.
@UnsupportedAppUsage
- public boolean saveLogin = false;
+ public transient boolean saveLogin = false;
public VpnProfile(String key) {
this.key = key;
@@ -103,6 +163,34 @@
ipsecServerCert = in.readString();
saveLogin = in.readInt() != 0;
proxy = in.readParcelable(null);
+ mAllowedAlgorithms = new ArrayList<>();
+ in.readList(mAllowedAlgorithms, null);
+ isBypassable = in.readBoolean();
+ isMetered = in.readBoolean();
+ maxMtu = in.readInt();
+ areAuthParamsInline = in.readBoolean();
+ }
+
+ /**
+ * Retrieves the list of allowed algorithms.
+ *
+ * <p>The contained elements are as listed in {@link IpSecAlgorithm}
+ */
+ public List<String> getAllowedAlgorithms() {
+ return Collections.unmodifiableList(mAllowedAlgorithms);
+ }
+
+ /**
+ * Validates and sets the list of algorithms that can be used for the IPsec transforms.
+ *
+ * @param allowedAlgorithms the list of allowable algorithms, as listed in {@link
+ * IpSecAlgorithm}.
+ * @throws IllegalArgumentException if any delimiters are used in algorithm names. See {@link
+ * #VALUE_DELIMITER} and {@link LIST_DELIMITER}.
+ */
+ public void setAllowedAlgorithms(List<String> allowedAlgorithms) {
+ validateAllowedAlgorithms(allowedAlgorithms);
+ mAllowedAlgorithms = allowedAlgorithms;
}
@Override
@@ -125,8 +213,18 @@
out.writeString(ipsecServerCert);
out.writeInt(saveLogin ? 1 : 0);
out.writeParcelable(proxy, flags);
+ out.writeList(mAllowedAlgorithms);
+ out.writeBoolean(isBypassable);
+ out.writeBoolean(isMetered);
+ out.writeInt(maxMtu);
+ out.writeBoolean(areAuthParamsInline);
}
+ /**
+ * Decodes a VpnProfile instance from the encoded byte array.
+ *
+ * <p>See {@link #encode()}
+ */
@UnsupportedAppUsage
public static VpnProfile decode(String key, byte[] value) {
try {
@@ -134,9 +232,11 @@
return null;
}
- String[] values = new String(value, StandardCharsets.UTF_8).split("\0", -1);
- // There can be 14 - 19 Bytes in values.length.
- if (values.length < 14 || values.length > 19) {
+ String[] values = new String(value, StandardCharsets.UTF_8).split(VALUE_DELIMITER, -1);
+ // Acceptable numbers of values are:
+ // 14-19: Standard profile, with option for serverCert, proxy
+ // 24: Standard profile with serverCert, proxy and platform-VPN parameters.
+ if ((values.length < 14 || values.length > 19) && values.length != 24) {
return null;
}
@@ -164,13 +264,23 @@
String port = (values.length > 16) ? values[16] : "";
String exclList = (values.length > 17) ? values[17] : "";
String pacFileUrl = (values.length > 18) ? values[18] : "";
- if (pacFileUrl.isEmpty()) {
+ if (!host.isEmpty() || !port.isEmpty() || !exclList.isEmpty()) {
profile.proxy = new ProxyInfo(host, port.isEmpty() ?
0 : Integer.parseInt(port), exclList);
- } else {
+ } else if (!pacFileUrl.isEmpty()) {
profile.proxy = new ProxyInfo(pacFileUrl);
}
- } // else profle.proxy = null
+ } // else profile.proxy = null
+
+ // Either all must be present, or none must be.
+ if (values.length >= 24) {
+ profile.mAllowedAlgorithms = Arrays.asList(values[19].split(LIST_DELIMITER));
+ profile.isBypassable = Boolean.parseBoolean(values[20]);
+ profile.isMetered = Boolean.parseBoolean(values[21]);
+ profile.maxMtu = Integer.parseInt(values[22]);
+ profile.areAuthParamsInline = Boolean.parseBoolean(values[23]);
+ }
+
profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
return profile;
} catch (Exception e) {
@@ -179,36 +289,52 @@
return null;
}
+ /**
+ * Encodes a VpnProfile instance to a byte array for storage.
+ *
+ * <p>See {@link #decode(String, byte[])}
+ */
public byte[] encode() {
StringBuilder builder = new StringBuilder(name);
- builder.append('\0').append(type);
- builder.append('\0').append(server);
- builder.append('\0').append(saveLogin ? username : "");
- builder.append('\0').append(saveLogin ? password : "");
- builder.append('\0').append(dnsServers);
- builder.append('\0').append(searchDomains);
- builder.append('\0').append(routes);
- builder.append('\0').append(mppe);
- builder.append('\0').append(l2tpSecret);
- builder.append('\0').append(ipsecIdentifier);
- builder.append('\0').append(ipsecSecret);
- builder.append('\0').append(ipsecUserCert);
- builder.append('\0').append(ipsecCaCert);
- builder.append('\0').append(ipsecServerCert);
+ builder.append(VALUE_DELIMITER).append(type);
+ builder.append(VALUE_DELIMITER).append(server);
+ builder.append(VALUE_DELIMITER).append(saveLogin ? username : "");
+ builder.append(VALUE_DELIMITER).append(saveLogin ? password : "");
+ builder.append(VALUE_DELIMITER).append(dnsServers);
+ builder.append(VALUE_DELIMITER).append(searchDomains);
+ builder.append(VALUE_DELIMITER).append(routes);
+ builder.append(VALUE_DELIMITER).append(mppe);
+ builder.append(VALUE_DELIMITER).append(l2tpSecret);
+ builder.append(VALUE_DELIMITER).append(ipsecIdentifier);
+ builder.append(VALUE_DELIMITER).append(ipsecSecret);
+ builder.append(VALUE_DELIMITER).append(ipsecUserCert);
+ builder.append(VALUE_DELIMITER).append(ipsecCaCert);
+ builder.append(VALUE_DELIMITER).append(ipsecServerCert);
if (proxy != null) {
- builder.append('\0').append(proxy.getHost() != null ? proxy.getHost() : "");
- builder.append('\0').append(proxy.getPort());
- builder.append('\0').append(proxy.getExclusionListAsString() != null ?
- proxy.getExclusionListAsString() : "");
- builder.append('\0').append(proxy.getPacFileUrl().toString());
+ builder.append(VALUE_DELIMITER).append(proxy.getHost() != null ? proxy.getHost() : "");
+ builder.append(VALUE_DELIMITER).append(proxy.getPort());
+ builder.append(VALUE_DELIMITER)
+ .append(
+ proxy.getExclusionListAsString() != null
+ ? proxy.getExclusionListAsString()
+ : "");
+ builder.append(VALUE_DELIMITER).append(proxy.getPacFileUrl().toString());
+ } else {
+ builder.append(ENCODED_NULL_PROXY_INFO);
}
+
+ builder.append(VALUE_DELIMITER).append(String.join(LIST_DELIMITER, mAllowedAlgorithms));
+ builder.append(VALUE_DELIMITER).append(isBypassable);
+ builder.append(VALUE_DELIMITER).append(isMetered);
+ builder.append(VALUE_DELIMITER).append(maxMtu);
+ builder.append(VALUE_DELIMITER).append(areAuthParamsInline);
+
return builder.toString().getBytes(StandardCharsets.UTF_8);
}
/**
- * Tests if profile is valid for lockdown, which requires IPv4 address for
- * both server and DNS. Server hostnames would require using DNS before
- * connection.
+ * Tests if profile is valid for lockdown, which requires IPv4 address for both server and DNS.
+ * Server hostnames would require using DNS before connection.
*/
public boolean isValidLockdownProfile() {
return isTypeValidForLockdown()
@@ -238,10 +364,7 @@
return !TextUtils.isEmpty(dnsServers);
}
- /**
- * Returns {@code true} if all DNS servers have numeric addresses,
- * e.g. 8.8.8.8
- */
+ /** Returns {@code true} if all DNS servers have numeric addresses, e.g. 8.8.8.8 */
public boolean areDnsAddressesNumeric() {
try {
for (String dnsServer : dnsServers.split(" +")) {
@@ -253,6 +376,62 @@
return true;
}
+ /**
+ * Validates that the provided list of algorithms does not contain illegal characters.
+ *
+ * @param allowedAlgorithms The list to be validated
+ */
+ public static void validateAllowedAlgorithms(List<String> allowedAlgorithms) {
+ for (final String alg : allowedAlgorithms) {
+ if (alg.contains(VALUE_DELIMITER) || alg.contains(LIST_DELIMITER)) {
+ throw new IllegalArgumentException(
+ "Algorithm contained illegal ('\0' or ',') character");
+ }
+ }
+ }
+
+ /** Generates a hashcode over the VpnProfile. */
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ key, type, server, username, password, dnsServers, searchDomains, routes, mppe,
+ l2tpSecret, ipsecIdentifier, ipsecSecret, ipsecUserCert, ipsecCaCert, ipsecServerCert,
+ proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline);
+ }
+
+ /** Checks VPN profiles for interior equality. */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof VpnProfile)) {
+ return false;
+ }
+
+ final VpnProfile other = (VpnProfile) obj;
+ return Objects.equals(key, other.key)
+ && Objects.equals(name, other.name)
+ && type == other.type
+ && Objects.equals(server, other.server)
+ && Objects.equals(username, other.username)
+ && Objects.equals(password, other.password)
+ && Objects.equals(dnsServers, other.dnsServers)
+ && Objects.equals(searchDomains, other.searchDomains)
+ && Objects.equals(routes, other.routes)
+ && mppe == other.mppe
+ && Objects.equals(l2tpSecret, other.l2tpSecret)
+ && Objects.equals(ipsecIdentifier, other.ipsecIdentifier)
+ && Objects.equals(ipsecSecret, other.ipsecSecret)
+ && Objects.equals(ipsecUserCert, other.ipsecUserCert)
+ && Objects.equals(ipsecCaCert, other.ipsecCaCert)
+ && Objects.equals(ipsecServerCert, other.ipsecServerCert)
+ && Objects.equals(proxy, other.proxy)
+ && Objects.equals(mAllowedAlgorithms, other.mAllowedAlgorithms)
+ && isBypassable == other.isBypassable
+ && isMetered == other.isMetered
+ && maxMtu == other.maxMtu
+ && areAuthParamsInline == other.areAuthParamsInline;
+ }
+
+ @NonNull
public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() {
@Override
public VpnProfile createFromParcel(Parcel in) {
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 179828c..7adb27c 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -19,6 +19,8 @@
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ApplicationErrorReport;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.type.DefaultMimeMapFactory;
import android.os.Build;
@@ -34,7 +36,9 @@
import com.android.internal.logging.AndroidConfig;
import com.android.server.NetworkManagementSocketTagger;
+import dalvik.annotation.compat.VersionCodes;
import dalvik.system.RuntimeHooks;
+import dalvik.system.ThreadPrioritySetter;
import dalvik.system.VMRuntime;
import libcore.content.type.MimeMap;
@@ -63,8 +67,17 @@
private static volatile boolean mCrashing = false;
+ /*
+ * Native heap allocations will now have a non-zero tag in the most significant byte.
+ * See {@linktourl https://source.android.com/devices/tech/debug/tagged-pointers}.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = VersionCodes.Q)
+ private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
+
private static final native void nativeFinishInit();
private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
+ private static native void nativeDisableHeapPointerTagging();
private static int Clog_e(String tag, String msg, Throwable tr) {
return Log.printlns(Log.LOG_ID_CRASH, Log.ERROR, tag, msg, tr);
@@ -204,6 +217,7 @@
*/
public static void preForkInit() {
if (DEBUG) Slog.d(TAG, "Entered preForkInit.");
+ RuntimeHooks.setThreadPrioritySetter(new RuntimeThreadPrioritySetter());
RuntimeInit.enableDdms();
// TODO(b/142019040#comment13): Decide whether to load the default instance eagerly, i.e.
// MimeMap.setDefault(DefaultMimeMapFactory.create());
@@ -216,6 +230,35 @@
MimeMap.setDefaultSupplier(DefaultMimeMapFactory::create);
}
+ private static class RuntimeThreadPrioritySetter implements ThreadPrioritySetter {
+ // Should remain consistent with kNiceValues[] in system/libartpalette/palette_android.cc
+ private static final int[] NICE_VALUES = {
+ Process.THREAD_PRIORITY_LOWEST, // 1 (MIN_PRIORITY)
+ Process.THREAD_PRIORITY_BACKGROUND + 6,
+ Process.THREAD_PRIORITY_BACKGROUND + 3,
+ Process.THREAD_PRIORITY_BACKGROUND,
+ Process.THREAD_PRIORITY_DEFAULT, // 5 (NORM_PRIORITY)
+ Process.THREAD_PRIORITY_DEFAULT - 2,
+ Process.THREAD_PRIORITY_DEFAULT - 4,
+ Process.THREAD_PRIORITY_URGENT_DISPLAY + 3,
+ Process.THREAD_PRIORITY_URGENT_DISPLAY + 2,
+ Process.THREAD_PRIORITY_URGENT_DISPLAY // 10 (MAX_PRIORITY)
+ };
+
+ @Override
+ public void setPriority(int nativeTid, int priority) {
+ // Check NICE_VALUES[] length first.
+ if (NICE_VALUES.length != (1 + Thread.MAX_PRIORITY - Thread.MIN_PRIORITY)) {
+ throw new AssertionError("Unexpected NICE_VALUES.length=" + NICE_VALUES.length);
+ }
+ // Priority should be in the range of MIN_PRIORITY (1) to MAX_PRIORITY (10).
+ if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
+ throw new IllegalArgumentException("Priority out of range: " + priority);
+ }
+ Process.setThreadPriority(nativeTid, NICE_VALUES[priority - Thread.MIN_PRIORITY]);
+ }
+ }
+
@UnsupportedAppUsage
protected static final void commonInit() {
if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
@@ -367,6 +410,20 @@
if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!");
}
+ private static void maybeDisableHeapPointerTagging(long[] disabledCompatChanges) {
+ // Heap tagging needs to be disabled before any additional threads are created, but the
+ // AppCompat framework is not initialized enough at this point.
+ // Check if the change is enabled manually.
+ if (disabledCompatChanges != null) {
+ for (int i = 0; i < disabledCompatChanges.length; i++) {
+ if (disabledCompatChanges[i] == NATIVE_HEAP_POINTER_TAGGING) {
+ nativeDisableHeapPointerTagging();
+ break;
+ }
+ }
+ }
+ }
+
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
// If the application calls System.exit(), terminate the process
@@ -379,6 +436,8 @@
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);
+ maybeDisableHeapPointerTagging(disabledCompatChanges);
+
final Arguments args = new Arguments(argv);
// The end of of the RuntimeInit event (see #zygoteInit).
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 33adec1..c1c74dc 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -35,6 +35,7 @@
import android.system.Os;
import android.util.Log;
+import dalvik.annotation.optimization.FastNative;
import dalvik.system.ZygoteHooks;
import libcore.io.IoUtils;
@@ -49,9 +50,9 @@
/** @hide */
public final class Zygote {
/*
- * Bit values for "runtimeFlags" argument. The definitions are duplicated
- * in the native code.
- */
+ * Bit values for "runtimeFlags" argument. The definitions are duplicated
+ * in the native code.
+ */
/** enable debugging over JDWP */
public static final int DEBUG_ENABLE_JDWP = 1;
@@ -187,6 +188,11 @@
*/
public static final int SOCKET_BUFFER_SIZE = 256;
+ /**
+ * @hide for internal use only
+ */
+ private static final int PRIORITY_MAX = -20;
+
/** a prototype instance for a future List.toArray() */
protected static final int[][] INT_ARRAY_2D = new int[0][0];
@@ -251,8 +257,7 @@
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
int targetSdkVersion) {
ZygoteHooks.preFork();
- // Resets nice priority for zygote process.
- resetNicePriority();
+
int pid = nativeForkAndSpecialize(
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
fdsToIgnore, startChildZygote, instructionSet, appDataDir);
@@ -264,6 +269,10 @@
// Note that this event ends at the end of handleChildProc,
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
}
+
+ // Set the Java Language thread priority to the default value for new apps.
+ Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
+
ZygoteHooks.postForkCommon();
return pid;
}
@@ -298,7 +307,7 @@
int[][] rlimits, int mountExternal, String seInfo, String niceName,
boolean startChildZygote, String instructionSet, String appDataDir) {
nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
- niceName, startChildZygote, instructionSet, appDataDir);
+ niceName, startChildZygote, instructionSet, appDataDir);
// Enable tracing as soon as possible for the child process.
Trace.setTracingEnabled(true, runtimeFlags);
@@ -306,6 +315,9 @@
// Note that this event ends at the end of handleChildProc.
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
+ // Set the Java Language thread priority to the default value for new apps.
+ Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
+
/*
* This is called here (instead of after the fork but before the specialize) to maintain
* consistancy with the code paths for forkAndSpecialize.
@@ -350,15 +362,19 @@
public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
ZygoteHooks.preFork();
- // Resets nice priority for zygote process.
- resetNicePriority();
+
int pid = nativeForkSystemServer(
uid, gid, gids, runtimeFlags, rlimits,
permittedCapabilities, effectiveCapabilities);
+
// Enable tracing as soon as we enter the system_server.
if (pid == 0) {
Trace.setTracingEnabled(true, runtimeFlags);
}
+
+ // Set the Java Language thread priority to the default value for new apps.
+ Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
+
ZygoteHooks.postForkCommon();
return pid;
}
@@ -476,13 +492,16 @@
/**
* Fork a new unspecialized app process from the zygote
*
+ * @param usapPoolSocket The server socket the USAP will call accept on
* @param sessionSocketRawFDs Anonymous session sockets that are currently open
+ * @param isPriorityFork Value controlling the process priority level until accept is called
* @return In the Zygote process this function will always return null; in unspecialized app
* processes this function will return a Runnable object representing the new
* application that is passed up from usapMain.
*/
static Runnable forkUsap(LocalServerSocket usapPoolSocket,
- int[] sessionSocketRawFDs) {
+ int[] sessionSocketRawFDs,
+ boolean isPriorityFork) {
FileDescriptor[] pipeFDs = null;
try {
@@ -492,7 +511,8 @@
}
int pid =
- nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), sessionSocketRawFDs);
+ nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(),
+ sessionSocketRawFDs, isPriorityFork);
if (pid == 0) {
IoUtils.closeQuietly(pipeFDs[0]);
@@ -506,8 +526,9 @@
}
private static native int nativeForkUsap(int readPipeFD,
- int writePipeFD,
- int[] sessionSocketRawFDs);
+ int writePipeFD,
+ int[] sessionSocketRawFDs,
+ boolean isPriorityFork);
/**
* This function is used by unspecialized app processes to wait for specialization requests from
@@ -518,7 +539,7 @@
* @return A runnable oject representing the new application.
*/
private static Runnable usapMain(LocalServerSocket usapPoolSocket,
- FileDescriptor writePipe) {
+ FileDescriptor writePipe) {
final int pid = Process.myPid();
Process.setArgV0(Process.is64Bit() ? "usap64" : "usap32");
@@ -527,6 +548,11 @@
Credentials peerCredentials = null;
ZygoteArguments args = null;
+ // Change the priority to max before calling accept so we can respond to new specialization
+ // requests as quickly as possible. This will be reverted to the default priority in the
+ // native specialization code.
+ boostUsapPriority();
+
while (true) {
try {
sessionSocket = usapPoolSocket.accept();
@@ -568,6 +594,7 @@
try {
// SIGTERM is blocked on loop exit. This prevents a USAP that is specializing from
// being killed during a pool flush.
+ setAppProcessName(args, "USAP");
applyUidSecurityPolicy(args, peerCredentials);
applyDebuggerSystemProperty(args);
@@ -628,23 +655,18 @@
}
specializeAppProcess(args.mUid, args.mGid, args.mGids,
- args.mRuntimeFlags, rlimits, args.mMountExternal,
- args.mSeInfo, args.mNiceName, args.mStartChildZygote,
- args.mInstructionSet, args.mAppDataDir);
+ args.mRuntimeFlags, rlimits, args.mMountExternal,
+ args.mSeInfo, args.mNiceName, args.mStartChildZygote,
+ args.mInstructionSet, args.mAppDataDir);
disableExecuteOnly(args.mTargetSdkVersion);
- if (args.mNiceName != null) {
- Process.setArgV0(args.mNiceName);
- }
-
- // End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return ZygoteInit.zygoteInit(args.mTargetSdkVersion,
- args.mDisabledCompatChanges,
- args.mRemainingArgs,
- null /* classLoader */);
+ args.mDisabledCompatChanges,
+ args.mRemainingArgs,
+ null /* classLoader */);
} finally {
// Unblock SIGTERM to restore the process to default behavior.
unblockSigTerm();
@@ -663,6 +685,22 @@
private static native void nativeUnblockSigTerm();
+ private static void boostUsapPriority() {
+ nativeBoostUsapPriority();
+ }
+
+ private static native void nativeBoostUsapPriority();
+
+ static void setAppProcessName(ZygoteArguments args, String loggingTag) {
+ if (args.mNiceName != null) {
+ Process.setArgV0(args.mNiceName);
+ } else if (args.mPackageName != null) {
+ Process.setArgV0(args.mPackageName);
+ } else {
+ Log.w(loggingTag, "Unable to set package name.");
+ }
+ }
+
private static final String USAP_ERROR_PREFIX = "Invalid command to USAP: ";
/**
@@ -685,7 +723,7 @@
throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--start-child-zygote");
} else if (args.mApiBlacklistExemptions != null) {
throw new IllegalArgumentException(
- USAP_ERROR_PREFIX + "--set-api-blacklist-exemptions");
+ USAP_ERROR_PREFIX + "--set-api-blacklist-exemptions");
} else if (args.mHiddenApiAccessLogSampleRate != -1) {
throw new IllegalArgumentException(
USAP_ERROR_PREFIX + "--hidden-api-log-sampling-rate=");
@@ -696,8 +734,8 @@
throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--invoke-with");
} else if (args.mPermittedCapabilities != 0 || args.mEffectiveCapabilities != 0) {
throw new ZygoteSecurityException("Client may not specify capabilities: "
- + "permitted=0x" + Long.toHexString(args.mPermittedCapabilities)
- + ", effective=0x" + Long.toHexString(args.mEffectiveCapabilities));
+ + "permitted=0x" + Long.toHexString(args.mPermittedCapabilities)
+ + ", effective=0x" + Long.toHexString(args.mEffectiveCapabilities));
}
}
@@ -754,7 +792,7 @@
if (uidRestricted && args.mUidSpecified && (args.mUid < Process.SYSTEM_UID)) {
throw new ZygoteSecurityException(
"System UID may not launch process with UID < "
- + Process.SYSTEM_UID);
+ + Process.SYSTEM_UID);
}
}
@@ -804,8 +842,8 @@
if (args.mInvokeWith != null && peerUid != 0
&& (args.mRuntimeFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) {
throw new ZygoteSecurityException("Peer is permitted to specify an "
- + "explicit invoke-with wrapper command only for debuggable "
- + "applications.");
+ + "explicit invoke-with wrapper command only for debuggable "
+ + "applications.");
}
}
@@ -888,7 +926,7 @@
return new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
- "Error building socket from file descriptor: " + fileDesc, ex);
+ "Error building socket from file descriptor: " + fileDesc, ex);
}
}
@@ -903,15 +941,6 @@
}
/**
- * Resets the calling thread priority to the default value (Thread.NORM_PRIORITY
- * or nice value 0). This updates both the priority value in java.lang.Thread and
- * the nice value (setpriority).
- */
- static void resetNicePriority() {
- Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
- }
-
- /**
* Executes "/system/bin/sh -c <command>" using the exec() system call.
* This method throws a runtime exception if exec() failed, otherwise, this
* method never returns.
@@ -941,4 +970,19 @@
command.append(" '").append(arg.replace("'", "'\\''")).append("'");
}
}
+
+ /**
+ * Parse the given unsolicited zygote message as type SIGCHLD,
+ * extract the payload information into the given output buffer.
+ *
+ * @param in The unsolicited zygote message to be parsed
+ * @param length The number of bytes in the message
+ * @param out The output buffer where the payload information will be placed
+ * @return Number of elements being place into output buffer, or -1 if
+ * either the message is malformed or not the type as expected here.
+ *
+ * @hide
+ */
+ @FastNative
+ public static native int nativeParseSigChld(byte[] in, int length, int[] out);
}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index e8d6681..2666d52 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -346,7 +346,7 @@
if (zygoteServer.isUsapPoolEnabled()) {
Runnable fpResult =
zygoteServer.fillUsapPool(
- new int[]{mSocket.getFileDescriptor().getInt$()});
+ new int[]{mSocket.getFileDescriptor().getInt$()}, false);
if (fpResult != null) {
zygoteServer.setForkChild();
@@ -485,9 +485,7 @@
closeSocket();
- if (parsedArgs.mNiceName != null) {
- Process.setArgV0(parsedArgs.mNiceName);
- }
+ Zygote.setAppProcessName(parsedArgs, TAG);
// End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index fd02237..348262e 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -825,6 +825,18 @@
return result;
}
+ /**
+ * This is the entry point for a Zygote process. It creates the Zygote server, loads resources,
+ * and handles other tasks related to preparing the process for forking into applications.
+ *
+ * This process is started with a nice value of -20 (highest priority). All paths that flow
+ * into new processes are required to either set the priority to the default value or terminate
+ * before executing any non-system code. The native side of this occurs in SpecializeCommon,
+ * while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess,
+ * ZygoteConnection.handleChildProc, and Zygote.usapMain.
+ *
+ * @param argv Command line arguments used to specify the Zygote's configuration.
+ */
@UnsupportedAppUsage
public static void main(String argv[]) {
ZygoteServer zygoteServer = null;
@@ -888,8 +900,6 @@
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
- } else {
- Zygote.resetNicePriority();
}
// Do an initial gc to clean up after startup
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index 1fd6e26..8d281b7 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -66,6 +66,12 @@
/** The default value used for the USAP_POOL_SIZE_MIN device property */
private static final String USAP_POOL_SIZE_MIN_DEFAULT = "1";
+ /** The default value used for the USAP_REFILL_DELAY_MS device property */
+ private static final String USAP_POOL_REFILL_DELAY_MS_DEFAULT = "3000";
+
+ /** The "not a timestamp" value for the refill delay timestamp mechanism. */
+ private static final int INVALID_TIMESTAMP = -1;
+
/**
* Indicates if this Zygote server can support a unspecialized app process pool. Currently this
* should only be true for the primary and secondary Zygotes, and not the App Zygotes or the
@@ -131,6 +137,24 @@
*/
private int mUsapPoolRefillThreshold = 0;
+ /**
+ * Number of milliseconds to delay before refilling the pool if it hasn't reached its
+ * minimum value.
+ */
+ private int mUsapPoolRefillDelayMs = -1;
+
+ /**
+ * If and when we should refill the USAP pool.
+ */
+ private UsapPoolRefillAction mUsapPoolRefillAction;
+ private long mUsapPoolRefillTriggerTimestamp;
+
+ private enum UsapPoolRefillAction {
+ DELAYED,
+ IMMEDIATE,
+ NONE
+ }
+
ZygoteServer() {
mUsapPoolEventFD = null;
mZygoteSocket = null;
@@ -160,9 +184,8 @@
Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
}
- fetchUsapPoolPolicyProps();
-
mUsapPoolSupported = true;
+ fetchUsapPoolPolicyProps();
}
void setForkChild() {
@@ -267,6 +290,13 @@
mUsapPoolSizeMax);
}
+ final String usapPoolRefillDelayMsPropString = Zygote.getConfigurationProperty(
+ ZygoteConfig.USAP_POOL_REFILL_DELAY_MS, USAP_POOL_REFILL_DELAY_MS_DEFAULT);
+
+ if (!usapPoolRefillDelayMsPropString.isEmpty()) {
+ mUsapPoolRefillDelayMs = Integer.parseInt(usapPoolRefillDelayMsPropString);
+ }
+
// Sanity check
if (mUsapPoolSizeMin >= mUsapPoolSizeMax) {
Log.w(TAG, "The max size of the USAP pool must be greater than the minimum size."
@@ -293,9 +323,16 @@
}
}
+ private void fetchUsapPoolPolicyPropsIfUnfetched() {
+ if (mIsFirstPropertyCheck) {
+ mIsFirstPropertyCheck = false;
+ fetchUsapPoolPolicyProps();
+ }
+ }
+
/**
- * Checks to see if the current policy says that pool should be refilled, and spawns new USAPs
- * if necessary.
+ * Refill the USAP Pool to the appropriate level, determined by whether this is a priority
+ * refill event or not.
*
* @param sessionSocketRawFDs Anonymous session sockets that are currently open
* @return In the Zygote process this function will always return null; in unspecialized app
@@ -303,39 +340,48 @@
* application that is passed up from usapMain.
*/
- Runnable fillUsapPool(int[] sessionSocketRawFDs) {
+ Runnable fillUsapPool(int[] sessionSocketRawFDs, boolean isPriorityRefill) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillUsapPool");
// Ensure that the pool properties have been fetched.
- fetchUsapPoolPolicyPropsWithMinInterval();
+ fetchUsapPoolPolicyPropsIfUnfetched();
int usapPoolCount = Zygote.getUsapPoolCount();
- int numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount;
+ int numUsapsToSpawn;
- if (usapPoolCount < mUsapPoolSizeMin
- || numUsapsToSpawn >= mUsapPoolRefillThreshold) {
-
- // Disable some VM functionality and reset some system values
- // before forking.
- ZygoteHooks.preFork();
- Zygote.resetNicePriority();
-
- while (usapPoolCount++ < mUsapPoolSizeMax) {
- Runnable caller = Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs);
-
- if (caller != null) {
- return caller;
- }
- }
-
- // Re-enable runtime services for the Zygote. Services for unspecialized app process
- // are re-enabled in specializeAppProcess.
- ZygoteHooks.postForkCommon();
+ if (isPriorityRefill) {
+ // Refill to min
+ numUsapsToSpawn = mUsapPoolSizeMin - usapPoolCount;
Log.i("zygote",
- "Filled the USAP pool. New USAPs: " + numUsapsToSpawn);
+ "Priority USAP Pool refill. New USAPs: " + numUsapsToSpawn);
+ } else {
+ // Refill up to max
+ numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount;
+
+ Log.i("zygote",
+ "Delayed USAP Pool refill. New USAPs: " + numUsapsToSpawn);
}
+ // Disable some VM functionality and reset some system values
+ // before forking.
+ ZygoteHooks.preFork();
+
+ while (--numUsapsToSpawn >= 0) {
+ Runnable caller =
+ Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs, isPriorityRefill);
+
+ if (caller != null) {
+ return caller;
+ }
+ }
+
+ // Re-enable runtime services for the Zygote. Services for unspecialized app process
+ // are re-enabled in specializeAppProcess.
+ ZygoteHooks.postForkCommon();
+
+ resetUsapRefillState();
+
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return null;
@@ -358,13 +404,18 @@
mUsapPoolEnabled = newStatus;
if (newStatus) {
- return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() });
+ return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() }, false);
} else {
Zygote.emptyUsapPool();
return null;
}
}
+ void resetUsapRefillState() {
+ mUsapPoolRefillAction = UsapPoolRefillAction.NONE;
+ mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
+ }
+
/**
* Runs the zygote process's select loop. Accepts new connections as
* they happen, and reads commands from connections one spawn-request's
@@ -377,8 +428,11 @@
socketFDs.add(mZygoteSocket.getFileDescriptor());
peers.add(null);
+ mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
+
while (true) {
fetchUsapPoolPolicyPropsWithMinInterval();
+ mUsapPoolRefillAction = UsapPoolRefillAction.NONE;
int[] usapPipeFDs = null;
StructPollfd[] pollFDs;
@@ -430,140 +484,199 @@
}
}
+ int pollTimeoutMs;
+
+ if (mUsapPoolRefillTriggerTimestamp == INVALID_TIMESTAMP) {
+ pollTimeoutMs = -1;
+ } else {
+ long elapsedTimeMs = System.currentTimeMillis() - mUsapPoolRefillTriggerTimestamp;
+
+ if (elapsedTimeMs >= mUsapPoolRefillDelayMs) {
+ // Normalize the poll timeout value when the time between one poll event and the
+ // next pushes us over the delay value. This prevents poll receiving a 0
+ // timeout value, which would result in it returning immediately.
+ pollTimeoutMs = -1;
+
+ } else if (elapsedTimeMs <= 0) {
+ // This can occur if the clock used by currentTimeMillis is reset, which is
+ // possible because it is not guaranteed to be monotonic. Because we can't tell
+ // how far back the clock was set the best way to recover is to simply re-start
+ // the respawn delay countdown.
+ pollTimeoutMs = mUsapPoolRefillDelayMs;
+
+ } else {
+ pollTimeoutMs = (int) (mUsapPoolRefillDelayMs - elapsedTimeMs);
+ }
+ }
+
+ int pollReturnValue;
try {
- Os.poll(pollFDs, -1);
+ pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
- boolean usapPoolFDRead = false;
+ if (pollReturnValue == 0) {
+ // The poll timeout has been exceeded. This only occurs when we have finished the
+ // USAP pool refill delay period.
- while (--pollIndex >= 0) {
- if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
- continue;
- }
+ mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
+ mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;
- if (pollIndex == 0) {
- // Zygote server socket
+ } else {
+ boolean usapPoolFDRead = false;
- ZygoteConnection newPeer = acceptCommandPeer(abiList);
- peers.add(newPeer);
- socketFDs.add(newPeer.getFileDescriptor());
-
- } else if (pollIndex < usapPoolEventFDIndex) {
- // Session socket accepted from the Zygote server socket
-
- try {
- ZygoteConnection connection = peers.get(pollIndex);
- final Runnable command = connection.processOneCommand(this);
-
- // TODO (chriswailes): Is this extra check necessary?
- if (mIsForkChild) {
- // We're in the child. We should always have a command to run at this
- // stage if processOneCommand hasn't called "exec".
- if (command == null) {
- throw new IllegalStateException("command == null");
- }
-
- return command;
- } else {
- // We're in the server - we should never have any commands to run.
- if (command != null) {
- throw new IllegalStateException("command != null");
- }
-
- // We don't know whether the remote side of the socket was closed or
- // not until we attempt to read from it from processOneCommand. This
- // shows up as a regular POLLIN event in our regular processing loop.
- if (connection.isClosedByPeer()) {
- connection.closeSocket();
- peers.remove(pollIndex);
- socketFDs.remove(pollIndex);
- }
- }
- } catch (Exception e) {
- if (!mIsForkChild) {
- // We're in the server so any exception here is one that has taken place
- // pre-fork while processing commands or reading / writing from the
- // control socket. Make a loud noise about any such exceptions so that
- // we know exactly what failed and why.
-
- Slog.e(TAG, "Exception executing zygote command: ", e);
-
- // Make sure the socket is closed so that the other end knows
- // immediately that something has gone wrong and doesn't time out
- // waiting for a response.
- ZygoteConnection conn = peers.remove(pollIndex);
- conn.closeSocket();
-
- socketFDs.remove(pollIndex);
- } else {
- // We're in the child so any exception caught here has happened post
- // fork and before we execute ActivityThread.main (or any other main()
- // method). Log the details of the exception and bring down the process.
- Log.e(TAG, "Caught post-fork exception in child process.", e);
- throw e;
- }
- } finally {
- // Reset the child flag, in the event that the child process is a child-
- // zygote. The flag will not be consulted this loop pass after the Runnable
- // is returned.
- mIsForkChild = false;
- }
- } else {
- // Either the USAP pool event FD or a USAP reporting pipe.
-
- // If this is the event FD the payload will be the number of USAPs removed.
- // If this is a reporting pipe FD the payload will be the PID of the USAP
- // that was just specialized.
- long messagePayload = -1;
-
- try {
- byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];
- int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
-
- if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {
- DataInputStream inputStream =
- new DataInputStream(new ByteArrayInputStream(buffer));
-
- messagePayload = inputStream.readLong();
- } else {
- Log.e(TAG, "Incomplete read from USAP management FD of size "
- + readBytes);
- continue;
- }
- } catch (Exception ex) {
- if (pollIndex == usapPoolEventFDIndex) {
- Log.e(TAG, "Failed to read from USAP pool event FD: "
- + ex.getMessage());
- } else {
- Log.e(TAG, "Failed to read from USAP reporting pipe: "
- + ex.getMessage());
- }
-
+ while (--pollIndex >= 0) {
+ if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
continue;
}
- if (pollIndex > usapPoolEventFDIndex) {
- Zygote.removeUsapTableEntry((int) messagePayload);
- }
+ if (pollIndex == 0) {
+ // Zygote server socket
- usapPoolFDRead = true;
+ ZygoteConnection newPeer = acceptCommandPeer(abiList);
+ peers.add(newPeer);
+ socketFDs.add(newPeer.getFileDescriptor());
+
+ } else if (pollIndex < usapPoolEventFDIndex) {
+ // Session socket accepted from the Zygote server socket
+
+ try {
+ ZygoteConnection connection = peers.get(pollIndex);
+ final Runnable command = connection.processOneCommand(this);
+
+ // TODO (chriswailes): Is this extra check necessary?
+ if (mIsForkChild) {
+ // We're in the child. We should always have a command to run at
+ // this stage if processOneCommand hasn't called "exec".
+ if (command == null) {
+ throw new IllegalStateException("command == null");
+ }
+
+ return command;
+ } else {
+ // We're in the server - we should never have any commands to run.
+ if (command != null) {
+ throw new IllegalStateException("command != null");
+ }
+
+ // We don't know whether the remote side of the socket was closed or
+ // not until we attempt to read from it from processOneCommand. This
+ // shows up as a regular POLLIN event in our regular processing
+ // loop.
+ if (connection.isClosedByPeer()) {
+ connection.closeSocket();
+ peers.remove(pollIndex);
+ socketFDs.remove(pollIndex);
+ }
+ }
+ } catch (Exception e) {
+ if (!mIsForkChild) {
+ // We're in the server so any exception here is one that has taken
+ // place pre-fork while processing commands or reading / writing
+ // from the control socket. Make a loud noise about any such
+ // exceptions so that we know exactly what failed and why.
+
+ Slog.e(TAG, "Exception executing zygote command: ", e);
+
+ // Make sure the socket is closed so that the other end knows
+ // immediately that something has gone wrong and doesn't time out
+ // waiting for a response.
+ ZygoteConnection conn = peers.remove(pollIndex);
+ conn.closeSocket();
+
+ socketFDs.remove(pollIndex);
+ } else {
+ // We're in the child so any exception caught here has happened post
+ // fork and before we execute ActivityThread.main (or any other
+ // main() method). Log the details of the exception and bring down
+ // the process.
+ Log.e(TAG, "Caught post-fork exception in child process.", e);
+ throw e;
+ }
+ } finally {
+ // Reset the child flag, in the event that the child process is a child-
+ // zygote. The flag will not be consulted this loop pass after the
+ // Runnable is returned.
+ mIsForkChild = false;
+ }
+
+ } else {
+ // Either the USAP pool event FD or a USAP reporting pipe.
+
+ // If this is the event FD the payload will be the number of USAPs removed.
+ // If this is a reporting pipe FD the payload will be the PID of the USAP
+ // that was just specialized. The `continue` statements below ensure that
+ // the messagePayload will always be valid if we complete the try block
+ // without an exception.
+ long messagePayload;
+
+ try {
+ byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];
+ int readBytes =
+ Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
+
+ if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {
+ DataInputStream inputStream =
+ new DataInputStream(new ByteArrayInputStream(buffer));
+
+ messagePayload = inputStream.readLong();
+ } else {
+ Log.e(TAG, "Incomplete read from USAP management FD of size "
+ + readBytes);
+ continue;
+ }
+ } catch (Exception ex) {
+ if (pollIndex == usapPoolEventFDIndex) {
+ Log.e(TAG, "Failed to read from USAP pool event FD: "
+ + ex.getMessage());
+ } else {
+ Log.e(TAG, "Failed to read from USAP reporting pipe: "
+ + ex.getMessage());
+ }
+
+ continue;
+ }
+
+ if (pollIndex > usapPoolEventFDIndex) {
+ Zygote.removeUsapTableEntry((int) messagePayload);
+ }
+
+ usapPoolFDRead = true;
+ }
+ }
+
+ if (usapPoolFDRead) {
+ int usapPoolCount = Zygote.getUsapPoolCount();
+
+ if (usapPoolCount < mUsapPoolSizeMin) {
+ // Immediate refill
+ mUsapPoolRefillAction = UsapPoolRefillAction.IMMEDIATE;
+ } else if (mUsapPoolSizeMax - usapPoolCount >= mUsapPoolRefillThreshold) {
+ // Delayed refill
+ mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis();
+ }
}
}
- // Check to see if the USAP pool needs to be refilled.
- if (usapPoolFDRead) {
+ if (mUsapPoolRefillAction != UsapPoolRefillAction.NONE) {
int[] sessionSocketRawFDs =
socketFDs.subList(1, socketFDs.size())
.stream()
.mapToInt(FileDescriptor::getInt$)
.toArray();
- final Runnable command = fillUsapPool(sessionSocketRawFDs);
+ final boolean isPriorityRefill =
+ mUsapPoolRefillAction == UsapPoolRefillAction.IMMEDIATE;
+
+ final Runnable command =
+ fillUsapPool(sessionSocketRawFDs, isPriorityRefill);
if (command != null) {
return command;
+ } else if (isPriorityRefill) {
+ // Schedule a delayed refill to finish refilling the pool.
+ mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis();
}
}
}
diff --git a/core/java/com/android/internal/util/LocationPermissionChecker.java b/core/java/com/android/internal/util/LocationPermissionChecker.java
new file mode 100644
index 0000000..dc318b4
--- /dev/null
+++ b/core/java/com/android/internal/util/LocationPermissionChecker.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.Manifest;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.location.LocationManager;
+import android.os.Binder;
+import android.os.Build;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+
+/**
+ * The methods used for location permission and location mode checking.
+ *
+ * @hide
+ */
+public class LocationPermissionChecker {
+
+ private static final String TAG = "LocationPermissionChecker";
+
+ private final Context mContext;
+ private final AppOpsManager mAppOpsManager;
+ private final UserManager mUserManager;
+ private final LocationManager mLocationManager;
+
+ public LocationPermissionChecker(Context context) {
+ mContext = context;
+ mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mLocationManager =
+ (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ }
+
+ /**
+ * Check location permission granted by the caller.
+ *
+ * This API check if the location mode enabled for the caller and the caller has
+ * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION.
+ *
+ * @param pkgName package name of the application requesting access
+ * @param featureId The feature in the package
+ * @param uid The uid of the package
+ * @param message A message describing why the permission was checked. Only needed if this is
+ * not inside of a two-way binder call from the data receiver
+ *
+ * @return {@code true} returns if the caller has location permission and the location mode is
+ * enabled.
+ */
+ public boolean checkLocationPermission(String pkgName, @Nullable String featureId,
+ int uid, @Nullable String message) {
+ try {
+ enforceLocationPermission(pkgName, featureId, uid, message);
+ return true;
+ } catch (SecurityException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Enforce the caller has location permission.
+ *
+ * This API determines if the location mode enabled for the caller and the caller has
+ * ACCESS_COARSE_LOCATION permission is targetSDK<29, otherwise, has ACCESS_FINE_LOCATION.
+ * SecurityException is thrown if the caller has no permission or the location mode is disabled.
+ *
+ * @param pkgName package name of the application requesting access
+ * @param featureId The feature in the package
+ * @param uid The uid of the package
+ * @param message A message describing why the permission was checked. Only needed if this is
+ * not inside of a two-way binder call from the data receiver
+ */
+ public void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid,
+ @Nullable String message) throws SecurityException {
+
+ checkPackage(uid, pkgName);
+
+ // Location mode must be enabled
+ if (!isLocationModeEnabled()) {
+ throw new SecurityException("Location mode is disabled for the device");
+ }
+
+ // LocationAccess by App: caller must have Coarse/Fine Location permission to have access to
+ // location information.
+ if (!checkCallersLocationPermission(pkgName, featureId,
+ uid, /* coarseForTargetSdkLessThanQ */ true, message)) {
+ throw new SecurityException("UID " + uid + " has no location permission");
+ }
+ }
+
+ /**
+ * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION or
+ * android.Manifest.permission.ACCESS_COARSE_LOCATION (depending on config/targetSDK level)
+ * and a corresponding app op is allowed for this package and uid.
+ *
+ * @param pkgName PackageName of the application requesting access
+ * @param featureId The feature in the package
+ * @param uid The uid of the package
+ * @param coarseForTargetSdkLessThanQ If true and the targetSDK < Q then will check for COARSE
+ * else (false or targetSDK >= Q) then will check for FINE
+ * @param message A message describing why the permission was checked. Only needed if this is
+ * not inside of a two-way binder call from the data receiver
+ */
+ public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId,
+ int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) {
+
+ boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid);
+
+ String permissionType = Manifest.permission.ACCESS_FINE_LOCATION;
+ if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) {
+ // Having FINE permission implies having COARSE permission (but not the reverse)
+ permissionType = Manifest.permission.ACCESS_COARSE_LOCATION;
+ }
+ if (getUidPermission(permissionType, uid) == PackageManager.PERMISSION_DENIED) {
+ return false;
+ }
+
+ // Always checking FINE - even if will not enforce. This will record the request for FINE
+ // so that a location request by the app is surfaced to the user.
+ boolean isFineLocationAllowed = noteAppOpAllowed(
+ AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid, message);
+ if (isFineLocationAllowed) {
+ return true;
+ }
+ if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) {
+ return noteAppOpAllowed(AppOpsManager.OPSTR_COARSE_LOCATION, pkgName, featureId, uid,
+ message);
+ }
+ return false;
+ }
+
+ /**
+ * Retrieves a handle to LocationManager (if not already done) and check if location is enabled.
+ */
+ public boolean isLocationModeEnabled() {
+ try {
+ return mLocationManager.isLocationEnabledForUser(UserHandle.of(
+ getCurrentUser()));
+ } catch (Exception e) {
+ Log.e(TAG, "Failure to get location mode via API, falling back to settings", e);
+ return false;
+ }
+ }
+
+ private boolean isTargetSdkLessThan(String packageName, int versionCode, int callingUid) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ if (mContext.getPackageManager().getApplicationInfoAsUser(
+ packageName, 0,
+ UserHandle.getUserHandleForUid(callingUid)).targetSdkVersion
+ < versionCode) {
+ return true;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ // In case of exception, assume unknown app (more strict checking)
+ // Note: This case will never happen since checkPackage is
+ // called to verify validity before checking App's version.
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ return false;
+ }
+
+ private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId,
+ int uid, @Nullable String message) {
+ return mAppOpsManager.noteOp(op, uid, pkgName) == AppOpsManager.MODE_ALLOWED;
+ }
+
+ private void checkPackage(int uid, String pkgName)
+ throws SecurityException {
+ if (pkgName == null) {
+ throw new SecurityException("Checking UID " + uid + " but Package Name is Null");
+ }
+ mAppOpsManager.checkPackage(uid, pkgName);
+ }
+
+ @VisibleForTesting
+ protected int getCurrentUser() {
+ return ActivityManager.getCurrentUser();
+ }
+
+ private int getUidPermission(String permissionType, int uid) {
+ // We don't care about pid, pass in -1
+ return mContext.checkPermission(permissionType, -1, uid);
+ }
+}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 8e0e1c6..551541e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -47,6 +47,7 @@
#include <signal.h>
#include <dirent.h>
#include <assert.h>
+#include <bionic/malloc.h>
#include <string>
#include <vector>
@@ -279,6 +280,14 @@
gCurRuntime->setExitWithoutCleanup(exitWithoutCleanup);
}
+static void com_android_internal_os_RuntimeInit_nativeDisableHeapPointerTagging(
+ JNIEnv* env, jobject clazz) {
+ HeapTaggingLevel tag_level = M_HEAP_TAGGING_LEVEL_NONE;
+ if (!android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &tag_level, sizeof(tag_level))) {
+ ALOGE("ERROR: could not disable heap pointer tagging\n");
+ }
+}
+
/*
* JNI registration.
*/
@@ -286,10 +295,12 @@
int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
{
const JNINativeMethod methods[] = {
- { "nativeFinishInit", "()V",
- (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
- { "nativeSetExitWithoutCleanup", "(Z)V",
- (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
+ {"nativeFinishInit", "()V",
+ (void*)com_android_internal_os_RuntimeInit_nativeFinishInit},
+ {"nativeSetExitWithoutCleanup", "(Z)V",
+ (void*)com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup},
+ {"nativeDisableHeapPointerTagging", "()V",
+ (void*)com_android_internal_os_RuntimeInit_nativeDisableHeapPointerTagging},
};
return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
methods, NELEM(methods));
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 52ce54b..7bf35f9 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -193,7 +193,8 @@
{
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 58fd9c0..486df62 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -63,6 +63,7 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
+#include <sys/un.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -164,11 +165,26 @@
static int gUsapPoolEventFD = -1;
/**
+ * The socket file descriptor used to send notifications to the
+ * system_server.
+ */
+static int gSystemServerSocketFd = -1;
+
+/**
* The maximum value that the gUSAPPoolSizeMax variable may take. This value
* is a mirror of ZygoteServer.USAP_POOL_SIZE_MAX_LIMIT
*/
static constexpr int USAP_POOL_SIZE_MAX_LIMIT = 100;
+/** The numeric value for the maximum priority a process may possess. */
+static constexpr int PROCESS_PRIORITY_MAX = -20;
+
+/** The numeric value for the minimum priority a process may possess. */
+static constexpr int PROCESS_PRIORITY_MIN = 19;
+
+/** The numeric value for the normal priority a process should have. */
+static constexpr int PROCESS_PRIORITY_DEFAULT = 0;
+
/**
* A helper class containing accounting information for USAPs.
*/
@@ -305,6 +321,26 @@
PROFILE_FROM_SHELL = 1 << 15,
};
+enum UnsolicitedZygoteMessageTypes : uint32_t {
+ UNSOLICITED_ZYGOTE_MESSAGE_TYPE_RESERVED = 0,
+ UNSOLICITED_ZYGOTE_MESSAGE_TYPE_SIGCHLD = 1,
+};
+
+struct UnsolicitedZygoteMessageSigChld {
+ struct {
+ UnsolicitedZygoteMessageTypes type;
+ } header;
+ struct {
+ pid_t pid;
+ uid_t uid;
+ int status;
+ } payload;
+};
+
+// Keep sync with services/core/java/com/android/server/am/ProcessList.java
+static constexpr struct sockaddr_un kSystemServerSockAddr =
+ {.sun_family = AF_LOCAL, .sun_path = "/data/system/unsolzygotesocket"};
+
// Forward declaration so we don't have to move the signal handler.
static bool RemoveUsapTableEntry(pid_t usap_pid);
@@ -314,8 +350,37 @@
env->FatalError(oss.str().c_str());
}
+// Create the socket which is going to be used to send unsolicited message
+// to system_server, the socket will be closed post forking a child process.
+// It's expected to be called at each zygote's initialization.
+static void initUnsolSocketToSystemServer() {
+ gSystemServerSocketFd = socket(AF_LOCAL, SOCK_DGRAM | SOCK_NONBLOCK, 0);
+ if (gSystemServerSocketFd >= 0) {
+ ALOGV("Zygote:systemServerSocketFD = %d", gSystemServerSocketFd);
+ } else {
+ ALOGE("Unable to create socket file descriptor to connect to system_server");
+ }
+}
+
+static void sendSigChildStatus(const pid_t pid, const uid_t uid, const int status) {
+ int socketFd = gSystemServerSocketFd;
+ if (socketFd >= 0) {
+ // fill the message buffer
+ struct UnsolicitedZygoteMessageSigChld data =
+ {.header = {.type = UNSOLICITED_ZYGOTE_MESSAGE_TYPE_SIGCHLD},
+ .payload = {.pid = pid, .uid = uid, .status = status}};
+ if (TEMP_FAILURE_RETRY(
+ sendto(socketFd, &data, sizeof(data), 0,
+ reinterpret_cast<const struct sockaddr*>(&kSystemServerSockAddr),
+ sizeof(kSystemServerSockAddr))) == -1) {
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Zygote failed to write to system_server FD: %s",
+ strerror(errno));
+ }
+ }
+}
// This signal handler is for zygote mode, since the zygote must reap its children
-static void SigChldHandler(int /*signal_number*/) {
+static void SigChldHandler(int /*signal_number*/, siginfo_t* info, void* /*ucontext*/) {
pid_t pid;
int status;
int64_t usaps_removed = 0;
@@ -329,6 +394,8 @@
int saved_errno = errno;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ // Notify system_server that we received a SIGCHLD
+ sendSigChildStatus(pid, info->si_uid, status);
// Log process-death status that we care about.
if (WIFEXITED(status)) {
async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
@@ -402,8 +469,7 @@
// This ends up being called repeatedly before each fork(), but there's
// no real harm in that.
static void SetSignalHandlers() {
- struct sigaction sig_chld = {};
- sig_chld.sa_handler = SigChldHandler;
+ struct sigaction sig_chld = {.sa_flags = SA_SIGINFO, .sa_sigaction = SigChldHandler};
if (sigaction(SIGCHLD, &sig_chld, nullptr) < 0) {
ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
@@ -903,7 +969,8 @@
// Utility routine to fork a process from the zygote.
static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
const std::vector<int>& fds_to_close,
- const std::vector<int>& fds_to_ignore) {
+ const std::vector<int>& fds_to_ignore,
+ bool is_priority_fork) {
SetSignalHandlers();
// Curry a failure function.
@@ -936,6 +1003,12 @@
pid_t pid = fork();
if (pid == 0) {
+ if (is_priority_fork) {
+ setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
+ } else {
+ setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
+ }
+
// The child process.
PreApplicationInit();
@@ -951,6 +1024,9 @@
// Turn fdsan back on.
android_fdsan_set_error_level(fdsan_error_level);
+
+ // Reset the fd to the unsolicited zygote socket
+ gSystemServerSocketFd = -1;
} else {
ALOGD("Forked child process %d", pid);
}
@@ -987,22 +1063,16 @@
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.
@@ -1018,11 +1088,12 @@
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) {
@@ -1130,9 +1201,16 @@
}
}
+ if (is_child_zygote) {
+ initUnsolSocketToSystemServer();
+ }
+
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
is_system_server, is_child_zygote, managed_instruction_set);
+ // Reset the process priority to the default value.
+ setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_DEFAULT);
+
if (env->ExceptionCheck()) {
fail_fn("Error calling post fork hooks.");
}
@@ -1372,7 +1450,12 @@
fds_to_ignore.push_back(gUsapPoolEventFD);
}
- pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore);
+ if (gSystemServerSocketFd != -1) {
+ fds_to_close.push_back(gSystemServerSocketFd);
+ fds_to_ignore.push_back(gSystemServerSocketFd);
+ }
+
+ pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore, true);
if (pid == 0) {
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
@@ -1397,9 +1480,15 @@
fds_to_ignore.push_back(gUsapPoolEventFD);
}
+ if (gSystemServerSocketFd != -1) {
+ fds_to_close.push_back(gSystemServerSocketFd);
+ fds_to_ignore.push_back(gSystemServerSocketFd);
+ }
+
pid_t pid = ForkCommon(env, true,
fds_to_close,
- fds_to_ignore);
+ fds_to_ignore,
+ true);
if (pid == 0) {
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
permitted_capabilities, effective_capabilities,
@@ -1441,13 +1530,15 @@
* zygote in managed code.
* @param managed_session_socket_fds A list of anonymous session sockets that must be ignored by
* the FD hygiene code and automatically "closed" in the new USAP.
+ * @param is_priority_fork Controls the nice level assigned to the newly created process
* @return
*/
static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env,
jclass,
jint read_pipe_fd,
jint write_pipe_fd,
- jintArray managed_session_socket_fds) {
+ jintArray managed_session_socket_fds,
+ jboolean is_priority_fork) {
std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()),
fds_to_ignore(fds_to_close);
@@ -1461,6 +1552,9 @@
fds_to_close.push_back(gZygoteSocketFD);
fds_to_close.push_back(gUsapPoolEventFD);
fds_to_close.insert(fds_to_close.end(), session_socket_fds.begin(), session_socket_fds.end());
+ if (gSystemServerSocketFd != -1) {
+ fds_to_close.push_back(gSystemServerSocketFd);
+ }
fds_to_ignore.push_back(gZygoteSocketFD);
fds_to_ignore.push_back(gUsapPoolSocketFD);
@@ -1468,8 +1562,12 @@
fds_to_ignore.push_back(read_pipe_fd);
fds_to_ignore.push_back(write_pipe_fd);
fds_to_ignore.insert(fds_to_ignore.end(), session_socket_fds.begin(), session_socket_fds.end());
+ if (gSystemServerSocketFd != -1) {
+ fds_to_ignore.push_back(gSystemServerSocketFd);
+ }
- pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore);
+ pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore,
+ is_priority_fork == JNI_TRUE);
if (usap_pid != 0) {
++gUsapPoolCount;
@@ -1567,6 +1665,7 @@
ALOGE("Unable to fetch USAP pool socket file descriptor");
}
+ initUnsolSocketToSystemServer();
/*
* Security Initialization
*/
@@ -1706,6 +1805,48 @@
UnblockSignal(SIGTERM, fail_fn);
}
+static void com_android_internal_os_Zygote_nativeBoostUsapPriority(JNIEnv* env, jclass) {
+ setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
+}
+
+static jint com_android_internal_os_Zygote_nativeParseSigChld(JNIEnv* env, jclass, jbyteArray in,
+ jint length, jintArray out) {
+ if (length != sizeof(struct UnsolicitedZygoteMessageSigChld)) {
+ // Apparently it's not the message we are expecting.
+ return -1;
+ }
+ if (in == nullptr || out == nullptr) {
+ // Invalid parameter
+ jniThrowException(env, "java/lang/IllegalArgumentException", nullptr);
+ return -1;
+ }
+ ScopedByteArrayRO source(env, in);
+ if (source.size() < length) {
+ // Invalid parameter
+ jniThrowException(env, "java/lang/IllegalArgumentException", nullptr);
+ return -1;
+ }
+ const struct UnsolicitedZygoteMessageSigChld* msg =
+ reinterpret_cast<const struct UnsolicitedZygoteMessageSigChld*>(source.get());
+
+ switch (msg->header.type) {
+ case UNSOLICITED_ZYGOTE_MESSAGE_TYPE_SIGCHLD: {
+ ScopedIntArrayRW buf(env, out);
+ if (buf.size() != 3) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", nullptr);
+ return UNSOLICITED_ZYGOTE_MESSAGE_TYPE_RESERVED;
+ }
+ buf[0] = msg->payload.pid;
+ buf[1] = msg->payload.uid;
+ buf[2] = msg->payload.status;
+ return 3;
+ }
+ default:
+ break;
+ }
+ return -1;
+}
+
static const JNINativeMethod gMethods[] = {
{ "nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I",
@@ -1718,7 +1859,7 @@
(void *) com_android_internal_os_Zygote_nativePreApplicationInit },
{ "nativeInstallSeccompUidGidFilter", "(II)V",
(void *) com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter },
- { "nativeForkUsap", "(II[I)I",
+ { "nativeForkUsap", "(II[IZ)I",
(void *) com_android_internal_os_Zygote_nativeForkUsap },
{ "nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V",
@@ -1740,7 +1881,11 @@
{ "nativeBlockSigTerm", "()V",
(void* ) com_android_internal_os_Zygote_nativeBlockSigTerm },
{ "nativeUnblockSigTerm", "()V",
- (void* ) com_android_internal_os_Zygote_nativeUnblockSigTerm }
+ (void* ) com_android_internal_os_Zygote_nativeUnblockSigTerm },
+ { "nativeBoostUsapPriority", "()V",
+ (void* ) com_android_internal_os_Zygote_nativeBoostUsapPriority },
+ {"nativeParseSigChld", "([BI[I)I",
+ (void* ) com_android_internal_os_Zygote_nativeParseSigChld},
};
int register_com_android_internal_os_Zygote(JNIEnv* env) {
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index 74ced89..4892faa 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -14,6 +14,7 @@
# Frameworks
ogunwale@google.com
jjaggi@google.com
+per-file usagestatsservice.proto, usagestatsservice_v2.proto = mwachens@google.com
# Launcher
hyunyoungs@google.com
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 2873379..7452f80 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -232,6 +232,8 @@
// Whether or not TimeController should skip setting wakeup alarms for jobs that aren't
// ready now.
optional bool skip_not_ready_jobs = 1;
+ // Whether or not TimeController will use a non-wakeup alarm for delay constraints.
+ optional bool use_non_wakeup_alarm_for_delay = 2;
}
optional TimeController time_controller = 25;
diff --git a/core/proto/android/stats/otaupdate/updateengine_enums.proto b/core/proto/android/stats/otaupdate/updateengine_enums.proto
new file mode 100644
index 0000000..a6e9919
--- /dev/null
+++ b/core/proto/android/stats/otaupdate/updateengine_enums.proto
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.stats.otaupdate;
+
+// The payload type of an OTA update attempt on A/B devices.
+enum PayloadType {
+ FULL = 10000;
+ DELTA = 10001;
+}
+
+// The attempt result reported by the update engine for an OTA update.
+enum AttemptResult {
+ UPDATE_SUCCEEDED = 10000;
+ INTERNAL_ERROR = 10001;
+ PAYLOAD_DOWNLOAD_ERROR = 10002;
+ METADATA_MALFORMED = 10003;
+ OPERATION_MALFORMED = 10004;
+ OPERATION_EXECUTION_ERROR = 10005;
+ METADATA_VERIFICATION_FAILED = 10006;
+ PAYLOAD_VERIFICATION_FAILED = 10007;
+ VERIFICATION_FAILED = 10008;
+ POSTINSTALL_FAILED = 10009;
+ ABNORMAL_TERMINATION = 10010;
+ UPDATE_CANCELED = 10011;
+ UPDATE_SUCCEEDED_NOT_ACTIVE = 10012;
+}
+
+// The error code reported by the update engine after an OTA update attempt
+// on A/B devices. More details in system/update_engine/common/error_code.h
+enum ErrorCode {
+ SUCCESS = 10000;
+ ERROR = 10001;
+ FILESYSTEM_COPIER_ERROR = 10004;
+ POST_INSTALL_RUNNER_ERROR = 10005;
+ PAYLOAD_MISMATCHED_TYPE_ERROR = 10006;
+ INSTALL_DEVICE_OPEN_ERROR = 10007;
+ KERNEL_DEVICE_OPEN_ERROR = 10008;
+ DOWNLOAD_TRANSFER_ERROR = 10009;
+ PAYLOAD_HASH_MISMATCH_ERROR = 10010;
+ PAYLOAD_SIZE_MISMATCH_ERROR = 10011;
+ DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 10012;
+ DOWNLOAD_NEW_PARTITION_INFO_ERROR = 10013;
+ DOWNLOAD_WRITE_ERROR = 10014;
+ NEW_ROOTFS_VERIFICATION_ERROR = 10015;
+ SIGNED_DELTA_PAYLOAD_EXPECTED_ERROR = 10017;
+ DOWNLOAD_PAYLOAD_PUB_KEY_VERIFICATION_ERROR = 10018;
+ DOWNLOAD_STATE_INITIALIZATION_ERROR = 10020;
+ DOWNLOAD_INVALID_METADATA_MAGIC_STRING = 10021;
+ DOWNLOAD_SIGNATURE_MISSING_IN_MANIFEST = 10022;
+ DOWNLOAD_MANIFEST_PARSE_ERROR = 10023;
+ DOWNLOAD_METADATA_SIGNATURE_ERROR = 10024;
+ DOWNLOAD_METADATA_SIGNATURE_VERIFICATION_ERROR = 10025;
+ DOWNLOAD_METADATA_SIGNATURE_MISMATCH = 10026;
+ DOWNLOAD_OPERATION_HASH_VERIFICATION_ERROR = 10027;
+ DOWNLOAD_OPERATION_EXECUTION_ERROR = 10028;
+ DOWNLOAD_OPERATION_HASH_MISMATCH = 10029;
+ DOWNLOAD_INVALID_METADATA_SIZE = 10032;
+ DOWNLOAD_INVALID_METADATA_SIGNATURE = 10033;
+ DOWNLOAD_OPERATION_HASH_MISSING_ERROR = 10038;
+ DOWNLOAD_METADATA_SIGNATURE_MISSING_ERROR = 10039;
+ UNSUPPORTED_MAJOR_PAYLOAD_VERSION = 10044;
+ UNSUPPORTED_MINOR_PAYLOAD_VERSION = 10045;
+ FILESYSTEM_VERIFIER_ERROR = 10047;
+ USER_CANCELED = 10048;
+ PAYLOAD_TIMESTAMP_ERROR = 10051;
+ UPDATED_BUT_NOT_ACTIVE = 10052;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5cd717a..6960aef 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -556,10 +556,12 @@
<protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
- <protected-broadcast android:name="com.android.phone.SIP_INCOMING_CALL" />
+ <protected-broadcast android:name="android.net.sip.action.SIP_INCOMING_CALL" />
<protected-broadcast android:name="com.android.phone.SIP_ADD_PHONE" />
- <protected-broadcast android:name="com.android.phone.SIP_REMOVE_PHONE" />
- <protected-broadcast android:name="com.android.phone.SIP_CALL_OPTION_CHANGED" />
+ <protected-broadcast android:name="android.net.sip.action.SIP_REMOVE_PROFILE" />
+ <protected-broadcast android:name="android.net.sip.action.SIP_SERVICE_UP" />
+ <protected-broadcast android:name="android.net.sip.action.SIP_CALL_OPTION_CHANGED" />
+ <protected-broadcast android:name="android.net.sip.action.START_SIP" />
<protected-broadcast android:name="android.bluetooth.adapter.action.BLE_ACL_CONNECTED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED" />
@@ -2080,6 +2082,11 @@
<permission android:name="android.permission.READ_ACTIVE_EMERGENCY_SESSION"
android:protectionLevel="signature" />
+ <!-- @SystemApi Allows listen permission to always reported signal strength.
+ @hide Used internally. -->
+ <permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH"
+ android:protectionLevel="signature|telephony" />
+
<!-- @SystemApi Protects the ability to register any PhoneAccount with
PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION. This capability indicates that the PhoneAccount
corresponds to a device SIM.
@@ -2551,7 +2558,7 @@
<!-- Allows telephony to suggest the time / time zone.
<p>Not for use by third-party applications.
- @hide
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @hide
-->
<permission android:name="android.permission.SUGGEST_PHONE_TIME_AND_ZONE"
android:protectionLevel="signature|telephony" />
@@ -4693,6 +4700,19 @@
<permission android:name="android.permission.ACCESS_SHARED_LIBRARIES"
android:protectionLevel="signature|installer" />
+ <!-- Allows an app to log compat change usage.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.LOG_COMPAT_CHANGE"
+ android:protectionLevel="signature" />
+ <!-- Allows an app to read compat change config.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"
+ android:protectionLevel="signature" />
+ <!-- Allows an app to override compat change config.
+ @hide <p>Not for use by third-party applications.</p> -->
+ <permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"
+ android:protectionLevel="signature" />
+
<!-- Allows input events to be monitored. Very dangerous! @hide -->
<permission android:name="android.permission.MONITOR_INPUT"
android:protectionLevel="signature" />
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index f058985..567581e 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -165,7 +165,7 @@
<item>中文 (繁體)</item>
</string-array>
- <array name="sim_colors">
+ <array name="simColors">
<item>@color/Teal_700</item>
<item>@color/Blue_700</item>
<item>@color/Indigo_700</item>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index fb54566..8a7b515 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3021,6 +3021,10 @@
<public-group type="color" first-id="0x0106001d">
</public-group>
+ <public-group type="array" first-id="0x01070006">
+ <!-- @hide @SystemApi -->
+ <public name="simColors" />
+ </public-group>
<!-- ===============================================================
DO NOT ADD UN-GROUPED ITEMS HERE
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4aa44fc..9bc0d96 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 383fcd4..001d7c0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1303,7 +1303,7 @@
<java-symbol type="array" name="preloaded_color_state_lists" />
<java-symbol type="array" name="preloaded_drawables" />
<java-symbol type="array" name="preloaded_freeform_multi_window_drawables" />
- <java-symbol type="array" name="sim_colors" />
+ <java-symbol type="array" name="simColors" />
<java-symbol type="array" name="special_locale_codes" />
<java-symbol type="array" name="special_locale_names" />
<java-symbol type="array" name="supported_locales" />
@@ -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 0000000..a2fcef5
--- /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 e7348d5..d58d939 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/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
new file mode 100644
index 0000000..6a0a3dc
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/LocationPermissionCheckerTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.util;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.location.LocationManager;
+import android.os.Binder;
+import android.os.Build;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.HashMap;
+
+/** Unit tests for {@link LocationPermissionChecker}. */
+public class LocationPermissionCheckerTest {
+
+ public static final String TAG = "ConnectivityUtilTest";
+
+ // Mock objects for testing
+ @Mock private Context mMockContext;
+ @Mock private PackageManager mMockPkgMgr;
+ @Mock private ApplicationInfo mMockApplInfo;
+ @Mock private AppOpsManager mMockAppOps;
+ @Mock private UserManager mMockUserManager;
+ @Mock private LocationManager mLocationManager;
+
+ private static final String TEST_PKG_NAME = "com.google.somePackage";
+ private static final String TEST_FEATURE_ID = "com.google.someFeature";
+ private static final int MANAGED_PROFILE_UID = 1100000;
+ private static final int OTHER_USER_UID = 1200000;
+
+ private final String mInteractAcrossUsersFullPermission =
+ "android.permission.INTERACT_ACROSS_USERS_FULL";
+ private final String mManifestStringCoarse =
+ Manifest.permission.ACCESS_COARSE_LOCATION;
+ private final String mManifestStringFine =
+ Manifest.permission.ACCESS_FINE_LOCATION;
+
+ // Test variables
+ private int mWifiScanAllowApps;
+ private int mUid;
+ private int mCoarseLocationPermission;
+ private int mAllowCoarseLocationApps;
+ private int mFineLocationPermission;
+ private int mAllowFineLocationApps;
+ private int mCurrentUser;
+ private boolean mIsLocationEnabled;
+ private boolean mThrowSecurityException;
+ private Answer<Integer> mReturnPermission;
+ private HashMap<String, Integer> mPermissionsList = new HashMap<String, Integer>();
+ private LocationPermissionChecker mChecker;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ initTestVars();
+ }
+
+ private void setupMocks() throws Exception {
+ when(mMockPkgMgr.getApplicationInfoAsUser(eq(TEST_PKG_NAME), eq(0), any()))
+ .thenReturn(mMockApplInfo);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPkgMgr);
+ when(mMockAppOps.noteOp(AppOpsManager.OPSTR_WIFI_SCAN, mUid, TEST_PKG_NAME))
+ .thenReturn(mWifiScanAllowApps);
+ when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_COARSE_LOCATION), eq(mUid),
+ eq(TEST_PKG_NAME)))
+ .thenReturn(mAllowCoarseLocationApps);
+ when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_FINE_LOCATION), eq(mUid),
+ eq(TEST_PKG_NAME)))
+ .thenReturn(mAllowFineLocationApps);
+ if (mThrowSecurityException) {
+ doThrow(new SecurityException("Package " + TEST_PKG_NAME + " doesn't belong"
+ + " to application bound to user " + mUid))
+ .when(mMockAppOps).checkPackage(mUid, TEST_PKG_NAME);
+ }
+ when(mMockContext.getSystemService(Context.APP_OPS_SERVICE))
+ .thenReturn(mMockAppOps);
+ when(mMockContext.getSystemService(Context.USER_SERVICE))
+ .thenReturn(mMockUserManager);
+ when(mMockContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager);
+ }
+
+ private void setupTestCase() throws Exception {
+ setupMocks();
+ setupMockInterface();
+ }
+
+ private void initTestVars() {
+ mPermissionsList.clear();
+ mReturnPermission = createPermissionAnswer();
+ mWifiScanAllowApps = AppOpsManager.MODE_ERRORED;
+ mUid = OTHER_USER_UID;
+ mThrowSecurityException = true;
+ mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.M;
+ mIsLocationEnabled = false;
+ mCurrentUser = ActivityManager.getCurrentUser();
+ mCoarseLocationPermission = PackageManager.PERMISSION_DENIED;
+ mFineLocationPermission = PackageManager.PERMISSION_DENIED;
+ mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED;
+ mAllowFineLocationApps = AppOpsManager.MODE_ERRORED;
+ mChecker = new LocationPermissionChecker(mMockContext);
+ }
+
+ private void setupMockInterface() {
+ Binder.restoreCallingIdentity((((long) mUid) << 32) | Binder.getCallingPid());
+ doAnswer(mReturnPermission).when(mMockContext).checkPermission(
+ anyString(), anyInt(), anyInt());
+ when(mMockUserManager.isSameProfileGroup(UserHandle.SYSTEM.getIdentifier(),
+ UserHandle.getUserHandleForUid(MANAGED_PROFILE_UID).getIdentifier()))
+ .thenReturn(true);
+ when(mMockContext.checkPermission(mManifestStringCoarse, -1, mUid))
+ .thenReturn(mCoarseLocationPermission);
+ when(mMockContext.checkPermission(mManifestStringFine, -1, mUid))
+ .thenReturn(mFineLocationPermission);
+ when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled);
+ }
+
+ private Answer<Integer> createPermissionAnswer() {
+ return new Answer<Integer>() {
+ @Override
+ public Integer answer(InvocationOnMock invocation) {
+ int myUid = (int) invocation.getArguments()[1];
+ String myPermission = (String) invocation.getArguments()[0];
+ mPermissionsList.get(myPermission);
+ if (mPermissionsList.containsKey(myPermission)) {
+ int uid = mPermissionsList.get(myPermission);
+ if (myUid == uid) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+ }
+ return PackageManager.PERMISSION_DENIED;
+ }
+ };
+ }
+
+ @Test
+ public void testEnforceLocationPermission_HasAllPermissions_BeforeQ() throws Exception {
+ mIsLocationEnabled = true;
+ mThrowSecurityException = false;
+ mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED;
+ mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED;
+ mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
+ mUid = mCurrentUser;
+ setupTestCase();
+ mChecker.enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
+ }
+
+ @Test
+ public void testEnforceLocationPermission_HasAllPermissions_AfterQ() throws Exception {
+ mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.Q;
+ mIsLocationEnabled = true;
+ mThrowSecurityException = false;
+ mUid = mCurrentUser;
+ mFineLocationPermission = PackageManager.PERMISSION_GRANTED;
+ mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED;
+ mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
+ setupTestCase();
+ mChecker.enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null);
+ }
+
+ @Test
+ public void testEnforceLocationPermission_PkgNameAndUidMismatch() throws Exception {
+ mThrowSecurityException = true;
+ mIsLocationEnabled = true;
+ mFineLocationPermission = PackageManager.PERMISSION_GRANTED;
+ mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED;
+ mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
+ setupTestCase();
+
+ assertThrows(SecurityException.class,
+ () -> mChecker.enforceLocationPermission(
+ TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+ }
+
+ @Test
+ public void testenforceCanAccessScanResults_NoCoarseLocationPermission() throws Exception {
+ mThrowSecurityException = false;
+ mIsLocationEnabled = true;
+ setupTestCase();
+ assertThrows(SecurityException.class,
+ () -> mChecker.enforceLocationPermission(
+ TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+ }
+
+ @Test
+ public void testenforceCanAccessScanResults_NoFineLocationPermission() throws Exception {
+ mThrowSecurityException = false;
+ mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.Q;
+ mIsLocationEnabled = true;
+ mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED;
+ mAllowFineLocationApps = AppOpsManager.MODE_ERRORED;
+ mUid = MANAGED_PROFILE_UID;
+ setupTestCase();
+
+ assertThrows(SecurityException.class,
+ () -> mChecker.enforceLocationPermission(
+ TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+ verify(mMockAppOps, never()).noteOp(anyInt(), anyInt(), anyString());
+ }
+
+ @Test
+ public void testenforceCanAccessScanResults_LocationModeDisabled() throws Exception {
+ mThrowSecurityException = false;
+ mUid = MANAGED_PROFILE_UID;
+ mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED;
+ mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid);
+ mIsLocationEnabled = false;
+
+ setupTestCase();
+
+ assertThrows(SecurityException.class,
+ () -> mChecker.enforceLocationPermission(
+ TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null));
+ }
+
+ private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
+ try {
+ r.run();
+ Assert.fail("Expected " + exceptionClass + " to be thrown.");
+ } catch (Exception exception) {
+ assertTrue(exceptionClass.isInstance(exception));
+ }
+ }
+}
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 4493f3a..0d12e1f 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -43,7 +43,7 @@
prebuilt_etc {
name: "privapp_whitelist_com.android.carrierconfig",
- product_specific: true,
+ system_ext_specific: true,
sub_dir: "permissions",
src: "com.android.carrierconfig.xml",
filename_from_src: true,
@@ -67,7 +67,7 @@
prebuilt_etc {
name: "privapp_whitelist_com.android.emergency",
- product_specific: true,
+ system_ext_specific: true,
sub_dir: "permissions",
src: "com.android.emergency.xml",
filename_from_src: true,
@@ -82,7 +82,7 @@
prebuilt_etc {
name: "privapp_whitelist_com.android.launcher3",
- product_specific: true,
+ system_ext_specific: true,
sub_dir: "permissions",
src: "com.android.launcher3.xml",
filename_from_src: true,
@@ -90,7 +90,7 @@
prebuilt_etc {
name: "privapp_whitelist_com.android.provision",
- product_specific: true,
+ system_ext_specific: true,
sub_dir: "permissions",
src: "com.android.provision.xml",
filename_from_src: true,
@@ -98,7 +98,7 @@
prebuilt_etc {
name: "privapp_whitelist_com.android.settings",
- product_specific: true,
+ system_ext_specific: true,
sub_dir: "permissions",
src: "com.android.settings.xml",
filename_from_src: true,
@@ -114,7 +114,7 @@
prebuilt_etc {
name: "privapp_whitelist_com.android.storagemanager",
- product_specific: true,
+ system_ext_specific: true,
sub_dir: "permissions",
src: "com.android.storagemanager.xml",
filename_from_src: true,
@@ -122,7 +122,7 @@
prebuilt_etc {
name: "privapp_whitelist_com.android.systemui",
- product_specific: true,
+ system_ext_specific: true,
sub_dir: "permissions",
src: "com.android.systemui.xml",
filename_from_src: true,
diff --git a/data/etc/CleanSpec.mk b/data/etc/CleanSpec.mk
new file mode 100644
index 0000000..783a7ed
--- /dev/null
+++ b/data/etc/CleanSpec.mk
@@ -0,0 +1,60 @@
+# 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.carrierconfig.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.carrierconfig.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.emergency.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.emergency.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.provision.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.provision.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.settings.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.settings.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.launcher3.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.launcher3.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.systemui.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.systemui.xml)
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp
index 9272ea5..7faf4cd 100644
--- a/data/etc/car/Android.bp
+++ b/data/etc/car/Android.bp
@@ -126,5 +126,5 @@
sub_dir: "permissions",
src: "com.android.car.developeroptions.xml",
filename_from_src: true,
- product_specific: true,
+ system_ext_specific: true,
}
diff --git a/data/etc/car/CleanSpec.mk b/data/etc/car/CleanSpec.mk
new file mode 100644
index 0000000..18f7d34
--- /dev/null
+++ b/data/etc/car/CleanSpec.mk
@@ -0,0 +1,50 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.car.developeroptions.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.car.developeroptions.xml)
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index a305d48..1d73567 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -22,7 +22,6 @@
<permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
<permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/>
<permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
- <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
<permission name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"/>
<permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
<permission name="android.permission.CONTROL_VPN"/>
@@ -38,6 +37,7 @@
<permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
+ <permission name="android.permission.OBSERVE_NETWORK_POLICY"/>
<permission name="android.permission.OVERRIDE_WIFI_CONFIG"/>
<permission name="android.permission.READ_DREAM_STATE"/>
<permission name="android.permission.READ_FRAME_BUFFER"/>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index a818119..7f9a4ec 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -67,7 +67,6 @@
<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"/>
@@ -344,6 +343,9 @@
<permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
<!-- Permission required for Tethering CTS tests. -->
<permission name="android.permission.TETHER_PRIVILEGED"/>
+ <!-- Permissions required to test ambient display. -->
+ <permission name="android.permission.READ_DREAM_STATE" />
+ <permission name="android.permission.WRITE_DREAM_STATE" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
@@ -362,7 +364,6 @@
</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 0000000..e69de29
--- /dev/null
+++ b/identity/MODULE_LICENSE_APACHE2
diff --git a/identity/NOTICE b/identity/NOTICE
new file mode 100644
index 0000000..64aaa8d
--- /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 0000000..533d90b
--- /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 0000000..10e451c
--- /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 0000000..3d59450
--- /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 0000000..1933882
--- /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 0000000..e7a6c89
--- /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 0000000..c520331
--- /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 0000000..dcc6b95
--- /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 0000000..ef7afca
--- /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 0000000..335636c
--- /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 0000000..754e44a
--- /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 0000000..265f271
--- /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 0000000..bd43919
--- /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 0000000..c811380
--- /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 0000000..a1dfc77
--- /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 0000000..3f70270
--- /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 0000000..b0c073c
--- /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 0000000..7a6169e
--- /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 0000000..7f40403
--- /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 0000000..44370a1
--- /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 0000000..0982c8a
--- /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 0000000..8c24060
--- /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 0000000..f454b2c
--- /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 0000000..6eefeb8
--- /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 0000000..e2a389b
--- /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 => [ + 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/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 4c08a38..98de9c3 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -25,11 +25,6 @@
// GCC false-positives on this warning, and since we -Werror that's
// a problem
"-Wno-free-nonheap-object",
-
- // Clang is producing non-determistic binary when the new pass manager is
- // enabled. Disable the new PM as a temporary workaround.
- // b/142372146
- "-fno-experimental-new-pass-manager",
],
include_dirs: [
diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroupChangeHandler.java b/media/java/android/media/audiopolicy/AudioVolumeGroupChangeHandler.java
index 074188e..adf4d3d 100644
--- a/media/java/android/media/audiopolicy/AudioVolumeGroupChangeHandler.java
+++ b/media/java/android/media/audiopolicy/AudioVolumeGroupChangeHandler.java
@@ -157,9 +157,7 @@
Handler handler = eventHandler.handler();
if (handler != null) {
Message m = handler.obtainMessage(what, arg1, arg2, obj);
- if (what != AUDIOVOLUMEGROUP_EVENT_NEW_LISTENER) {
- handler.removeMessages(what);
- }
+ // Do not remove previous messages, as we would lose notification of group changes
handler.sendMessage(m);
}
}
diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
index 56e5566..77596a5 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
@@ -22,7 +22,7 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index ada77c5..3f0aec6 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -23,7 +23,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.hardware.soundtrigger.SoundTrigger;
diff --git a/media/java/android/media/tv/DvbDeviceInfo.java b/media/java/android/media/tv/DvbDeviceInfo.java
index 96c8528..54fc39e 100644
--- a/media/java/android/media/tv/DvbDeviceInfo.java
+++ b/media/java/android/media/tv/DvbDeviceInfo.java
@@ -16,6 +16,7 @@
package android.media.tv;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
@@ -23,9 +24,13 @@
import android.util.Log;
/**
- * Simple container for information about DVB device.
- * Not for third-party developers.
+ * A digital video broadcasting (DVB) device.
*
+ * <p> Simple wrapper around a <a href="https://www.linuxtv.org/docs/dvbapi/dvbapi.html">Linux DVB
+ * v3</a> device.
+ *
+ * @see TvInputManager#getDvbDeviceList()
+ * @see TvInputManager#openDvbDevice(DvbDeviceInfo, int)
* @hide
*/
@SystemApi
@@ -67,17 +72,19 @@
}
/**
- * Returns the adapter ID of DVB device, in terms of enumerating the DVB device adapters
- * installed in the system. The adapter ID counts from zero.
+ * Returns the adapter ID.
+ *
+ * <p>DVB Adapters contain one or more devices.
*/
+ @IntRange(from = 0)
public int getAdapterId() {
return mAdapterId;
}
/**
- * Returns the device ID of DVB device, in terms of enumerating the DVB devices attached to
- * the same device adapter. The device ID counts from zero.
+ * Returns the device ID.
*/
+ @IntRange(from = 0)
public int getDeviceId() {
return mDeviceId;
}
diff --git a/media/java/android/media/tv/TvContentRating.java b/media/java/android/media/tv/TvContentRating.java
index 6197c70..5babb16 100644
--- a/media/java/android/media/tv/TvContentRating.java
+++ b/media/java/android/media/tv/TvContentRating.java
@@ -17,7 +17,6 @@
package android.media.tv;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.text.TextUtils;
import com.android.internal.util.Preconditions;
@@ -179,6 +178,10 @@
* <td>TV content rating system for Canada (French)</td>
* </tr>
* <tr>
+ * <td>DTMB</td>
+ * <td>DTMB content rating system</td>
+ * </tr>
+ * <tr>
* <td>DVB</td>
* <td>DVB content rating system</td>
* </tr>
@@ -199,10 +202,18 @@
* <td>TV content rating system for South Korea</td>
* </tr>
* <tr>
+ * <td>NZ_TV</td>
+ * <td>TV content rating system for New Zealand</td>
+ * </tr>
+ * <tr>
* <td>SG_TV</td>
* <td>TV content rating system for Singapore</td>
* </tr>
* <tr>
+ * <td>TH_TV</td>
+ * <td>TV content rating system for Thailand</td>
+ * </tr>
+ * <tr>
* <td>US_MV</td>
* <td>Movie content rating system for the United States</td>
* </tr>
@@ -356,6 +367,67 @@
* <td>Only to be viewed by adults</td>
* </tr>
* <tr>
+ * <td valign="top" rowspan="15">DTMB</td>
+ * <td>DTMB_4</td>
+ * <td>Recommended for ages 4 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_5</td>
+ * <td>Recommended for ages 5 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_6</td>
+ * <td>Recommended for ages 6 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_7</td>
+ * <td>Recommended for ages 7 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_8</td>
+ * <td>Recommended for ages 8 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_9</td>
+ * <td>Recommended for ages 9 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_10</td>
+ * <td>Recommended for ages 10 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_11</td>
+ * <td>Recommended for ages 11 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_12</td>
+ * <td>Recommended for ages 12 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_13</td>
+ * <td>Recommended for ages 13 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_14</td>
+ * <td>Recommended for ages 14 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_15</td>
+ * <td>Recommended for ages 15 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_16</td>
+ * <td>Recommended for ages 16 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_17</td>
+ * <td>Recommended for ages 17 and over</td>
+ * </tr>
+ * <tr>
+ * <td>DTMB_18</td>
+ * <td>Recommended for ages 18 and over</td>
+ * </tr>
+ * <tr>
* <td valign="top" rowspan="15">DVB</td>
* <td>DVB_4</td>
* <td>Recommended for ages 4 and over</td>
@@ -648,6 +720,22 @@
* <td>For adults only</td>
* </tr>
* <tr>
+ * <td valign="top" rowspan="3">NZ_TV</td>
+ * <td>NZ_TV_G</td>
+ * <td>Programmes which exclude material likely to be unsuitable for children. Programmes
+ * may not necessarily be designed for child viewers but should not contain material likely
+ * to alarm or distress them</td>
+ * </tr>
+ * <tr>
+ * <td>NZ_TV_PGR</td>
+ * <td>Programmes containing material more suited for mature audiences but not necessarily
+ * unsuitable for child viewers when subject to the guidance of a parent or an adult</td>
+ * </tr>
+ * <tr>
+ * <td>NZ_TV_AO</td>
+ * <td>Programmes containing adult themes and directed primarily at mature audiences</td>
+ * </tr>
+ * <tr>
* <td valign="top" rowspan="6">SG_TV</td>
* <td>SG_TV_G</td>
* <td>Suitable for all ages</td>
@@ -674,6 +762,31 @@
* <td>Suitable for adults aged 21 and above</td>
* </tr>
* <tr>
+ * <td valign="top" rowspan="6">TH_TV</td>
+ * <td>TH_TV_4</td>
+ * <td>Suitable for audiences 3 to 5 years of age</td>
+ * </tr>
+ * <tr>
+ * <td>TH_TV_6</td>
+ * <td>Suitable for audiences 6 to 12 years of age</td>
+ * </tr>
+ * <tr>
+ * <td>TH_TV_10</td>
+ * <td>Suitable for all audiences</td>
+ * </tr>
+ * <tr>
+ * <td>TH_TV_13</td>
+ * <td>Parental guidance suggested for viewers age below 13</td>
+ * </tr>
+ * <tr>
+ * <td>TH_TV_18</td>
+ * <td>Parental guidance suggested for viewers age below 18</td>
+ * </tr>
+ * <tr>
+ * <td>TH_TV_19</td>
+ * <td>Not suitable for children and teenagers</td>
+ * </tr>
+ * <tr>
* <td valign="top" rowspan="5">US_MV</td>
* <td>US_MV_G</td>
* <td>General audiences</td>
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 1b9cac0..377b2bc 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -20,7 +20,7 @@
import android.annotation.NonNull;
import android.annotation.StringRes;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 854ea43..ed4fe4b 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -1664,7 +1664,7 @@
}
/**
- * Returns the list of currently available DVB devices on the system.
+ * Returns the list of currently available DVB frontend devices on the system.
*
* @return the list of {@link DvbDeviceInfo} objects representing available DVB devices.
* @hide
@@ -1681,16 +1681,17 @@
}
/**
- * Returns a {@link ParcelFileDescriptor} of a specified DVB device for a given
- * {@link DvbDeviceInfo}
+ * Returns a {@link ParcelFileDescriptor} of a specified DVB device of a given type for a given
+ * {@link DvbDeviceInfo}.
*
* @param info A {@link DvbDeviceInfo} to open a DVB device.
- * @param deviceType A DVB device type. The type can be {@link #DVB_DEVICE_DEMUX},
- * {@link #DVB_DEVICE_DVR} or {@link #DVB_DEVICE_FRONTEND}.
+ * @param deviceType A DVB device type.
* @return a {@link ParcelFileDescriptor} of a specified DVB device for a given
- * {@link DvbDeviceInfo}, or {@code null} if the given {@link DvbDeviceInfo}
- * failed to open.
+ * {@link DvbDeviceInfo}, or {@code null} if the given {@link DvbDeviceInfo}
+ * failed to open.
* @throws IllegalArgumentException if {@code deviceType} is invalid or the device is not found.
+
+ * @see <a href="https://www.linuxtv.org/docs/dvbapi/dvbapi.html">Linux DVB API v3</a>
* @hide
*/
@SystemApi
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 5c11ed9b..7fbb337 100755
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -22,9 +22,9 @@
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
import android.app.ActivityManager;
import android.app.Service;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index 4318a0a..d4c4a62 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -352,8 +352,7 @@
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 @@
@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/media/java/android/mtp/MtpPropertyList.java b/media/java/android/mtp/MtpPropertyList.java
index 557f099..53d838d 100644
--- a/media/java/android/mtp/MtpPropertyList.java
+++ b/media/java/android/mtp/MtpPropertyList.java
@@ -16,7 +16,8 @@
package android.mtp;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
import java.util.ArrayList;
import java.util.List;
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index 65d0fef..d385816 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -16,7 +16,7 @@
package android.mtp;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.storage.StorageVolume;
import android.provider.MediaStore;
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 86a1076..06adf30 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -21,8 +21,8 @@
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.UnsupportedAppUsage;
import android.app.Service;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
diff --git a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java
index dfbf5d2..121443f 100644
--- a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java
+++ b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java
@@ -17,12 +17,11 @@
package android.media.effect;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.filterfw.core.Filter;
import android.filterfw.core.FilterFactory;
import android.filterfw.core.FilterFunction;
import android.filterfw.core.Frame;
-import android.media.effect.EffectContext;
/**
* Effect subclass for effects based on a single Filter. Subclasses need only invoke the
diff --git a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
index 52615bf..3a7f1ed 100644
--- a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
+++ b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
@@ -17,11 +17,11 @@
package android.filterfw;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.filterfw.core.AsyncRunner;
-import android.filterfw.core.FilterGraph;
import android.filterfw.core.FilterContext;
+import android.filterfw.core.FilterGraph;
import android.filterfw.core.FrameManager;
import android.filterfw.core.GraphRunner;
import android.filterfw.core.RoundRobinScheduler;
diff --git a/media/mca/filterfw/java/android/filterfw/core/Filter.java b/media/mca/filterfw/java/android/filterfw/core/Filter.java
index 4f56b92..a608ef5 100644
--- a/media/mca/filterfw/java/android/filterfw/core/Filter.java
+++ b/media/mca/filterfw/java/android/filterfw/core/Filter.java
@@ -17,19 +17,15 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.FilterContext;
-import android.filterfw.core.FilterPort;
-import android.filterfw.core.KeyValueMap;
-import android.filterfw.io.TextGraphReader;
-import android.filterfw.io.GraphIOException;
+import android.compat.annotation.UnsupportedAppUsage;
import android.filterfw.format.ObjectFormat;
+import android.filterfw.io.GraphIOException;
+import android.filterfw.io.TextGraphReader;
import android.util.Log;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
-import java.lang.Thread;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterContext.java b/media/mca/filterfw/java/android/filterfw/core/FilterContext.java
index a19220e..6b0a219 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FilterContext.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FilterContext.java
@@ -17,11 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.Filter;
-import android.filterfw.core.Frame;
-import android.filterfw.core.FrameManager;
-import android.filterfw.core.GLEnvironment;
+import android.compat.annotation.UnsupportedAppUsage;
import java.util.HashMap;
import java.util.HashSet;
diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java b/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java
index e6ca11f..35a298f 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java
@@ -17,6 +17,11 @@
package android.filterfw.core;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.filterpacks.base.FrameBranch;
+import android.filterpacks.base.NullFilter;
+import android.util.Log;
+
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -25,14 +30,6 @@
import java.util.Set;
import java.util.Stack;
-import android.filterfw.core.FilterContext;
-import android.filterfw.core.KeyValueMap;
-import android.filterpacks.base.FrameBranch;
-import android.filterpacks.base.NullFilter;
-
-import android.annotation.UnsupportedAppUsage;
-import android.util.Log;
-
/**
* @hide
*/
diff --git a/media/mca/filterfw/java/android/filterfw/core/Frame.java b/media/mca/filterfw/java/android/filterfw/core/Frame.java
index e880783..c4d935a 100644
--- a/media/mca/filterfw/java/android/filterfw/core/Frame.java
+++ b/media/mca/filterfw/java/android/filterfw/core/Frame.java
@@ -17,9 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.FrameFormat;
-import android.filterfw.core.FrameManager;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Bitmap;
import java.nio.ByteBuffer;
diff --git a/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java b/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java
index eb0ff0a..a87e9b9 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java
@@ -17,9 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.KeyValueMap;
-import android.filterfw.core.MutableFrameFormat;
+import android.compat.annotation.UnsupportedAppUsage;
import java.util.Arrays;
import java.util.Map.Entry;
diff --git a/media/mca/filterfw/java/android/filterfw/core/FrameManager.java b/media/mca/filterfw/java/android/filterfw/core/FrameManager.java
index 85c8fcd..e49aaf1 100644
--- a/media/mca/filterfw/java/android/filterfw/core/FrameManager.java
+++ b/media/mca/filterfw/java/android/filterfw/core/FrameManager.java
@@ -17,10 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.Frame;
-import android.filterfw.core.FrameFormat;
-import android.filterfw.core.MutableFrameFormat;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* @hide
diff --git a/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java b/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java
index e25d6a7..7e4e8a6 100644
--- a/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java
+++ b/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java
@@ -17,13 +17,12 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.NativeAllocatorTag;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.SurfaceTexture;
+import android.media.MediaRecorder;
import android.os.Looper;
import android.util.Log;
import android.view.Surface;
-import android.media.MediaRecorder;
/**
* @hide
diff --git a/media/mca/filterfw/java/android/filterfw/core/GLFrame.java b/media/mca/filterfw/java/android/filterfw/core/GLFrame.java
index 9e3025f..1ccd7fe 100644
--- a/media/mca/filterfw/java/android/filterfw/core/GLFrame.java
+++ b/media/mca/filterfw/java/android/filterfw/core/GLFrame.java
@@ -17,15 +17,10 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.Frame;
-import android.filterfw.core.FrameFormat;
-import android.filterfw.core.FrameManager;
-import android.filterfw.core.NativeFrame;
-import android.filterfw.core.StopWatchMap;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Bitmap;
-import android.opengl.GLES20;
import android.graphics.Rect;
+import android.opengl.GLES20;
import java.nio.ByteBuffer;
diff --git a/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java b/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java
index 250cfaa..b57e8bb 100644
--- a/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java
+++ b/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java
@@ -17,7 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* @hide
diff --git a/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java b/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java
index ae2ad99..da00b1f 100644
--- a/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java
+++ b/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java
@@ -17,9 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.FrameFormat;
-import android.filterfw.core.KeyValueMap;
+import android.compat.annotation.UnsupportedAppUsage;
import java.util.Arrays;
diff --git a/media/mca/filterfw/java/android/filterfw/core/Program.java b/media/mca/filterfw/java/android/filterfw/core/Program.java
index 376c085..145388e 100644
--- a/media/mca/filterfw/java/android/filterfw/core/Program.java
+++ b/media/mca/filterfw/java/android/filterfw/core/Program.java
@@ -17,8 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.Frame;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* @hide
diff --git a/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java b/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java
index f41636e..e043be0 100644
--- a/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java
+++ b/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java
@@ -17,12 +17,7 @@
package android.filterfw.core;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.core.Frame;
-import android.filterfw.core.NativeAllocatorTag;
-import android.filterfw.core.Program;
-import android.filterfw.core.StopWatchMap;
-import android.filterfw.core.VertexFrame;
+import android.compat.annotation.UnsupportedAppUsage;
import android.filterfw.geometry.Quad;
import android.opengl.GLES20;
diff --git a/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java b/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java
index ac08730..0e05092 100644
--- a/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java
+++ b/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java
@@ -17,7 +17,7 @@
package android.filterfw.format;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.filterfw.core.FrameFormat;
import android.filterfw.core.MutableFrameFormat;
import android.graphics.Bitmap;
diff --git a/media/mca/filterfw/java/android/filterfw/geometry/Point.java b/media/mca/filterfw/java/android/filterfw/geometry/Point.java
index d7acf12..96d2d7b 100644
--- a/media/mca/filterfw/java/android/filterfw/geometry/Point.java
+++ b/media/mca/filterfw/java/android/filterfw/geometry/Point.java
@@ -17,8 +17,7 @@
package android.filterfw.geometry;
-import android.annotation.UnsupportedAppUsage;
-import java.lang.Math;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* @hide
diff --git a/media/mca/filterfw/java/android/filterfw/geometry/Quad.java b/media/mca/filterfw/java/android/filterfw/geometry/Quad.java
index 610e5b8..2b308a9 100644
--- a/media/mca/filterfw/java/android/filterfw/geometry/Quad.java
+++ b/media/mca/filterfw/java/android/filterfw/geometry/Quad.java
@@ -17,10 +17,8 @@
package android.filterfw.geometry;
-import android.annotation.UnsupportedAppUsage;
-import android.filterfw.geometry.Point;
+import android.compat.annotation.UnsupportedAppUsage;
-import java.lang.Float;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
diff --git a/opengl/java/android/opengl/EGL14.java b/opengl/java/android/opengl/EGL14.java
index 728e6e1..90b46fd 100644
--- a/opengl/java/android/opengl/EGL14.java
+++ b/opengl/java/android/opengl/EGL14.java
@@ -18,11 +18,11 @@
package android.opengl;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.SurfaceTexture;
import android.view.Surface;
-import android.view.SurfaceView;
import android.view.SurfaceHolder;
+import android.view.SurfaceView;
/**
* EGL 1.4
diff --git a/opengl/java/android/opengl/GLES20.java b/opengl/java/android/opengl/GLES20.java
index d66e7ac..e853e44 100644
--- a/opengl/java/android/opengl/GLES20.java
+++ b/opengl/java/android/opengl/GLES20.java
@@ -19,7 +19,7 @@
package android.opengl;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/** OpenGL ES 2.0
*/
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 8a3e6a0..75131b0 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -16,7 +16,7 @@
package android.opengl;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Trace;
import android.util.AttributeSet;
diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java
index f94f69f..b4ea0a6 100644
--- a/opengl/java/com/google/android/gles_jni/EGLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java
@@ -16,13 +16,12 @@
package com.google.android.gles_jni;
+import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.SurfaceTexture;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
diff --git a/opengl/java/com/google/android/gles_jni/GLImpl.java b/opengl/java/com/google/android/gles_jni/GLImpl.java
index 2a8d07f..3c808a6 100644
--- a/opengl/java/com/google/android/gles_jni/GLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/GLImpl.java
@@ -20,14 +20,13 @@
package com.google.android.gles_jni;
import android.app.AppGlobals;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.os.Build;
import android.os.UserHandle;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.nio.Buffer;
import javax.microedition.khronos.opengles.GL10;
diff --git a/opengl/java/javax/microedition/khronos/egl/EGL10.java b/opengl/java/javax/microedition/khronos/egl/EGL10.java
index 8a25170..ea571c7 100644
--- a/opengl/java/javax/microedition/khronos/egl/EGL10.java
+++ b/opengl/java/javax/microedition/khronos/egl/EGL10.java
@@ -16,8 +16,7 @@
package javax.microedition.khronos.egl;
-import android.annotation.UnsupportedAppUsage;
-import java.lang.String;
+import android.compat.annotation.UnsupportedAppUsage;
public interface EGL10 extends EGL {
int EGL_SUCCESS = 0x3000;
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 672879a..68da999 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -82,7 +82,7 @@
],
platform_apis: true,
- product_specific: true,
+ system_ext_specific: true,
certificate: "platform",
privileged: true,
diff --git a/packages/CarSystemUI/CleanSpec.mk b/packages/CarSystemUI/CleanSpec.mk
new file mode 100644
index 0000000..ceac67c
--- /dev/null
+++ b/packages/CarSystemUI/CleanSpec.mk
@@ -0,0 +1,50 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/priv-app/CarSystemUI)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/priv-app/CarSystemUI)
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index c2ce840..9ccb837 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -56,6 +56,7 @@
import android.os.RemoteException;
import android.os.image.DynamicSystemClient;
import android.os.image.DynamicSystemManager;
+import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
@@ -74,6 +75,8 @@
// TODO (b/131866826): This is currently for test only. Will move this to System API.
static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED";
+ static final String KEY_DSU_SLOT = "KEY_DSU_SLOT";
+ static final String DEFAULT_DSU_SLOT = "dsu";
/*
* Intent actions
@@ -244,10 +247,15 @@
long systemSize = intent.getLongExtra(DynamicSystemClient.KEY_SYSTEM_SIZE, 0);
long userdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0);
mEnableWhenCompleted = intent.getBooleanExtra(KEY_ENABLE_WHEN_COMPLETED, false);
+ String dsuSlot = intent.getStringExtra(KEY_DSU_SLOT);
+ if (TextUtils.isEmpty(dsuSlot)) {
+ dsuSlot = DEFAULT_DSU_SLOT;
+ }
// TODO: better constructor or builder
- mInstallTask = new InstallationAsyncTask(
- url, systemSize, userdataSize, this, mDynSystem, this);
+ mInstallTask =
+ new InstallationAsyncTask(
+ url, dsuSlot, systemSize, userdataSize, this, mDynSystem, this);
mInstallTask.execute();
@@ -409,7 +417,9 @@
break;
case STATUS_READY:
- builder.setContentText(getString(R.string.notification_install_completed));
+ String msgCompleted = getString(R.string.notification_install_completed);
+ builder.setContentText(msgCompleted)
+ .setStyle(new Notification.BigTextStyle().bigText(msgCompleted));
builder.addAction(new Notification.Action.Builder(
null, getString(R.string.notification_action_discard),
@@ -422,7 +432,9 @@
break;
case STATUS_IN_USE:
- builder.setContentText(getString(R.string.notification_dynsystem_in_use));
+ String msgInUse = getString(R.string.notification_dynsystem_in_use);
+ builder.setContentText(msgInUse)
+ .setStyle(new Notification.BigTextStyle().bigText(msgInUse));
builder.addAction(new Notification.Action.Builder(
null, getString(R.string.notification_action_uninstall),
@@ -452,7 +464,49 @@
}
private void postStatus(int status, int cause, Throwable detail) {
- Log.d(TAG, "postStatus(): statusCode=" + status + ", causeCode=" + cause);
+ String statusString;
+ String causeString;
+
+ switch (status) {
+ case STATUS_NOT_STARTED:
+ statusString = "NOT_STARTED";
+ break;
+ case STATUS_IN_PROGRESS:
+ statusString = "IN_PROGRESS";
+ break;
+ case STATUS_READY:
+ statusString = "READY";
+ break;
+ case STATUS_IN_USE:
+ statusString = "IN_USE";
+ break;
+ default:
+ statusString = "UNKNOWN";
+ break;
+ }
+
+ switch (cause) {
+ case CAUSE_INSTALL_COMPLETED:
+ causeString = "INSTALL_COMPLETED";
+ break;
+ case CAUSE_INSTALL_CANCELLED:
+ causeString = "INSTALL_CANCELLED";
+ break;
+ case CAUSE_ERROR_IO:
+ causeString = "ERROR_IO";
+ break;
+ case CAUSE_ERROR_INVALID_URL:
+ causeString = "ERROR_INVALID_URL";
+ break;
+ case CAUSE_ERROR_EXCEPTION:
+ causeString = "ERROR_EXCEPTION";
+ break;
+ default:
+ causeString = "CAUSE_NOT_SPECIFIED";
+ break;
+ }
+
+ Log.d(TAG, "status=" + statusString + ", cause=" + causeString);
boolean notifyOnNotificationBar = true;
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index b206a1f..9aea0e7 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -89,10 +89,12 @@
interface ProgressListener {
void onProgressUpdate(Progress progress);
+
void onResult(int resultCode, Throwable detail);
}
private final String mUrl;
+ private final String mDsuSlot;
private final long mSystemSize;
private final long mUserdataSize;
private final Context mContext;
@@ -106,9 +108,16 @@
private InputStream mStream;
private ZipFile mZipFile;
- InstallationAsyncTask(String url, long systemSize, long userdataSize, Context context,
- DynamicSystemManager dynSystem, ProgressListener listener) {
+ InstallationAsyncTask(
+ String url,
+ String dsuSlot,
+ long systemSize,
+ long userdataSize,
+ Context context,
+ DynamicSystemManager dynSystem,
+ ProgressListener listener) {
mUrl = url;
+ mDsuSlot = dsuSlot;
mSystemSize = systemSize;
mUserdataSize = userdataSize;
mContext = context;
@@ -126,14 +135,17 @@
verifyAndPrepare();
- mDynSystem.startInstallation();
+ mDynSystem.startInstallation(mDsuSlot);
installUserdata();
if (isCancelled()) {
mDynSystem.remove();
return null;
}
-
+ if (mUrl == null) {
+ mDynSystem.finishInstallation();
+ return null;
+ }
installImages();
if (isCancelled()) {
mDynSystem.remove();
@@ -194,6 +206,9 @@
}
private void verifyAndPrepare() throws Exception {
+ if (mUrl == null) {
+ return;
+ }
String extension = mUrl.substring(mUrl.lastIndexOf('.') + 1);
if ("gz".equals(extension) || "gzip".equals(extension)) {
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
index 3b3933b..e42ded7 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java
@@ -28,11 +28,9 @@
import android.util.FeatureFlagUtils;
import android.util.Log;
-
/**
- * This Activity starts KeyguardManager and ask the user to confirm
- * before any installation request. If the device is not protected by
- * a password, it approves the request by default.
+ * This Activity starts KeyguardManager and ask the user to confirm before any installation request.
+ * If the device is not protected by a password, it approves the request by default.
*/
public class VerificationActivity extends Activity {
@@ -88,11 +86,15 @@
Uri url = callingIntent.getData();
Bundle extras = callingIntent.getExtras();
- sVerifiedUrl = url.toString();
+ if (url != null) {
+ sVerifiedUrl = url.toString();
+ }
// start service
Intent intent = new Intent(this, DynamicSystemInstallationService.class);
- intent.setData(url);
+ if (url != null) {
+ intent.setData(url);
+ }
intent.setAction(DynamicSystemClient.ACTION_START_INSTALL);
intent.putExtras(extras);
@@ -106,6 +108,7 @@
}
static boolean isVerified(String url) {
+ if (url == null) return true;
return sVerifiedUrl != null && sVerifiedUrl.equals(url);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index abfee1d..9765074 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 @@
}
}
+ /**
+ * 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 @@
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 @@
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 @@
*/
if (!mProfiles.isEmpty()
&& ((mConnectAttempted + timeout) > SystemClock.elapsedRealtime())) {
- connectWithoutResettingTimer(false);
+ connectAllEnabledProfiles();
}
dispatchAttributesChanged();
@@ -644,7 +630,7 @@
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 4e16c66..56b14c6 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 @@
final CachedBluetoothDevice cachedDevice =
((BluetoothMediaDevice) device).getCachedDevice();
if (!cachedDevice.isConnected() && !cachedDevice.isBusy()) {
- cachedDevice.connect(true);
+ cachedDevice.connect();
return;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index b11585a..8bd5f57f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -90,7 +90,7 @@
public void setListening(boolean listening) {
if (listening) {
mNetworkScoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
- mWifiNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK);
+ mWifiNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK);
mWifiNetworkScoreCache.registerListener(mCacheListener);
mConnectivityManager.registerNetworkCallback(
mNetworkRequest, mNetworkCallback, mHandler);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 3e359d2..f713139 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -359,7 +359,7 @@
mNetworkScoreManager.registerNetworkScoreCache(
NetworkKey.TYPE_WIFI,
mScoreCache,
- NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS);
+ NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS);
}
private void requestScoresForNetworkKeys(Collection<NetworkKey> keys) {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/OWNER b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/OWNER
new file mode 100644
index 0000000..5c2a7b8
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/OWNER
@@ -0,0 +1,4 @@
+# People who can approve changes for submission
+arcwang@google.com
+govenliu@google.com
+qal@google.com
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 98bb74a..4b9f6c2 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 @@
mLocalMediaManager.registerCallback(mCallback);
mLocalMediaManager.connectDevice(device);
- verify(cachedDevice).connect(true);
+ verify(cachedDevice).connect();
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/OWNER b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/OWNER
new file mode 100644
index 0000000..5c2a7b8
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/OWNER
@@ -0,0 +1,4 @@
+# People who can approve changes for submission
+arcwang@google.com
+govenliu@google.com
+qal@google.com
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index af2569d..5a5a757 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -108,6 +108,7 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.CREATE_USERS" />
@@ -219,6 +220,10 @@
<!-- Permission required for CTS test - TetheringManagerTest -->
<uses-permission android:name="android.permission.TETHER_PRIVILEGED"/>
+ <!-- Permissions required to test ambient display. -->
+ <uses-permission android:name="android.permission.READ_DREAM_STATE"/>
+ <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index d674be4..dbfaca0 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -142,7 +142,7 @@
resource_dirs: [],
platform_apis: true,
- product_specific: true,
+ system_ext_specific: true,
certificate: "platform",
privileged: true,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 403e894..262365d 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -72,7 +72,7 @@
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
<uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
diff --git a/packages/SystemUI/CleanSpec.mk b/packages/SystemUI/CleanSpec.mk
new file mode 100644
index 0000000..2a2e4e4
--- /dev/null
+++ b/packages/SystemUI/CleanSpec.mk
@@ -0,0 +1,50 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/priv-app/SystemUI)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/priv-app/SystemUI)
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 8631e86..d330732 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -19,16 +19,12 @@
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
import static android.telephony.PhoneStateListener.LISTEN_NONE;
-import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
-
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.Handler;
-import android.os.SystemProperties;
-import android.telephony.CarrierConfigManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
@@ -37,20 +33,18 @@
import android.text.TextUtils;
import android.util.Log;
-import androidx.annotation.VisibleForTesting;
-
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
import com.android.settingslib.WirelessUtils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.keyguard.WakefulnessLifecycle;
-import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import androidx.annotation.VisibleForTesting;
+
/**
* Controller that generates text including the carrier names and/or the status of all the SIM
* interfaces in the device. Through a callback, the updates can be retrieved either as a list or
@@ -73,8 +67,6 @@
private Context mContext;
private CharSequence mSeparator;
private WakefulnessLifecycle mWakefulnessLifecycle;
- @VisibleForTesting
- protected boolean mDisplayOpportunisticSubscriptionCarrierText;
private final WakefulnessLifecycle.Observer mWakefulnessObserver =
new WakefulnessLifecycle.Observer() {
@Override
@@ -173,9 +165,6 @@
mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
mSimSlotsNumber = getTelephonyManager().getSupportedModemCount();
mSimErrorState = new boolean[mSimSlotsNumber];
- updateDisplayOpportunisticSubscriptionCarrierText(SystemProperties.getBoolean(
- TelephonyProperties.DISPLAY_OPPORTUNISTIC_SUBSCRIPTION_CARRIER_TEXT_PROPERTY_NAME,
- false));
}
private TelephonyManager getTelephonyManager() {
@@ -255,63 +244,8 @@
}
}
- /**
- * @param subscriptions
- */
- private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) {
- if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) {
- SubscriptionInfo info1 = subscriptions.get(0);
- SubscriptionInfo info2 = subscriptions.get(1);
- if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
- // If both subscriptions are primary, show both.
- if (!info1.isOpportunistic() && !info2.isOpportunistic()) return;
-
- // If carrier required, always show signal bar of primary subscription.
- // Otherwise, show whichever subscription is currently active for Internet.
- boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig()
- .getBoolean(CarrierConfigManager
- .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN);
- if (alwaysShowPrimary) {
- subscriptions.remove(info1.isOpportunistic() ? info1 : info2);
- } else {
- subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription
- ? info2 : info1);
- }
-
- }
- }
- }
-
- /**
- * updates if opportunistic sub carrier text should be displayed or not
- *
- */
- @VisibleForTesting
- public void updateDisplayOpportunisticSubscriptionCarrierText(boolean isEnable) {
- mDisplayOpportunisticSubscriptionCarrierText = isEnable;
- }
-
protected List<SubscriptionInfo> getSubscriptionInfo() {
- List<SubscriptionInfo> subs;
- if (mDisplayOpportunisticSubscriptionCarrierText) {
- SubscriptionManager subscriptionManager = ((SubscriptionManager) mContext
- .getSystemService(
- Context.TELEPHONY_SUBSCRIPTION_SERVICE));
- subs = subscriptionManager.getActiveSubscriptionInfoList(false);
- if (subs == null) {
- subs = new ArrayList<>();
- } else {
- filterMobileSubscriptionInSameGroup(subs);
- }
- } else {
- subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
- if (subs == null) {
- subs = new ArrayList<>();
- } else {
- filterMobileSubscriptionInSameGroup(subs);
- }
- }
- return subs;
+ return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
}
protected void updateCarrierText() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 8d858dc..0ede50d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -30,6 +30,7 @@
import static android.os.BatteryManager.EXTRA_STATUS;
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
+import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -77,6 +78,7 @@
import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
+import android.telephony.CarrierConfigManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
@@ -257,6 +259,7 @@
private boolean mLogoutEnabled;
// If the user long pressed the lock icon, disabling face auth for the current session.
private boolean mLockIconPressed;
+ private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
/**
* Short delay before restarting biometric authentication after a successful try
@@ -392,9 +395,11 @@
}
};
- private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+ @VisibleForTesting
+ public PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
public void onActiveDataSubscriptionIdChanged(int subId) {
+ mActiveMobileDataSubscription = subId;
mHandler.sendEmptyMessage(MSG_SIM_SUBSCRIPTION_INFO_CHANGED);
}
};
@@ -496,7 +501,9 @@
}
}
- /** @return List of SubscriptionInfo records, maybe empty but never null */
+ /**
+ * @return List of SubscriptionInfo records, maybe empty but never null.
+ */
public List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
List<SubscriptionInfo> sil = mSubscriptionInfo;
if (sil == null || forceReload) {
@@ -508,7 +515,42 @@
} else {
mSubscriptionInfo = sil;
}
- return mSubscriptionInfo;
+ return new ArrayList<>(mSubscriptionInfo);
+ }
+
+ /**
+ * This method returns filtered list of SubscriptionInfo from {@link #getSubscriptionInfo}.
+ * above. Maybe empty but never null.
+ *
+ * In DSDS mode if both subscriptions are grouped and one is opportunistic, we filter out one
+ * of them based on carrier config. e.g. In this case we should only show one carrier name
+ * on the status bar and quick settings.
+ */
+ public List<SubscriptionInfo> getFilteredSubscriptionInfo(boolean forceReload) {
+ List<SubscriptionInfo> subscriptions = getSubscriptionInfo(false);
+ if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) {
+ SubscriptionInfo info1 = subscriptions.get(0);
+ SubscriptionInfo info2 = subscriptions.get(1);
+ if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
+ // If both subscriptions are primary, show both.
+ if (!info1.isOpportunistic() && !info2.isOpportunistic()) return subscriptions;
+
+ // If carrier required, always show signal bar of primary subscription.
+ // Otherwise, show whichever subscription is currently active for Internet.
+ boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig()
+ .getBoolean(CarrierConfigManager
+ .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN);
+ if (alwaysShowPrimary) {
+ subscriptions.remove(info1.isOpportunistic() ? info1 : info2);
+ } else {
+ subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription
+ ? info2 : info1);
+ }
+
+ }
+ }
+
+ return subscriptions;
}
@Override
@@ -1061,7 +1103,7 @@
// 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();
@@ -2637,6 +2679,7 @@
pw.println(" " + mSubscriptionInfo.get(i));
}
}
+ pw.println(" Current active data subId=" + mActiveMobileDataSubscription);
pw.println(" Service states:");
for (int subId : mServiceStates.keySet()) {
pw.println(" " + subId + "=" + mServiceStates.get(subId));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
index d1b3c3c..2a5ccdb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
@@ -134,7 +134,7 @@
private void updateText() {
CharSequence displayText = null;
- List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
+ List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
final int N = subs.size();
for (int i = 0; i < N; i++) {
int subId = subs.get(i).getSubscriptionId();
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 17c200e..b2f4f16 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 @@
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/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
index 0d6178b..f2c0434 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
@@ -97,7 +97,7 @@
boolean allSimsMissing = true;
CharSequence displayText = null;
- List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
+ List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
final int N = subs.size();
for (int i = 0; i < N; i++) {
int subId = subs.get(i).getSubscriptionId();
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 7a09455..4523374 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 @@
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/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index efb4ff0..a897b00 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -35,7 +35,6 @@
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_VR_MANAGER" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.REQUEST_NETWORK_SCORES" />
<uses-permission android:name="android.permission.CONTROL_VPN" />
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index 4d9ea29..5a8ff4b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -19,7 +19,7 @@
import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
import static android.telephony.SubscriptionManager.DATA_ROAMING_ENABLE;
-import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE;
+import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT;
import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertFalse;
@@ -77,21 +77,16 @@
private static final CharSequence AIRPLANE_MODE_TEXT = "Airplane mode";
private static final String TEST_CARRIER = "TEST_CARRIER";
private static final String TEST_CARRIER_2 = "TEST_CARRIER_2";
- private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24";
private static final int TEST_CARRIER_ID = 1;
private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(0, "", 0,
- TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
- DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, TEST_GROUP_UUID,
- TEST_CARRIER_ID, 0);
- private static final SubscriptionInfo TEST_SUBSCRIPTION_2 = new SubscriptionInfo(0, "", 0,
- TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
- DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID,
+ TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
+ DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, null,
TEST_CARRIER_ID, 0);
private static final SubscriptionInfo TEST_SUBSCRIPTION_NULL = new SubscriptionInfo(0, "", 0,
- TEST_CARRIER, null, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "", DATA_ROAMING_DISABLE,
+ TEST_CARRIER, null, NAME_SOURCE_DEFAULT, 0xFFFFFF, "", DATA_ROAMING_DISABLE,
null, null, null, null, false, null, "");
private static final SubscriptionInfo TEST_SUBSCRIPTION_ROAMING = new SubscriptionInfo(0, "", 0,
- TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT_SOURCE, 0xFFFFFF, "",
+ TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
DATA_ROAMING_ENABLE, null, null, null, null, false, null, "");
@Mock
private WifiManager mWifiManager;
@@ -136,7 +131,6 @@
mKeyguardUpdateMonitor);
// This should not start listening on any of the real dependencies
mCarrierTextController.setListening(mCarrierTextCallback);
- mCarrierTextController.updateDisplayOpportunisticSubscriptionCarrierText(false);
}
@Test
@@ -145,7 +139,7 @@
reset(mCarrierTextCallback);
List<SubscriptionInfo> list = new ArrayList<>();
list.add(TEST_SUBSCRIPTION);
- when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+ when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -165,7 +159,7 @@
reset(mCarrierTextCallback);
List<SubscriptionInfo> list = new ArrayList<>();
list.add(TEST_SUBSCRIPTION);
- when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+ when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY);
when(mKeyguardUpdateMonitor.getSimState(1)).thenReturn(
IccCardConstants.State.CARD_IO_ERROR);
@@ -198,7 +192,7 @@
@Test
public void testWrongSlots() {
reset(mCarrierTextCallback);
- when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(
+ when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(
new ArrayList<>());
when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
IccCardConstants.State.CARD_IO_ERROR);
@@ -212,7 +206,7 @@
@Test
public void testMoreSlotsThanSubs() {
reset(mCarrierTextCallback);
- when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(
+ when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(
new ArrayList<>());
// STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
@@ -262,7 +256,7 @@
List<SubscriptionInfo> list = new ArrayList<>();
list.add(TEST_SUBSCRIPTION);
when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
- when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+ when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -286,7 +280,7 @@
List<SubscriptionInfo> list = new ArrayList<>();
list.add(TEST_SUBSCRIPTION_ROAMING);
when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
- when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+ when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -366,7 +360,7 @@
@Test
public void testCreateInfo_noSubscriptions() {
reset(mCarrierTextCallback);
- when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(
+ when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(
new ArrayList<>());
ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -390,7 +384,7 @@
list.add(TEST_SUBSCRIPTION);
list.add(TEST_SUBSCRIPTION);
when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
- when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+ when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -415,7 +409,7 @@
when(mKeyguardUpdateMonitor.getSimState(anyInt()))
.thenReturn(IccCardConstants.State.READY)
.thenReturn(IccCardConstants.State.NOT_READY);
- when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+ when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -440,7 +434,7 @@
when(mKeyguardUpdateMonitor.getSimState(anyInt()))
.thenReturn(IccCardConstants.State.NOT_READY)
.thenReturn(IccCardConstants.State.READY);
- when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+ when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -467,7 +461,7 @@
.thenReturn(IccCardConstants.State.READY)
.thenReturn(IccCardConstants.State.NOT_READY)
.thenReturn(IccCardConstants.State.READY);
- when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+ when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -482,30 +476,6 @@
captor.getValue().carrierText);
}
- @Test
- public void testCarrierText_GroupedSubWithOpportunisticCarrierText() {
- reset(mCarrierTextCallback);
- List<SubscriptionInfo> list = new ArrayList<>();
- list.add(TEST_SUBSCRIPTION);
- list.add(TEST_SUBSCRIPTION_2);
- when(mKeyguardUpdateMonitor.getSimState(anyInt()))
- .thenReturn(IccCardConstants.State.READY);
-
- mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
- mCarrierTextController.updateDisplayOpportunisticSubscriptionCarrierText(true);
- when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
-
- ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
- ArgumentCaptor.forClass(
- CarrierTextController.CarrierTextCallbackInfo.class);
-
- mCarrierTextController.updateCarrierText();
- mTestableLooper.processAllMessages();
- verify(mCarrierTextCallback).updateCarrierInfo(captor.capture());
-
- assertEquals(TEST_CARRIER_2, captor.getValue().carrierText);
- }
-
public static class TestCarrierTextController extends CarrierTextController {
private KeyguardUpdateMonitor mKUM;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index db6177a..cfffcbc 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -16,15 +16,18 @@
package com.android.keyguard;
+import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
+import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -42,6 +45,7 @@
import android.os.Bundle;
import android.os.UserManager;
import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -62,6 +66,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@SmallTest
@@ -73,7 +79,18 @@
// new tests.
@RunWithLooper(setAsMainLooper = true)
public class KeyguardUpdateMonitorTest extends SysuiTestCase {
-
+ private static final String TEST_CARRIER = "TEST_CARRIER";
+ private static final String TEST_CARRIER_2 = "TEST_CARRIER_2";
+ private static final int TEST_CARRIER_ID = 1;
+ private static final String TEST_GROUP_UUID = "59b5c870-fc4c-47a4-a99e-9db826b48b24";
+ private static final SubscriptionInfo TEST_SUBSCRIPTION = new SubscriptionInfo(1, "", 0,
+ TEST_CARRIER, TEST_CARRIER, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
+ DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", false, TEST_GROUP_UUID,
+ TEST_CARRIER_ID, 0);
+ private static final SubscriptionInfo TEST_SUBSCRIPTION_2 = new SubscriptionInfo(2, "", 0,
+ TEST_CARRIER, TEST_CARRIER_2, NAME_SOURCE_DEFAULT, 0xFFFFFF, "",
+ DATA_ROAMING_DISABLE, null, null, null, null, false, null, "", true, TEST_GROUP_UUID,
+ TEST_CARRIER_ID, 0);
@Mock
private KeyguardUpdateMonitor.StrongAuthTracker mStrongAuthTracker;
@Mock
@@ -92,6 +109,8 @@
private DevicePolicyManager mDevicePolicyManager;
@Mock
private KeyguardBypassController mKeyguardBypassController;
+ @Mock
+ private SubscriptionManager mSubscriptionManager;
private TestableLooper mTestableLooper;
private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -119,6 +138,7 @@
context.addMockSystemService(FaceManager.class, mFaceManager);
context.addMockSystemService(UserManager.class, mUserManager);
context.addMockSystemService(DevicePolicyManager.class, mDevicePolicyManager);
+ context.addMockSystemService(SubscriptionManager.class, mSubscriptionManager);
mTestableLooper = TestableLooper.get(this);
mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(context);
@@ -133,7 +153,7 @@
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",
@@ -441,6 +461,22 @@
assertThat(mKeyguardUpdateMonitor.getUserCanSkipBouncer(user)).isTrue();
}
+ @Test
+ public void testGetSubscriptionInfo_whenInGroupedSubWithOpportunistic() {
+ List<SubscriptionInfo> list = new ArrayList<>();
+ list.add(TEST_SUBSCRIPTION);
+ list.add(TEST_SUBSCRIPTION_2);
+ when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
+ mKeyguardUpdateMonitor.mPhoneStateListener.onActiveDataSubscriptionIdChanged(
+ TEST_SUBSCRIPTION_2.getSubscriptionId());
+ mTestableLooper.processAllMessages();
+
+ List<SubscriptionInfo> listToVerify = mKeyguardUpdateMonitor
+ .getFilteredSubscriptionInfo(false);
+ assertThat(listToVerify.size()).isEqualTo(1);
+ assertThat(listToVerify.get(0)).isEqualTo(TEST_SUBSCRIPTION_2);
+ }
+
private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) {
int subscription = simInited
? 1/* mock subid=1 */ : SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE;
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index d297f3f..1315ed0 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -34,7 +34,7 @@
"framework-tethering",
"unsupportedappusage",
],
-
+ plugins: ["java_api_finder"],
manifest: "AndroidManifestBase.xml",
}
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 264ce44..e0adb34d 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -19,7 +19,15 @@
local_include_dir: "src",
include_dirs: ["frameworks/base/core/java"], // For framework parcelables.
srcs: [
- "src/android/net/*.aidl",
+ // @JavaOnlyStableParcelable aidl declarations must not be listed here, as this would cause
+ // compilation to fail (b/148001843).
+ "src/android/net/IIntResultListener.aidl",
+ "src/android/net/ITetheringConnector.aidl",
+ "src/android/net/ITetheringEventCallback.aidl",
+ "src/android/net/TetheringCallbackStartedParcel.aidl",
+ "src/android/net/TetheringConfigurationParcel.aidl",
+ "src/android/net/TetheringRequestParcel.aidl",
+ "src/android/net/TetherStatesParcel.aidl",
],
backend: {
ndk: {
@@ -35,7 +43,9 @@
name: "framework-tethering",
sdk_version: "system_current",
srcs: [
+ "src/android/net/TetheredClient.java",
"src/android/net/TetheringManager.java",
+ "src/android/net/TetheringConstants.java",
":framework-tethering-annotations",
],
static_libs: [
@@ -62,11 +72,16 @@
filegroup {
name: "framework-tethering-srcs",
srcs: [
+ "src/android/net/TetheredClient.aidl",
+ "src/android/net/TetheredClient.java",
"src/android/net/TetheringManager.java",
+ "src/android/net/TetheringConstants.java",
"src/android/net/IIntResultListener.aidl",
"src/android/net/ITetheringEventCallback.aidl",
"src/android/net/ITetheringConnector.aidl",
+ "src/android/net/TetheringCallbackStartedParcel.aidl",
"src/android/net/TetheringConfigurationParcel.aidl",
+ "src/android/net/TetheringRequestParcel.aidl",
"src/android/net/TetherStatesParcel.aidl",
],
path: "src"
diff --git a/packages/Tethering/common/TetheringLib/jarjar-rules.txt b/packages/Tethering/common/TetheringLib/jarjar-rules.txt
index 35e0f88..1403bba 100644
--- a/packages/Tethering/common/TetheringLib/jarjar-rules.txt
+++ b/packages/Tethering/common/TetheringLib/jarjar-rules.txt
@@ -1 +1,2 @@
rule android.annotation.** com.android.networkstack.tethering.annotation.@1
+rule com.android.internal.annotations.** com.android.networkstack.tethering.annotation.@1
\ No newline at end of file
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
index d30c399..5febe73 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
@@ -17,6 +17,7 @@
import android.net.IIntResultListener;
import android.net.ITetheringEventCallback;
+import android.net.TetheringRequestParcel;
import android.os.ResultReceiver;
/** @hide */
@@ -27,8 +28,8 @@
void setUsbTethering(boolean enable, String callerPkg, IIntResultListener receiver);
- void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi,
- String callerPkg);
+ void startTethering(in TetheringRequestParcel request, String callerPkg,
+ IIntResultListener receiver);
void stopTethering(int type, String callerPkg, IIntResultListener receiver);
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
index 2836195..28a810d 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
@@ -18,6 +18,7 @@
import android.net.Network;
import android.net.TetheringConfigurationParcel;
+import android.net.TetheringCallbackStartedParcel;
import android.net.TetherStatesParcel;
/**
@@ -26,8 +27,8 @@
*/
oneway interface ITetheringEventCallback
{
- void onCallbackStarted(in Network network, in TetheringConfigurationParcel config,
- in TetherStatesParcel states);
+ /** Called immediately after the callbacks are registered */
+ void onCallbackStarted(in TetheringCallbackStartedParcel parcel);
void onCallbackStopped(int errorCode);
void onUpstreamChanged(in Network network);
void onConfigurationChanged(in TetheringConfigurationParcel config);
diff --git a/core/java/android/net/NetworkMisc.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl
similarity index 76%
copy from core/java/android/net/NetworkMisc.aidl
copy to packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl
index c65583f..0b279b8 100644
--- a/core/java/android/net/NetworkMisc.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
+/**
+ * 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
+ * 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,
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package android.net;
-parcelable NetworkMisc;
+@JavaOnlyStableParcelable parcelable TetheredClient;
\ No newline at end of file
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
new file mode 100644
index 0000000..6514688
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
@@ -0,0 +1,212 @@
+/*
+ * 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 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.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Information on a tethered downstream client.
+ * @hide
+ */
+@SystemApi
+@TestApi
+public final class TetheredClient implements Parcelable {
+ @NonNull
+ private final MacAddress mMacAddress;
+ @NonNull
+ private final List<AddressInfo> mAddresses;
+ // TODO: use an @IntDef here
+ private final int mTetheringType;
+
+ public TetheredClient(@NonNull MacAddress macAddress,
+ @NonNull Collection<AddressInfo> addresses, int tetheringType) {
+ mMacAddress = macAddress;
+ mAddresses = new ArrayList<>(addresses);
+ mTetheringType = tetheringType;
+ }
+
+ private TetheredClient(@NonNull Parcel in) {
+ this(in.readParcelable(null), in.createTypedArrayList(AddressInfo.CREATOR), in.readInt());
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mMacAddress, flags);
+ dest.writeTypedList(mAddresses);
+ dest.writeInt(mTetheringType);
+ }
+
+ @NonNull
+ public MacAddress getMacAddress() {
+ return mMacAddress;
+ }
+
+ @NonNull
+ public List<AddressInfo> getAddresses() {
+ return new ArrayList<>(mAddresses);
+ }
+
+ public int getTetheringType() {
+ return mTetheringType;
+ }
+
+ /**
+ * Return a new {@link TetheredClient} that has all the attributes of this instance, plus the
+ * {@link AddressInfo} of the provided {@link TetheredClient}.
+ *
+ * <p>Duplicate addresses are removed.
+ * @hide
+ */
+ public TetheredClient addAddresses(@NonNull TetheredClient other) {
+ final HashSet<AddressInfo> newAddresses = new HashSet<>(
+ mAddresses.size() + other.mAddresses.size());
+ newAddresses.addAll(mAddresses);
+ newAddresses.addAll(other.mAddresses);
+ return new TetheredClient(mMacAddress, newAddresses, mTetheringType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mMacAddress, mAddresses, mTetheringType);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof TetheredClient)) return false;
+ final TetheredClient other = (TetheredClient) obj;
+ return mMacAddress.equals(other.mMacAddress)
+ && mAddresses.equals(other.mAddresses)
+ && mTetheringType == other.mTetheringType;
+ }
+
+ /**
+ * Information on an lease assigned to a tethered client.
+ */
+ public static final class AddressInfo implements Parcelable {
+ @NonNull
+ private final LinkAddress mAddress;
+ @Nullable
+ private final String mHostname;
+ // TODO: use LinkAddress expiration time once it is supported
+ private final long mExpirationTime;
+
+ /** @hide */
+ public AddressInfo(@NonNull LinkAddress address, @Nullable String hostname) {
+ this(address, hostname, 0);
+ }
+
+ /** @hide */
+ public AddressInfo(@NonNull LinkAddress address, String hostname, long expirationTime) {
+ this.mAddress = address;
+ this.mHostname = hostname;
+ this.mExpirationTime = expirationTime;
+ }
+
+ private AddressInfo(Parcel in) {
+ this(in.readParcelable(null), in.readString(), in.readLong());
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mAddress, flags);
+ dest.writeString(mHostname);
+ dest.writeLong(mExpirationTime);
+ }
+
+ @NonNull
+ public LinkAddress getAddress() {
+ return mAddress;
+ }
+
+ @Nullable
+ public String getHostname() {
+ return mHostname;
+ }
+
+ /** @hide TODO: use expiration time in LinkAddress */
+ public long getExpirationTime() {
+ return mExpirationTime;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAddress, mHostname, mExpirationTime);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof AddressInfo)) return false;
+ final AddressInfo other = (AddressInfo) obj;
+ // Use .equals() for addresses as all changes, including address expiry changes,
+ // should be included.
+ return other.mAddress.equals(mAddress)
+ && Objects.equals(mHostname, other.mHostname)
+ && mExpirationTime == other.mExpirationTime;
+ }
+
+ @NonNull
+ public static final Creator<AddressInfo> CREATOR = new Creator<AddressInfo>() {
+ @NonNull
+ @Override
+ public AddressInfo createFromParcel(@NonNull Parcel in) {
+ return new AddressInfo(in);
+ }
+
+ @NonNull
+ @Override
+ public AddressInfo[] newArray(int size) {
+ return new AddressInfo[size];
+ }
+ };
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Creator<TetheredClient> CREATOR = new Creator<TetheredClient>() {
+ @NonNull
+ @Override
+ public TetheredClient createFromParcel(@NonNull Parcel in) {
+ return new TetheredClient(in);
+ }
+
+ @NonNull
+ @Override
+ public TetheredClient[] newArray(int size) {
+ return new TetheredClient[size];
+ }
+ };
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
new file mode 100644
index 0000000..14ee2d3
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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 android.net.Network;
+import android.net.TetheringConfigurationParcel;
+import android.net.TetherStatesParcel;
+
+/**
+ * Initial information reported by tethering upon callback registration.
+ * @hide
+ */
+parcelable TetheringCallbackStartedParcel {
+ boolean tetheringSupported;
+ Network upstreamNetwork;
+ TetheringConfigurationParcel config;
+ TetherStatesParcel states;
+}
\ No newline at end of file
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
new file mode 100644
index 0000000..00cf98e
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.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.net;
+
+import android.os.ResultReceiver;
+
+/**
+ * Collections of constants for internal tethering usage.
+ *
+ * <p>These hidden constants are not in TetheringManager as they are not part of the API stubs
+ * generated for TetheringManager, which prevents the tethering module from linking them at
+ * build time.
+ * TODO: investigate changing the tethering build rules so that Tethering can reference hidden
+ * symbols from framework-tethering even when they are in a non-hidden class.
+ * @hide
+ */
+public class TetheringConstants {
+ /**
+ * Extra used for communicating with the TetherService. Includes the type of tethering to
+ * enable if any.
+ *
+ * {@hide}
+ */
+ public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
+ /**
+ * Extra used for communicating with the TetherService. Includes the type of tethering for
+ * which to cancel provisioning.
+ *
+ * {@hide}
+ */
+ public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
+ /**
+ * Extra used for communicating with the TetherService. True to schedule a recheck of tether
+ * provisioning.
+ *
+ * {@hide}
+ */
+ public static final String EXTRA_SET_ALARM = "extraSetAlarm";
+ /**
+ * Tells the TetherService to run a provision check now.
+ *
+ * {@hide}
+ */
+ public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
+ /**
+ * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
+ * which will receive provisioning results. Can be left empty.
+ *
+ * {@hide}
+ */
+ public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 11e5718..53a358f 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -15,9 +15,14 @@
*/
package android.net;
+import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.content.Context;
-import android.net.ConnectivityManager.OnTetheringEventCallback;
+import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.IBinder;
import android.os.RemoteException;
@@ -25,7 +30,17 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.function.Supplier;
/**
* This class provides the APIs to control the tethering service.
@@ -34,21 +49,28 @@
*
* @hide
*/
-// TODO: make it @SystemApi
+@SystemApi
+@TestApi
public class TetheringManager {
private static final String TAG = TetheringManager.class.getSimpleName();
private static final int DEFAULT_TIMEOUT_MS = 60_000;
+ private static final long CONNECTOR_POLL_INTERVAL_MILLIS = 200L;
- private static TetheringManager sInstance;
+ @GuardedBy("mConnectorWaitQueue")
+ @Nullable
+ private ITetheringConnector mConnector;
+ @GuardedBy("mConnectorWaitQueue")
+ @NonNull
+ private final List<ConnectorConsumer> mConnectorWaitQueue = new ArrayList<>();
+ private final Supplier<IBinder> mConnectorSupplier;
- private final ITetheringConnector mConnector;
private final TetheringCallbackInternal mCallback;
private final Context mContext;
- private final ArrayMap<OnTetheringEventCallback, ITetheringEventCallback>
+ private final ArrayMap<TetheringEventCallback, ITetheringEventCallback>
mTetheringEventCallbacks = new ArrayMap<>();
- private TetheringConfigurationParcel mTetheringConfiguration;
- private TetherStatesParcel mTetherStatesParcel;
+ private volatile TetheringConfigurationParcel mTetheringConfiguration;
+ private volatile TetherStatesParcel mTetherStatesParcel;
/**
* Broadcast Action: A tetherable connection has come or gone.
@@ -72,7 +94,7 @@
* gives a String[] listing all the interfaces currently in local-only
* mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding)
*/
- public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray";
+ public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
/**
* gives a String[] listing all the interfaces currently tethered
@@ -119,33 +141,16 @@
public static final int TETHERING_WIFI_P2P = 3;
/**
- * Extra used for communicating with the TetherService. Includes the type of tethering to
- * enable if any.
+ * Ncm local tethering type.
+ * @see #startTethering(TetheringRequest, Executor, StartTetheringCallback)
*/
- public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
+ public static final int TETHERING_NCM = 4;
/**
- * Extra used for communicating with the TetherService. Includes the type of tethering for
- * which to cancel provisioning.
+ * Ethernet tethering type.
+ * @see #startTethering(TetheringRequest, Executor, StartTetheringCallback)
*/
- public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
-
- /**
- * Extra used for communicating with the TetherService. True to schedule a recheck of tether
- * provisioning.
- */
- public static final String EXTRA_SET_ALARM = "extraSetAlarm";
-
- /**
- * Tells the TetherService to run a provision check now.
- */
- public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
-
- /**
- * Extra used for communicating with the TetherService. Contains the {@link ResultReceiver}
- * which will receive provisioning results. Can be left empty.
- */
- public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
+ public static final int TETHERING_ETHERNET = 5;
public static final int TETHER_ERROR_NO_ERROR = 0;
public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
@@ -160,34 +165,146 @@
public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10;
public static final int TETHER_ERROR_PROVISION_FAILED = 11;
public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12;
- public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13;
+ public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13;
public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14;
public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15;
/**
* Create a TetheringManager object for interacting with the tethering service.
+ *
+ * @param context Context for the manager.
+ * @param connectorSupplier Supplier for the manager connector; may return null while the
+ * service is not connected.
+ * {@hide}
*/
- public TetheringManager(@NonNull final Context context, @NonNull final IBinder service) {
+ public TetheringManager(@NonNull final Context context,
+ @NonNull Supplier<IBinder> connectorSupplier) {
mContext = context;
- mConnector = ITetheringConnector.Stub.asInterface(service);
mCallback = new TetheringCallbackInternal();
+ mConnectorSupplier = connectorSupplier;
final String pkgName = mContext.getOpPackageName();
+
+ final IBinder connector = mConnectorSupplier.get();
+ // If the connector is available on start, do not start a polling thread. This introduces
+ // differences in the thread that sends the oneway binder calls to the service between the
+ // first few seconds after boot and later, but it avoids always having differences between
+ // the first usage of TetheringManager from a process and subsequent usages (so the
+ // difference is only on boot). On boot binder calls may be queued until the service comes
+ // up and be sent from a worker thread; later, they are always sent from the caller thread.
+ // Considering that it's just oneway binder calls, and ordering is preserved, this seems
+ // better than inconsistent behavior persisting after boot.
+ if (connector != null) {
+ mConnector = ITetheringConnector.Stub.asInterface(connector);
+ } else {
+ startPollingForConnector();
+ }
+
Log.i(TAG, "registerTetheringEventCallback:" + pkgName);
+ getConnector(c -> c.registerTetheringEventCallback(mCallback, pkgName));
+ }
+
+ private void startPollingForConnector() {
+ new Thread(() -> {
+ while (true) {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ // Not much to do here, the system needs to wait for the connector
+ }
+
+ final IBinder connector = mConnectorSupplier.get();
+ if (connector != null) {
+ onTetheringConnected(ITetheringConnector.Stub.asInterface(connector));
+ return;
+ }
+ }
+ }).start();
+ }
+
+ private interface ConnectorConsumer {
+ void onConnectorAvailable(ITetheringConnector connector) throws RemoteException;
+ }
+
+ private void onTetheringConnected(ITetheringConnector connector) {
+ // Process the connector wait queue in order, including any items that are added
+ // while processing.
+ //
+ // 1. Copy the queue to a local variable under lock.
+ // 2. Drain the local queue with the lock released (otherwise, enqueuing future commands
+ // would block on the lock).
+ // 3. Acquire the lock again. If any new tasks were queued during step 2, goto 1.
+ // If not, set mConnector to non-null so future tasks are run immediately, not queued.
+ //
+ // For this to work, all calls to the tethering service must use getConnector(), which
+ // ensures that tasks are added to the queue with the lock held.
+ //
+ // Once mConnector is set to non-null, it will never be null again. If the network stack
+ // process crashes, no recovery is possible.
+ // TODO: evaluate whether it is possible to recover from network stack process crashes
+ // (though in most cases the system will have crashed when the network stack process
+ // crashes).
+ do {
+ final List<ConnectorConsumer> localWaitQueue;
+ synchronized (mConnectorWaitQueue) {
+ localWaitQueue = new ArrayList<>(mConnectorWaitQueue);
+ mConnectorWaitQueue.clear();
+ }
+
+ // Allow more tasks to be added at the end without blocking while draining the queue.
+ for (ConnectorConsumer task : localWaitQueue) {
+ try {
+ task.onConnectorAvailable(connector);
+ } catch (RemoteException e) {
+ // Most likely the network stack process crashed, which is likely to crash the
+ // system. Keep processing other requests but report the error loudly.
+ Log.wtf(TAG, "Error processing request for the tethering connector", e);
+ }
+ }
+
+ synchronized (mConnectorWaitQueue) {
+ if (mConnectorWaitQueue.size() == 0) {
+ mConnector = connector;
+ return;
+ }
+ }
+ } while (true);
+ }
+
+ /**
+ * Asynchronously get the ITetheringConnector to execute some operation.
+ *
+ * <p>If the connector is already available, the operation will be executed on the caller's
+ * thread. Otherwise it will be queued and executed on a worker thread. The operation should be
+ * limited to performing oneway binder calls to minimize differences due to threading.
+ */
+ private void getConnector(ConnectorConsumer consumer) {
+ final ITetheringConnector connector;
+ synchronized (mConnectorWaitQueue) {
+ connector = mConnector;
+ if (connector == null) {
+ mConnectorWaitQueue.add(consumer);
+ return;
+ }
+ }
+
try {
- mConnector.registerTetheringEventCallback(mCallback, pkgName);
+ consumer.onConnectorAvailable(connector);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
}
private interface RequestHelper {
- void runRequest(IIntResultListener listener);
+ void runRequest(ITetheringConnector connector, IIntResultListener listener);
}
+ // Used to dispatch legacy ConnectivityManager methods that expect tethering to be able to
+ // return results and perform operations synchronously.
+ // TODO: remove once there are no callers of these legacy methods.
private class RequestDispatcher {
private final ConditionVariable mWaiting;
- public int mRemoteResult;
+ public volatile int mRemoteResult;
private final IIntResultListener mListener = new IIntResultListener.Stub() {
@Override
@@ -202,7 +319,7 @@
}
int waitForResult(final RequestHelper request) {
- request.runRequest(mListener);
+ getConnector(c -> request.runRequest(c, mListener));
if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) {
throw new IllegalStateException("Callback timeout");
}
@@ -225,14 +342,13 @@
}
private class TetheringCallbackInternal extends ITetheringEventCallback.Stub {
- private int mError = TETHER_ERROR_NO_ERROR;
+ private volatile int mError = TETHER_ERROR_NO_ERROR;
private final ConditionVariable mWaitForCallback = new ConditionVariable();
@Override
- public void onCallbackStarted(Network network, TetheringConfigurationParcel config,
- TetherStatesParcel states) {
- mTetheringConfiguration = config;
- mTetherStatesParcel = states;
+ public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
+ mTetheringConfiguration = parcel.config;
+ mTetherStatesParcel = parcel.states;
mWaitForCallback.open();
}
@@ -275,6 +391,8 @@
*
* @param iface the interface name to tether.
* @return error a {@code TETHER_ERROR} value indicating success or failure type
+ *
+ * {@hide}
*/
@Deprecated
public int tether(@NonNull final String iface) {
@@ -282,9 +400,9 @@
Log.i(TAG, "tether caller:" + callerPkg);
final RequestDispatcher dispatcher = new RequestDispatcher();
- return dispatcher.waitForResult(listener -> {
+ return dispatcher.waitForResult((connector, listener) -> {
try {
- mConnector.tether(iface, callerPkg, listener);
+ connector.tether(iface, callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -296,6 +414,8 @@
*
* @deprecated The only usages is PanService. It uses this for legacy reasons
* and will migrate away as soon as possible.
+ *
+ * {@hide}
*/
@Deprecated
public int untether(@NonNull final String iface) {
@@ -304,9 +424,9 @@
final RequestDispatcher dispatcher = new RequestDispatcher();
- return dispatcher.waitForResult(listener -> {
+ return dispatcher.waitForResult((connector, listener) -> {
try {
- mConnector.untether(iface, callerPkg, listener);
+ connector.untether(iface, callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -320,6 +440,8 @@
* #startTethering or #stopTethering which encapsulate proper entitlement logic. If the API is
* used and an entitlement check is needed, downstream USB tethering will be enabled but will
* not have any upstream.
+ *
+ * {@hide}
*/
@Deprecated
public int setUsbTethering(final boolean enable) {
@@ -328,9 +450,9 @@
final RequestDispatcher dispatcher = new RequestDispatcher();
- return dispatcher.waitForResult(listener -> {
+ return dispatcher.waitForResult((connector, listener) -> {
try {
- mConnector.setUsbTethering(enable, callerPkg, listener);
+ connector.setUsbTethering(enable, callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -338,48 +460,246 @@
}
/**
+ * Use with {@link #startTethering} to specify additional parameters when starting tethering.
+ */
+ public static class TetheringRequest {
+ /** A configuration set for TetheringRequest. */
+ private final TetheringRequestParcel mRequestParcel;
+
+ private TetheringRequest(final TetheringRequestParcel request) {
+ mRequestParcel = request;
+ }
+
+ /** Builder used to create TetheringRequest. */
+ public static class Builder {
+ private final TetheringRequestParcel mBuilderParcel;
+
+ /** Default constructor of Builder. */
+ public Builder(final int type) {
+ mBuilderParcel = new TetheringRequestParcel();
+ mBuilderParcel.tetheringType = type;
+ mBuilderParcel.localIPv4Address = null;
+ mBuilderParcel.exemptFromEntitlementCheck = false;
+ mBuilderParcel.showProvisioningUi = true;
+ }
+
+ /**
+ * Configure tethering with static IPv4 assignment (with DHCP disabled).
+ *
+ * @param localIPv4Address The preferred local IPv4 address to use.
+ */
+ @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
+ @NonNull
+ public Builder useStaticIpv4Addresses(@NonNull final LinkAddress localIPv4Address) {
+ mBuilderParcel.localIPv4Address = localIPv4Address;
+ return this;
+ }
+
+ /** Start tethering without entitlement checks. */
+ @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
+ @NonNull
+ public Builder setExemptFromEntitlementCheck(boolean exempt) {
+ mBuilderParcel.exemptFromEntitlementCheck = exempt;
+ return this;
+ }
+
+ /** Start tethering without showing the provisioning UI. */
+ @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
+ @NonNull
+ public Builder setSilentProvisioning(boolean silent) {
+ mBuilderParcel.showProvisioningUi = silent;
+ return this;
+ }
+
+ /** Build {@link TetheringRequest] with the currently set configuration. */
+ @NonNull
+ public TetheringRequest build() {
+ return new TetheringRequest(mBuilderParcel);
+ }
+ }
+
+ /**
+ * Get a TetheringRequestParcel from the configuration
+ * @hide
+ */
+ public TetheringRequestParcel getParcel() {
+ return mRequestParcel;
+ }
+
+ /** String of TetheringRequest detail. */
+ public String toString() {
+ return "TetheringRequest [ type= " + mRequestParcel.tetheringType
+ + ", localIPv4Address= " + mRequestParcel.localIPv4Address
+ + ", exemptFromEntitlementCheck= "
+ + mRequestParcel.exemptFromEntitlementCheck + ", showProvisioningUi= "
+ + mRequestParcel.showProvisioningUi + " ]";
+ }
+ }
+
+ /**
+ * Callback for use with {@link #startTethering} to find out whether tethering succeeded.
+ */
+ public abstract static class StartTetheringCallback {
+ /**
+ * Called when tethering has been successfully started.
+ */
+ public void onTetheringStarted() {}
+
+ /**
+ * Called when starting tethering failed.
+ *
+ * @param resultCode One of the {@code TETHER_ERROR_*} constants.
+ */
+ public void onTetheringFailed(final int resultCode) {}
+ }
+
+ /**
* Starts tethering and runs tether provisioning for the given type if needed. If provisioning
* fails, stopTethering will be called automatically.
*
+ * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+ * fail if a tethering entitlement check is required.
+ *
+ * @param request a {@link TetheringRequest} which can specify the preferred configuration.
+ * @param executor {@link Executor} to specify the thread upon which the callback of
+ * TetheringRequest will be invoked.
+ * @param callback A callback that will be called to indicate the success status of the
+ * tethering start request.
*/
- // TODO: improve the usage of ResultReceiver, b/145096122
- public void startTethering(final int type, @NonNull final ResultReceiver receiver,
- final boolean showProvisioningUi) {
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ android.Manifest.permission.WRITE_SETTINGS
+ })
+ public void startTethering(@NonNull final TetheringRequest request,
+ @NonNull final Executor executor, @NonNull final StartTetheringCallback callback) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "startTethering caller:" + callerPkg);
- try {
- mConnector.startTethering(type, receiver, showProvisioningUi, callerPkg);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
+ final IIntResultListener listener = new IIntResultListener.Stub() {
+ @Override
+ public void onResult(final int resultCode) {
+ executor.execute(() -> {
+ if (resultCode == TETHER_ERROR_NO_ERROR) {
+ callback.onTetheringStarted();
+ } else {
+ callback.onTetheringFailed(resultCode);
+ }
+ });
+ }
+ };
+ getConnector(c -> c.startTethering(request.getParcel(), callerPkg, listener));
+ }
+
+ /**
+ * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
+ * fails, stopTethering will be called automatically.
+ *
+ * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+ * fail if a tethering entitlement check is required.
+ *
+ * @param type The tethering type, on of the {@code TetheringManager#TETHERING_*} constants.
+ * @param executor {@link Executor} to specify the thread upon which the callback of
+ * TetheringRequest will be invoked.
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ android.Manifest.permission.WRITE_SETTINGS
+ })
+ public void startTethering(int type, @NonNull final Executor executor,
+ @NonNull final StartTetheringCallback callback) {
+ startTethering(new TetheringRequest.Builder(type).build(), executor, callback);
}
/**
* Stops tethering for the given type. Also cancels any provisioning rechecks for that type if
* applicable.
+ *
+ * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+ * fail if a tethering entitlement check is required.
*/
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ android.Manifest.permission.WRITE_SETTINGS
+ })
public void stopTethering(final int type) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "stopTethering caller:" + callerPkg);
- final RequestDispatcher dispatcher = new RequestDispatcher();
-
- dispatcher.waitForResult(listener -> {
- try {
- mConnector.stopTethering(type, callerPkg, listener);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
+ getConnector(c -> c.stopTethering(type, callerPkg, new IIntResultListener.Stub() {
+ @Override
+ public void onResult(int resultCode) {
+ // TODO: provide an API to obtain result
+ // This has never been possible as stopTethering has always been void and never
+ // taken a callback object. The only indication that callers have is if the call
+ // results in a TETHER_STATE_CHANGE broadcast.
}
- });
+ }));
+ }
+
+ /**
+ * Callback for use with {@link #getLatestTetheringEntitlementResult} to find out whether
+ * entitlement succeeded.
+ */
+ public interface OnTetheringEntitlementResultListener {
+ /**
+ * Called to notify entitlement result.
+ *
+ * @param resultCode an int value of entitlement result. It may be one of
+ * {@link #TETHER_ERROR_NO_ERROR},
+ * {@link #TETHER_ERROR_PROVISION_FAILED}, or
+ * {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN}.
+ */
+ void onTetheringEntitlementResult(int resultCode);
}
/**
* Request the latest value of the tethering entitlement check.
*
- * Note: Allow privileged apps who have TETHER_PRIVILEGED permission to access. If it turns
- * out some such apps are observed to abuse this API, change to per-UID limits on this API
- * if it's really needed.
+ * <p>This method will only return the latest entitlement result if it is available. If no
+ * cached entitlement result is available, and {@code showEntitlementUi} is false,
+ * {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN} will be returned. If {@code showEntitlementUi} is
+ * true, entitlement will be run.
+ *
+ * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+ * fail if a tethering entitlement check is required.
+ *
+ * @param type the downstream type of tethering. Must be one of {@code #TETHERING_*} constants.
+ * @param showEntitlementUi a boolean indicating whether to run UI-based entitlement check.
+ * @param executor the executor on which callback will be invoked.
+ * @param listener an {@link OnTetheringEntitlementResultListener} which will be called to
+ * notify the caller of the result of entitlement check. The listener may be called zero
+ * or one time.
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ android.Manifest.permission.WRITE_SETTINGS
+ })
+ public void requestLatestTetheringEntitlementResult(int type, boolean showEntitlementUi,
+ @NonNull Executor executor,
+ @NonNull final OnTetheringEntitlementResultListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException(
+ "OnTetheringEntitlementResultListener cannot be null.");
+ }
+
+ ResultReceiver wrappedListener = new ResultReceiver(null /* handler */) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ executor.execute(() -> {
+ listener.onTetheringEntitlementResult(resultCode);
+ });
+ }
+ };
+
+ requestLatestTetheringEntitlementResult(type, wrappedListener,
+ showEntitlementUi);
+ }
+
+ /**
+ * Helper function of #requestLatestTetheringEntitlementResult to remain backwards compatible
+ * with ConnectivityManager#getLatestTetheringEntitlementResult
+ *
+ * {@hide}
*/
// TODO: improve the usage of ResultReceiver, b/145096122
public void requestLatestTetheringEntitlementResult(final int type,
@@ -387,34 +707,166 @@
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "getLatestTetheringEntitlementResult caller:" + callerPkg);
- try {
- mConnector.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi,
- callerPkg);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
+ getConnector(c -> c.requestLatestTetheringEntitlementResult(
+ type, receiver, showEntitlementUi, callerPkg));
+ }
+
+ /**
+ * Callback for use with {@link registerTetheringEventCallback} to find out tethering
+ * upstream status.
+ */
+ public abstract static class TetheringEventCallback {
+ /**
+ * Called when tethering supported status changed.
+ *
+ * <p>This will be called immediately after the callback is registered, and may be called
+ * multiple times later upon changes.
+ *
+ * <p>Tethering may be disabled via system properties, device configuration, or device
+ * policy restrictions.
+ *
+ * @param supported The new supported status
+ */
+ public void onTetheringSupported(boolean supported) {}
+
+ /**
+ * Called when tethering upstream changed.
+ *
+ * <p>This will be called immediately after the callback is registered, and may be called
+ * multiple times later upon changes.
+ *
+ * @param network the {@link Network} of tethering upstream. Null means tethering doesn't
+ * have any upstream.
+ */
+ public void onUpstreamChanged(@Nullable Network network) {}
+
+ /**
+ * Called when there was a change in tethering interface regular expressions.
+ *
+ * <p>This will be called immediately after the callback is registered, and may be called
+ * multiple times later upon changes.
+ * @param reg The new regular expressions.
+ * @deprecated Referencing interfaces by regular expressions is a deprecated mechanism.
+ */
+ @Deprecated
+ public void onTetherableInterfaceRegexpsChanged(@NonNull TetheringInterfaceRegexps reg) {}
+
+ /**
+ * Called when there was a change in the list of tetherable interfaces.
+ *
+ * <p>This will be called immediately after the callback is registered, and may be called
+ * multiple times later upon changes.
+ * @param interfaces The list of tetherable interfaces.
+ */
+ public void onTetherableInterfacesChanged(@NonNull List<String> interfaces) {}
+
+ /**
+ * Called when there was a change in the list of tethered interfaces.
+ *
+ * <p>This will be called immediately after the callback is registered, and may be called
+ * multiple times later upon changes.
+ * @param interfaces The list of tethered interfaces.
+ */
+ public void onTetheredInterfacesChanged(@NonNull List<String> interfaces) {}
+
+ /**
+ * Called when an error occurred configuring tethering.
+ *
+ * <p>This will be called immediately after the callback is registered if the latest status
+ * on the interface is an error, and may be called multiple times later upon changes.
+ * @param ifName Name of the interface.
+ * @param error One of {@code TetheringManager#TETHER_ERROR_*}.
+ */
+ public void onError(@NonNull String ifName, int error) {}
+
+ /**
+ * Called when the list of tethered clients changes.
+ *
+ * <p>This callback provides best-effort information on connected clients based on state
+ * known to the system, however the list cannot be completely accurate (and should not be
+ * used for security purposes). For example, clients behind a bridge and using static IP
+ * assignments are not visible to the tethering device; or even when using DHCP, such
+ * clients may still be reported by this callback after disconnection as the system cannot
+ * determine if they are still connected.
+ * @param clients The new set of tethered clients; the collection is not ordered.
+ */
+ public void onClientsChanged(@NonNull Collection<TetheredClient> clients) {}
+ }
+
+ /**
+ * Regular expressions used to identify tethering interfaces.
+ * @deprecated Referencing interfaces by regular expressions is a deprecated mechanism.
+ */
+ @Deprecated
+ public static class TetheringInterfaceRegexps {
+ private final String[] mTetherableBluetoothRegexs;
+ private final String[] mTetherableUsbRegexs;
+ private final String[] mTetherableWifiRegexs;
+
+ public TetheringInterfaceRegexps(@NonNull String[] tetherableBluetoothRegexs,
+ @NonNull String[] tetherableUsbRegexs, @NonNull String[] tetherableWifiRegexs) {
+ mTetherableBluetoothRegexs = tetherableBluetoothRegexs.clone();
+ mTetherableUsbRegexs = tetherableUsbRegexs.clone();
+ mTetherableWifiRegexs = tetherableWifiRegexs.clone();
+ }
+
+ @NonNull
+ public List<String> getTetherableBluetoothRegexs() {
+ return Collections.unmodifiableList(Arrays.asList(mTetherableBluetoothRegexs));
+ }
+
+ @NonNull
+ public List<String> getTetherableUsbRegexs() {
+ return Collections.unmodifiableList(Arrays.asList(mTetherableUsbRegexs));
+ }
+
+ @NonNull
+ public List<String> getTetherableWifiRegexs() {
+ return Collections.unmodifiableList(Arrays.asList(mTetherableWifiRegexs));
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTetherableBluetoothRegexs, mTetherableUsbRegexs,
+ mTetherableWifiRegexs);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (!(obj instanceof TetheringInterfaceRegexps)) return false;
+ final TetheringInterfaceRegexps other = (TetheringInterfaceRegexps) obj;
+ return Arrays.equals(mTetherableBluetoothRegexs, other.mTetherableBluetoothRegexs)
+ && Arrays.equals(mTetherableUsbRegexs, other.mTetherableUsbRegexs)
+ && Arrays.equals(mTetherableWifiRegexs, other.mTetherableWifiRegexs);
}
}
/**
* Start listening to tethering change events. Any new added callback will receive the last
* tethering status right away. If callback is registered,
- * {@link OnTetheringEventCallback#onUpstreamChanged} will immediately be called. If tethering
+ * {@link TetheringEventCallback#onUpstreamChanged} will immediately be called. If tethering
* has no upstream or disabled, the argument of callback will be null. The same callback object
* cannot be registered twice.
*
* @param executor the executor on which callback will be invoked.
* @param callback the callback to be called when tethering has change events.
*/
+ @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
public void registerTetheringEventCallback(@NonNull Executor executor,
- @NonNull OnTetheringEventCallback callback) {
+ @NonNull TetheringEventCallback callback) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "registerTetheringEventCallback caller:" + callerPkg);
synchronized (mTetheringEventCallbacks) {
- if (!mTetheringEventCallbacks.containsKey(callback)) {
+ if (mTetheringEventCallbacks.containsKey(callback)) {
throw new IllegalArgumentException("callback was already registered.");
}
final ITetheringEventCallback remoteCallback = new ITetheringEventCallback.Stub() {
+ // Only accessed with a lock on this object
+ private final HashMap<String, Integer> mErrorStates = new HashMap<>();
+ private String[] mLastTetherableInterfaces = null;
+ private String[] mLastTetheredInterfaces = null;
+
@Override
public void onUpstreamChanged(Network network) throws RemoteException {
executor.execute(() -> {
@@ -422,11 +874,45 @@
});
}
+ private synchronized void sendErrorCallbacks(final TetherStatesParcel newStates) {
+ for (int i = 0; i < newStates.erroredIfaceList.length; i++) {
+ final String iface = newStates.erroredIfaceList[i];
+ final Integer lastError = mErrorStates.get(iface);
+ final int newError = newStates.lastErrorList[i];
+ if (newError != TETHER_ERROR_NO_ERROR
+ && !Objects.equals(lastError, newError)) {
+ callback.onError(iface, newError);
+ }
+ mErrorStates.put(iface, newError);
+ }
+ }
+
+ private synchronized void maybeSendTetherableIfacesChangedCallback(
+ final TetherStatesParcel newStates) {
+ if (Arrays.equals(mLastTetherableInterfaces, newStates.availableList)) return;
+ mLastTetherableInterfaces = newStates.availableList.clone();
+ callback.onTetherableInterfacesChanged(
+ Collections.unmodifiableList(Arrays.asList(mLastTetherableInterfaces)));
+ }
+
+ private synchronized void maybeSendTetheredIfacesChangedCallback(
+ final TetherStatesParcel newStates) {
+ if (Arrays.equals(mLastTetheredInterfaces, newStates.tetheredList)) return;
+ mLastTetheredInterfaces = newStates.tetheredList.clone();
+ callback.onTetheredInterfacesChanged(
+ Collections.unmodifiableList(Arrays.asList(mLastTetheredInterfaces)));
+ }
+
+ // Called immediately after the callbacks are registered.
@Override
- public void onCallbackStarted(Network network, TetheringConfigurationParcel config,
- TetherStatesParcel states) {
+ public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
executor.execute(() -> {
- callback.onUpstreamChanged(network);
+ callback.onTetheringSupported(parcel.tetheringSupported);
+ callback.onUpstreamChanged(parcel.upstreamNetwork);
+ sendErrorCallbacks(parcel.states);
+ sendRegexpsChanged(parcel.config);
+ maybeSendTetherableIfacesChangedCallback(parcel.states);
+ maybeSendTetheredIfacesChangedCallback(parcel.states);
});
}
@@ -437,17 +923,28 @@
});
}
- @Override
- public void onConfigurationChanged(TetheringConfigurationParcel config) { }
+ private void sendRegexpsChanged(TetheringConfigurationParcel parcel) {
+ callback.onTetherableInterfaceRegexpsChanged(new TetheringInterfaceRegexps(
+ parcel.tetherableBluetoothRegexs,
+ parcel.tetherableUsbRegexs,
+ parcel.tetherableWifiRegexs));
+ }
@Override
- public void onTetherStatesChanged(TetherStatesParcel states) { }
+ public void onConfigurationChanged(TetheringConfigurationParcel config) {
+ executor.execute(() -> sendRegexpsChanged(config));
+ }
+
+ @Override
+ public void onTetherStatesChanged(TetherStatesParcel states) {
+ executor.execute(() -> {
+ sendErrorCallbacks(states);
+ maybeSendTetherableIfacesChangedCallback(states);
+ maybeSendTetheredIfacesChangedCallback(states);
+ });
+ }
};
- try {
- mConnector.registerTetheringEventCallback(remoteCallback, callerPkg);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
+ getConnector(c -> c.registerTetheringEventCallback(remoteCallback, callerPkg));
mTetheringEventCallbacks.put(callback, remoteCallback);
}
}
@@ -458,7 +955,11 @@
*
* @param callback previously registered callback.
*/
- public void unregisterTetheringEventCallback(@NonNull final OnTetheringEventCallback callback) {
+ @RequiresPermission(anyOf = {
+ Manifest.permission.TETHER_PRIVILEGED,
+ Manifest.permission.ACCESS_NETWORK_STATE
+ })
+ public void unregisterTetheringEventCallback(@NonNull final TetheringEventCallback callback) {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "unregisterTetheringEventCallback caller:" + callerPkg);
@@ -467,11 +968,8 @@
if (remoteCallback == null) {
throw new IllegalArgumentException("callback was not registered.");
}
- try {
- mConnector.unregisterTetheringEventCallback(remoteCallback, callerPkg);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
+
+ getConnector(c -> c.unregisterTetheringEventCallback(remoteCallback, callerPkg));
}
}
@@ -482,6 +980,7 @@
* @param iface The name of the interface of interest
* @return error The error code of the last error tethering or untethering the named
* interface
+ * @hide
*/
public int getLastTetherError(@NonNull final String iface) {
mCallback.waitForStarted();
@@ -503,6 +1002,7 @@
*
* @return an array of 0 or more regular expression Strings defining
* what interfaces are considered tetherable usb interfaces.
+ * @hide
*/
public @NonNull String[] getTetherableUsbRegexs() {
mCallback.waitForStarted();
@@ -516,6 +1016,7 @@
*
* @return an array of 0 or more regular expression Strings defining
* what interfaces are considered tetherable wifi interfaces.
+ * @hide
*/
public @NonNull String[] getTetherableWifiRegexs() {
mCallback.waitForStarted();
@@ -529,6 +1030,7 @@
*
* @return an array of 0 or more regular expression Strings defining
* what interfaces are considered tetherable bluetooth interfaces.
+ * @hide
*/
public @NonNull String[] getTetherableBluetoothRegexs() {
mCallback.waitForStarted();
@@ -540,6 +1042,7 @@
* device configuration and current interface existence.
*
* @return an array of 0 or more Strings of tetherable interface names.
+ * @hide
*/
public @NonNull String[] getTetherableIfaces() {
mCallback.waitForStarted();
@@ -552,6 +1055,7 @@
* Get the set of tethered interfaces.
*
* @return an array of 0 or more String of currently tethered interface names.
+ * @hide
*/
public @NonNull String[] getTetheredIfaces() {
mCallback.waitForStarted();
@@ -570,6 +1074,7 @@
*
* @return an array of 0 or more String indicating the interface names
* which failed to tether.
+ * @hide
*/
public @NonNull String[] getTetheringErroredIfaces() {
mCallback.waitForStarted();
@@ -582,6 +1087,7 @@
* Get the set of tethered dhcp ranges.
*
* @deprecated This API just return the default value which is not used in DhcpServer.
+ * @hide
*/
@Deprecated
public @NonNull String[] getTetheredDhcpRanges() {
@@ -595,14 +1101,15 @@
* due to device configuration.
*
* @return a boolean - {@code true} indicating Tethering is supported.
+ * @hide
*/
public boolean isTetheringSupported() {
final String callerPkg = mContext.getOpPackageName();
final RequestDispatcher dispatcher = new RequestDispatcher();
- final int ret = dispatcher.waitForResult(listener -> {
+ final int ret = dispatcher.waitForResult((connector, listener) -> {
try {
- mConnector.isTetheringSupported(callerPkg, listener);
+ connector.isTetheringSupported(callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -613,18 +1120,26 @@
/**
* Stop all active tethering.
+ *
+ * <p>Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
+ * fail if a tethering entitlement check is required.
*/
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.TETHER_PRIVILEGED,
+ android.Manifest.permission.WRITE_SETTINGS
+ })
public void stopAllTethering() {
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "stopAllTethering caller:" + callerPkg);
- final RequestDispatcher dispatcher = new RequestDispatcher();
- dispatcher.waitForResult(listener -> {
- try {
- mConnector.stopAllTethering(callerPkg, listener);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
+ getConnector(c -> c.stopAllTethering(callerPkg, new IIntResultListener.Stub() {
+ @Override
+ public void onResult(int resultCode) {
+ // TODO: add an API parameter to send result to caller.
+ // This has never been possible as stopAllTethering has always been void and never
+ // taken a callback object. The only indication that callers have is if the call
+ // results in a TETHER_STATE_CHANGE broadcast.
}
- });
+ }));
}
}
diff --git a/core/java/android/net/NetworkMisc.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
similarity index 64%
copy from core/java/android/net/NetworkMisc.aidl
copy to packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
index c65583f..bf19d85 100644
--- a/core/java/android/net/NetworkMisc.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -16,4 +16,15 @@
package android.net;
-parcelable NetworkMisc;
+import android.net.LinkAddress;
+
+/**
+ * Configuration details for requesting tethering.
+ * @hide
+ */
+parcelable TetheringRequestParcel {
+ int tetheringType;
+ LinkAddress localIPv4Address;
+ boolean exemptFromEntitlementCheck;
+ boolean showProvisioningUi;
+}
diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml
index 6fa1f77..379cd18 100644
--- a/packages/Tethering/res/values/config.xml
+++ b/packages/Tethering/res/values/config.xml
@@ -29,6 +29,12 @@
</string-array>
<!-- List of regexpressions describing the interface (if any) that represent tetherable
+ NCM interfaces. If the device doesn't want to support tethering over NCM this should
+ be empty. -->
+ <string-array translatable="false" name="config_tether_ncm_regexs">
+ </string-array>
+
+ <!-- List of regexpressions describing the interface (if any) that represent tetherable
Wifi interfaces. If the device doesn't want to support tethering over Wifi this
should be empty. An example would be "softap.*" -->
<string-array translatable="false" name="config_tether_wifi_regexs">
diff --git a/packages/Tethering/res/values/overlayable.xml b/packages/Tethering/res/values/overlayable.xml
index e089d9d..fe025c7 100644
--- a/packages/Tethering/res/values/overlayable.xml
+++ b/packages/Tethering/res/values/overlayable.xml
@@ -17,6 +17,7 @@
<overlayable name="TetheringConfig">
<policy type="product|system|vendor">
<item type="array" name="config_tether_usb_regexs"/>
+ <item type="array" name="config_tether_ncm_regexs" />
<item type="array" name="config_tether_wifi_regexs"/>
<item type="array" name="config_tether_wifi_p2p_regexs"/>
<item type="array" name="config_tether_bluetooth_regexs"/>
diff --git a/packages/Tethering/src/android/net/dhcp/DhcpServerCallbacks.java b/packages/Tethering/src/android/net/dhcp/DhcpServerCallbacks.java
index 7c413779..9fda125 100644
--- a/packages/Tethering/src/android/net/dhcp/DhcpServerCallbacks.java
+++ b/packages/Tethering/src/android/net/dhcp/DhcpServerCallbacks.java
@@ -28,4 +28,9 @@
public int getInterfaceVersion() {
return IDhcpServerCallbacks.VERSION;
}
+
+ @Override
+ public String getInterfaceHash() {
+ return IDhcpServerCallbacks.HASH;
+ }
}
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 4306cf0b..f39e7af 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -93,6 +93,8 @@
private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24;
private static final String WIFI_P2P_IFACE_ADDR = "192.168.49.1";
private static final int WIFI_P2P_IFACE_PREFIX_LENGTH = 24;
+ private static final String ETHERNET_IFACE_ADDR = "192.168.50.1";
+ private static final int ETHERNET_IFACE_PREFIX_LENGTH = 24;
// TODO: have PanService use some visible version of this constant
private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
@@ -299,6 +301,11 @@
public int getInterfaceVersion() {
return this.VERSION;
}
+
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
}
private class DhcpServerCallbacksImpl extends DhcpServerCallbacks {
@@ -416,7 +423,8 @@
final Inet4Address srvAddr;
int prefixLen = 0;
try {
- if (mInterfaceType == TetheringManager.TETHERING_USB) {
+ if (mInterfaceType == TetheringManager.TETHERING_USB
+ || mInterfaceType == TetheringManager.TETHERING_NCM) {
srvAddr = (Inet4Address) parseNumericAddress(USB_NEAR_IFACE_ADDR);
prefixLen = USB_PREFIX_LENGTH;
} else if (mInterfaceType == TetheringManager.TETHERING_WIFI) {
@@ -425,6 +433,10 @@
} else if (mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) {
srvAddr = (Inet4Address) parseNumericAddress(WIFI_P2P_IFACE_ADDR);
prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH;
+ } else if (mInterfaceType == TetheringManager.TETHERING_ETHERNET) {
+ // TODO: randomize address for tethering too, similarly to wifi
+ srvAddr = (Inet4Address) parseNumericAddress(ETHERNET_IFACE_ADDR);
+ prefixLen = ETHERNET_IFACE_PREFIX_LENGTH;
} else {
// BT configures the interface elsewhere: only start DHCP.
// TODO: make all tethering types behave the same way, and delete the bluetooth
@@ -441,7 +453,8 @@
}
final Boolean setIfaceUp;
- if (mInterfaceType == TetheringManager.TETHERING_WIFI) {
+ if (mInterfaceType == TetheringManager.TETHERING_WIFI
+ || mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) {
// The WiFi stack has ownership of the interface up/down state.
// It is unclear whether the Bluetooth or USB stacks will manage their own
// state.
diff --git a/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java b/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java
index 3218c0b..b1ffdb0 100644
--- a/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java
+++ b/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java
@@ -67,4 +67,9 @@
public int getInterfaceVersion() {
return INetdUnsolicitedEventListener.VERSION;
}
+
+ @Override
+ public String getInterfaceHash() {
+ return INetdUnsolicitedEventListener.HASH;
+ }
}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
index 1cabc8d..e81d6ac 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -16,14 +16,14 @@
package com.android.server.connectivity.tethering;
-import static android.net.TetheringManager.EXTRA_ADD_TETHER_TYPE;
-import static android.net.TetheringManager.EXTRA_PROVISION_CALLBACK;
-import static android.net.TetheringManager.EXTRA_RUN_PROVISION;
+import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE;
+import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK;
+import static android.net.TetheringConstants.EXTRA_RUN_PROVISION;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
import static android.net.TetheringManager.TETHERING_INVALID;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
-import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
+import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED;
@@ -577,7 +577,7 @@
private static String errorString(int value) {
switch (value) {
- case TETHER_ERROR_ENTITLEMENT_UNKONWN: return "TETHER_ERROR_ENTITLEMENT_UNKONWN";
+ case TETHER_ERROR_ENTITLEMENT_UNKNOWN: return "TETHER_ERROR_ENTITLEMENT_UNKONWN";
case TETHER_ERROR_NO_ERROR: return "TETHER_ERROR_NO_ERROR";
case TETHER_ERROR_PROVISION_FAILED: return "TETHER_ERROR_PROVISION_FAILED";
default:
@@ -657,7 +657,7 @@
}
final int cacheValue = mEntitlementCacheValue.get(
- downstream, TETHER_ERROR_ENTITLEMENT_UNKONWN);
+ downstream, TETHER_ERROR_ENTITLEMENT_UNKNOWN);
if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) {
receiver.send(cacheValue, null);
} else {
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index d372d1a..5b35bb6 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -19,6 +19,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
+import static android.hardware.usb.UsbManager.USB_FUNCTION_NCM;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
@@ -29,7 +30,9 @@
import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
import static android.net.TetheringManager.EXTRA_ERRORED_TETHER;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
import static android.net.TetheringManager.TETHERING_INVALID;
+import static android.net.TetheringManager.TETHERING_NCM;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
@@ -66,6 +69,8 @@
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
+import android.net.EthernetManager;
+import android.net.IIntResultListener;
import android.net.INetd;
import android.net.ITetheringEventCallback;
import android.net.IpPrefix;
@@ -74,7 +79,9 @@
import android.net.Network;
import android.net.NetworkInfo;
import android.net.TetherStatesParcel;
+import android.net.TetheringCallbackStartedParcel;
import android.net.TetheringConfigurationParcel;
+import android.net.TetheringRequestParcel;
import android.net.ip.IpServer;
import android.net.shared.NetdUtils;
import android.net.util.BaseNetdUnsolicitedEventListener;
@@ -107,6 +114,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.MessageUtils;
@@ -207,6 +215,14 @@
private Network mTetherUpstream;
private TetherStatesParcel mTetherStatesParcel;
private boolean mDataSaverEnabled = false;
+ private String mWifiP2pTetherInterface = null;
+
+ @GuardedBy("mPublicSync")
+ private EthernetManager.TetheredInterfaceRequest mEthernetIfaceRequest;
+ @GuardedBy("mPublicSync")
+ private String mConfiguredEthernetIface;
+ @GuardedBy("mPublicSync")
+ private EthernetCallback mEthernetCallback;
public Tethering(TetheringDependencies deps) {
mLog.mark("Tethering.constructed");
@@ -404,6 +420,8 @@
return TETHERING_USB;
} else if (cfg.isBluetooth(iface)) {
return TETHERING_BLUETOOTH;
+ } else if (cfg.isNcm(iface)) {
+ return TETHERING_NCM;
}
return TETHERING_INVALID;
}
@@ -422,9 +440,10 @@
}
}
- void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
- mEntitlementMgr.startProvisioningIfNeeded(type, showProvisioningUi);
- enableTetheringInternal(type, true /* enabled */, receiver);
+ void startTethering(final TetheringRequestParcel request, final IIntResultListener listener) {
+ mEntitlementMgr.startProvisioningIfNeeded(request.tetheringType,
+ request.showProvisioningUi);
+ enableTetheringInternal(request.tetheringType, true /* enabled */, listener);
}
void stopTethering(int type) {
@@ -436,29 +455,40 @@
* Enables or disables tethering for the given type. If provisioning is required, it will
* schedule provisioning rechecks for the specified interface.
*/
- private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
+ private void enableTetheringInternal(int type, boolean enable,
+ final IIntResultListener listener) {
int result;
switch (type) {
case TETHERING_WIFI:
result = setWifiTethering(enable);
- sendTetherResult(receiver, result);
+ sendTetherResult(listener, result);
break;
case TETHERING_USB:
result = setUsbTethering(enable);
- sendTetherResult(receiver, result);
+ sendTetherResult(listener, result);
break;
case TETHERING_BLUETOOTH:
- setBluetoothTethering(enable, receiver);
+ setBluetoothTethering(enable, listener);
+ break;
+ case TETHERING_NCM:
+ result = setNcmTethering(enable);
+ sendTetherResult(listener, result);
+ break;
+ case TETHERING_ETHERNET:
+ result = setEthernetTethering(enable);
+ sendTetherResult(listener, result);
break;
default:
Log.w(TAG, "Invalid tether type.");
- sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
+ sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE);
}
}
- private void sendTetherResult(ResultReceiver receiver, int result) {
- if (receiver != null) {
- receiver.send(result, null);
+ private void sendTetherResult(final IIntResultListener listener, int result) {
+ if (listener != null) {
+ try {
+ listener.onResult(result);
+ } catch (RemoteException e) { }
}
}
@@ -484,12 +514,12 @@
return TETHER_ERROR_MASTER_ERROR;
}
- private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
+ private void setBluetoothTethering(final boolean enable, final IIntResultListener listener) {
final BluetoothAdapter adapter = mDeps.getBluetoothAdapter();
if (adapter == null || !adapter.isEnabled()) {
Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: "
+ (adapter == null));
- sendTetherResult(receiver, TETHER_ERROR_SERVICE_UNAVAIL);
+ sendTetherResult(listener, TETHER_ERROR_SERVICE_UNAVAIL);
return;
}
@@ -518,12 +548,63 @@
final int result = (((BluetoothPan) proxy).isTetheringOn() == enable)
? TETHER_ERROR_NO_ERROR
: TETHER_ERROR_MASTER_ERROR;
- sendTetherResult(receiver, result);
+ sendTetherResult(listener, result);
adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
}
}, BluetoothProfile.PAN);
}
+ private int setEthernetTethering(final boolean enable) {
+ final EthernetManager em = (EthernetManager) mContext.getSystemService(
+ Context.ETHERNET_SERVICE);
+ synchronized (mPublicSync) {
+ if (enable) {
+ mEthernetCallback = new EthernetCallback();
+ mEthernetIfaceRequest = em.requestTetheredInterface(mEthernetCallback);
+ } else {
+ if (mConfiguredEthernetIface != null) {
+ stopEthernetTetheringLocked();
+ mEthernetIfaceRequest.release();
+ }
+ mEthernetCallback = null;
+ }
+ }
+ return TETHER_ERROR_NO_ERROR;
+ }
+
+ private void stopEthernetTetheringLocked() {
+ if (mConfiguredEthernetIface == null) return;
+ changeInterfaceState(mConfiguredEthernetIface, IpServer.STATE_AVAILABLE);
+ stopTrackingInterfaceLocked(mConfiguredEthernetIface);
+ mConfiguredEthernetIface = null;
+ }
+
+ private class EthernetCallback implements EthernetManager.TetheredInterfaceCallback {
+ @Override
+ public void onAvailable(String iface) {
+ synchronized (mPublicSync) {
+ if (this != mEthernetCallback) {
+ // Ethernet callback arrived after Ethernet tethering stopped. Ignore.
+ return;
+ }
+ maybeTrackNewInterfaceLocked(iface, TETHERING_ETHERNET);
+ changeInterfaceState(iface, IpServer.STATE_TETHERED);
+ mConfiguredEthernetIface = iface;
+ }
+ }
+
+ @Override
+ public void onUnavailable() {
+ synchronized (mPublicSync) {
+ if (this != mEthernetCallback) {
+ // onAvailable called after stopping Ethernet tethering.
+ return;
+ }
+ stopEthernetTetheringLocked();
+ }
+ }
+ }
+
int tether(String iface) {
return tether(iface, IpServer.STATE_TETHERED);
}
@@ -574,6 +655,7 @@
stopTethering(TETHERING_WIFI_P2P);
stopTethering(TETHERING_USB);
stopTethering(TETHERING_BLUETOOTH);
+ stopTethering(TETHERING_ETHERNET);
}
int getLastTetherError(String iface) {
@@ -741,8 +823,7 @@
.setContentIntent(pi);
mLastNotificationId = id;
- notificationManager.notify(null, mLastNotificationId,
- mTetheredNotificationBuilder.buildInto(new Notification()));
+ notificationManager.notify(null, mLastNotificationId, mTetheredNotificationBuilder.build());
}
@VisibleForTesting
@@ -798,6 +879,7 @@
final boolean usbConnected = intent.getBooleanExtra(USB_CONNECTED, false);
final boolean usbConfigured = intent.getBooleanExtra(USB_CONFIGURED, false);
final boolean rndisEnabled = intent.getBooleanExtra(USB_FUNCTION_RNDIS, false);
+ final boolean ncmEnabled = intent.getBooleanExtra(USB_FUNCTION_NCM, false);
mLog.log(String.format("USB bcast connected:%s configured:%s rndis:%s",
usbConnected, usbConfigured, rndisEnabled));
@@ -825,6 +907,8 @@
} else if (usbConfigured && rndisEnabled) {
// Tether if rndis is enabled and usb is configured.
tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
+ } else if (usbConnected && ncmEnabled) {
+ tetherMatchingInterfaces(IpServer.STATE_LOCAL_ONLY, TETHERING_NCM);
}
mRndisEnabled = usbConfigured && rndisEnabled;
}
@@ -853,6 +937,11 @@
}
}
+ private boolean isGroupOwner(WifiP2pGroup group) {
+ return group != null && group.isGroupOwner()
+ && !TextUtils.isEmpty(group.getInterface());
+ }
+
private void handleWifiP2pAction(Intent intent) {
if (mConfig.isWifiP2pLegacyTetheringMode()) return;
@@ -865,24 +954,31 @@
Log.d(TAG, "WifiP2pAction: P2pInfo: " + p2pInfo + " Group: " + group);
}
- if (p2pInfo == null) return;
- // When a p2p group is disconnected, p2pInfo would be cleared.
- // group is still valid for detecting whether this device is group owner.
- if (group == null || !group.isGroupOwner()
- || TextUtils.isEmpty(group.getInterface())) return;
-
synchronized (Tethering.this.mPublicSync) {
- // Enter below only if this device is Group Owner with a valid interface.
- if (p2pInfo.groupFormed) {
- TetherState tetherState = mTetherStates.get(group.getInterface());
- if (tetherState == null
- || (tetherState.lastState != IpServer.STATE_TETHERED
- && tetherState.lastState != IpServer.STATE_LOCAL_ONLY)) {
- enableWifiIpServingLocked(group.getInterface(), IFACE_IP_MODE_LOCAL_ONLY);
- }
- } else {
- disableWifiP2pIpServingLocked(group.getInterface());
+ // if no group is formed, bring it down if needed.
+ if (p2pInfo == null || !p2pInfo.groupFormed) {
+ disableWifiP2pIpServingLockedIfNeeded(mWifiP2pTetherInterface);
+ mWifiP2pTetherInterface = null;
+ return;
}
+
+ // If there is a group but the device is not the owner, bail out.
+ if (!isGroupOwner(group)) return;
+
+ // If already serving from the correct interface, nothing to do.
+ if (group.getInterface().equals(mWifiP2pTetherInterface)) return;
+
+ // If already serving from another interface, turn it down first.
+ if (!TextUtils.isEmpty(mWifiP2pTetherInterface)) {
+ mLog.w("P2P tethered interface " + mWifiP2pTetherInterface
+ + "is different from current interface "
+ + group.getInterface() + ", re-tether it");
+ disableWifiP2pIpServingLockedIfNeeded(mWifiP2pTetherInterface);
+ }
+
+ // Finally bring up serving on the new interface
+ mWifiP2pTetherInterface = group.getInterface();
+ enableWifiIpServingLocked(mWifiP2pTetherInterface, IFACE_IP_MODE_LOCAL_ONLY);
}
}
@@ -939,6 +1035,7 @@
mWrapper.showTetheredNotification(
R.drawable.stat_sys_tether_general, false);
mWrapper.untetherAll();
+ // TODO(b/148139325): send tetheringSupported on restriction change
}
}
}
@@ -980,7 +1077,9 @@
disableWifiIpServingLockedCommon(TETHERING_WIFI, ifname, apState);
}
- private void disableWifiP2pIpServingLocked(String ifname) {
+ private void disableWifiP2pIpServingLockedIfNeeded(String ifname) {
+ if (TextUtils.isEmpty(ifname)) return;
+
disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0);
}
@@ -1111,6 +1210,16 @@
return TETHER_ERROR_NO_ERROR;
}
+ private int setNcmTethering(boolean enable) {
+ if (VDBG) Log.d(TAG, "setNcmTethering(" + enable + ")");
+ UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
+ synchronized (mPublicSync) {
+ usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_NCM
+ : UsbManager.FUNCTION_NONE);
+ }
+ return TETHER_ERROR_NO_ERROR;
+ }
+
// TODO review API - figure out how to delete these entirely.
String[] getTetheredIfaces() {
ArrayList<String> list = new ArrayList<String>();
@@ -1830,9 +1939,13 @@
void registerTetheringEventCallback(ITetheringEventCallback callback) {
mHandler.post(() -> {
mTetheringEventCallbacks.register(callback);
+ final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel();
+ parcel.tetheringSupported = mDeps.isTetheringSupported();
+ parcel.upstreamNetwork = mTetherUpstream;
+ parcel.config = mConfig.toStableParcelable();
+ parcel.states = mTetherStatesParcel;
try {
- callback.onCallbackStarted(mTetherUpstream, mConfig.toStableParcelable(),
- mTetherStatesParcel);
+ callback.onCallbackStarted(parcel);
} catch (RemoteException e) {
// Not really very much to do here.
}
@@ -1867,6 +1980,7 @@
for (int i = 0; i < length; i++) {
try {
mTetheringEventCallbacks.getBroadcastItem(i).onConfigurationChanged(config);
+ // TODO(b/148139325): send tetheringSupported on configuration change
} catch (RemoteException e) {
// Not really very much to do here.
}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 068c346..7e9e26f 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -83,6 +83,7 @@
public final String[] tetherableWifiRegexs;
public final String[] tetherableWifiP2pRegexs;
public final String[] tetherableBluetoothRegexs;
+ public final String[] tetherableNcmRegexs;
public final boolean isDunRequired;
public final boolean chooseUpstreamAutomatically;
public final Collection<Integer> preferredUpstreamIfaceTypes;
@@ -103,6 +104,7 @@
Resources res = getResources(ctx, activeDataSubId);
tetherableUsbRegexs = getResourceStringArray(res, R.array.config_tether_usb_regexs);
+ tetherableNcmRegexs = getResourceStringArray(res, R.array.config_tether_ncm_regexs);
// TODO: Evaluate deleting this altogether now that Wi-Fi always passes
// us an interface name. Careful consideration needs to be given to
// implications for Settings and for provisioning checks.
@@ -156,6 +158,11 @@
return matchesDownstreamRegexs(iface, tetherableBluetoothRegexs);
}
+ /** Check if interface is ncm */
+ public boolean isNcm(String iface) {
+ return matchesDownstreamRegexs(iface, tetherableNcmRegexs);
+ }
+
/** Check whether no ui entitlement application is available.*/
public boolean hasMobileHotspotProvisionApp() {
return !TextUtils.isEmpty(provisioningAppNoUi);
@@ -170,6 +177,7 @@
dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs);
dumpStringArray(pw, "tetherableWifiP2pRegexs", tetherableWifiP2pRegexs);
dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs);
+ dumpStringArray(pw, "tetherableNcmRegexs", tetherableNcmRegexs);
pw.print("isDunRequired: ");
pw.println(isDunRequired);
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java
index 247ed47..e019c3a 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -24,9 +24,7 @@
import android.net.util.SharedLog;
import android.os.Handler;
import android.os.IBinder;
-import android.os.INetworkManagementService;
import android.os.Looper;
-import android.os.ServiceManager;
import com.android.internal.util.StateMachine;
@@ -96,16 +94,6 @@
}
/**
- * Get a reference to INetworkManagementService to registerTetheringStatsProvider from
- * OffloadController. Note: This should be removed soon by Usage refactor work in R
- * development cycle.
- */
- public INetworkManagementService getINetworkManagementService() {
- return INetworkManagementService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
- }
-
- /**
* Get a reference to INetd to be used by tethering.
*/
public INetd getINetd(Context context) {
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
index cb7d392..7dc5c5f 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
@@ -33,6 +33,7 @@
import android.net.ITetheringEventCallback;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
+import android.net.TetheringRequestParcel;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.ip.IpServer;
@@ -143,11 +144,11 @@
}
@Override
- public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
- String callerPkg) {
- if (checkAndNotifyCommonError(callerPkg, receiver)) return;
+ public void startTethering(TetheringRequestParcel request, String callerPkg,
+ IIntResultListener listener) {
+ if (checkAndNotifyCommonError(callerPkg, listener)) return;
- mTethering.startTethering(type, receiver, showProvisioningUi);
+ mTethering.startTethering(request, listener);
}
@Override
diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp
index 53782fed..13174c5 100644
--- a/packages/Tethering/tests/unit/Android.bp
+++ b/packages/Tethering/tests/unit/Android.bp
@@ -19,6 +19,7 @@
certificate: "platform",
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
],
test_suites: [
"device-tests",
diff --git a/packages/Tethering/tests/unit/AndroidManifest.xml b/packages/Tethering/tests/unit/AndroidManifest.xml
index 0a1cdd3..530bc07 100644
--- a/packages/Tethering/tests/unit/AndroidManifest.xml
+++ b/packages/Tethering/tests/unit/AndroidManifest.xml
@@ -16,6 +16,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.networkstack.tethering.tests.unit">
+ <uses-permission android:name="android.permission.TETHER_PRIVILEGED"/>
+
<application android:debuggable="true">
<uses-library android:name="android.test.runner" />
</application>
diff --git a/packages/Tethering/tests/unit/src/android/net/TetheredClientTest.kt b/packages/Tethering/tests/unit/src/android/net/TetheredClientTest.kt
new file mode 100644
index 0000000..83c19ec
--- /dev/null
+++ b/packages/Tethering/tests/unit/src/android/net/TetheredClientTest.kt
@@ -0,0 +1,95 @@
+/*
+ * 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 android.net.InetAddresses.parseNumericAddress
+import android.net.TetheredClient.AddressInfo
+import android.net.TetheringManager.TETHERING_BLUETOOTH
+import android.net.TetheringManager.TETHERING_USB
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.assertParcelSane
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertEquals
+import kotlin.test.assertNotEquals
+
+private val TEST_MACADDR = MacAddress.fromBytes(byteArrayOf(12, 23, 34, 45, 56, 67))
+private val TEST_OTHER_MACADDR = MacAddress.fromBytes(byteArrayOf(23, 34, 45, 56, 67, 78))
+private val TEST_ADDR1 = LinkAddress(parseNumericAddress("192.168.113.3"), 24)
+private val TEST_ADDR2 = LinkAddress(parseNumericAddress("fe80::1:2:3"), 64)
+private val TEST_ADDRINFO1 = AddressInfo(TEST_ADDR1, "test_hostname")
+private val TEST_ADDRINFO2 = AddressInfo(TEST_ADDR2, null)
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class TetheredClientTest {
+ @Test
+ fun testParceling() {
+ assertParcelSane(makeTestClient(), fieldCount = 3)
+ }
+
+ @Test
+ fun testEquals() {
+ assertEquals(makeTestClient(), makeTestClient())
+
+ // Different mac address
+ assertNotEquals(makeTestClient(), TetheredClient(
+ TEST_OTHER_MACADDR,
+ listOf(TEST_ADDRINFO1, TEST_ADDRINFO2),
+ TETHERING_BLUETOOTH))
+
+ // Different hostname
+ assertNotEquals(makeTestClient(), TetheredClient(
+ TEST_MACADDR,
+ listOf(AddressInfo(TEST_ADDR1, "test_other_hostname"), TEST_ADDRINFO2),
+ TETHERING_BLUETOOTH))
+
+ // Null hostname
+ assertNotEquals(makeTestClient(), TetheredClient(
+ TEST_MACADDR,
+ listOf(AddressInfo(TEST_ADDR1, null), TEST_ADDRINFO2),
+ TETHERING_BLUETOOTH))
+
+ // Missing address
+ assertNotEquals(makeTestClient(), TetheredClient(
+ TEST_MACADDR,
+ listOf(TEST_ADDRINFO2),
+ TETHERING_BLUETOOTH))
+
+ // Different type
+ assertNotEquals(makeTestClient(), TetheredClient(
+ TEST_MACADDR,
+ listOf(TEST_ADDRINFO1, TEST_ADDRINFO2),
+ TETHERING_BLUETOOTH))
+ }
+
+ @Test
+ fun testAddAddresses() {
+ val client1 = TetheredClient(TEST_MACADDR, listOf(TEST_ADDRINFO1), TETHERING_USB)
+ val client2 = TetheredClient(TEST_OTHER_MACADDR, listOf(TEST_ADDRINFO2), TETHERING_USB)
+ assertEquals(TetheredClient(
+ TEST_MACADDR,
+ listOf(TEST_ADDRINFO1, TEST_ADDRINFO2),
+ TETHERING_USB), client1.addAddresses(client2))
+ }
+
+ private fun makeTestClient() = TetheredClient(
+ TEST_MACADDR,
+ listOf(TEST_ADDRINFO1, TEST_ADDRINFO2),
+ TETHERING_BLUETOOTH)
+}
\ No newline at end of file
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 1f50b6b..f29ad78 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -273,7 +273,7 @@
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
InOrder inOrder = inOrder(mCallback, mNetd);
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
- IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
+ IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP)));
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
@@ -547,4 +547,14 @@
fail("Missing flag: " + match);
return false;
}
+
+ private boolean assertNotContainsFlag(String[] flags, String match) {
+ for (String flag : flags) {
+ if (flag.equals(match)) {
+ fail("Unexpected flag: " + match);
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index 4f07461..3a1d4a6 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -19,7 +19,7 @@
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
-import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
+import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED;
import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
@@ -110,7 +110,7 @@
}
public class WrappedEntitlementManager extends EntitlementManager {
- public int fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
+ public int fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKNOWN;
public int uiProvisionCount = 0;
public int silentProvisionCount = 0;
@@ -120,7 +120,7 @@
}
public void reset() {
- fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
+ fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKNOWN;
uiProvisionCount = 0;
silentProvisionCount = 0;
}
@@ -274,7 +274,7 @@
receiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
- assertEquals(TETHER_ERROR_ENTITLEMENT_UNKONWN, resultCode);
+ assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode);
mCallbacklatch.countDown();
}
};
@@ -343,7 +343,7 @@
receiver = new ResultReceiver(null) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
- assertEquals(TETHER_ERROR_ENTITLEMENT_UNKONWN, resultCode);
+ assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode);
mCallbacklatch.countDown();
}
};
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index 0dcd0a5..e7c3e55 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -18,6 +18,7 @@
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
+import static android.hardware.usb.UsbManager.USB_FUNCTION_NCM;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
@@ -27,6 +28,7 @@
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.TetheringManager.TETHERING_NCM;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
@@ -74,7 +76,6 @@
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
import android.net.INetd;
-import android.net.INetworkPolicyManager;
import android.net.ITetheringEventCallback;
import android.net.InetAddresses;
import android.net.InterfaceConfigurationParcel;
@@ -87,7 +88,9 @@
import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.TetherStatesParcel;
+import android.net.TetheringCallbackStartedParcel;
import android.net.TetheringConfigurationParcel;
+import android.net.TetheringRequestParcel;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServer;
@@ -103,7 +106,6 @@
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Bundle;
import android.os.Handler;
-import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.PersistableBundle;
import android.os.RemoteException;
@@ -151,15 +153,14 @@
private static final String TEST_USB_IFNAME = "test_rndis0";
private static final String TEST_WLAN_IFNAME = "test_wlan0";
private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0";
+ private static final String TEST_NCM_IFNAME = "test_ncm0";
private static final String TETHERING_NAME = "Tethering";
private static final int DHCPSERVER_START_TIMEOUT_MS = 1000;
@Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext;
- @Mock private INetworkManagementService mNMService;
@Mock private NetworkStatsManager mStatsManager;
- @Mock private INetworkPolicyManager mPolicyManager;
@Mock private OffloadHardwareInterface mOffloadHardwareInterface;
@Mock private Resources mResources;
@Mock private TelephonyManager mTelephonyManager;
@@ -254,9 +255,11 @@
ifName.equals(TEST_USB_IFNAME)
|| ifName.equals(TEST_WLAN_IFNAME)
|| ifName.equals(TEST_MOBILE_IFNAME)
- || ifName.equals(TEST_P2P_IFNAME));
+ || ifName.equals(TEST_P2P_IFNAME)
+ || ifName.equals(TEST_NCM_IFNAME));
final String[] ifaces = new String[] {
- TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME, TEST_P2P_IFNAME};
+ TEST_USB_IFNAME, TEST_WLAN_IFNAME, TEST_MOBILE_IFNAME, TEST_P2P_IFNAME,
+ TEST_NCM_IFNAME};
return new InterfaceParams(ifName, ArrayUtils.indexOf(ifaces, ifName) + IFINDEX_OFFSET,
MacAddress.ALL_ZEROS_ADDRESS);
}
@@ -343,11 +346,6 @@
}
@Override
- public INetworkManagementService getINetworkManagementService() {
- return mNMService;
- }
-
- @Override
public INetd getINetd(Context context) {
return mNetd;
}
@@ -435,13 +433,16 @@
.thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
.thenReturn(new String[0]);
+ when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
+ .thenReturn(new String[] { "test_ncm\\d" });
when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]);
when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(false);
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
false);
when(mNetd.interfaceGetList())
.thenReturn(new String[] {
- TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME});
+ TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME,
+ TEST_NCM_IFNAME});
when(mResources.getString(R.string.config_wifi_tether_enable)).thenReturn("");
mInterfaceConfiguration = new InterfaceConfigurationParcel();
mInterfaceConfiguration.flags = new String[0];
@@ -476,6 +477,16 @@
return new Tethering(mTetheringDependencies);
}
+ private TetheringRequestParcel createTetheringRquestParcel(final int type) {
+ final TetheringRequestParcel request = new TetheringRequestParcel();
+ request.tetheringType = type;
+ request.localIPv4Address = null;
+ request.exemptFromEntitlementCheck = false;
+ request.showProvisioningUi = false;
+
+ return request;
+ }
+
@After
public void tearDown() {
mServiceContext.unregisterReceiver(mBroadcastReceiver);
@@ -502,26 +513,35 @@
private void sendWifiP2pConnectionChanged(
boolean isGroupFormed, boolean isGroupOwner, String ifname) {
+ WifiP2pGroup group = null;
WifiP2pInfo p2pInfo = new WifiP2pInfo();
p2pInfo.groupFormed = isGroupFormed;
- p2pInfo.isGroupOwner = isGroupOwner;
+ if (isGroupFormed) {
+ p2pInfo.isGroupOwner = isGroupOwner;
+ group = mock(WifiP2pGroup.class);
+ when(group.isGroupOwner()).thenReturn(isGroupOwner);
+ when(group.getInterface()).thenReturn(ifname);
+ }
- WifiP2pGroup group = new WifiP2pGroup();
- group.setIsGroupOwner(isGroupOwner);
- group.setInterface(ifname);
+ final Intent intent = mock(Intent.class);
+ when(intent.getAction()).thenReturn(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+ when(intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO)).thenReturn(p2pInfo);
+ when(intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP)).thenReturn(group);
- final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
- intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, p2pInfo);
- intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, group);
mServiceContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL,
P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST);
}
- private void sendUsbBroadcast(boolean connected, boolean configured, boolean rndisFunction) {
+ private void sendUsbBroadcast(boolean connected, boolean configured, boolean function,
+ int type) {
final Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
intent.putExtra(USB_CONNECTED, connected);
intent.putExtra(USB_CONFIGURED, configured);
- intent.putExtra(USB_FUNCTION_RNDIS, rndisFunction);
+ if (type == TETHERING_USB) {
+ intent.putExtra(USB_FUNCTION_RNDIS, function);
+ } else {
+ intent.putExtra(USB_FUNCTION_NCM, function);
+ }
mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -571,13 +591,22 @@
verifyNoMoreInteractions(mWifiManager);
}
+ private void prepareNcmTethering() {
+ // Emulate startTethering(TETHERING_NCM) called
+ mTethering.startTethering(createTetheringRquestParcel(TETHERING_NCM), null);
+ mLooper.dispatchAll();
+ verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NCM);
+
+ mTethering.interfaceStatusChanged(TEST_NCM_IFNAME, true);
+ }
+
private void prepareUsbTethering(UpstreamNetworkState upstreamState) {
when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
.thenReturn(upstreamState);
// Emulate pressing the USB tethering button in Settings UI.
- mTethering.startTethering(TETHERING_USB, null, false);
+ mTethering.startTethering(createTetheringRquestParcel(TETHERING_USB), null);
mLooper.dispatchAll();
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
@@ -593,7 +622,7 @@
verifyNoMoreInteractions(mNetd);
// Pretend we then receive USB configured broadcast.
- sendUsbBroadcast(true, true, true);
+ sendUsbBroadcast(true, true, true, TETHERING_USB);
mLooper.dispatchAll();
// Now we should see the start of tethering mechanics (in this case:
// tetherMatchingInterfaces() which starts by fetching all interfaces).
@@ -684,7 +713,7 @@
private void runUsbTethering(UpstreamNetworkState upstreamState) {
prepareUsbTethering(upstreamState);
- sendUsbBroadcast(true, true, true);
+ sendUsbBroadcast(true, true, true, TETHERING_USB);
mLooper.dispatchAll();
}
@@ -807,6 +836,29 @@
verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
}
+ private void runNcmTethering() {
+ prepareNcmTethering();
+ sendUsbBroadcast(true, true, true, TETHERING_NCM);
+ mLooper.dispatchAll();
+ }
+
+ @Test
+ public void workingNcmTethering() throws Exception {
+ runNcmTethering();
+
+ verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).start(any());
+ }
+
+ @Test
+ public void workingNcmTethering_LegacyDhcp() {
+ when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
+ true);
+ sendConfigurationChanged();
+ runNcmTethering();
+
+ verify(mIpServerDependencies, never()).makeDhcpServer(any(), any(), any());
+ }
+
@Test
public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
workingLocalOnlyHotspotEnrichedApBroadcast(true);
@@ -823,7 +875,7 @@
when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
- mTethering.startTethering(TETHERING_WIFI, null, false);
+ mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
@@ -850,7 +902,7 @@
when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
- mTethering.startTethering(TETHERING_WIFI, null, false);
+ mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
@@ -927,7 +979,7 @@
doThrow(new RemoteException()).when(mNetd).ipfwdEnableForwarding(TETHERING_NAME);
// Emulate pressing the WiFi tethering button.
- mTethering.startTethering(TETHERING_WIFI, null, false);
+ mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
@@ -1118,11 +1170,10 @@
}
@Override
- public void onCallbackStarted(Network network, TetheringConfigurationParcel config,
- TetherStatesParcel states) {
- mActualUpstreams.add(network);
- mTetheringConfigs.add(config);
- mTetherStates.add(states);
+ public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
+ mActualUpstreams.add(parcel.upstreamNetwork);
+ mTetheringConfigs.add(parcel.config);
+ mTetherStates.add(parcel.states);
}
@Override
@@ -1193,7 +1244,7 @@
tetherState = callback.pollTetherStatesChanged();
assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME});
- mTethering.startTethering(TETHERING_WIFI, null, false);
+ mTethering.startTethering(createTetheringRquestParcel(TETHERING_WIFI), null);
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
mLooper.dispatchAll();
tetherState = callback.pollTetherStatesChanged();
diff --git a/packages/WAPPushManager/Android.bp b/packages/WAPPushManager/Android.bp
index c391369..083dac9 100644
--- a/packages/WAPPushManager/Android.bp
+++ b/packages/WAPPushManager/Android.bp
@@ -10,5 +10,5 @@
proguard_flags_files: ["proguard.flags"],
},
- product_specific: true,
+ system_ext_specific: true,
}
diff --git a/packages/WAPPushManager/CleanSpec.mk b/packages/WAPPushManager/CleanSpec.mk
index 2dcbb10..f4e316c 100644
--- a/packages/WAPPushManager/CleanSpec.mk
+++ b/packages/WAPPushManager/CleanSpec.mk
@@ -49,3 +49,5 @@
# ************************************************
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/WAPPushManager)
+$(call add-clean-step, rm -rf $(TARGET_OUT_PRODUCT)/app/WAPPushManager)
+
diff --git a/packages/WallpaperCropper/Android.bp b/packages/WallpaperCropper/Android.bp
index 40c4235..ac38b27 100644
--- a/packages/WallpaperCropper/Android.bp
+++ b/packages/WallpaperCropper/Android.bp
@@ -3,7 +3,7 @@
srcs: ["src/**/*.java"],
platform_apis: true,
certificate: "platform",
- product_specific: true,
+ system_ext_specific: true,
privileged: true,
optimize: {
proguard_flags_files: ["proguard.flags"],
diff --git a/packages/WallpaperCropper/CleanSpec.mk b/packages/WallpaperCropper/CleanSpec.mk
index e6d8d5a..f08c343 100644
--- a/packages/WallpaperCropper/CleanSpec.mk
+++ b/packages/WallpaperCropper/CleanSpec.mk
@@ -44,6 +44,7 @@
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/WallpaperCropper)
+$(call add-clean-step, rm -rf $(TARGET_OUT_PRODUCT)/priv-app/WallpaperCropper)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java
index b7e05d9..7b5514b 100644
--- a/rs/java/android/renderscript/BaseObj.java
+++ b/rs/java/android/renderscript/BaseObj.java
@@ -16,8 +16,10 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
import dalvik.system.CloseGuard;
+
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index b8eb3a1..0941907 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* <p>An Element represents one item within an {@link
diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java
index 9a6b0bc..7cc2825 100644
--- a/rs/java/android/renderscript/FileA3D.java
+++ b/rs/java/android/renderscript/FileA3D.java
@@ -16,13 +16,13 @@
package android.renderscript;
-import java.io.File;
-import java.io.InputStream;
-
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.AssetManager;
import android.content.res.Resources;
+import java.io.File;
+import java.io.InputStream;
+
/**
* @hide
* @deprecated in API 16
diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java
index 583350e..df9d801 100644
--- a/rs/java/android/renderscript/Font.java
+++ b/rs/java/android/renderscript/Font.java
@@ -16,17 +16,16 @@
package android.renderscript;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.os.Environment;
+
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
-import android.os.Environment;
-
-import android.annotation.UnsupportedAppUsage;
-import android.content.res.AssetManager;
-import android.content.res.Resources;
-
/**
* @hide
* @deprecated in API 16
diff --git a/rs/java/android/renderscript/Matrix4f.java b/rs/java/android/renderscript/Matrix4f.java
index 026c9fb..a9469c9 100644
--- a/rs/java/android/renderscript/Matrix4f.java
+++ b/rs/java/android/renderscript/Matrix4f.java
@@ -16,8 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
-import java.lang.Math;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java
index 5321dcb..826225a 100644
--- a/rs/java/android/renderscript/Mesh.java
+++ b/rs/java/android/renderscript/Mesh.java
@@ -16,7 +16,8 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
import java.util.Vector;
/**
diff --git a/rs/java/android/renderscript/Program.java b/rs/java/android/renderscript/Program.java
index e28d646..ff07218 100644
--- a/rs/java/android/renderscript/Program.java
+++ b/rs/java/android/renderscript/Program.java
@@ -17,14 +17,14 @@
package android.renderscript;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.res.Resources;
+import android.util.Log;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
-import android.annotation.UnsupportedAppUsage;
-import android.content.res.Resources;
-import android.util.Log;
-
/**
* @hide
diff --git a/rs/java/android/renderscript/ProgramFragment.java b/rs/java/android/renderscript/ProgramFragment.java
index 3dde9b6..8805312 100644
--- a/rs/java/android/renderscript/ProgramFragment.java
+++ b/rs/java/android/renderscript/ProgramFragment.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java
index d05d41d..c741ce6 100644
--- a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java
+++ b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/ProgramRaster.java b/rs/java/android/renderscript/ProgramRaster.java
index 33000ac..a21696c 100644
--- a/rs/java/android/renderscript/ProgramRaster.java
+++ b/rs/java/android/renderscript/ProgramRaster.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/ProgramStore.java b/rs/java/android/renderscript/ProgramStore.java
index 622fe21..7e61347 100644
--- a/rs/java/android/renderscript/ProgramStore.java
+++ b/rs/java/android/renderscript/ProgramStore.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/ProgramVertex.java b/rs/java/android/renderscript/ProgramVertex.java
index 83d9ea7..9257234 100644
--- a/rs/java/android/renderscript/ProgramVertex.java
+++ b/rs/java/android/renderscript/ProgramVertex.java
@@ -38,7 +38,7 @@
**/
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/ProgramVertexFixedFunction.java b/rs/java/android/renderscript/ProgramVertexFixedFunction.java
index 579d3bb..03c2eaf 100644
--- a/rs/java/android/renderscript/ProgramVertexFixedFunction.java
+++ b/rs/java/android/renderscript/ProgramVertexFixedFunction.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
diff --git a/rs/java/android/renderscript/RSSurfaceView.java b/rs/java/android/renderscript/RSSurfaceView.java
index 561373c..6bdde38 100644
--- a/rs/java/android/renderscript/RSSurfaceView.java
+++ b/rs/java/android/renderscript/RSSurfaceView.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index f4c2777..46c49e5 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
diff --git a/rs/java/android/renderscript/RenderScriptCacheDir.java b/rs/java/android/renderscript/RenderScriptCacheDir.java
index 1797bef..862d032 100644
--- a/rs/java/android/renderscript/RenderScriptCacheDir.java
+++ b/rs/java/android/renderscript/RenderScriptCacheDir.java
@@ -16,7 +16,8 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
+
import java.io.File;
/**
diff --git a/rs/java/android/renderscript/RenderScriptGL.java b/rs/java/android/renderscript/RenderScriptGL.java
index 6fac83e..dafaf36 100644
--- a/rs/java/android/renderscript/RenderScriptGL.java
+++ b/rs/java/android/renderscript/RenderScriptGL.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.view.Surface;
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index 9ad9aea..d1d3a76 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -16,7 +16,7 @@
package android.renderscript;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.util.SparseArray;
/**
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 0000000..31cd5d5
--- /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 cdfd310..fa8eda5 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.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 @@
// 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 @@
private boolean mBinding;
private boolean mUnbinding;
+ private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener;
+
// used inside handler thread
private boolean mQuietEnable = false;
private boolean mEnable;
@@ -257,68 +261,65 @@
}
};
- 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);
- }
- }
-
- 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());
-
+ public void onAirplaneModeChanged() {
+ synchronized (this) {
+ if (isBluetoothPersistedStateOn()) {
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();
- }
- } 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());
+ 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();
+ }
+
+ 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 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();
+ }
+ } 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 @@
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 @@
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 @@
}
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 @@
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 6572072..e98c370 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_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;
@@ -65,6 +66,7 @@
import android.net.ConnectionInfo;
import android.net.ConnectivityManager;
import android.net.ICaptivePortal;
+import android.net.IConnectivityDiagnosticsCallback;
import android.net.IConnectivityManager;
import android.net.IDnsResolver;
import android.net.IIpConnectivityMetrics;
@@ -86,12 +88,11 @@
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;
@@ -212,6 +213,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
@@ -1573,48 +1575,49 @@
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
@@ -1623,7 +1626,8 @@
return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
}
- private NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions(
+ @VisibleForTesting
+ NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions(
NetworkCapabilities nc, int callerPid, int callerUid) {
final NetworkCapabilities newNc = new NetworkCapabilities(nc);
if (!checkSettingsPermission(callerPid, callerUid)) {
@@ -1633,13 +1637,55 @@
if (newNc.getNetworkSpecifier() != null) {
newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
}
+ newNc.setAdministratorUids(Collections.EMPTY_LIST);
+
+ maybeSanitizeLocationInfoForCaller(newNc, callerUid);
+
return newNc;
}
+ private void maybeSanitizeLocationInfoForCaller(
+ NetworkCapabilities nc, int callerUid) {
+ // TODO(b/142072839): Conditionally reset the owner UID if the following
+ // conditions are not met:
+ // 1. The destination app is the network owner
+ // 2. The destination app has the ACCESS_COARSE_LOCATION permission granted
+ // if target SDK<29 or otherwise has the ACCESS_FINE_LOCATION permission granted
+ // 3. The user's location toggle is on
+ nc.setOwnerUid(INVALID_UID);
+ }
+
+ 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());
}
+ nc.setAdministratorUids(Collections.EMPTY_LIST);
+
+ // Clear owner UID; this can never come from an app.
+ nc.setOwnerUid(INVALID_UID);
}
private void restrictBackgroundRequestForCaller(NetworkCapabilities nc) {
@@ -2624,8 +2670,8 @@
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 +2679,7 @@
// 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 +2711,10 @@
}
// 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 +2724,7 @@
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 +2783,7 @@
// 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 +2842,10 @@
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 +2882,11 @@
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);
}
}
@@ -2923,6 +2955,11 @@
public int getInterfaceVersion() {
return this.VERSION;
}
+
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
}
private boolean networkRequiresPrivateDnsValidation(NetworkAgentInfo nai) {
@@ -3163,8 +3200,8 @@
// 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 +3501,16 @@
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 +3547,8 @@
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 +3773,7 @@
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 +3806,15 @@
// 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 +5534,14 @@
// 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 +5556,13 @@
* 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 +5574,8 @@
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 +5593,7 @@
// 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) {
@@ -5776,7 +5818,7 @@
}
final Set<UidRange> ranges = nai.networkCapabilities.getUids();
- final int vpnAppUid = nai.networkCapabilities.getEstablishingVpnAppUid();
+ final int vpnAppUid = nai.networkCapabilities.getOwnerUid();
// TODO: this create a window of opportunity for apps to receive traffic between the time
// when the old rules are removed and the time when new rules are added. To fix this,
// make eBPF support two whitelisted interfaces so here new rules can be added before the
@@ -5803,6 +5845,19 @@
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 +5898,6 @@
} 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 +5905,12 @@
}
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 +5930,11 @@
* @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 +5945,19 @@
// 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 +5965,9 @@
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,8 +6016,8 @@
LinkProperties lp) {
if (nc == null || lp == null) return false;
return nai.isVPN()
- && !nai.networkMisc.allowBypass
- && nc.getEstablishingVpnAppUid() != Process.SYSTEM_UID
+ && !nai.networkAgentConfig.allowBypass
+ && nc.getOwnerUid() != Process.SYSTEM_UID
&& lp.getInterfaceName() != null
&& (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute());
}
@@ -6003,12 +6065,10 @@
// TODO Fix this window by computing an accurate diff on Set<UidRange>, so the old range
// to be removed will never overlap with the new range to be added.
if (wasFiltering && !prevRanges.isEmpty()) {
- mPermissionMonitor.onVpnUidRangesRemoved(iface, prevRanges,
- prevNc.getEstablishingVpnAppUid());
+ mPermissionMonitor.onVpnUidRangesRemoved(iface, prevRanges, prevNc.getOwnerUid());
}
if (shouldFilter && !newRanges.isEmpty()) {
- mPermissionMonitor.onVpnUidRangesAdded(iface, newRanges,
- newNc.getEstablishingVpnAppUid());
+ mPermissionMonitor.onVpnUidRangesAdded(iface, newRanges, newNc.getOwnerUid());
}
} catch (Exception e) {
// Never crash!
@@ -6127,7 +6187,8 @@
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 +6205,8 @@
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 +6315,30 @@
}
}
+ // 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 +6384,8 @@
// 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 +6393,22 @@
// 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 +6511,12 @@
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 +6538,24 @@
// 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 +6587,24 @@
}
}
+ /**
+ * 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 +6696,31 @@
}
}
- 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 +6762,7 @@
// 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 +6802,6 @@
}
} 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);
}
}
@@ -7223,4 +7329,20 @@
return mTNS;
}
}
+
+ @Override
+ public void registerConnectivityDiagnosticsCallback(
+ @NonNull IConnectivityDiagnosticsCallback callback, @NonNull NetworkRequest request) {
+ // TODO(b/146444622): implement register IConnectivityDiagnosticsCallback functionality
+ throw new UnsupportedOperationException(
+ "registerConnectivityDiagnosticsCallback not yet implemented");
+ }
+
+ @Override
+ public void unregisterConnectivityDiagnosticsCallback(
+ @NonNull IConnectivityDiagnosticsCallback callback) {
+ // TODO(b/146444622): implement register IConnectivityDiagnosticsCallback functionality
+ throw new UnsupportedOperationException(
+ "unregisterConnectivityDiagnosticsCallback not yet implemented");
+ }
}
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 7909e30..c60460f 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -44,9 +44,9 @@
private static final String TAG = "DynamicSystemService";
private static final String NO_SERVICE_ERROR = "no gsiservice";
private static final int GSID_ROUGH_TIMEOUT_MS = 8192;
- private static final String PATH_DEFAULT = "/data/gsi";
+ private static final String PATH_DEFAULT = "/data/gsi/";
private Context mContext;
- private String mInstallPath;
+ private String mInstallPath, mDsuSlot;
private volatile IGsiService mGsiService;
DynamicSystemService(Context context) {
@@ -115,7 +115,7 @@
}
@Override
- public boolean startInstallation() throws RemoteException {
+ public boolean startInstallation(String dsuSlot) throws RemoteException {
IGsiService service = getGsiService();
// priority from high to low: sysprop -> sdcard -> /data
String path = SystemProperties.get("os.aot.path");
@@ -129,16 +129,17 @@
if (!Environment.MEDIA_MOUNTED.equals(volume.getState())) continue;
File sdCard = volume.getPathFile();
if (sdCard.isDirectory()) {
- path = sdCard.getPath();
+ path = new File(sdCard, dsuSlot).getPath();
break;
}
}
if (path.isEmpty()) {
- path = PATH_DEFAULT;
+ path = PATH_DEFAULT + dsuSlot;
}
Slog.i(TAG, "startInstallation -> " + path);
}
mInstallPath = path;
+ mDsuSlot = dsuSlot;
if (service.openInstall(path) != 0) {
Slog.i(TAG, "Failed to open " + path);
return false;
@@ -203,7 +204,7 @@
public boolean setEnable(boolean enable, boolean oneShot) throws RemoteException {
IGsiService gsiService = getGsiService();
if (enable) {
- return gsiService.enableGsi(oneShot) == 0;
+ return gsiService.enableGsi(oneShot, mDsuSlot) == 0;
} else {
return gsiService.disableGsi();
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 1daed1b..33a82d8 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -734,6 +734,11 @@
public int getInterfaceVersion() {
return INetdUnsolicitedEventListener.VERSION;
}
+
+ @Override
+ public String getInterfaceHash() {
+ return INetdUnsolicitedEventListener.HASH;
+ }
}
//
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 9a7a4e7..2fb1f77 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -54,7 +54,6 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.IntArray;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -527,7 +526,7 @@
@Override
public void accept(INetworkScoreCache networkScoreCache, Object cookie) {
- int filterType = NetworkScoreManager.CACHE_FILTER_NONE;
+ int filterType = NetworkScoreManager.SCORE_FILTER_NONE;
if (cookie instanceof Integer) {
filterType = (Integer) cookie;
}
@@ -551,17 +550,17 @@
private List<ScoredNetwork> filterScores(List<ScoredNetwork> scoredNetworkList,
int filterType) {
switch (filterType) {
- case NetworkScoreManager.CACHE_FILTER_NONE:
+ case NetworkScoreManager.SCORE_FILTER_NONE:
return scoredNetworkList;
- case NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK:
+ case NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK:
if (mCurrentNetworkFilter == null) {
mCurrentNetworkFilter =
new CurrentNetworkScoreCacheFilter(new WifiInfoSupplier(mContext));
}
return mCurrentNetworkFilter.apply(scoredNetworkList);
- case NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS:
+ case NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS:
if (mScanResultsFilter == null) {
mScanResultsFilter = new ScanResultsScoreCacheFilter(
new ScanResultsSupplier(mContext));
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 1ff455ea..c34dd98 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 7894788..0000000
--- 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/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index d1bc6af..39ad354 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2648,9 +2648,11 @@
*/
@Override
public boolean supportsCheckpoint() throws RemoteException {
- // Only the system process is permitted to start checkpoints
- if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
- throw new SecurityException("no permission to check filesystem checkpoint support");
+ // Only the root, system_server and shell processes are permitted to start checkpoints
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID
+ && callingUid != Process.SHELL_UID) {
+ throw new SecurityException("no permission to start filesystem checkpoint");
}
return mVold.supportsCheckpoint();
@@ -2665,8 +2667,10 @@
*/
@Override
public void startCheckpoint(int numTries) throws RemoteException {
- // Only the system process is permitted to start checkpoints
- if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+ // Only the root, system_server and shell processes are permitted to start checkpoints
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID
+ && callingUid != Process.SHELL_UID) {
throw new SecurityException("no permission to start filesystem checkpoint");
}
@@ -2784,6 +2788,24 @@
}
/*
+ * Clear disk encryption key bound to the associated token / secret pair. Removing the user
+ * binding of the Disk encryption key is done in two phases: first, this call will retrieve
+ * the disk encryption key using the provided token / secret pair and store it by
+ * encrypting it with a keymaster key not bound to the user, then fixateNewestUserKeyAuth
+ * is called to delete all other bindings of the disk encryption key.
+ */
+ @Override
+ public void clearUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
+ enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
+
+ try {
+ mVold.clearUserKeyAuth(userId, serialNumber, encodeBytes(token), encodeBytes(secret));
+ } catch (Exception e) {
+ Slog.wtf(TAG, e);
+ }
+ }
+
+ /*
* Delete all disk encryption token/secret pairs except the most recently added one
*/
@Override
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 630554d..a10d57a 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -50,6 +50,13 @@
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
import android.telephony.CellLocation;
+import android.telephony.CellSignalStrength;
+import android.telephony.CellSignalStrengthCdma;
+import android.telephony.CellSignalStrengthGsm;
+import android.telephony.CellSignalStrengthLte;
+import android.telephony.CellSignalStrengthNr;
+import android.telephony.CellSignalStrengthTdscdma;
+import android.telephony.CellSignalStrengthWcdma;
import android.telephony.DataFailCause;
import android.telephony.DisconnectCause;
import android.telephony.LocationAccessPolicy;
@@ -280,12 +287,21 @@
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
| PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS;
+ static final int READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK =
+ PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT
+ | PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED
+ | PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED
+ | PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE;
+
private static final int MSG_USER_SWITCHED = 1;
private static final int MSG_UPDATE_DEFAULT_SUB = 2;
@@ -404,7 +420,11 @@
mVoiceActivationState = copyOf(mVoiceActivationState, mNumPhones);
mDataActivationState = copyOf(mDataActivationState, mNumPhones);
mUserMobileDataState = copyOf(mUserMobileDataState, mNumPhones);
- mSignalStrength = copyOf(mSignalStrength, mNumPhones);
+ if (mSignalStrength != null) {
+ mSignalStrength = copyOf(mSignalStrength, mNumPhones);
+ } else {
+ mSignalStrength = new SignalStrength[mNumPhones];
+ }
mMessageWaiting = copyOf(mMessageWaiting, mNumPhones);
mCallForwarding = copyOf(mCallForwarding, mNumPhones);
mCellIdentity = copyOf(mCellIdentity, mNumPhones);
@@ -438,7 +458,7 @@
mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
mCallIncomingNumber[i] = "";
mServiceState[i] = new ServiceState();
- mSignalStrength[i] = new SignalStrength();
+ mSignalStrength[i] = null;
mUserMobileDataState[i] = false;
mMessageWaiting[i] = false;
mCallForwarding[i] = false;
@@ -522,7 +542,7 @@
mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
mCallIncomingNumber[i] = "";
mServiceState[i] = new ServiceState();
- mSignalStrength[i] = new SignalStrength();
+ mSignalStrength[i] = null;
mUserMobileDataState[i] = false;
mMessageWaiting[i] = false;
mCallForwarding[i] = false;
@@ -799,10 +819,12 @@
}
if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
try {
- int gsmSignalStrength = mSignalStrength[phoneId]
- .getGsmSignalStrength();
- r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
- : gsmSignalStrength));
+ if (mSignalStrength[phoneId] != null) {
+ int gsmSignalStrength = mSignalStrength[phoneId]
+ .getGsmSignalStrength();
+ r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
+ : gsmSignalStrength));
+ }
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -859,11 +881,17 @@
}
if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
try {
- r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
+ if (mSignalStrength[phoneId] != null) {
+ r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
+ }
} catch (RemoteException ex) {
remove(r.binder);
}
}
+ if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
+ != 0) {
+ updateReportSignalStrengthDecision(r.subId);
+ }
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
try {
if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = "
@@ -987,6 +1015,27 @@
}
}
+ private void updateReportSignalStrengthDecision(int subscriptionId) {
+ synchronized (mRecords) {
+ TelephonyManager telephonyManager = (TelephonyManager) mContext
+ .getSystemService(Context.TELEPHONY_SERVICE);
+ for (Record r : mRecords) {
+ // If any of the system clients wants to always listen to signal strength,
+ // we need to set it on.
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)) {
+ telephonyManager.createForSubscriptionId(subscriptionId)
+ .setAlwaysReportSignalStrength(true);
+ return;
+ }
+ }
+ // If none of the system clients wants to always listen to signal strength,
+ // we need to set it off.
+ telephonyManager.createForSubscriptionId(subscriptionId)
+ .setAlwaysReportSignalStrength(false);
+ }
+ }
+
private String getCallIncomingNumber(Record record, int phoneId) {
// Only reveal the incoming number if the record has read call log permission.
return record.canReadCallLog() ? mCallIncomingNumber[phoneId] : "";
@@ -1044,6 +1093,14 @@
}
mRecords.remove(i);
+
+ // Every time a client that is registrating to always receive the signal
+ // strength is removed from registry records, we need to check if
+ // the signal strength decision needs to update on its slot.
+ if (r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)) {
+ updateReportSignalStrengthDecision(r.subId);
+ }
return;
}
}
@@ -1293,7 +1350,8 @@
// only CarrierService with carrier privilege rule should have the permission
int[] subIds = Arrays.stream(SubscriptionManager.from(mContext)
.getActiveSubscriptionIdList(false))
- .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(i)).toArray();
+ .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(mContext,
+ i)).toArray();
if (ArrayUtils.isEmpty(subIds)) {
loge("notifyCarrierNetworkChange without carrier privilege");
// the active subId does not have carrier privilege.
@@ -1595,7 +1653,7 @@
TelephonyManager.DATA_UNKNOWN,
TelephonyManager.NETWORK_TYPE_UNKNOWN,
ApnSetting.getApnTypesBitmaskFromString(apnType), null, null,
- DataFailCause.NONE));
+ DataFailCause.NONE, null));
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
@@ -1780,7 +1838,7 @@
TelephonyManager.DATA_UNKNOWN,
TelephonyManager.NETWORK_TYPE_UNKNOWN,
ApnSetting.getApnTypesBitmaskFromString(apnType), null, null,
- failCause));
+ failCause, null));
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
@@ -2203,13 +2261,32 @@
Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED);
Bundle data = new Bundle();
- signalStrength.fillInNotifierBundle(data);
+ fillInSignalStrengthNotifierBundle(signalStrength, data);
intent.putExtras(data);
intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
+ private void fillInSignalStrengthNotifierBundle(SignalStrength signalStrength, Bundle bundle) {
+ List<CellSignalStrength> cellSignalStrengths = signalStrength.getCellSignalStrengths();
+ for (CellSignalStrength cellSignalStrength : cellSignalStrengths) {
+ if (cellSignalStrength instanceof CellSignalStrengthLte) {
+ bundle.putParcelable("Lte", (CellSignalStrengthLte) cellSignalStrength);
+ } else if (cellSignalStrength instanceof CellSignalStrengthCdma) {
+ bundle.putParcelable("Cdma", (CellSignalStrengthCdma) cellSignalStrength);
+ } else if (cellSignalStrength instanceof CellSignalStrengthGsm) {
+ bundle.putParcelable("Gsm", (CellSignalStrengthGsm) cellSignalStrength);
+ } else if (cellSignalStrength instanceof CellSignalStrengthWcdma) {
+ bundle.putParcelable("Wcdma", (CellSignalStrengthWcdma) cellSignalStrength);
+ } else if (cellSignalStrength instanceof CellSignalStrengthTdscdma) {
+ bundle.putParcelable("Tdscdma", (CellSignalStrengthTdscdma) cellSignalStrength);
+ } else if (cellSignalStrength instanceof CellSignalStrengthNr) {
+ bundle.putParcelable("Nr", (CellSignalStrengthNr) cellSignalStrength);
+ }
+ }
+ }
+
/**
* Broadcasts an intent notifying apps of a phone state change. {@code subId} can be
* a valid subId, in which case this function fires a subId-specific intent, or it
@@ -2301,7 +2378,7 @@
return;
}
- TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+ TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext,
SubscriptionManager.getDefaultSubscriptionId(), method);
}
@@ -2362,8 +2439,14 @@
}
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) {
@@ -2371,41 +2454,11 @@
android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null);
}
- if ((events & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) {
+ if ((events & READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
}
- if ((events & PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED) != 0) {
- mContext.enforceCallingOrSelfPermission(
- 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);
- }
-
- if ((events & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) != 0) {
- mContext.enforceCallingOrSelfPermission(
- 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;
}
@@ -2518,11 +2571,14 @@
if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
try {
- SignalStrength signalStrength = mSignalStrength[phoneId];
- if (DBG) {
- log("checkPossibleMissNotify: onSignalStrengthsChanged SS=" + signalStrength);
+ if (mSignalStrength[phoneId] != null) {
+ SignalStrength signalStrength = mSignalStrength[phoneId];
+ if (DBG) {
+ log("checkPossibleMissNotify: onSignalStrengthsChanged SS="
+ + signalStrength);
+ }
+ r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
}
- r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -2530,14 +2586,16 @@
if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) {
try {
- int gsmSignalStrength = mSignalStrength[phoneId]
- .getGsmSignalStrength();
- if (DBG) {
- log("checkPossibleMissNotify: onSignalStrengthChanged SS=" +
- gsmSignalStrength);
+ if (mSignalStrength[phoneId] != null) {
+ int gsmSignalStrength = mSignalStrength[phoneId]
+ .getGsmSignalStrength();
+ if (DBG) {
+ log("checkPossibleMissNotify: onSignalStrengthChanged SS="
+ + gsmSignalStrength);
+ }
+ r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
+ : gsmSignalStrength));
}
- r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
- : gsmSignalStrength));
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index d19d2dd..a7e36b2 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -219,7 +219,7 @@
// 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 @@
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/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index a1480e3..e7179e0 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -60,7 +60,6 @@
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.util.DebugUtils;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.StatsLog;
@@ -162,8 +161,7 @@
private int mHapticFeedbackIntensity;
private int mNotificationIntensity;
private int mRingIntensity;
- private SparseArray<Pair<VibrationEffect, AudioAttributes>> mAlwaysOnEffects =
- new SparseArray<>();
+ private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>();
static native boolean vibratorExists();
static native void vibratorInit();
@@ -477,6 +475,10 @@
Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
true, mSettingObserver, UserHandle.USER_ALL);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
+ true, mSettingObserver, UserHandle.USER_ALL);
+
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -524,7 +526,8 @@
}
@Override // Binder call
- public boolean setAlwaysOnEffect(int id, VibrationEffect effect, AudioAttributes attrs) {
+ public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect,
+ AudioAttributes attrs) {
if (!hasPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)) {
throw new SecurityException("Requires VIBRATE_ALWAYS_ON permission");
}
@@ -534,8 +537,8 @@
}
if (effect == null) {
synchronized (mLock) {
- mAlwaysOnEffects.delete(id);
- vibratorAlwaysOnDisable(id);
+ mAlwaysOnEffects.delete(alwaysOnId);
+ vibratorAlwaysOnDisable(alwaysOnId);
}
} else {
if (!verifyVibrationEffect(effect)) {
@@ -545,14 +548,11 @@
Slog.e(TAG, "Only prebaked effects supported for always-on.");
return false;
}
- if (attrs == null) {
- attrs = new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_UNKNOWN)
- .build();
- }
+ attrs = fixupVibrationAttributes(attrs);
synchronized (mLock) {
- mAlwaysOnEffects.put(id, Pair.create(effect, attrs));
- updateAlwaysOnLocked(id, effect, attrs);
+ Vibration vib = new Vibration(null, effect, attrs, uid, opPkg, null);
+ mAlwaysOnEffects.put(alwaysOnId, vib);
+ updateAlwaysOnLocked(alwaysOnId, vib);
}
}
return true;
@@ -592,6 +592,25 @@
return true;
}
+ private AudioAttributes fixupVibrationAttributes(AudioAttributes attrs) {
+ if (attrs == null) {
+ attrs = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_UNKNOWN)
+ .build();
+ }
+ if (shouldBypassDnd(attrs)) {
+ if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) {
+ final int flags = attrs.getAllFlags()
+ & ~AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
+ attrs = new AudioAttributes.Builder(attrs).replaceFlags(flags).build();
+ }
+ }
+
+ return attrs;
+ }
+
private static long[] getLongIntArray(Resources r, int resid) {
int[] ar = r.getIntArray(resid);
if (ar == null) {
@@ -621,21 +640,7 @@
return;
}
- if (attrs == null) {
- attrs = new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_UNKNOWN)
- .build();
- }
-
- if (shouldBypassDnd(attrs)) {
- if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) {
- final int flags = attrs.getAllFlags()
- & ~AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
- attrs = new AudioAttributes.Builder(attrs).replaceFlags(flags).build();
- }
- }
+ attrs = fixupVibrationAttributes(attrs);
// If our current vibration is longer than the new vibration and is the same amplitude,
// then just let the current one finish.
@@ -796,29 +801,8 @@
private void startVibrationLocked(final Vibration vib) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
try {
- if (!isAllowedToVibrateLocked(vib)) {
- return;
- }
-
final int intensity = getCurrentIntensityLocked(vib);
- if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
- return;
- }
-
- if (vib.isRingtone() && !shouldVibrateForRingtone()) {
- if (DEBUG) {
- Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
- }
- return;
- }
-
- final int mode = getAppOpMode(vib);
- if (mode != AppOpsManager.MODE_ALLOWED) {
- if (mode == AppOpsManager.MODE_ERRORED) {
- // We might be getting calls from within system_server, so we don't actually
- // want to throw a SecurityException here.
- Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
- }
+ if (!shouldVibrate(vib, intensity)) {
return;
}
applyVibrationIntensityScalingLocked(vib, intensity);
@@ -985,6 +969,35 @@
return mode;
}
+ private boolean shouldVibrate(Vibration vib, int intensity) {
+ if (!isAllowedToVibrateLocked(vib)) {
+ return false;
+ }
+
+ if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
+ return false;
+ }
+
+ if (vib.isRingtone() && !shouldVibrateForRingtone()) {
+ if (DEBUG) {
+ Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
+ }
+ return false;
+ }
+
+ final int mode = getAppOpMode(vib);
+ if (mode != AppOpsManager.MODE_ALLOWED) {
+ if (mode == AppOpsManager.MODE_ERRORED) {
+ // We might be getting calls from within system_server, so we don't actually
+ // want to throw a SecurityException here.
+ Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
+ }
+ return false;
+ }
+
+ return true;
+ }
+
@GuardedBy("mLock")
private void reportFinishVibrationLocked() {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
@@ -1096,14 +1109,12 @@
mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
}
- private void updateAlwaysOnLocked(int id, VibrationEffect effect, AudioAttributes attrs) {
- // TODO: Check DND and LowPower settings
- final Vibration vib = new Vibration(null, effect, attrs, 0, null, null);
+ private void updateAlwaysOnLocked(int id, Vibration vib) {
final int intensity = getCurrentIntensityLocked(vib);
- if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
+ if (!shouldVibrate(vib, intensity)) {
vibratorAlwaysOnDisable(id);
} else {
- final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
+ final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
final int strength = intensityToEffectStrength(intensity);
vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
}
@@ -1112,8 +1123,8 @@
private void updateAlwaysOnLocked() {
for (int i = 0; i < mAlwaysOnEffects.size(); i++) {
int id = mAlwaysOnEffects.keyAt(i);
- Pair<VibrationEffect, AudioAttributes> pair = mAlwaysOnEffects.valueAt(i);
- updateAlwaysOnLocked(id, pair.first, pair.second);
+ Vibration vib = mAlwaysOnEffects.valueAt(i);
+ updateAlwaysOnLocked(id, vib);
}
}
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index 7fd98e0..c125b1b 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 @@
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 @@
}
}
+ /**
+ * @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/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index f021008..5833d16 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -272,6 +272,7 @@
static final int MSG_BG_START_TIMEOUT = 1;
static final int MSG_UPDATE_FOREGROUND_APPS = 2;
+ static final int MSG_ENSURE_NOT_START_BG = 3;
ServiceMap(Looper looper, int userId) {
super(looper);
@@ -289,6 +290,11 @@
case MSG_UPDATE_FOREGROUND_APPS: {
updateForegroundApps(this);
} break;
+ case MSG_ENSURE_NOT_START_BG: {
+ synchronized (mAm) {
+ rescheduleDelayedStartsLocked();
+ }
+ } break;
}
}
@@ -296,7 +302,9 @@
if (mStartingBackground.remove(r)) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
"No longer background starting: " + r);
- rescheduleDelayedStartsLocked();
+ removeMessages(MSG_ENSURE_NOT_START_BG);
+ Message msg = obtainMessage(MSG_ENSURE_NOT_START_BG);
+ sendMessage(msg);
}
if (mDelayedStartList.remove(r)) {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "No longer delaying start: " + r);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 766fa3b..c2652c0 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -20,6 +20,7 @@
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO;
+import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static android.os.Process.getFreeMemory;
@@ -57,6 +58,8 @@
import android.content.pm.IPackageManager;
import android.content.res.Resources;
import android.graphics.Point;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
import android.os.AppZygote;
import android.os.Binder;
import android.os.Build;
@@ -74,6 +77,7 @@
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
+import android.system.Os;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.EventLog;
@@ -102,6 +106,7 @@
import dalvik.system.VMRuntime;
import java.io.File;
+import java.io.FileDescriptor;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
@@ -245,6 +250,10 @@
private static final String PROPERTY_USE_APP_IMAGE_STARTUP_CACHE =
"persist.device_config.runtime_native.use_app_image_startup_cache";
+ // The socket path for zygote to send unsolicited msg.
+ // Must keep sync with com_android_internal_os_Zygote.cpp.
+ private static final String UNSOL_ZYGOTE_MSG_SOCKET_PATH = "/data/system/unsolzygotesocket";
+
// Low Memory Killer Daemon command codes.
// These must be kept in sync with lmk_cmd definitions in lmkd.h
//
@@ -388,6 +397,28 @@
private PlatformCompat mPlatformCompat = null;
+ /**
+ * The server socket in system_server, zygote will connect to it
+ * in order to send unsolicited messages to system_server.
+ */
+ private LocalSocket mSystemServerSocketForZygote;
+
+ /**
+ * Maximum number of bytes that an incoming unsolicited zygote message could be.
+ * To be updated if new message type needs to be supported.
+ */
+ private static final int MAX_ZYGOTE_UNSOLICITED_MESSAGE_SIZE = 16;
+
+ /**
+ * The buffer to be used to receive the incoming unsolicited zygote message.
+ */
+ private final byte[] mZygoteUnsolicitedMessage = new byte[MAX_ZYGOTE_UNSOLICITED_MESSAGE_SIZE];
+
+ /**
+ * The buffer to be used to receive the SIGCHLD data, it includes pid/uid/status.
+ */
+ private final int[] mZygoteSigChldMessage = new int[3];
+
interface LmkdKillListener {
/**
* Called when there is a process kill by lmkd.
@@ -645,6 +676,13 @@
}
}
);
+ // Start listening on incoming connections from zygotes.
+ mSystemServerSocketForZygote = createSystemServerSocketForZygote();
+ if (mSystemServerSocketForZygote != null) {
+ sKillHandler.getLooper().getQueue().addOnFileDescriptorEventListener(
+ mSystemServerSocketForZygote.getFileDescriptor(),
+ EVENT_INPUT, this::handleZygoteMessages);
+ }
}
}
@@ -3267,4 +3305,66 @@
}
}
}
+
+ private void handleZygoteSigChld(int pid, int uid, int status) {
+ // Just log it now.
+ if (DEBUG_PROCESSES) {
+ Slog.i(TAG, "Got SIGCHLD from zygote: pid=" + pid + ", uid=" + uid
+ + ", status=" + Integer.toHexString(status));
+ }
+ }
+
+ /**
+ * Create a server socket in system_server, zygote will connect to it
+ * in order to send unsolicited messages to system_server.
+ */
+ private LocalSocket createSystemServerSocketForZygote() {
+ // The file system entity for this socket is created with 0666 perms, owned
+ // by system:system. selinux restricts things so that only zygotes can
+ // access it.
+ final File socketFile = new File(UNSOL_ZYGOTE_MSG_SOCKET_PATH);
+ if (socketFile.exists()) {
+ socketFile.delete();
+ }
+
+ LocalSocket serverSocket = null;
+ try {
+ serverSocket = new LocalSocket(LocalSocket.SOCKET_DGRAM);
+ serverSocket.bind(new LocalSocketAddress(
+ UNSOL_ZYGOTE_MSG_SOCKET_PATH, LocalSocketAddress.Namespace.FILESYSTEM));
+ Os.chmod(UNSOL_ZYGOTE_MSG_SOCKET_PATH, 0666);
+ } catch (Exception e) {
+ if (serverSocket != null) {
+ try {
+ serverSocket.close();
+ } catch (IOException ex) {
+ }
+ serverSocket = null;
+ }
+ }
+ return serverSocket;
+ }
+
+ /**
+ * Handle the unsolicited message from zygote.
+ */
+ private int handleZygoteMessages(FileDescriptor fd, int events) {
+ final int eventFd = fd.getInt$();
+ if ((events & EVENT_INPUT) != 0) {
+ // An incoming message from zygote
+ try {
+ final int len = Os.read(fd, mZygoteUnsolicitedMessage, 0,
+ mZygoteUnsolicitedMessage.length);
+ if (len > 0 && mZygoteSigChldMessage.length == Zygote.nativeParseSigChld(
+ mZygoteUnsolicitedMessage, len, mZygoteSigChldMessage)) {
+ handleZygoteSigChld(mZygoteSigChldMessage[0] /* pid */,
+ mZygoteSigChldMessage[1] /* uid */,
+ mZygoteSigChldMessage[2] /* status */);
+ }
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception in reading unsolicited zygote message: " + e);
+ }
+ }
+ return EVENT_INPUT;
+ }
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index b311233..1452e25 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1538,6 +1538,9 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
+ // Also, add the UserHandle for mainline modules which can't use the @hide
+ // EXTRA_USER_HANDLE.
+ intent.putExtra(Intent.EXTRA_USER, UserHandle.of(profileUserId));
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
@@ -1554,6 +1557,9 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
+ // Also, add the UserHandle for mainline modules which can't use the @hide
+ // EXTRA_USER_HANDLE.
+ intent.putExtra(Intent.EXTRA_USER, UserHandle.of(profileUserId));
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
@@ -1563,6 +1569,9 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
+ // Also, add the UserHandle for mainline modules which can't use the @hide
+ // EXTRA_USER_HANDLE.
+ intent.putExtra(Intent.EXTRA_USER, UserHandle.of(newUserId));
mInjector.broadcastIntent(intent,
null, null, 0, null, null,
new String[] {android.Manifest.permission.MANAGE_USERS},
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 314e04c..d45bc72a 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1110,8 +1110,8 @@
return Collections.emptyList();
}
synchronized (this) {
- Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */,
- false /* uidMismatchExpected */);
+ Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* isPrivileged */,
+ false /* edit */);
if (pkgOps == null) {
return null;
}
@@ -1208,8 +1208,7 @@
private void pruneOp(Op op, int uid, String packageName) {
if (!op.hasAnyTime()) {
- Ops ops = getOpsRawLocked(uid, packageName, false /* edit */,
- false /* uidMismatchExpected */);
+ Ops ops = getOpsRawLocked(uid, packageName, false /* isPrivileged */, false /* edit */);
if (ops != null) {
ops.remove(op.op);
if (ops.size() <= 0) {
@@ -1409,11 +1408,6 @@
}
}
- @Override
- public void setMode(int code, int uid, String packageName, int mode) {
- setMode(code, uid, packageName, mode, true, false);
- }
-
/**
* Sets the mode for a certain op and uid.
*
@@ -1421,19 +1415,25 @@
* @param uid The UID for which to set
* @param packageName The package for which to set
* @param mode The new mode to set
- * @param verifyUid Iff {@code true}, check that the package name belongs to the uid
- * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid ==
- * false})
*/
- private void setMode(int code, int uid, @NonNull String packageName, int mode,
- boolean verifyUid, boolean isPrivileged) {
+ @Override
+ public void setMode(int code, int uid, @NonNull String packageName, int mode) {
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
+
+ boolean isPrivileged;
+ try {
+ isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+ } catch (SecurityException e) {
+ Slog.e(TAG, "Cannot setMode", e);
+ return;
+ }
+
synchronized (this) {
UidState uidState = getUidStateLocked(uid, false);
- Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged);
+ Op op = getOpLocked(code, uid, packageName, isPrivileged, true);
if (op != null) {
if (op.mode != mode) {
op.mode = mode;
@@ -1799,34 +1799,32 @@
}
/**
- * @see #checkOperationUnchecked(int, int, String, boolean, boolean)
- */
- private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
- boolean raw) {
- return checkOperationUnchecked(code, uid, packageName, raw, true);
- }
-
- /**
* Get the mode of an app-op.
*
* @param code The code of the op
* @param uid The uid of the package the op belongs to
* @param packageName The package the op belongs to
* @param raw If the raw state of eval-ed state should be checked.
- * @param verify If the code should check the package belongs to the uid
*
* @return The mode of the op
*/
private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
- boolean raw, boolean verify) {
+ boolean raw) {
if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
return AppOpsManager.MODE_IGNORED;
}
+
+ boolean isPrivileged;
+
+ try {
+ isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+ } catch (SecurityException e) {
+ Slog.e(TAG, "checkOperation", e);
+ return AppOpsManager.opToDefaultMode(code);
+ }
+
synchronized (this) {
- if (verify) {
- checkPackage(uid, packageName);
- }
- if (isOpRestrictedLocked(uid, code, packageName)) {
+ if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
return AppOpsManager.MODE_IGNORED;
}
code = AppOpsManager.opToSwitch(code);
@@ -1836,7 +1834,7 @@
final int rawMode = uidState.opModes.get(code);
return raw ? rawMode : uidState.evalMode(code, rawMode);
}
- Op op = getOpLocked(code, uid, packageName, false, verify, false);
+ Op op = getOpLocked(code, uid, packageName, false, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
@@ -1941,14 +1939,12 @@
@Override
public int checkPackage(int uid, String packageName) {
Preconditions.checkNotNull(packageName);
- synchronized (this) {
- Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
- true /* uidMismatchExpected */);
- if (ops != null) {
- return AppOpsManager.MODE_ALLOWED;
- } else {
- return AppOpsManager.MODE_ERRORED;
- }
+ try {
+ verifyAndGetIsPrivileged(uid, packageName);
+
+ return AppOpsManager.MODE_ALLOWED;
+ } catch (SecurityException ignored) {
+ return AppOpsManager.MODE_ERRORED;
}
}
@@ -2011,9 +2007,16 @@
private int noteOperationUnchecked(int code, int uid, String packageName,
int proxyUid, String proxyPackageName, @OpFlags int flags) {
+ boolean isPrivileged;
+ try {
+ isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+ } catch (SecurityException e) {
+ Slog.e(TAG, "noteOperation", e);
+ return AppOpsManager.MODE_ERRORED;
+ }
+
synchronized (this) {
- final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
- false /* uidMismatchExpected */);
+ final Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, true /* edit */);
if (ops == null) {
scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_IGNORED);
@@ -2022,7 +2025,7 @@
return AppOpsManager.MODE_ERRORED;
}
final Op op = getOpLocked(ops, code, true);
- if (isOpRestrictedLocked(uid, code, packageName)) {
+ if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) {
scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_IGNORED);
return AppOpsManager.MODE_IGNORED;
@@ -2181,16 +2184,25 @@
return AppOpsManager.MODE_IGNORED;
}
ClientState client = (ClientState)token;
+
+ boolean isPrivileged;
+ try {
+ isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+ } catch (SecurityException e) {
+ Slog.e(TAG, "startOperation", e);
+ return AppOpsManager.MODE_ERRORED;
+ }
+
synchronized (this) {
- final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */,
- false /* uidMismatchExpected */);
+ final Ops ops = getOpsRawLocked(uid, resolvedPackageName, isPrivileged,
+ true /* edit */);
if (ops == null) {
if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
+ " package " + resolvedPackageName);
return AppOpsManager.MODE_ERRORED;
}
final Op op = getOpLocked(ops, code, true);
- if (isOpRestrictedLocked(uid, code, resolvedPackageName)) {
+ if (isOpRestrictedLocked(uid, code, resolvedPackageName, isPrivileged)) {
return AppOpsManager.MODE_IGNORED;
}
final int switchCode = AppOpsManager.opToSwitch(code);
@@ -2262,8 +2274,17 @@
return;
}
ClientState client = (ClientState) token;
+
+ boolean isPrivileged;
+ try {
+ isPrivileged = verifyAndGetIsPrivileged(uid, packageName);
+ } catch (SecurityException e) {
+ Slog.e(TAG, "Cannot finishOperation", e);
+ return;
+ }
+
synchronized (this) {
- Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false);
+ Op op = getOpLocked(code, uid, resolvedPackageName, isPrivileged, true);
if (op == null) {
return;
}
@@ -2513,8 +2534,76 @@
uidState.pendingStateCommitTime = 0;
}
- private Ops getOpsRawLocked(int uid, String packageName, boolean edit,
- boolean uidMismatchExpected) {
+ /**
+ * Verify that package belongs to uid and return whether the package is privileged.
+ *
+ * @param uid The uid the package belongs to
+ * @param packageName The package the might belong to the uid
+ *
+ * @return {@code true} iff the package is privileged
+ */
+ private boolean verifyAndGetIsPrivileged(int uid, String packageName) {
+ if (uid == Process.ROOT_UID) {
+ // For backwards compatibility, don't check package name for root UID.
+ return false;
+ }
+
+ // Do not check if uid/packageName is already known
+ synchronized (this) {
+ UidState uidState = mUidStates.get(uid);
+ if (uidState != null && uidState.pkgOps != null) {
+ Ops ops = uidState.pkgOps.get(packageName);
+
+ if (ops != null) {
+ return ops.isPrivileged;
+ }
+ }
+ }
+
+ boolean isPrivileged = false;
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ int pkgUid;
+
+ ApplicationInfo appInfo = LocalServices.getService(PackageManagerInternal.class)
+ .getApplicationInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_INSTANT,
+ Process.SYSTEM_UID, UserHandle.getUserId(uid));
+ if (appInfo != null) {
+ pkgUid = appInfo.uid;
+ isPrivileged = (appInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
+ } else {
+ pkgUid = resolveUid(packageName);
+ if (pkgUid >= 0) {
+ isPrivileged = false;
+ }
+ }
+ if (pkgUid != uid) {
+ throw new SecurityException("Specified package " + packageName + " under uid " + uid
+ + " but it is really " + pkgUid);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ return isPrivileged;
+ }
+
+ /**
+ * Get (and potentially create) ops.
+ *
+ * @param uid The uid the package belongs to
+ * @param packageName The name of the package
+ * @param isPrivileged If the package is privilidged (ignored if {@code edit} is false)
+ * @param edit If an ops does not exist, create the ops?
+
+ * @return
+ */
+ private Ops getOpsRawLocked(int uid, String packageName, boolean isPrivileged, boolean edit) {
UidState uidState = getUidStateLocked(uid, edit);
if (uidState == null) {
return null;
@@ -2532,47 +2621,6 @@
if (!edit) {
return null;
}
- boolean isPrivileged = false;
- // This is the first time we have seen this package name under this uid,
- // so let's make sure it is valid.
- if (uid != 0) {
- final long ident = Binder.clearCallingIdentity();
- try {
- int pkgUid = -1;
- try {
- ApplicationInfo appInfo = ActivityThread.getPackageManager()
- .getApplicationInfo(packageName,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- UserHandle.getUserId(uid));
- if (appInfo != null) {
- pkgUid = appInfo.uid;
- isPrivileged = (appInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
- } else {
- pkgUid = resolveUid(packageName);
- if (pkgUid >= 0) {
- isPrivileged = false;
- }
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Could not contact PackageManager", e);
- }
- if (pkgUid != uid) {
- // Oops! The package name is not valid for the uid they are calling
- // under. Abort.
- if (!uidMismatchExpected) {
- RuntimeException ex = new RuntimeException("here");
- ex.fillInStackTrace();
- Slog.w(TAG, "Bad call: specified package " + packageName
- + " under uid " + uid + " but it is really " + pkgUid, ex);
- }
- return null;
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
ops = new Ops(packageName, uidState, isPrivileged);
uidState.pkgOps.put(packageName, ops);
}
@@ -2580,7 +2628,7 @@
}
/**
- * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>.
+ * Get the state of all ops for a package.
*
* <p>Usually callers should use {@link #getOpLocked} and not call this directly.
*
@@ -2638,23 +2686,15 @@
* @param code The code of the op
* @param uid The uid the of the package
* @param packageName The package name for which to get the state for
+ * @param isPrivileged Whether the package is privileged or not (only used if {@code edit
+ * == true})
* @param edit Iff {@code true} create the {@link Op} object if not yet created
- * @param verifyUid Iff {@code true} check that the package belongs to the uid
- * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid
- * == false})
*
* @return The {@link Op state} of the op
*/
- private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit,
- boolean verifyUid, boolean isPrivileged) {
- Ops ops;
-
- if (verifyUid) {
- ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */);
- } else {
- ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
- }
-
+ private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
+ boolean isPrivileged, boolean edit) {
+ Ops ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged);
if (ops == null) {
return null;
}
@@ -2684,7 +2724,8 @@
return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid));
}
- private boolean isOpRestrictedLocked(int uid, int code, String packageName) {
+ private boolean isOpRestrictedLocked(int uid, int code, String packageName,
+ boolean isPrivileged) {
int userHandle = UserHandle.getUserId(uid);
final int restrictionSetCount = mOpUserRestrictions.size();
@@ -2696,8 +2737,8 @@
if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
// If we are the system, bypass user restrictions for certain codes
synchronized (this) {
- Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
- false /* uidMismatchExpected */);
+ Ops ops = getOpsRawLocked(uid, packageName, isPrivileged,
+ true /* edit */);
if ((ops != null) && ops.isPrivileged) {
return false;
}
@@ -3068,7 +3109,7 @@
out.attribute(null, "n", Integer.toString(pkg.getUid()));
synchronized (this) {
Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(),
- false /* edit */, false /* uidMismatchExpected */);
+ false /* isPrivileged */, false /* edit */);
// Should always be present as the list of PackageOps is generated
// from Ops.
if (ops != null) {
@@ -4647,18 +4688,8 @@
}
@Override
- public void setUidMode(int code, int uid, int mode) {
- AppOpsService.this.setUidMode(code, uid, mode);
- }
-
- @Override
public void setAllPkgModesToDefault(int code, int uid) {
AppOpsService.this.setAllPkgModesToDefault(code, uid);
}
-
- @Override
- public @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName) {
- return AppOpsService.this.checkOperationUnchecked(code, uid, packageName, true, false);
- }
}
}
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
index a53797d..1a5dac5 100644
--- a/services/core/java/com/android/server/appop/TEST_MAPPING
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -10,6 +10,14 @@
"include-filter": "com.android.server.appop"
}
]
+ },
+ {
+ "name": "FrameworksMockingServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.appop"
+ }
+ ]
}
]
}
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
index dfc0080..4bf606e 100644
--- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -53,6 +53,7 @@
public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) {
boolean debuggableBuild = false;
boolean finalBuild = false;
+ int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId);
debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild();
finalBuild = mAndroidBuildClassifier.isFinalBuild();
@@ -76,15 +77,14 @@
if ((applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
return new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1);
}
- int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId);
- // Do not allow overriding non-target sdk gated changes on user builds
- if (minTargetSdk == -1) {
- return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, minTargetSdk);
- }
// Allow overriding any change for debuggable apps on non-final builds.
if (!finalBuild) {
return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
}
+ // Do not allow overriding non-target sdk gated changes on user builds
+ if (minTargetSdk == -1) {
+ return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, minTargetSdk);
+ }
// Only allow to opt-in for a targetSdk gated change.
if (applicationInfo.targetSdkVersion < minTargetSdk) {
return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 029b7bc..e48169f 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -16,6 +16,11 @@
package com.android.server.compat;
+import static android.Manifest.permission.LOG_COMPAT_CHANGE;
+import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG;
+import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
@@ -67,12 +72,14 @@
@Override
public void reportChange(long changeId, ApplicationInfo appInfo) {
+ checkCompatChangeLogPermission();
reportChange(changeId, appInfo.uid,
StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED);
}
@Override
public void reportChangeByPackageName(long changeId, String packageName, int userId) {
+ checkCompatChangeLogPermission();
ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo == null) {
return;
@@ -82,11 +89,13 @@
@Override
public void reportChangeByUid(long changeId, int uid) {
+ checkCompatChangeLogPermission();
reportChange(changeId, uid, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED);
}
@Override
public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
+ checkCompatChangeReadPermission();
if (mCompatConfig.isChangeEnabled(changeId, appInfo)) {
reportChange(changeId, appInfo.uid,
StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED);
@@ -99,6 +108,7 @@
@Override
public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) {
+ checkCompatChangeReadPermission();
ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo == null) {
return true;
@@ -108,6 +118,7 @@
@Override
public boolean isChangeEnabledByUid(long changeId, int uid) {
+ checkCompatChangeReadPermission();
String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
if (packages == null || packages.length == 0) {
return true;
@@ -140,6 +151,7 @@
@Override
public void setOverrides(CompatibilityChangeConfig overrides, String packageName)
throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
mCompatConfig.addOverrides(overrides, packageName);
killPackage(packageName);
}
@@ -147,11 +159,13 @@
@Override
public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName)
throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
mCompatConfig.addOverrides(overrides, packageName);
}
@Override
public void clearOverrides(String packageName) throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
killPackage(packageName);
}
@@ -159,12 +173,14 @@
@Override
public void clearOverridesForTest(String packageName)
throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
}
@Override
public boolean clearOverride(long changeId, String packageName)
throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
boolean existed = mCompatConfig.removeOverride(changeId, packageName);
killPackage(packageName);
return existed;
@@ -172,11 +188,13 @@
@Override
public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
+ checkCompatChangeReadPermission();
return mCompatConfig.getAppConfig(appInfo);
}
@Override
public CompatibilityChangeInfo[] listAllChanges() {
+ checkCompatChangeReadPermission();
return mCompatConfig.dumpChanges();
}
@@ -215,6 +233,7 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ checkCompatChangeReadPermission();
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
mCompatConfig.dumpConfig(pw);
}
@@ -276,4 +295,25 @@
Binder.restoreCallingIdentity(identity);
}
}
+
+ private void checkCompatChangeLogPermission() throws SecurityException {
+ if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE)
+ != PERMISSION_GRANTED) {
+ throw new SecurityException("Cannot log compat change usage");
+ }
+ }
+
+ private void checkCompatChangeReadPermission() throws SecurityException {
+ if (mContext.checkCallingOrSelfPermission(READ_COMPAT_CHANGE_CONFIG)
+ != PERMISSION_GRANTED) {
+ throw new SecurityException("Cannot read compat change");
+ }
+ }
+
+ private void checkCompatChangeOverridePermission() throws SecurityException {
+ if (mContext.checkCallingOrSelfPermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
+ != PERMISSION_GRANTED) {
+ throw new SecurityException("Cannot override compat change");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 6fa999c..04c792a 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -26,6 +26,7 @@
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH;
import static com.android.server.net.NetworkPolicyManagerService.OPPORTUNISTIC_QUOTA_UNKNOWN;
@@ -46,19 +47,18 @@
import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
import android.net.NetworkStats;
import android.net.NetworkTemplate;
-import android.net.StringNetworkSpecifier;
+import android.net.TelephonyNetworkSpecifier;
+import android.net.Uri;
import android.os.BestClock;
import android.os.Handler;
import android.os.SystemClock;
-import android.net.Uri;
import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.TelephonyManager;
-import android.util.DataUnit;
import android.util.DebugUtils;
-import android.util.Pair;
import android.util.Range;
import android.util.Slog;
@@ -74,7 +74,6 @@
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
-import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@@ -185,7 +184,6 @@
// Track information on mobile networks as they come and go.
class MultipathTracker {
final Network network;
- final int subId;
final String subscriberId;
private long mQuota;
@@ -198,13 +196,14 @@
public MultipathTracker(Network network, NetworkCapabilities nc) {
this.network = network;
this.mNetworkCapabilities = new NetworkCapabilities(nc);
- try {
- subId = Integer.parseInt(
- ((StringNetworkSpecifier) nc.getNetworkSpecifier()).toString());
- } catch (ClassCastException | NullPointerException | NumberFormatException e) {
+ NetworkSpecifier specifier = nc.getNetworkSpecifier();
+ int subId = INVALID_SUBSCRIPTION_ID;
+ if (specifier instanceof TelephonyNetworkSpecifier) {
+ subId = ((TelephonyNetworkSpecifier) specifier).getSubscriptionId();
+ } else {
throw new IllegalStateException(String.format(
- "Can't get subId from mobile network %s (%s): %s",
- network, nc, e.getMessage()));
+ "Can't get subId from mobile network %s (%s)",
+ network, nc));
}
TelephonyManager tele = mContext.getSystemService(TelephonyManager.class);
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index aea6d8d..f636d67 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 @@
&& !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/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index dbc339b..d15ebe0 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -310,6 +310,11 @@
return this.VERSION;
}
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
+
private void addWakeupEvent(WakeupEvent event) {
String iface = event.iface;
mWakeupEvents.append(event);
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 5e085ca..d66aec5 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.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 @@
// 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 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 @@
mConnService = connService;
mContext = context;
mHandler = handler;
- networkMisc = misc;
+ networkAgentConfig = config;
this.factorySerialNumber = factorySerialNumber;
}
@@ -309,8 +309,8 @@
return mConnService;
}
- public NetworkMisc netMisc() {
- return networkMisc;
+ public NetworkAgentConfig netAgentConfig() {
+ return networkAgentConfig;
}
public Handler handler() {
@@ -451,15 +451,6 @@
&& !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 @@
// 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 @@
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 @@
+ "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/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 2179518..2c41557 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -28,7 +28,7 @@
import android.content.Intent;
import android.content.res.Resources;
import android.net.NetworkSpecifier;
-import android.net.StringNetworkSpecifier;
+import android.net.TelephonyNetworkSpecifier;
import android.net.wifi.WifiInfo;
import android.os.UserHandle;
import android.telephony.SubscriptionManager;
@@ -223,14 +223,8 @@
// name has been added to it
NetworkSpecifier specifier = nai.networkCapabilities.getNetworkSpecifier();
int subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
- if (specifier instanceof StringNetworkSpecifier) {
- try {
- subId = Integer.parseInt(
- ((StringNetworkSpecifier) specifier).specifier);
- } catch (NumberFormatException e) {
- Slog.e(TAG, "NumberFormatException on "
- + ((StringNetworkSpecifier) specifier).specifier);
- }
+ if (specifier instanceof TelephonyNetworkSpecifier) {
+ subId = ((TelephonyNetworkSpecifier) specifier).getSubscriptionId();
}
details = mTelephonyManager.createForSubscriptionId(subId)
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a46ada8..2933fab 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.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 int getNetId() {
- return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET;
+ return mNetworkAgent != null ? mNetworkAgent.network.netId : NETID_UNSET;
}
private LinkProperties makeLinkProperties() {
@@ -914,7 +914,7 @@
* 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,17 +947,17 @@
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.setOwnerUid(Binder.getCallingUid());
mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserHandle,
mConfig.allowedApplications, mConfig.disallowedApplications));
long token = Binder.clearCallingIdentity();
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/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 6330270..69cbc22 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3454,7 +3454,7 @@
}
/**
- * This is kept due to {@link android.annotation.UnsupportedAppUsage} in
+ * This is kept due to {@link android.compat.annotation.UnsupportedAppUsage} in
* {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in
* {@link InputMethodService#onCreate()}.
*
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index ababad9..97df557 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -325,8 +325,7 @@
&& !wouldBeReadyWithConstraintLocked(
job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
if (DEBUG) {
- Slog.i(TAG,
- "Skipping " + job + " because delay won't make it ready.");
+ Slog.i(TAG, "Skipping " + job + " because delay won't make it ready.");
}
continue;
}
@@ -385,7 +384,8 @@
/**
* Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's
* delay will expire.
- * This alarm <b>will</b> wake up the phone.
+ * This alarm <b>will not</b> wake up the phone if
+ * {@link TcConstants#USE_NON_WAKEUP_ALARM_FOR_DELAY} is true.
*/
private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
@@ -393,8 +393,11 @@
return;
}
mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
- updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener,
- mNextDelayExpiredElapsedMillis, ws);
+ final int alarmType =
+ mTcConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY
+ ? AlarmManager.ELAPSED_REALTIME : AlarmManager.ELAPSED_REALTIME_WAKEUP;
+ updateAlarmWithListenerLocked(DELAY_TAG, alarmType,
+ mNextDelayExpiredListener, mNextDelayExpiredElapsedMillis, ws);
}
/**
@@ -408,16 +411,16 @@
return;
}
mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
- updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener,
- mNextJobExpiredElapsedMillis, ws);
+ updateAlarmWithListenerLocked(DEADLINE_TAG, AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mDeadlineExpiredListener, mNextJobExpiredElapsedMillis, ws);
}
private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) {
return Math.max(proposedAlarmTimeElapsedMillis, sElapsedRealtimeClock.millis());
}
- private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener,
- long alarmTimeElapsed, WorkSource ws) {
+ private void updateAlarmWithListenerLocked(String tag, @AlarmManager.AlarmType int alarmType,
+ OnAlarmListener listener, long alarmTimeElapsed, WorkSource ws) {
ensureAlarmServiceLocked();
if (alarmTimeElapsed == Long.MAX_VALUE) {
mAlarmService.cancel(listener);
@@ -425,7 +428,7 @@
if (DEBUG) {
Slog.d(TAG, "Setting " + tag + " for: " + alarmTimeElapsed);
}
- mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsed,
+ mAlarmService.set(alarmType, alarmTimeElapsed,
AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, ws);
}
}
@@ -464,8 +467,11 @@
private final KeyValueListParser mParser = new KeyValueListParser(',');
private static final String KEY_SKIP_NOT_READY_JOBS = "skip_not_ready_jobs";
+ private static final String KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY =
+ "use_non_wakeup_delay_alarm";
private static final boolean DEFAULT_SKIP_NOT_READY_JOBS = true;
+ private static final boolean DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY = true;
/**
* Whether or not TimeController should skip setting wakeup alarms for jobs that aren't
@@ -474,6 +480,12 @@
public boolean SKIP_NOT_READY_JOBS = DEFAULT_SKIP_NOT_READY_JOBS;
/**
+ * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't
+ * ready now.
+ */
+ public boolean USE_NON_WAKEUP_ALARM_FOR_DELAY = DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY;
+
+ /**
* Creates a content observer.
*
* @param handler The handler to run {@link #onChange} on, or null if none.
@@ -510,6 +522,12 @@
recheckAlarmsLocked();
}
}
+
+ USE_NON_WAKEUP_ALARM_FOR_DELAY = mParser.getBoolean(
+ KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY, DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY);
+ // Intentionally not calling checkExpiredDelaysAndResetAlarm() here. There's no need to
+ // iterate through the entire list again for this constant change. The next delay alarm
+ // that is set will make use of the new constant value.
}
private void dump(IndentingPrintWriter pw) {
@@ -517,12 +535,16 @@
pw.println("TimeController:");
pw.increaseIndent();
pw.printPair(KEY_SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS).println();
+ pw.printPair(KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY,
+ USE_NON_WAKEUP_ALARM_FOR_DELAY).println();
pw.decreaseIndent();
}
private void dump(ProtoOutputStream proto) {
final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER);
proto.write(ConstantsProto.TimeController.SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS);
+ proto.write(ConstantsProto.TimeController.USE_NON_WAKEUP_ALARM_FOR_DELAY,
+ USE_NON_WAKEUP_ALARM_FOR_DELAY);
proto.end(tcToken);
}
}
diff --git a/services/core/java/com/android/server/lights/OWNERS b/services/core/java/com/android/server/lights/OWNERS
index c7c6d56..0e795b9 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/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 9510db0..288484f 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -25,7 +25,6 @@
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
-import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.USER_FRP;
@@ -1511,7 +1510,7 @@
if (credential != null) {
Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
}
- clearUserKeyProtection(userId);
+ clearUserKeyProtection(userId, null);
getGateKeeperService().clearSecureUserId(userId);
mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
setKeystorePassword(null, userId);
@@ -1688,9 +1687,17 @@
addUserKeyAuth(userId, token, secretFromCredential(credential));
}
- private void clearUserKeyProtection(int userId) throws RemoteException {
+ private void clearUserKeyProtection(int userId, byte[] secret) {
if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId);
- addUserKeyAuth(userId, null, null);
+ final UserInfo userInfo = mUserManager.getUserInfo(userId);
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ mStorageManager.clearUserKeyAuth(userId, userInfo.serialNumber, null, secret);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("clearUserKeyAuth failed user=" + userId);
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
}
private static byte[] secretFromCredential(byte[] credential) throws RemoteException {
@@ -2512,7 +2519,7 @@
setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
setKeystorePassword(auth.deriveKeyStorePassword(), userId);
} else {
- clearUserKeyProtection(userId);
+ clearUserKeyProtection(userId, null);
setKeystorePassword(null, userId);
getGateKeeperService().clearSecureUserId(userId);
}
@@ -2532,23 +2539,12 @@
return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER;
}
long handle = getSyntheticPasswordHandleLocked(userId);
- // This is a global setting
- long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
- SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM);
- return enabled != 0 && handle != SyntheticPasswordManager.DEFAULT_HANDLE;
+ return handle != SyntheticPasswordManager.DEFAULT_HANDLE;
}
@VisibleForTesting
protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) {
- long handle = getSyntheticPasswordHandleLocked(userId);
- // This is a global setting
- long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY,
- SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, UserHandle.USER_SYSTEM);
- return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE;
- }
-
- private void enableSyntheticPasswordLocked() {
- setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
+ return true;
}
private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential,
@@ -2698,7 +2694,7 @@
// during boot. Vold storage needs to be unlocked before manipulation of the keys can
// succeed.
unlockUserKey(userId, null, auth.deriveDiskEncryptionKey());
- clearUserKeyProtection(userId);
+ clearUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
fixateNewestUserKeyAuth(userId);
unlockKeystore(auth.deriveKeyStorePassword(), userId);
setKeystorePassword(null, userId);
@@ -2829,7 +2825,6 @@
throws RemoteException {
if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
synchronized (mSpManager) {
- enableSyntheticPasswordLocked();
// Migrate to synthetic password based credentials if the user has no password,
// the token can then be activated immediately.
AuthenticationToken auth = null;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b18b8c6..9760185 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -161,7 +161,7 @@
import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkTemplate;
-import android.net.StringNetworkSpecifier;
+import android.net.TelephonyNetworkSpecifier;
import android.net.TrafficStats;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
@@ -169,6 +169,7 @@
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 @@
// Listen for subscriber changes
mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener(
- new OnSubscriptionsChangedListener(mHandler.getLooper()) {
+ new HandlerExecutor(mHandler),
+ new OnSubscriptionsChangedListener() {
@Override
public void onSubscriptionsChanged() {
updateNetworksInternal();
@@ -5302,16 +5304,12 @@
}
private int parseSubId(NetworkState state) {
- // TODO: moved to using a legitimate NetworkSpecifier instead of string parsing
int subId = INVALID_SUBSCRIPTION_ID;
if (state != null && state.networkCapabilities != null
&& state.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier();
- if (spec instanceof StringNetworkSpecifier) {
- try {
- subId = Integer.parseInt(((StringNetworkSpecifier) spec).specifier);
- } catch (NumberFormatException e) {
- }
+ if (spec instanceof TelephonyNetworkSpecifier) {
+ subId = ((TelephonyNetworkSpecifier) spec).getSubscriptionId();
}
}
return subId;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7e7822c..d8f5dfb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -21009,7 +21009,7 @@
// Disable any carrier apps. We do this very early in boot to prevent the apps from being
// disabled after already being started.
CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this,
- mContext.getContentResolver(), UserHandle.USER_SYSTEM);
+ UserHandle.USER_SYSTEM, mContext);
disableSkuSpecificApps();
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index e991a91..609a415 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 @@
}
abandonSession = false;
- if (!params.sessionParams.isStaged || !params.waitForStagedSessionReady) {
+ if (!params.sessionParams.isStaged || !params.mWaitForStagedSessionReady) {
pw.println("Success");
return 0;
}
@@ -1197,7 +1197,7 @@
+ 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 @@
SessionParams sessionParams;
String installerPackageName;
int userId = UserHandle.USER_ALL;
- boolean waitForStagedSessionReady = false;
+ boolean mWaitForStagedSessionReady = true;
long timeoutMs = DEFAULT_WAIT_MS;
}
@@ -2615,13 +2615,16 @@
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/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 2705455..349a003 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -41,6 +41,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
+import android.os.ParcelableException;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -414,29 +415,28 @@
} else {
params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
}
- int apkSessionId = mPi.createSession(
- params, originalSession.getInstallerPackageName(),
- 0 /* UserHandle.SYSTEM */);
- PackageInstallerSession apkSession = mPi.getSession(apkSessionId);
-
try {
+ int apkSessionId = mPi.createSession(
+ params, originalSession.getInstallerPackageName(),
+ 0 /* UserHandle.SYSTEM */);
+ PackageInstallerSession apkSession = mPi.getSession(apkSessionId);
apkSession.open();
for (String apkFilePath : apkFilePaths) {
File apkFile = new File(apkFilePath);
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(apkFile,
ParcelFileDescriptor.MODE_READ_ONLY);
- long sizeBytes = pfd.getStatSize();
+ long sizeBytes = (pfd == null) ? -1 : pfd.getStatSize();
if (sizeBytes < 0) {
Slog.e(TAG, "Unable to get size of: " + apkFilePath);
return null;
}
apkSession.write(apkFile.getName(), 0, sizeBytes, pfd);
}
- } catch (IOException e) {
+ return apkSession;
+ } catch (IOException | ParcelableException e) {
Slog.e(TAG, "Failure to install APK staged session " + originalSession.sessionId, e);
return null;
}
- return apkSession;
}
private boolean commitApkSession(@NonNull PackageInstallerSession apkSession,
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index f56231f..9e86a4b 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -229,6 +229,7 @@
// If the dex file is the primary apk (or a split) and not isUsedByOtherApps
// do not record it. This case does not bring any new usable information
// and can be safely skipped.
+ dexPathIndex++;
continue;
}
diff --git a/services/core/java/com/android/server/policy/GlobalKeyManager.java b/services/core/java/com/android/server/policy/GlobalKeyManager.java
index e08c004..157f825 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 @@
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/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index 9347d21..cdf8ea3 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -49,7 +49,7 @@
import libcore.timezone.TimeZoneDataFiles;
import libcore.timezone.TimeZoneFinder;
import libcore.timezone.TzDataSetVersion;
-import libcore.timezone.ZoneInfoDB;
+import libcore.timezone.ZoneInfoDb;
import java.io.File;
import java.io.FileDescriptor;
@@ -518,9 +518,9 @@
case 'a': {
// Report the active rules version (i.e. the rules in use by the current
// process).
- pw.println("Active rules version (ICU, ZoneInfoDB, TimeZoneFinder): "
+ pw.println("Active rules version (ICU, ZoneInfoDb, TimeZoneFinder): "
+ TimeZone.getTZDataVersion() + ","
- + ZoneInfoDB.getInstance().getVersion() + ","
+ + ZoneInfoDb.getInstance().getVersion() + ","
+ TimeZoneFinder.getInstance().getIanaVersion());
break;
}
@@ -536,7 +536,7 @@
pw.println("RulesManagerService state: " + toString());
pw.println("Active rules version (ICU, ZoneInfoDB, TimeZoneFinder): "
+ TimeZone.getTZDataVersion() + ","
- + ZoneInfoDB.getInstance().getVersion() + ","
+ + ZoneInfoDb.getInstance().getVersion() + ","
+ TimeZoneFinder.getInstance().getIanaVersion());
pw.println("Distro state: " + rulesState.toString());
mPackageTracker.dump(pw);
diff --git a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp
index 9cd743b..8b6526f 100644
--- a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp
+++ b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp
@@ -20,6 +20,7 @@
#include <inttypes.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <vector>
#include <jni.h>
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b5b21f4..c566341 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1695,7 +1695,7 @@
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/net/Android.bp b/services/net/Android.bp
index 9c7cfc1..cf84bdf 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -23,7 +23,6 @@
name: "services-tethering-shared-srcs",
srcs: [
":framework-annotations",
- "java/android/net/util/NetdService.java",
"java/android/net/util/NetworkConstants.java",
],
visibility: ["//frameworks/base/packages/Tethering"],
diff --git a/services/net/java/android/net/IpMemoryStore.java b/services/net/java/android/net/IpMemoryStore.java
index 6f91e00..dcefb53 100644
--- a/services/net/java/android/net/IpMemoryStore.java
+++ b/services/net/java/android/net/IpMemoryStore.java
@@ -52,6 +52,11 @@
public int getInterfaceVersion() {
return this.VERSION;
}
+
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
});
}
diff --git a/services/net/java/android/net/ip/IpClientUtil.java b/services/net/java/android/net/ip/IpClientUtil.java
index 7f723b1..a3618b4 100644
--- a/services/net/java/android/net/ip/IpClientUtil.java
+++ b/services/net/java/android/net/ip/IpClientUtil.java
@@ -189,6 +189,11 @@
public int getInterfaceVersion() {
return this.VERSION;
}
+
+ @Override
+ public String getInterfaceHash() {
+ return this.HASH;
+ }
}
/**
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 32d7d02..1200c0c 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -20,6 +20,7 @@
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.HARDWARE_TEST"/>
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<application android:testOnly="true"
android:debuggable="true">
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
similarity index 75%
rename from services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java
rename to services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 7166145..698e491 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -25,14 +25,27 @@
import static android.app.AppOpsManager.OP_WIFI_SCAN;
import static android.app.AppOpsManager.OP_WRITE_SMS;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
+
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.AppOpsManager.OpEntry;
import android.app.AppOpsManager.PackageOps;
import android.content.Context;
+import android.content.pm.PackageManagerInternal;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
@@ -43,12 +56,17 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.server.LocalServices;
+
+import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.quality.Strictness;
import java.io.File;
import java.util.List;
@@ -69,21 +87,46 @@
// State will be persisted into this XML file.
private static final String APP_OPS_FILENAME = "appops-service-test.xml";
+ private static final Context sContext = InstrumentationRegistry.getTargetContext();
+ private static final String sMyPackageName = sContext.getOpPackageName();
+
private File mAppOpsFile;
- private Context mContext;
private Handler mHandler;
- private AppOpsManager mAppOpsManager;
private AppOpsService mAppOpsService;
- private String mMyPackageName;
private int mMyUid;
private long mTestStartMillis;
+ private StaticMockitoSession mMockingSession;
+
+ @Before
+ public void mockPackageManagerInternalGetApplicationInfo() {
+ mMockingSession = mockitoSession()
+ .strictness(Strictness.LENIENT)
+ .spyStatic(LocalServices.class)
+ .startMocking();
+
+ // Mock LocalServices.getService(PackageManagerInternal.class).getApplicationInfo dependency
+ // needed by AppOpsService
+ PackageManagerInternal mockPackageManagerInternal = mock(PackageManagerInternal.class);
+ when(mockPackageManagerInternal.getApplicationInfo(eq(sMyPackageName), anyInt(), anyInt(),
+ anyInt())).thenReturn(sContext.getApplicationInfo());
+ doReturn(mockPackageManagerInternal).when(
+ () -> LocalServices.getService(PackageManagerInternal.class));
+ }
+
+ private void setupAppOpsService() {
+ mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
+ mAppOpsService.mContext = spy(sContext);
+
+ // Always approve all permission checks
+ doNothing().when(mAppOpsService.mContext).enforcePermission(anyString(), anyInt(),
+ anyInt(), nullable(String.class));
+ }
private static String sDefaultAppopHistoryParameters;
@Before
public void setUp() {
- mContext = InstrumentationRegistry.getTargetContext();
- mAppOpsFile = new File(mContext.getFilesDir(), APP_OPS_FILENAME);
+ mAppOpsFile = new File(sContext.getFilesDir(), APP_OPS_FILENAME);
if (mAppOpsFile.exists()) {
// Start with a clean state (persisted into XML).
mAppOpsFile.delete();
@@ -92,13 +135,10 @@
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
- mMyPackageName = mContext.getOpPackageName();
mMyUid = Process.myUid();
- mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
- mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
- mAppOpsService.mHistoricalRegistry.systemReady(mContext.getContentResolver());
- mAppOpsService.mContext = mContext;
+ setupAppOpsService();
+ mAppOpsService.mHistoricalRegistry.systemReady(sContext.getContentResolver());
mTestStartMillis = System.currentTimeMillis();
}
@@ -118,6 +158,11 @@
sDefaultAppopHistoryParameters);
}
+ @After
+ public void resetStaticMocks() {
+ mMockingSession.finishMocking();
+ }
+
@Test
public void testGetOpsForPackage_noOpsLogged() {
assertThat(getLoggedOps()).isNull();
@@ -125,16 +170,16 @@
@Test
public void testNoteOperationAndGetOpsForPackage() {
- mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
- mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED);
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
+ mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED);
// Note an op that's allowed.
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
List<PackageOps> loggedOps = getLoggedOps();
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
// Note another op that's not allowed.
- mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName);
+ mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName);
loggedOps = getLoggedOps();
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
@@ -148,17 +193,17 @@
@Test
public void testNoteOperationAndGetOpsForPackage_controlledByDifferentOp() {
// This op controls WIFI_SCAN
- mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ALLOWED);
+ mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ALLOWED);
- assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName))
.isEqualTo(MODE_ALLOWED);
assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, -1,
MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
// Now set COARSE_LOCATION to ERRORED -> this will make WIFI_SCAN disabled as well.
- mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ERRORED);
- assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName))
+ mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ERRORED);
+ assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName))
.isEqualTo(MODE_ERRORED);
assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, mTestStartMillis,
@@ -168,15 +213,14 @@
// Tests the dumping and restoring of the in-memory state to/from XML.
@Test
public void testStatePersistence() {
- mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
- mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED);
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
- mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName);
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
+ mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
+ mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName);
mAppOpsService.writeState();
// Create a new app ops service, and initialize its state from XML.
- mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
- mAppOpsService.mContext = mContext;
+ setupAppOpsService();
mAppOpsService.readState();
// Query the state of the 2nd service.
@@ -188,13 +232,12 @@
// Tests that ops are persisted during shutdown.
@Test
public void testShutdown() {
- mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
mAppOpsService.shutdown();
// Create a new app ops service, and initialize its state from XML.
- mAppOpsService = new AppOpsService(mAppOpsFile, mHandler);
- mAppOpsService.mContext = mContext;
+ setupAppOpsService();
mAppOpsService.readState();
// Query the state of the 2nd service.
@@ -204,21 +247,21 @@
@Test
public void testGetOpsForPackage() {
- mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
// Query all ops
List<PackageOps> loggedOps = mAppOpsService.getOpsForPackage(
- mMyUid, mMyPackageName, null /* all ops */);
+ mMyUid, sMyPackageName, null /* all ops */);
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
// Query specific ops
loggedOps = mAppOpsService.getOpsForPackage(
- mMyUid, mMyPackageName, new int[]{OP_READ_SMS, OP_WRITE_SMS});
+ mMyUid, sMyPackageName, new int[]{OP_READ_SMS, OP_WRITE_SMS});
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
// Query unknown UID
- loggedOps = mAppOpsService.getOpsForPackage(mMyUid + 1, mMyPackageName, null /* all ops */);
+ loggedOps = mAppOpsService.getOpsForPackage(mMyUid + 1, sMyPackageName, null /* all ops */);
assertThat(loggedOps).isNull();
// Query unknown package name
@@ -226,31 +269,31 @@
assertThat(loggedOps).isNull();
// Query op code that's not been logged
- loggedOps = mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName,
+ loggedOps = mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName,
new int[]{OP_WRITE_SMS});
assertThat(loggedOps).isNull();
}
@Test
public void testPackageRemoved() {
- mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
List<PackageOps> loggedOps = getLoggedOps();
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
- mAppOpsService.packageRemoved(mMyUid, mMyPackageName);
+ mAppOpsService.packageRemoved(mMyUid, sMyPackageName);
assertThat(getLoggedOps()).isNull();
}
@Ignore("Historical appops are disabled in Android Q")
@Test
public void testPackageRemovedHistoricalOps() throws InterruptedException {
- mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
AppOpsManager.HistoricalOps historicalOps = new AppOpsManager.HistoricalOps(0, 15000);
- historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, mMyPackageName,
+ historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, sMyPackageName,
AppOpsManager.UID_STATE_PERSISTENT, 0, 1);
mAppOpsService.addHistoricalOps(historicalOps);
@@ -263,7 +306,7 @@
});
// First, do a fetch to ensure it's written
- mAppOpsService.getHistoricalOps(mMyUid, mMyPackageName, null, 0, Long.MAX_VALUE, 0,
+ mAppOpsService.getHistoricalOps(mMyUid, sMyPackageName, null, 0, Long.MAX_VALUE, 0,
callback);
latchRef.get().await(5, TimeUnit.SECONDS);
@@ -271,11 +314,11 @@
assertThat(resultOpsRef.get().isEmpty()).isFalse();
// Then, check it's deleted on removal
- mAppOpsService.packageRemoved(mMyUid, mMyPackageName);
+ mAppOpsService.packageRemoved(mMyUid, sMyPackageName);
latchRef.set(new CountDownLatch(1));
- mAppOpsService.getHistoricalOps(mMyUid, mMyPackageName, null, 0, Long.MAX_VALUE, 0,
+ mAppOpsService.getHistoricalOps(mMyUid, sMyPackageName, null, 0, Long.MAX_VALUE, 0,
callback);
latchRef.get().await(5, TimeUnit.SECONDS);
@@ -285,8 +328,8 @@
@Test
public void testUidRemoved() {
- mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED);
- mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName);
+ mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
+ mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName);
List<PackageOps> loggedOps = getLoggedOps();
assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
@@ -297,7 +340,7 @@
private void setupProcStateTests() {
// For the location proc state tests
- mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_FOREGROUND);
+ mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_FOREGROUND);
mAppOpsService.mConstants.FG_SERVICE_STATE_SETTLE_TIME = 0;
mAppOpsService.mConstants.TOP_STATE_SETTLE_TIME = 0;
mAppOpsService.mConstants.BG_STATE_SETTLE_TIME = 0;
@@ -308,18 +351,18 @@
setupProcStateTests();
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isNotEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
// Second time to make sure that settle time is overcome
Thread.sleep(50);
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isNotEqualTo(MODE_ALLOWED);
}
@@ -328,11 +371,11 @@
setupProcStateTests();
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isNotEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isNotEqualTo(MODE_ALLOWED);
}
@@ -341,12 +384,12 @@
setupProcStateTests();
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isNotEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid,
PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isEqualTo(MODE_ALLOWED);
}
@@ -355,18 +398,18 @@
setupProcStateTests();
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isNotEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
// Second time to make sure that settle time is overcome
Thread.sleep(50);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isNotEqualTo(MODE_ALLOWED);
}
@@ -375,30 +418,30 @@
setupProcStateTests();
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isNotEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
// Second time to make sure that settle time is overcome
Thread.sleep(50);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isEqualTo(MODE_ALLOWED);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
// Second time to make sure that settle time is overcome
Thread.sleep(50);
mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE);
- assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName))
+ assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName))
.isNotEqualTo(MODE_ALLOWED);
}
private List<PackageOps> getLoggedOps() {
- return mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName, null /* all ops */);
+ return mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName, null /* all ops */);
}
private void assertContainsOp(List<PackageOps> loggedOps, int opCode, long minMillis,
@@ -407,7 +450,7 @@
boolean opLogged = false;
for (PackageOps pkgOps : loggedOps) {
assertWithMessage("Unexpected UID").that(mMyUid).isEqualTo(pkgOps.getUid());
- assertWithMessage("Unexpected package name").that(mMyPackageName).isEqualTo(
+ assertWithMessage("Unexpected package name").that(sMyPackageName).isEqualTo(
pkgOps.getPackageName());
for (OpEntry opEntry : pkgOps.getOps()) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
index 19369db..6c29f60 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
@@ -530,6 +530,46 @@
}
@Test
+ public void testJobDelayWakeupAlarmToggling() {
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+
+ JobStatus job = createJobStatus(
+ "testMaybeStartTrackingJobLocked_DeadlineReverseOrder",
+ createJob().setMinimumLatency(HOUR_IN_MILLIS));
+
+ doReturn(true).when(mTimeController)
+ .wouldBeReadyWithConstraintLocked(eq(job), anyInt());
+
+ // Starting off with using a wakeup alarm.
+ mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = false;
+ InOrder inOrder = inOrder(mAlarmManager);
+
+ mTimeController.maybeStartTrackingJobLocked(job, null);
+ inOrder.verify(mAlarmManager, times(1))
+ .set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(now + HOUR_IN_MILLIS), anyLong(),
+ anyLong(),
+ eq(TAG_DELAY), any(), any(), any());
+
+ // Use a non wakeup alarm.
+ mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = true;
+
+ mTimeController.maybeStartTrackingJobLocked(job, null);
+ inOrder.verify(mAlarmManager, times(1))
+ .set(eq(AlarmManager.ELAPSED_REALTIME), eq(now + HOUR_IN_MILLIS), anyLong(),
+ anyLong(), eq(TAG_DELAY),
+ any(), any(), any());
+
+ // Back off, use a wakeup alarm.
+ mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = false;
+
+ mTimeController.maybeStartTrackingJobLocked(job, null);
+ inOrder.verify(mAlarmManager, times(1))
+ .set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(now + HOUR_IN_MILLIS), anyLong(),
+ anyLong(),
+ eq(TAG_DELAY), any(), any(), any());
+ }
+
+ @Test
public void testCheckExpiredDelaysAndResetAlarm_WithSkipping_AllReady() {
mConstants.SKIP_NOT_READY_JOBS = true;
mTimeController.recheckAlarmsLocked();
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 61fe01f..1e623e0 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -65,6 +65,8 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.SUSPEND_APPS"/>
<uses-permission android:name="android.permission.CONTROL_KEYGUARD"/>
+ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
+ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
<uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"/>
<uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
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 0000000..968a402
--- /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/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
index 50437b4..d367f71 100644
--- a/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
@@ -36,7 +36,7 @@
public void test1() {
assertTrue("dynamic_system service available", mService != null);
try {
- mService.startInstallation();
+ mService.startInstallation("dsu");
fail("DynamicSystemService did not throw SecurityException as expected");
} catch (SecurityException e) {
// expected
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 07b17eb..ca5dfb1 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -16,7 +16,7 @@
package com.android.server;
-import static android.net.NetworkScoreManager.CACHE_FILTER_NONE;
+import static android.net.NetworkScoreManager.SCORE_FILTER_NONE;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -304,7 +304,7 @@
bindToScorer(true /*callerIsScorer*/);
mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
- mNetworkScoreCache, CACHE_FILTER_NONE);
+ mNetworkScoreCache, SCORE_FILTER_NONE);
mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
@@ -319,9 +319,9 @@
bindToScorer(true /*callerIsScorer*/);
mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI,
- mNetworkScoreCache, CACHE_FILTER_NONE);
+ mNetworkScoreCache, SCORE_FILTER_NONE);
mNetworkScoreService.registerNetworkScoreCache(
- NetworkKey.TYPE_WIFI, mNetworkScoreCache2, CACHE_FILTER_NONE);
+ NetworkKey.TYPE_WIFI, mNetworkScoreCache2, SCORE_FILTER_NONE);
// updateScores should update both caches
mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK});
@@ -376,7 +376,7 @@
bindToScorer(true /*callerIsScorer*/);
mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
- CACHE_FILTER_NONE);
+ SCORE_FILTER_NONE);
mNetworkScoreService.clearScores();
verify(mNetworkScoreCache).clearScores();
@@ -390,7 +390,7 @@
.thenReturn(PackageManager.PERMISSION_GRANTED);
mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache,
- CACHE_FILTER_NONE);
+ SCORE_FILTER_NONE);
mNetworkScoreService.clearScores();
verify(mNetworkScoreCache).clearScores();
@@ -470,7 +470,7 @@
try {
mNetworkScoreService.registerNetworkScoreCache(
- NetworkKey.TYPE_WIFI, mNetworkScoreCache, CACHE_FILTER_NONE);
+ NetworkKey.TYPE_WIFI, mNetworkScoreCache, SCORE_FILTER_NONE);
fail("SecurityException expected");
} catch (SecurityException e) {
// expected
@@ -613,7 +613,7 @@
new ArrayList<>(scoredNetworkList),
NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
- consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE);
+ consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_NONE);
verify(mNetworkScoreCache).updateScores(scoredNetworkList);
verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter);
@@ -654,7 +654,7 @@
Collections.emptyList(),
NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter);
- consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE);
+ consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_NONE);
verifyZeroInteractions(mNetworkScoreCache, mCurrentNetworkFilter, mScanResultsFilter);
}
@@ -671,7 +671,7 @@
List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList);
filteredList.remove(SCORED_NETWORK);
when(mCurrentNetworkFilter.apply(scoredNetworkList)).thenReturn(filteredList);
- consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK);
+ consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK);
verify(mNetworkScoreCache).updateScores(filteredList);
verifyZeroInteractions(mScanResultsFilter);
@@ -689,7 +689,7 @@
List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList);
filteredList.remove(SCORED_NETWORK);
when(mScanResultsFilter.apply(scoredNetworkList)).thenReturn(filteredList);
- consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS);
+ consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS);
verify(mNetworkScoreCache).updateScores(filteredList);
verifyZeroInteractions(mCurrentNetworkFilter);
diff --git a/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java
index 4d229ef..625766a 100644
--- a/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java
+++ b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java
@@ -157,6 +157,8 @@
String expected =
"TestThread2 annotated stack trace:\n" +
" at java.lang.Object.wait(Native Method)\n" +
+ " at java.lang.Object.wait(Object.java:442)\n" +
+ " at java.lang.Object.wait(Object.java:568)\n" +
" at com.android.server.WatchdogDiagnosticsTest$TestThread2.y(" +
"WatchdogDiagnosticsTest.java:91)\n" +
" - locked <HASH> (a java.lang.String)\n" +
diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
index ecd07bd..b14291b 100644
--- a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
@@ -188,7 +188,7 @@
}
@Test
- public void getOverrideAllowedState_betaBuildEnabledChangeDebugApp_rejectOverride()
+ public void getOverrideAllowedState_betaBuildEnabledChangeDebugApp_allowOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
.addEnabledChangeWithId(1).build();
@@ -203,11 +203,11 @@
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
assertThat(allowedState)
- .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
}
@Test
- public void getOverrideAllowedState_betaBuildDisabledChangeDebugApp_rejectOverride()
+ public void getOverrideAllowedState_betaBuildDisabledChangeDebugApp_allowOverride()
throws Exception {
CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
.addDisabledChangeWithId(1).build();
@@ -221,7 +221,7 @@
overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
assertThat(allowedState)
- .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+ .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index 842cdd5..2aaf759 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -215,6 +215,18 @@
}
}).when(sm).addUserKeyAuth(anyInt(), anyInt(), any(), any());
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ mStorageManager.clearUserKeyAuth((int) args[0] /* userId */,
+ (int) args[1] /* serialNumber */,
+ (byte[]) args[2] /* token */,
+ (byte[]) args[3] /* secret */);
+ return null;
+ }
+ }).when(sm).clearUserKeyAuth(anyInt(), anyInt(), any(), any());
+
doAnswer(
new Answer<Void>() {
@Override
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java b/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java
index 1ae1fa6..102bac1 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/FakeStorageManager.java
@@ -36,6 +36,15 @@
getUserAuth(userId).add(new Pair<>(token, secret));
}
+ public void clearUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
+ ArrayList<Pair<byte[], byte[]>> auths = getUserAuth(userId);
+ if (token == null && secret == null) {
+ return;
+ }
+ auths.remove(new Pair<>(token, secret));
+ auths.add(new Pair<>(null, null));
+ }
+
public void fixateNewestUserKeyAuth(int userId) {
ArrayList<Pair<byte[], byte[]>> auths = mAuth.get(userId);
Pair<byte[], byte[]> latest = auths.get(auths.size() - 1);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index d9b1320..33f7924 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -103,31 +103,6 @@
return mService.getLong(SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId) != 0;
}
- @Test
- public void testPasswordMigration() throws RemoteException {
- final byte[] password = "testPasswordMigration-password".getBytes();
-
- disableSyntheticPassword();
- mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
- long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
- final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- enableSyntheticPassword();
- // Performs migration
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
- assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
- assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
-
- // SP-based verification
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password,
- LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
- assertArrayNotEquals(primaryStorageKey,
- mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
- }
-
protected void initializeCredentialUnderSP(byte[] password, int userId) throws RemoteException {
enableSyntheticPassword();
int quality = password != null ? PASSWORD_QUALITY_ALPHABETIC
@@ -270,86 +245,6 @@
}
@Test
- public void testManagedProfileUnifiedChallengeMigration() throws RemoteException {
- final byte[] UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd".getBytes();
- disableSyntheticPassword();
- mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
- mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
- final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
- final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
- final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- final byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
- assertTrue(primarySid != 0);
- assertTrue(profileSid != 0);
- assertTrue(profileSid != primarySid);
-
- // do migration
- enableSyntheticPassword();
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
-
- // verify
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
- assertEquals(primarySid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
- assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
- assertArrayNotEquals(primaryStorageKey,
- mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
- assertArrayNotEquals(profileStorageKey,
- mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID));
- assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
- assertTrue(hasSyntheticPassword(MANAGED_PROFILE_USER_ID));
- }
-
- @Test
- public void testManagedProfileSeparateChallengeMigration() throws RemoteException {
- final byte[] primaryPassword =
- "testManagedProfileSeparateChallengeMigration-primary".getBytes();
- final byte[] profilePassword =
- "testManagedProfileSeparateChallengeMigration-profile".getBytes();
- disableSyntheticPassword();
- mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
- mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
- PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID, false);
- final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
- final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
- final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- final byte[] profileStorageKey = mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID);
- assertTrue(primarySid != 0);
- assertTrue(profileSid != 0);
- assertTrue(profileSid != primarySid);
-
- // do migration
- enableSyntheticPassword();
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- 0, MANAGED_PROFILE_USER_ID).getResponseCode());
-
- // verify
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
- .getResponseCode());
- assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- 0, MANAGED_PROFILE_USER_ID).getResponseCode());
- assertEquals(primarySid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
- assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
- assertArrayNotEquals(primaryStorageKey,
- mStorageManager.getUserUnlockToken(PRIMARY_USER_ID));
- assertArrayNotEquals(profileStorageKey,
- mStorageManager.getUserUnlockToken(MANAGED_PROFILE_USER_ID));
- assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
- assertTrue(hasSyntheticPassword(MANAGED_PROFILE_USER_ID));
- }
-
- @Test
public void testTokenBasedResetPassword() throws RemoteException {
final byte[] password = "password".getBytes();
final byte[] pattern = "123654".getBytes();
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 7068308..2e58ad6 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -112,7 +112,7 @@
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
-import android.net.StringNetworkSpecifier;
+import android.net.TelephonyNetworkSpecifier;
import android.os.Binder;
import android.os.Handler;
import android.os.INetworkManagementService;
@@ -1838,7 +1838,8 @@
if (!roaming) {
nc.addCapability(NET_CAPABILITY_NOT_ROAMING);
}
- nc.setNetworkSpecifier(new StringNetworkSpecifier(String.valueOf(subId)));
+ nc.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+ .setSubscriptionId(subId).build());
return nc;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 0196279..a4ba056 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -160,6 +160,31 @@
}
@Test
+ public void testNotifyPrimaryAndSecondary() {
+ List<String> dexFiles = mFooUser0.getBaseAndSplitDexPaths();
+ List<String> secondaries = mFooUser0.getSecondaryDexPaths();
+ int baseAndSplitCount = dexFiles.size();
+ dexFiles.addAll(secondaries);
+
+ notifyDexLoad(mFooUser0, dexFiles, mUser0);
+
+ PackageUseInfo pui = getPackageUseInfo(mFooUser0);
+ assertIsUsedByOtherApps(mFooUser0, pui, false);
+ assertEquals(secondaries.size(), pui.getDexUseInfoMap().size());
+
+ String[] allExpectedContexts = DexoptUtils.processContextForDexLoad(
+ Arrays.asList(mFooUser0.mClassLoader),
+ Arrays.asList(String.join(File.pathSeparator, dexFiles)));
+ String[] secondaryExpectedContexts = Arrays.copyOfRange(allExpectedContexts,
+ baseAndSplitCount, dexFiles.size());
+
+ assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0,
+ secondaryExpectedContexts);
+
+ assertHasDclInfo(mFooUser0, mFooUser0, secondaries);
+ }
+
+ @Test
public void testNotifySecondaryForeign() {
// Foo loads bar secondary files.
List<String> barSecondaries = mBarUser0.getSecondaryDexPaths();
diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java
index 8b8c86b..ea641f8 100644
--- a/telecomm/java/android/telecom/AudioState.java
+++ b/telecomm/java/android/telecom/AudioState.java
@@ -19,7 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 86ad795..f54f8d1 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -20,12 +20,11 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import com.android.internal.telecom.IVideoProvider;
@@ -266,6 +265,29 @@
public static final String EVENT_HANDOVER_FAILED =
"android.telecom.event.HANDOVER_FAILED";
+
+ /**
+ * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this
+ * call because they have declined to answer it. This typically means that they are unable
+ * to answer the call at this time and would prefer it be sent to voicemail.
+ */
+ public static final int REJECT_REASON_DECLINED = 1;
+
+ /**
+ * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this
+ * call because it is an unwanted call. This allows the user to indicate that they are
+ * rejecting a call because it is likely a nuisance call.
+ */
+ public static final int REJECT_REASON_UNWANTED = 2;
+
+ /**
+ * @hide
+ */
+ @IntDef(prefix = { "REJECT_REASON_" },
+ value = {REJECT_REASON_DECLINED, REJECT_REASON_UNWANTED})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RejectReason {};
+
public static class Details {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -548,8 +570,14 @@
*/
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;
@@ -569,6 +597,7 @@
private final Bundle mExtras;
private final Bundle mIntentExtras;
private final long mCreationTimeMillis;
+ private final String mContactDisplayName;
private final @CallDirection int mCallDirection;
private final @Connection.VerificationStatus int mCallerNumberVerificationStatus;
@@ -726,6 +755,9 @@
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();
}
@@ -873,6 +905,17 @@
}
/**
+ * Returns the name of the caller on the remote end, as derived from a
+ * {@link android.provider.ContactsContract} lookup of the call's handle.
+ * @return The name of the caller, or {@code null} if the lookup is not yet complete, if
+ * there's no contacts entry for the caller, or if the {@link InCallService} does
+ * not hold the {@link android.Manifest.permission#READ_CONTACTS} permission.
+ */
+ public @Nullable String getContactDisplayName() {
+ return mContactDisplayName;
+ }
+
+ /**
* Indicates whether the call is an incoming or outgoing call.
* @return The call's direction.
*/
@@ -910,6 +953,7 @@
areBundlesEqual(mExtras, d.mExtras) &&
areBundlesEqual(mIntentExtras, d.mIntentExtras) &&
Objects.equals(mCreationTimeMillis, d.mCreationTimeMillis) &&
+ Objects.equals(mContactDisplayName, d.mContactDisplayName) &&
Objects.equals(mCallDirection, d.mCallDirection) &&
Objects.equals(mCallerNumberVerificationStatus,
d.mCallerNumberVerificationStatus);
@@ -934,6 +978,7 @@
mExtras,
mIntentExtras,
mCreationTimeMillis,
+ mContactDisplayName,
mCallDirection,
mCallerNumberVerificationStatus);
}
@@ -956,6 +1001,7 @@
Bundle extras,
Bundle intentExtras,
long creationTimeMillis,
+ String contactDisplayName,
int callDirection,
int callerNumberVerificationStatus) {
mTelecomCallId = telecomCallId;
@@ -974,6 +1020,7 @@
mExtras = extras;
mIntentExtras = intentExtras;
mCreationTimeMillis = creationTimeMillis;
+ mContactDisplayName = contactDisplayName;
mCallDirection = callDirection;
mCallerNumberVerificationStatus = callerNumberVerificationStatus;
}
@@ -997,6 +1044,7 @@
parcelableCall.getExtras(),
parcelableCall.getIntentExtras(),
parcelableCall.getCreationTimeMillis(),
+ parcelableCall.getContactDisplayName(),
parcelableCall.getCallDirection(),
parcelableCall.getCallerNumberVerificationStatus());
}
@@ -1446,6 +1494,7 @@
private boolean mChildrenCached;
private String mParentId = null;
+ private String mActiveGenericConferenceChild = null;
private int mState;
private List<String> mCannedTextResponses = null;
private String mCallingPackage;
@@ -1494,6 +1543,16 @@
}
/**
+ * Instructs the {@link ConnectionService} providing this {@link #STATE_RINGING} call that the
+ * user has chosen to reject the call and has indicated a reason why the call is being rejected.
+ *
+ * @param rejectReason the reason the call is being rejected.
+ */
+ public void reject(@RejectReason int rejectReason) {
+ mInCallAdapter.rejectCall(mTelecomCallId, rejectReason);
+ }
+
+ /**
* Instructs this {@code Call} to disconnect.
*/
public void disconnect() {
@@ -1944,6 +2003,20 @@
}
/**
+ * Returns the child {@link Call} in a generic conference that is currently active.
+ * For calls that are not generic conferences, or when the generic conference has more than
+ * 2 children, returns {@code null}.
+ * @see Details#PROPERTY_GENERIC_CONFERENCE
+ * @return The active child call.
+ */
+ public @Nullable Call getGenericConferenceActiveChildCall() {
+ if (mActiveGenericConferenceChild != null) {
+ return mPhone.internalGetCallByTelecomId(mActiveGenericConferenceChild);
+ }
+ return null;
+ }
+
+ /**
* Obtains a list of canned, pre-configured message responses to present to the user as
* ways of rejecting this {@code Call} using via a text message.
*
@@ -2191,6 +2264,13 @@
mChildrenCached = false;
}
+ String activeChildCallId = parcelableCall.getActiveChildCallId();
+ boolean activeChildChanged = !Objects.equals(activeChildCallId,
+ mActiveGenericConferenceChild);
+ if (activeChildChanged) {
+ mActiveGenericConferenceChild = activeChildCallId;
+ }
+
List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
for (String otherId : conferenceableCallIds) {
@@ -2250,7 +2330,7 @@
if (parentChanged) {
fireParentChanged(getParent());
}
- if (childrenChanged) {
+ if (childrenChanged || activeChildChanged) {
fireChildrenChanged(getChildren());
}
if (isRttChanged) {
diff --git a/telecomm/java/android/telecom/CallerInfo.java b/telecomm/java/android/telecom/CallerInfo.java
index a5d25e2..fb6f994 100644
--- a/telecomm/java/android/telecom/CallerInfo.java
+++ b/telecomm/java/android/telecom/CallerInfo.java
@@ -17,7 +17,7 @@
package android.telecom;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -41,8 +41,8 @@
import com.android.i18n.phonenumbers.PhoneNumberUtil;
import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
import com.android.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder;
-
import com.android.internal.annotations.VisibleForTesting;
+
import java.util.Locale;
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 456290c..6b0845f 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -69,6 +69,7 @@
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 @@
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 @@
}
/**
+ * 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 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
}
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 @@
}
}
+ 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 @@
@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 8808339..72c66d2 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -21,9 +21,9 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
import android.app.Notification;
import android.bluetooth.BluetoothDevice;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Intent;
import android.hardware.camera2.CameraManager;
import android.net.Uri;
@@ -497,8 +497,17 @@
@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 @@
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();
}
@@ -3024,6 +3037,17 @@
public void onReject() {}
/**
+ * Notifies this Connection, which is in {@link #STATE_RINGING}, of a request to reject.
+ * <p>
+ * For managed {@link ConnectionService}s, this will be called when the user rejects a call via
+ * the default dialer's {@link InCallService} using {@link Call#reject(int)}.
+ * @param rejectReason the reason the user provided for rejecting the call.
+ */
+ public void onReject(@android.telecom.Call.RejectReason int rejectReason) {
+ // to be implemented by ConnectionService.
+ }
+
+ /**
* Notifies this Connection, which is in {@link #STATE_RINGING}, of
* a request to reject with a message.
*/
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index 221f8f1..6d7ceca 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -26,6 +26,9 @@
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 @@
private boolean mShouldShowIncomingCallUi = false;
private ParcelFileDescriptor mRttPipeToInCall;
private ParcelFileDescriptor mRttPipeFromInCall;
+ private List<Uri> mParticipants;
+ private boolean mIsAdhocConference = false;
public Builder() { }
@@ -59,6 +64,15 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
mTelecomCallId,
mShouldShowIncomingCallUi,
mRttPipeFromInCall,
- mRttPipeToInCall);
+ mRttPipeToInCall,
+ mParticipants,
+ mIsAdhocConference);
}
}
@@ -155,6 +181,8 @@
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 @@
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 @@
mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
mRttPipeFromInCall = rttPipeFromInCall;
mRttPipeToInCall = rttPipeToInCall;
+ mParticipants = participants;
+ mIsAdhocConference = isAdhocConference;
}
private ConnectionRequest(Parcel in) {
@@ -233,6 +278,11 @@
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 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 @@
}
/**
+ * @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 @@
@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 @@
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 3a0494e..00c2918 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -154,6 +154,9 @@
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,10 @@
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 final int MSG_REJECT_WITH_REASON = 38;
private static Connection sNullConnection;
@@ -291,6 +298,63 @@
}
@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);
@@ -387,6 +451,21 @@
}
@Override
+ public void rejectWithReason(String callId,
+ @android.telecom.Call.RejectReason int rejectReason, Session.Info sessionInfo) {
+ Log.startSession(sessionInfo, SESSION_REJECT);
+ try {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.argi1 = rejectReason;
+ args.arg2 = Log.createSubsession();
+ mHandler.obtainMessage(MSG_REJECT_WITH_REASON, args).sendToTarget();
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ @Override
public void rejectWithMessage(String callId, String message, Session.Info sessionInfo) {
Log.startSession(sessionInfo, SESSION_REJECT_MESSAGE);
try {
@@ -802,6 +881,106 @@
}
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 +
@@ -890,6 +1069,17 @@
}
break;
}
+ case MSG_REJECT_WITH_REASON: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT);
+ try {
+ reject((String) args.arg1, args.argi1);
+ } finally {
+ args.recycle();
+ Log.endSession();
+ }
+ break;
+ }
case MSG_REJECT_WITH_MESSAGE: {
SomeArgs args = (SomeArgs) msg.obj;
Log.continueSession((Session) args.arg3,
@@ -1162,6 +1352,12 @@
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 +1488,13 @@
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 +1737,70 @@
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 +1912,18 @@
}
}
+ 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 +1948,24 @@
"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 +1973,20 @@
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 +1996,11 @@
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) {
@@ -1699,6 +2008,11 @@
findConnectionForAction(callId, "reject").onReject(rejectWithMessage);
}
+ private void reject(String callId, @android.telecom.Call.RejectReason int rejectReason) {
+ Log.d(this, "reject %s with reason %d", callId, rejectReason);
+ findConnectionForAction(callId, "reject").onReject(rejectReason);
+ }
+
private void silence(String callId) {
Log.d(this, "silence %s", callId);
findConnectionForAction(callId, "silence").onSilence();
@@ -2198,6 +2512,21 @@
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 +2541,19 @@
}
/**
+ * 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 +2592,47 @@
}
/**
+ * 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 +2672,36 @@
}
/**
+ * 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 04e930c..8f27323 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java
@@ -100,6 +100,19 @@
}
}
+ 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 60b2172..79ad51b 100644
--- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
+++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java
@@ -75,6 +75,7 @@
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 @@
}
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 @@
}
@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/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 2612468..594c1eb 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -89,6 +89,19 @@
}
/**
+ * Instructs Telecom to reject the specified call.
+ *
+ * @param callId The identifier of the call to reject.
+ * @param rejectReason The reason the call was rejected.
+ */
+ public void rejectCall(String callId, @Call.RejectReason int rejectReason) {
+ try {
+ mAdapter.rejectCallWithReason(callId, rejectReason);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Instructs Telecom to disconnect the specified call.
*
* @param callId The identifier of the call to disconnect.
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 7d4ee76..4f6a9d6 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -16,7 +16,7 @@
package android.telecom;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index a234bb0..415a817 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -16,27 +16,286 @@
package android.telecom;
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.Nullable;
+import android.compat.annotation.UnsupportedAppUsage;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.telecom.Call.Details.CallDirection;
+import com.android.internal.telecom.IVideoProvider;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import com.android.internal.telecom.IVideoProvider;
-
/**
* Information about a call that is used between InCallService and Telecom.
* @hide
*/
public final class ParcelableCall implements Parcelable {
+
+ public static class ParcelableCallBuilder {
+ private String mId;
+ private int mState;
+ private DisconnectCause mDisconnectCause;
+ private List<String> mCannedSmsResponses;
+ private int mCapabilities;
+ private int mProperties;
+ private int mSupportedAudioRoutes;
+ private long mConnectTimeMillis;
+ private Uri mHandle;
+ private int mHandlePresentation;
+ private String mCallerDisplayName;
+ private int mCallerDisplayNamePresentation;
+ private GatewayInfo mGatewayInfo;
+ private PhoneAccountHandle mAccountHandle;
+ private boolean mIsVideoCallProviderChanged;
+ private IVideoProvider mVideoCallProvider;
+ private boolean mIsRttCallChanged;
+ private ParcelableRttCall mRttCall;
+ private String mParentCallId;
+ private List<String> mChildCallIds;
+ private StatusHints mStatusHints;
+ private int mVideoState;
+ private List<String> mConferenceableCallIds;
+ private Bundle mIntentExtras;
+ private Bundle mExtras;
+ private long mCreationTimeMillis;
+ private int mCallDirection;
+ private int mCallerNumberVerificationStatus;
+ private String mContactDisplayName;
+ private String mActiveChildCallId;
+
+ public ParcelableCallBuilder setId(String id) {
+ mId = id;
+ return this;
+ }
+
+ public ParcelableCallBuilder setState(int state) {
+ mState = state;
+ return this;
+ }
+
+ public ParcelableCallBuilder setDisconnectCause(DisconnectCause disconnectCause) {
+ mDisconnectCause = disconnectCause;
+ return this;
+ }
+
+ public ParcelableCallBuilder setCannedSmsResponses(List<String> cannedSmsResponses) {
+ mCannedSmsResponses = cannedSmsResponses;
+ return this;
+ }
+
+ public ParcelableCallBuilder setCapabilities(int capabilities) {
+ mCapabilities = capabilities;
+ return this;
+ }
+
+ public ParcelableCallBuilder setProperties(int properties) {
+ mProperties = properties;
+ return this;
+ }
+
+ public ParcelableCallBuilder setSupportedAudioRoutes(int supportedAudioRoutes) {
+ mSupportedAudioRoutes = supportedAudioRoutes;
+ return this;
+ }
+
+ public ParcelableCallBuilder setConnectTimeMillis(long connectTimeMillis) {
+ mConnectTimeMillis = connectTimeMillis;
+ return this;
+ }
+
+ public ParcelableCallBuilder setHandle(Uri handle) {
+ mHandle = handle;
+ return this;
+ }
+
+ public ParcelableCallBuilder setHandlePresentation(int handlePresentation) {
+ mHandlePresentation = handlePresentation;
+ return this;
+ }
+
+ public ParcelableCallBuilder setCallerDisplayName(String callerDisplayName) {
+ mCallerDisplayName = callerDisplayName;
+ return this;
+ }
+
+ public ParcelableCallBuilder setCallerDisplayNamePresentation(
+ int callerDisplayNamePresentation) {
+ mCallerDisplayNamePresentation = callerDisplayNamePresentation;
+ return this;
+ }
+
+ public ParcelableCallBuilder setGatewayInfo(GatewayInfo gatewayInfo) {
+ mGatewayInfo = gatewayInfo;
+ return this;
+ }
+
+ public ParcelableCallBuilder setAccountHandle(PhoneAccountHandle accountHandle) {
+ mAccountHandle = accountHandle;
+ return this;
+ }
+
+ public ParcelableCallBuilder setIsVideoCallProviderChanged(
+ boolean isVideoCallProviderChanged) {
+ mIsVideoCallProviderChanged = isVideoCallProviderChanged;
+ return this;
+ }
+
+ public ParcelableCallBuilder setVideoCallProvider(IVideoProvider videoCallProvider) {
+ mVideoCallProvider = videoCallProvider;
+ return this;
+ }
+
+ public ParcelableCallBuilder setIsRttCallChanged(boolean isRttCallChanged) {
+ mIsRttCallChanged = isRttCallChanged;
+ return this;
+ }
+
+ public ParcelableCallBuilder setRttCall(ParcelableRttCall rttCall) {
+ mRttCall = rttCall;
+ return this;
+ }
+
+ public ParcelableCallBuilder setParentCallId(String parentCallId) {
+ mParentCallId = parentCallId;
+ return this;
+ }
+
+ public ParcelableCallBuilder setChildCallIds(List<String> childCallIds) {
+ mChildCallIds = childCallIds;
+ return this;
+ }
+
+ public ParcelableCallBuilder setStatusHints(StatusHints statusHints) {
+ mStatusHints = statusHints;
+ return this;
+ }
+
+ public ParcelableCallBuilder setVideoState(int videoState) {
+ mVideoState = videoState;
+ return this;
+ }
+
+ public ParcelableCallBuilder setConferenceableCallIds(
+ List<String> conferenceableCallIds) {
+ mConferenceableCallIds = conferenceableCallIds;
+ return this;
+ }
+
+ public ParcelableCallBuilder setIntentExtras(Bundle intentExtras) {
+ mIntentExtras = intentExtras;
+ return this;
+ }
+
+ public ParcelableCallBuilder setExtras(Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ public ParcelableCallBuilder setCreationTimeMillis(long creationTimeMillis) {
+ mCreationTimeMillis = creationTimeMillis;
+ return this;
+ }
+
+ public ParcelableCallBuilder setCallDirection(int callDirection) {
+ mCallDirection = callDirection;
+ return this;
+ }
+
+ public ParcelableCallBuilder setCallerNumberVerificationStatus(
+ int callerNumberVerificationStatus) {
+ mCallerNumberVerificationStatus = callerNumberVerificationStatus;
+ return this;
+ }
+
+ public ParcelableCallBuilder setContactDisplayName(String contactDisplayName) {
+ mContactDisplayName = contactDisplayName;
+ return this;
+ }
+
+ public ParcelableCallBuilder setActiveChildCallId(String activeChildCallId) {
+ mActiveChildCallId = activeChildCallId;
+ return this;
+ }
+
+ public ParcelableCall createParcelableCall() {
+ return new ParcelableCall(
+ mId,
+ mState,
+ mDisconnectCause,
+ mCannedSmsResponses,
+ mCapabilities,
+ mProperties,
+ mSupportedAudioRoutes,
+ mConnectTimeMillis,
+ mHandle,
+ mHandlePresentation,
+ mCallerDisplayName,
+ mCallerDisplayNamePresentation,
+ mGatewayInfo,
+ mAccountHandle,
+ mIsVideoCallProviderChanged,
+ mVideoCallProvider,
+ mIsRttCallChanged,
+ mRttCall,
+ mParentCallId,
+ mChildCallIds,
+ mStatusHints,
+ mVideoState,
+ mConferenceableCallIds,
+ mIntentExtras,
+ mExtras,
+ mCreationTimeMillis,
+ mCallDirection,
+ mCallerNumberVerificationStatus,
+ mContactDisplayName,
+ mActiveChildCallId);
+ }
+
+ public static ParcelableCallBuilder fromParcelableCall(ParcelableCall parcelableCall) {
+ ParcelableCallBuilder newBuilder = new ParcelableCallBuilder();
+ newBuilder.mId = parcelableCall.mId;
+ newBuilder.mState = parcelableCall.mState;
+ newBuilder.mDisconnectCause = parcelableCall.mDisconnectCause;
+ newBuilder.mCannedSmsResponses = parcelableCall.mCannedSmsResponses;
+ newBuilder.mCapabilities = parcelableCall.mCapabilities;
+ newBuilder.mProperties = parcelableCall.mProperties;
+ newBuilder.mSupportedAudioRoutes = parcelableCall.mSupportedAudioRoutes;
+ newBuilder.mConnectTimeMillis = parcelableCall.mConnectTimeMillis;
+ newBuilder.mHandle = parcelableCall.mHandle;
+ newBuilder.mHandlePresentation = parcelableCall.mHandlePresentation;
+ newBuilder.mCallerDisplayName = parcelableCall.mCallerDisplayName;
+ newBuilder.mCallerDisplayNamePresentation =
+ parcelableCall.mCallerDisplayNamePresentation;
+ newBuilder.mGatewayInfo = parcelableCall.mGatewayInfo;
+ newBuilder.mAccountHandle = parcelableCall.mAccountHandle;
+ newBuilder.mIsVideoCallProviderChanged = parcelableCall.mIsVideoCallProviderChanged;
+ newBuilder.mVideoCallProvider = parcelableCall.mVideoCallProvider;
+ newBuilder.mIsRttCallChanged = parcelableCall.mIsRttCallChanged;
+ newBuilder.mRttCall = parcelableCall.mRttCall;
+ newBuilder.mParentCallId = parcelableCall.mParentCallId;
+ newBuilder.mChildCallIds = parcelableCall.mChildCallIds;
+ newBuilder.mStatusHints = parcelableCall.mStatusHints;
+ newBuilder.mVideoState = parcelableCall.mVideoState;
+ newBuilder.mConferenceableCallIds = parcelableCall.mConferenceableCallIds;
+ newBuilder.mIntentExtras = parcelableCall.mIntentExtras;
+ newBuilder.mExtras = parcelableCall.mExtras;
+ newBuilder.mCreationTimeMillis = parcelableCall.mCreationTimeMillis;
+ newBuilder.mCallDirection = parcelableCall.mCallDirection;
+ newBuilder.mCallerNumberVerificationStatus =
+ parcelableCall.mCallerNumberVerificationStatus;
+ newBuilder.mContactDisplayName = parcelableCall.mContactDisplayName;
+ newBuilder.mActiveChildCallId = parcelableCall.mActiveChildCallId;
+ return newBuilder;
+ }
+ }
+
private final String mId;
private final int mState;
private final DisconnectCause mDisconnectCause;
@@ -66,6 +325,8 @@
private final long mCreationTimeMillis;
private final int mCallDirection;
private final int mCallerNumberVerificationStatus;
+ private final String mContactDisplayName;
+ private final String mActiveChildCallId; // Only valid for CDMA conferences
public ParcelableCall(
String id,
@@ -95,7 +356,10 @@
Bundle extras,
long creationTimeMillis,
int callDirection,
- int callerNumberVerificationStatus) {
+ int callerNumberVerificationStatus,
+ String contactDisplayName,
+ String activeChildCallId
+ ) {
mId = id;
mState = state;
mDisconnectCause = disconnectCause;
@@ -124,6 +388,8 @@
mCreationTimeMillis = creationTimeMillis;
mCallDirection = callDirection;
mCallerNumberVerificationStatus = callerNumberVerificationStatus;
+ mContactDisplayName = contactDisplayName;
+ mActiveChildCallId = activeChildCallId;
}
/** The unique ID of the call. */
@@ -333,6 +599,21 @@
return mCallerNumberVerificationStatus;
}
+ /**
+ * @return the name of the remote party as derived from a contacts DB lookup.
+ */
+ public @Nullable String getContactDisplayName() {
+ return mContactDisplayName;
+ }
+
+ /**
+ * @return On a CDMA conference with two participants, returns the ID of the child call that's
+ * currently active.
+ */
+ public @Nullable String getActiveChildCallId() {
+ return mActiveChildCallId;
+ }
+
/** Responsible for creating ParcelableCall objects for deserialized Parcels. */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static final @android.annotation.NonNull Parcelable.Creator<ParcelableCall> CREATOR =
@@ -372,35 +653,40 @@
long creationTimeMillis = source.readLong();
int callDirection = source.readInt();
int callerNumberVerificationStatus = source.readInt();
- return new ParcelableCall(
- id,
- state,
- disconnectCause,
- cannedSmsResponses,
- capabilities,
- properties,
- supportedAudioRoutes,
- connectTimeMillis,
- handle,
- handlePresentation,
- callerDisplayName,
- callerDisplayNamePresentation,
- gatewayInfo,
- accountHandle,
- isVideoCallProviderChanged,
- videoCallProvider,
- isRttCallChanged,
- rttCall,
- parentCallId,
- childCallIds,
- statusHints,
- videoState,
- conferenceableCallIds,
- intentExtras,
- extras,
- creationTimeMillis,
- callDirection,
- callerNumberVerificationStatus);
+ String contactDisplayName = source.readString();
+ String activeChildCallId = source.readString();
+ return new ParcelableCallBuilder()
+ .setId(id)
+ .setState(state)
+ .setDisconnectCause(disconnectCause)
+ .setCannedSmsResponses(cannedSmsResponses)
+ .setCapabilities(capabilities)
+ .setProperties(properties)
+ .setSupportedAudioRoutes(supportedAudioRoutes)
+ .setConnectTimeMillis(connectTimeMillis)
+ .setHandle(handle)
+ .setHandlePresentation(handlePresentation)
+ .setCallerDisplayName(callerDisplayName)
+ .setCallerDisplayNamePresentation(callerDisplayNamePresentation)
+ .setGatewayInfo(gatewayInfo)
+ .setAccountHandle(accountHandle)
+ .setIsVideoCallProviderChanged(isVideoCallProviderChanged)
+ .setVideoCallProvider(videoCallProvider)
+ .setIsRttCallChanged(isRttCallChanged)
+ .setRttCall(rttCall)
+ .setParentCallId(parentCallId)
+ .setChildCallIds(childCallIds)
+ .setStatusHints(statusHints)
+ .setVideoState(videoState)
+ .setConferenceableCallIds(conferenceableCallIds)
+ .setIntentExtras(intentExtras)
+ .setExtras(extras)
+ .setCreationTimeMillis(creationTimeMillis)
+ .setCallDirection(callDirection)
+ .setCallerNumberVerificationStatus(callerNumberVerificationStatus)
+ .setContactDisplayName(contactDisplayName)
+ .setActiveChildCallId(activeChildCallId)
+ .createParcelableCall();
}
@Override
@@ -447,6 +733,8 @@
destination.writeLong(mCreationTimeMillis);
destination.writeInt(mCallDirection);
destination.writeInt(mCallerNumberVerificationStatus);
+ destination.writeString(mContactDisplayName);
+ destination.writeString(mActiveChildCallId);
}
@Override
diff --git a/telecomm/java/android/telecom/ParcelableConference.java b/telecomm/java/android/telecom/ParcelableConference.java
index ede0594..90b69a3 100644
--- a/telecomm/java/android/telecom/ParcelableConference.java
+++ b/telecomm/java/android/telecom/ParcelableConference.java
@@ -47,6 +47,34 @@
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 @@
mAddressPresentation = addressPresentation;
mCallerDisplayName = callerDisplayName;
mCallerDisplayNamePresentation = callerDisplayNamePresentation;
+ mDisconnectCause = null;
+ mRingbackRequested = false;
}
@Override
@@ -100,6 +130,10 @@
.append(mVideoState)
.append(", VideoProvider: ")
.append(mVideoProvider)
+ .append(", isRingbackRequested: ")
+ .append(mRingbackRequested)
+ .append(", disconnectCause: ")
+ .append(mDisconnectCause)
.toString();
}
@@ -151,6 +185,13 @@
return mAddress;
}
+ public final DisconnectCause getDisconnectCause() {
+ return mDisconnectCause;
+ }
+
+ public boolean isRingbackRequested() {
+ return mRingbackRequested;
+ }
public int getHandlePresentation() {
return mAddressPresentation;
}
@@ -177,11 +218,14 @@
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 @@
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/Phone.java b/telecomm/java/android/telecom/Phone.java
index 61a639a1..a427ed6 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -17,8 +17,8 @@
package android.telecom;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
import android.bluetooth.BluetoothDevice;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Bundle;
import android.util.ArrayMap;
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index bb858cb..abb210f 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -331,7 +331,17 @@
*/
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 @@
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/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index eb568e0..e1bcb5f 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -18,7 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.os.Build;
import android.os.Parcel;
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 1e73bd6..76640e0 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -101,6 +101,14 @@
}
@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 af3c55a..f1dca03 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -26,7 +26,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -848,6 +848,17 @@
*/
public static final int PRESENTATION_PAYPHONE = 4;
+
+ /*
+ * Values for the adb property "persist.radio.videocall.audio.output"
+ */
+ /** @hide */
+ public static final int AUDIO_OUTPUT_ENABLE_SPEAKER = 0;
+ /** @hide */
+ public static final int AUDIO_OUTPUT_DISABLE_SPEAKER = 1;
+ /** @hide */
+ public static final int AUDIO_OUTPUT_DEFAULT = AUDIO_OUTPUT_ENABLE_SPEAKER;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(
@@ -1792,6 +1803,45 @@
}
/**
+ * 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.
@@ -1995,6 +2045,42 @@
}
}
+
+ /**
+ * 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/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index 4a1aa0a..109e7f8 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -16,7 +16,7 @@
package android.telecom;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index 64e6ca3..4197f3c 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -19,7 +19,6 @@
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntRange;
-import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index e35093c..4249dff 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -53,6 +53,20 @@
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);
@@ -63,6 +77,8 @@
void reject(String callId, in Session.Info sessionInfo);
+ void rejectWithReason(String callId, int rejectReason, in Session.Info sessionInfo);
+
void rejectWithMessage(String callId, String message, in Session.Info sessionInfo);
void disconnect(String callId, 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 9cf098c..4f63e08 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl
@@ -44,6 +44,12 @@
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/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 60745e4..eb2d714 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -34,6 +34,8 @@
void rejectCall(String callId, boolean rejectWithMessage, String textMessage);
+ void rejectCallWithReason(String callId, int rejectReason);
+
void disconnectCall(String callId);
void holdCall(String callId);
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 204c37e..9a47ae1 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -242,11 +242,22 @@
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/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
index 3f5aa0f..3c1e707 100644
--- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java
@@ -18,16 +18,18 @@
import android.annotation.Nullable;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.provider.Settings;
-import android.util.Log;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -75,7 +77,7 @@
*/
public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage,
IPackageManager packageManager, TelephonyManager telephonyManager,
- ContentResolver contentResolver, int userId) {
+ int userId, Context context) {
if (DEBUG) {
Log.d(TAG, "disableCarrierAppsUntilPrivileged");
}
@@ -84,6 +86,7 @@
config.getDisabledUntilUsedPreinstalledCarrierApps();
ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
+ ContentResolver contentResolver = getContentResolverForUser(context, userId);
disableCarrierAppsUntilPrivileged(callingPackage, packageManager, telephonyManager,
contentResolver, userId, systemCarrierAppsDisabledUntilUsed,
systemCarrierAssociatedAppsDisabledUntilUsed);
@@ -101,7 +104,7 @@
* Manager can kill it, and this can lead to crashes as the app is in an unexpected state.
*/
public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage,
- IPackageManager packageManager, ContentResolver contentResolver, int userId) {
+ IPackageManager packageManager, int userId, Context context) {
if (DEBUG) {
Log.d(TAG, "disableCarrierAppsUntilPrivileged");
}
@@ -112,23 +115,31 @@
ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed =
config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
+ ContentResolver contentResolver = getContentResolverForUser(context, userId);
disableCarrierAppsUntilPrivileged(callingPackage, packageManager,
null /* telephonyManager */, contentResolver, userId,
systemCarrierAppsDisabledUntilUsed, systemCarrierAssociatedAppsDisabledUntilUsed);
}
+ private static ContentResolver getContentResolverForUser(Context context, int userId) {
+ Context userContext = context.createContextAsUser(UserHandle.getUserHandleForUid(userId),
+ 0);
+ return userContext.getContentResolver();
+ }
+
/**
* Disable carrier apps until they are privileged
* Must be public b/c framework unit tests can't access package-private methods.
*/
+ // Must be public b/c framework unit tests can't access package-private methods.
@VisibleForTesting
public static void disableCarrierAppsUntilPrivileged(String callingPackage,
IPackageManager packageManager, @Nullable TelephonyManager telephonyManager,
ContentResolver contentResolver, int userId,
ArraySet<String> systemCarrierAppsDisabledUntilUsed,
ArrayMap<String, List<String>> systemCarrierAssociatedAppsDisabledUntilUsed) {
- List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager,
- userId, systemCarrierAppsDisabledUntilUsed);
+ List<ApplicationInfo> candidates = getDefaultNotUpdatedCarrierAppCandidatesHelper(
+ packageManager, userId, systemCarrierAppsDisabledUntilUsed);
if (candidates == null || candidates.isEmpty()) {
return;
}
@@ -139,9 +150,8 @@
systemCarrierAssociatedAppsDisabledUntilUsed);
List<String> enabledCarrierPackages = new ArrayList<>();
-
- boolean hasRunOnce = Settings.Secure.getIntForUser(
- contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 0, userId) == 1;
+ boolean hasRunOnce = Settings.Secure.getInt(contentResolver,
+ Settings.Secure.CARRIER_APPS_HANDLED, 0) == 1;
try {
for (ApplicationInfo ai : candidates) {
@@ -165,15 +175,16 @@
}
}
+ int enabledSetting = packageManager.getApplicationEnabledSetting(packageName,
+ userId);
if (hasPrivileges) {
// Only update enabled state for the app on /system. Once it has been
// updated we shouldn't touch it.
- if (!ai.isUpdatedSystemApp()
- && (ai.enabledSetting
+ if (enabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
- || ai.enabledSetting
+ || enabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
- || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) {
+ || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
Log.i(TAG, "Update state(" + packageName + "): ENABLED for user "
+ userId);
packageManager.setSystemAppInstallState(
@@ -191,9 +202,12 @@
// Also enable any associated apps for this carrier app.
if (associatedAppList != null) {
for (ApplicationInfo associatedApp : associatedAppList) {
- if (associatedApp.enabledSetting
+ int associatedAppEnabledSetting =
+ packageManager.getApplicationEnabledSetting(
+ associatedApp.packageName, userId);
+ if (associatedAppEnabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
- || associatedApp.enabledSetting
+ || associatedAppEnabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
|| (associatedApp.flags
& ApplicationInfo.FLAG_INSTALLED) == 0) {
@@ -218,8 +232,7 @@
} else { // No carrier privileges
// Only update enabled state for the app on /system. Once it has been
// updated we shouldn't touch it.
- if (!ai.isUpdatedSystemApp()
- && ai.enabledSetting
+ if (enabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
&& (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
Log.i(TAG, "Update state(" + packageName
@@ -236,7 +249,10 @@
if (!hasRunOnce) {
if (associatedAppList != null) {
for (ApplicationInfo associatedApp : associatedAppList) {
- if (associatedApp.enabledSetting
+ int associatedAppEnabledSetting =
+ packageManager.getApplicationEnabledSetting(
+ associatedApp.packageName, userId);
+ if (associatedAppEnabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
&& (associatedApp.flags
& ApplicationInfo.FLAG_INSTALLED) != 0) {
@@ -256,8 +272,7 @@
// Mark the execution so we do not disable apps again.
if (!hasRunOnce) {
- Settings.Secure.putIntForUser(
- contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 1, userId);
+ Settings.Secure.putInt(contentResolver, Settings.Secure.CARRIER_APPS_HANDLED, 1);
}
if (!enabledCarrierPackages.isEmpty()) {
@@ -348,6 +363,31 @@
return apps;
}
+ private static List<ApplicationInfo> getDefaultNotUpdatedCarrierAppCandidatesHelper(
+ IPackageManager packageManager,
+ int userId,
+ ArraySet<String> systemCarrierAppsDisabledUntilUsed) {
+ if (systemCarrierAppsDisabledUntilUsed == null) {
+ return null;
+ }
+
+ int size = systemCarrierAppsDisabledUntilUsed.size();
+ if (size == 0) {
+ return null;
+ }
+
+ List<ApplicationInfo> apps = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ String packageName = systemCarrierAppsDisabledUntilUsed.valueAt(i);
+ ApplicationInfo ai =
+ getApplicationInfoIfNotUpdatedSystemApp(packageManager, userId, packageName);
+ if (ai != null) {
+ apps.add(ai);
+ }
+ }
+ return apps;
+ }
+
private static Map<String, List<ApplicationInfo>> getDefaultCarrierAssociatedAppsHelper(
IPackageManager packageManager,
int userId,
@@ -360,11 +400,11 @@
systemCarrierAssociatedAppsDisabledUntilUsed.valueAt(i);
for (int j = 0; j < associatedAppPackages.size(); j++) {
ApplicationInfo ai =
- getApplicationInfoIfSystemApp(
+ getApplicationInfoIfNotUpdatedSystemApp(
packageManager, userId, associatedAppPackages.get(j));
// Only update enabled state for the app on /system. Once it has been updated we
// shouldn't touch it.
- if (ai != null && !ai.isUpdatedSystemApp()) {
+ if (ai != null) {
List<ApplicationInfo> appList = associatedApps.get(carrierAppPackage);
if (appList == null) {
appList = new ArrayList<>();
@@ -378,6 +418,26 @@
}
@Nullable
+ private static ApplicationInfo getApplicationInfoIfNotUpdatedSystemApp(
+ IPackageManager packageManager,
+ int userId,
+ String packageName) {
+ try {
+ ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
+ PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+ | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+ | PackageManager.MATCH_SYSTEM_ONLY
+ | PackageManager.MATCH_FACTORY_ONLY, userId);
+ if (ai != null) {
+ return ai;
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not reach PackageManager", e);
+ }
+ return null;
+ }
+
+ @Nullable
private static ApplicationInfo getApplicationInfoIfSystemApp(
IPackageManager packageManager,
int userId,
@@ -385,8 +445,9 @@
try {
ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
- | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, userId);
- if (ai != null && ai.isSystemApp()) {
+ | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
+ | PackageManager.MATCH_SYSTEM_ONLY, userId);
+ if (ai != null) {
return ai;
}
} catch (RemoteException e) {
diff --git a/telephony/common/com/android/internal/telephony/GsmAlphabet.java b/telephony/common/com/android/internal/telephony/GsmAlphabet.java
index f7383ab..60cd400 100644
--- a/telephony/common/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/common/com/android/internal/telephony/GsmAlphabet.java
@@ -16,7 +16,7 @@
package com.android.internal.telephony;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
import android.os.Build;
import android.util.Log;
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index 39ff447..3a900d9 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.role.RoleManager;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -48,8 +49,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
diff --git a/telephony/common/com/android/internal/telephony/SmsConstants.java b/telephony/common/com/android/internal/telephony/SmsConstants.java
index 19f52b0..3aa8bbf 100644
--- a/telephony/common/com/android/internal/telephony/SmsConstants.java
+++ b/telephony/common/com/android/internal/telephony/SmsConstants.java
@@ -15,7 +15,7 @@
*/
package com.android.internal.telephony;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* SMS Constants and must be the same as the corresponding
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 72ad4cd..2077800 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -27,8 +27,6 @@
import android.os.Binder;
import android.os.Build;
import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -41,7 +39,6 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import java.util.function.Supplier;
/** Utility class for Telephony permission enforcement. */
public final class TelephonyPermissions {
@@ -49,9 +46,6 @@
private static final boolean DBG = false;
- private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () ->
- ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
-
/**
* Whether to disable the new device identifier access restrictions.
*/
@@ -137,49 +131,6 @@
public static boolean checkReadPhoneState(
Context context, int subId, int pid, int uid, String callingPackage,
@Nullable String callingFeatureId, String message) {
- return checkReadPhoneState(
- context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingFeatureId,
- message);
- }
-
- /**
- * Check whether the calling packages has carrier privileges for the passing subscription.
- * @return {@code true} if the caller has carrier privileges, {@false} otherwise.
- */
- public static boolean checkCarrierPrivilegeForSubId(int subId) {
- if (SubscriptionManager.isValidSubscriptionId(subId)
- && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, Binder.getCallingUid())
- == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
- return true;
- }
- return false;
- }
-
- /**
- * Check whether the app with the given pid/uid can read phone state.
- *
- * <p>This method behaves in one of the following ways:
- * <ul>
- * <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
- * READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
- * <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for
- * apps which support runtime permissions, if the caller does not currently have any of
- * these permissions.
- * <li>return false: if the caller lacks all of these permissions and doesn't support runtime
- * permissions. This implies that the user revoked the ability to read phone state
- * manually (via AppOps). In this case we can't throw as it would break app compatibility,
- * so we return false to indicate that the calling function should return dummy data.
- * </ul>
- *
- * <p>Note: for simplicity, this method always returns false for callers using legacy
- * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged.
- * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+
- * devices.
- */
- @VisibleForTesting
- public static boolean checkReadPhoneState(
- Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
- String callingPackage, @Nullable String callingFeatureId, String message) {
try {
context.enforcePermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
@@ -194,7 +145,7 @@
// If we don't have the runtime permission, but do have carrier privileges, that
// suffices for reading phone state.
if (SubscriptionManager.isValidSubscriptionId(subId)) {
- enforceCarrierPrivilege(telephonySupplier, subId, uid, message);
+ enforceCarrierPrivilege(context, subId, uid, message);
return true;
}
throw phoneStateException;
@@ -209,6 +160,19 @@
}
/**
+ * Check whether the calling packages has carrier privileges for the passing subscription.
+ * @return {@code true} if the caller has carrier privileges, {@false} otherwise.
+ */
+ public static boolean checkCarrierPrivilegeForSubId(Context context, int subId) {
+ if (SubscriptionManager.isValidSubscriptionId(subId)
+ && getCarrierPrivilegeStatus(context, subId, Binder.getCallingUid())
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Check whether the app with the given pid/uid can read phone state, or has carrier
* privileges on any active subscription.
*
@@ -224,28 +188,6 @@
*/
public static boolean checkReadPhoneStateOnAnyActiveSub(Context context, int pid, int uid,
String callingPackage, @Nullable String callingFeatureId, String message) {
- return checkReadPhoneStateOnAnyActiveSub(context, TELEPHONY_SUPPLIER, pid, uid,
- callingPackage, callingFeatureId, message);
- }
-
- /**
- * Check whether the app with the given pid/uid can read phone state, or has carrier
- * privileges on any active subscription.
- *
- * <p>If the app does not have carrier privilege, this method will return {@code false} instead
- * of throwing a SecurityException. Therefore, the callers cannot tell the difference
- * between M+ apps which declare the runtime permission but do not have it, and pre-M apps
- * which declare the static permission but had access revoked via AppOps. Apps in the former
- * category expect SecurityExceptions; apps in the latter don't. So this method is suitable for
- * use only if the behavior in both scenarios is meant to be identical.
- *
- * @return {@code true} if the app can read phone state or has carrier privilege;
- * {@code false} otherwise.
- */
- @VisibleForTesting
- public static boolean checkReadPhoneStateOnAnyActiveSub(
- Context context, Supplier<ITelephony> telephonySupplier, int pid, int uid,
- String callingPackage, @Nullable String callingFeatureId, String message) {
try {
context.enforcePermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
@@ -259,7 +201,7 @@
} catch (SecurityException phoneStateException) {
// If we don't have the runtime permission, but do have carrier privileges, that
// suffices for reading phone state.
- return checkCarrierPrivilegeForAnySubId(context, telephonySupplier, uid);
+ return checkCarrierPrivilegeForAnySubId(context, uid);
}
}
@@ -374,12 +316,11 @@
}
// If the calling package has carrier privileges for specified sub, then allow access.
- if (checkCarrierPrivilegeForSubId(subId)) return true;
+ if (checkCarrierPrivilegeForSubId(context, subId)) return true;
// If the calling package has carrier privileges for any subscription
// and allowCarrierPrivilegeOnAnySub is set true, then allow access.
- if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(
- context, TELEPHONY_SUPPLIER, uid)) {
+ if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(context, uid)) {
return true;
}
@@ -424,7 +365,6 @@
private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
int uid, String callingPackage, String message) {
boolean isPreinstalled = false;
- boolean isPrivApp = false;
ApplicationInfo callingPackageInfo = null;
try {
callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser(
@@ -432,9 +372,6 @@
if (callingPackageInfo != null) {
if (callingPackageInfo.isSystemApp()) {
isPreinstalled = true;
- if (callingPackageInfo.isPrivilegedApp()) {
- isPrivApp = true;
- }
}
}
} catch (PackageManager.NameNotFoundException e) {
@@ -457,10 +394,10 @@
}
invokedMethods.add(message);
StatsLog.write(StatsLog.DEVICE_IDENTIFIER_ACCESS_DENIED, callingPackage, message,
- isPreinstalled, isPrivApp);
+ isPreinstalled, false);
}
Log.w(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message
- + ":isPreinstalled=" + isPreinstalled + ":isPrivApp=" + isPrivApp);
+ + ":isPreinstalled=" + isPreinstalled);
// if the target SDK is pre-Q then check if the calling package would have previously
// had access to device identifiers.
if (callingPackageInfo != null && (
@@ -471,7 +408,7 @@
uid) == PackageManager.PERMISSION_GRANTED) {
return false;
}
- if (checkCarrierPrivilegeForSubId(subId)) {
+ if (checkCarrierPrivilegeForSubId(context, subId)) {
return false;
}
}
@@ -487,26 +424,12 @@
public static boolean checkReadCallLog(
Context context, int subId, int pid, int uid, String callingPackage,
@Nullable String callingPackageName) {
- return checkReadCallLog(
- context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingPackageName);
- }
-
- /**
- * Check whether the app with the given pid/uid can read the call log.
- * @return {@code true} if the specified app has the read call log permission and AppOpp granted
- * to it, {@code false} otherwise.
- */
- @VisibleForTesting
- public static boolean checkReadCallLog(
- Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
- String callingPackage, @Nullable String callingFeatureId) {
-
if (context.checkPermission(Manifest.permission.READ_CALL_LOG, pid, uid)
!= PERMISSION_GRANTED) {
// If we don't have the runtime permission, but do have carrier privileges, that
// suffices for being able to see the call phone numbers.
if (SubscriptionManager.isValidSubscriptionId(subId)) {
- enforceCarrierPrivilege(telephonySupplier, subId, uid, "readCallLog");
+ enforceCarrierPrivilege(context, subId, uid, "readCallLog");
return true;
}
return false;
@@ -529,7 +452,7 @@
Context context, int subId, String callingPackage, @Nullable String callingFeatureId,
String message) {
return checkReadPhoneNumber(
- context, TELEPHONY_SUPPLIER, subId, Binder.getCallingPid(), Binder.getCallingUid(),
+ context, subId, Binder.getCallingPid(), Binder.getCallingUid(),
callingPackage, callingFeatureId, message);
}
@@ -541,7 +464,7 @@
*/
@VisibleForTesting
public static boolean checkReadPhoneNumber(
- Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
+ Context context, int subId, int pid, int uid,
String callingPackage, @Nullable String callingFeatureId, String message) {
// Default SMS app can always read it.
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
@@ -556,7 +479,7 @@
// First, check if we can read the phone state.
try {
return checkReadPhoneState(
- context, telephonySupplier, subId, pid, uid, callingPackage, callingFeatureId,
+ context, subId, pid, uid, callingPackage, callingFeatureId,
message);
} catch (SecurityException readPhoneStateSecurityException) {
}
@@ -598,7 +521,7 @@
}
if (DBG) Log.d(LOG_TAG, "No modify permission, check carrier privilege next.");
- enforceCallingOrSelfCarrierPrivilege(subId, message);
+ enforceCallingOrSelfCarrierPrivilege(context, subId, message);
}
/**
@@ -618,7 +541,7 @@
Log.d(LOG_TAG, "No READ_PHONE_STATE permission, check carrier privilege next.");
}
- enforceCallingOrSelfCarrierPrivilege(subId, message);
+ enforceCallingOrSelfCarrierPrivilege(context, subId, message);
}
/**
@@ -635,11 +558,38 @@
}
if (DBG) {
- Log.d(LOG_TAG, "No READ_PRIVILEDED_PHONE_STATE permission, "
+ Log.d(LOG_TAG, "No READ_PRIVILEGED_PHONE_STATE permission, "
+ "check carrier privilege next.");
}
- enforceCallingOrSelfCarrierPrivilege(subId, message);
+ enforceCallingOrSelfCarrierPrivilege(context, subId, message);
+ }
+
+ /**
+ * Ensure the caller (or self, if not processing an IPC) has
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or carrier privileges.
+ *
+ * @throws SecurityException if the caller does not have the required permission/privileges
+ */
+ public static void enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ Context context, int subId, String message) {
+ if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ == PERMISSION_GRANTED) {
+ return;
+ }
+
+ if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ == PERMISSION_GRANTED) {
+ return;
+ }
+
+ if (DBG) {
+ Log.d(LOG_TAG, "No READ_PRIVILEGED_PHONE_STATE nor READ_PRECISE_PHONE_STATE permission"
+ + ", check carrier privilege next.");
+ }
+
+ enforceCallingOrSelfCarrierPrivilege(context, subId, message);
}
/**
@@ -647,21 +597,18 @@
*
* @throws SecurityException if the caller does not have the required privileges
*/
- public static void enforceCallingOrSelfCarrierPrivilege(int subId, String message) {
+ public static void enforceCallingOrSelfCarrierPrivilege(
+ Context context, int subId, String message) {
// NOTE: It's critical that we explicitly pass the calling UID here rather than call
// TelephonyManager#hasCarrierPrivileges directly, as the latter only works when called from
// the phone process. When called from another process, it will check whether that process
// has carrier privileges instead.
- enforceCarrierPrivilege(subId, Binder.getCallingUid(), message);
- }
-
- private static void enforceCarrierPrivilege(int subId, int uid, String message) {
- enforceCarrierPrivilege(TELEPHONY_SUPPLIER, subId, uid, message);
+ enforceCarrierPrivilege(context, subId, Binder.getCallingUid(), message);
}
private static void enforceCarrierPrivilege(
- Supplier<ITelephony> telephonySupplier, int subId, int uid, String message) {
- if (getCarrierPrivilegeStatus(telephonySupplier, subId, uid)
+ Context context, int subId, int uid, String message) {
+ if (getCarrierPrivilegeStatus(context, subId, uid)
!= TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
if (DBG) Log.e(LOG_TAG, "No Carrier Privilege.");
throw new SecurityException(message);
@@ -669,13 +616,12 @@
}
/** Returns whether the provided uid has carrier privileges for any active subscription ID. */
- private static boolean checkCarrierPrivilegeForAnySubId(
- Context context, Supplier<ITelephony> telephonySupplier, int uid) {
+ private static boolean checkCarrierPrivilegeForAnySubId(Context context, int uid) {
SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
Context.TELEPHONY_SUBSCRIPTION_SERVICE);
int[] activeSubIds = sm.getActiveSubscriptionIdList(/* visibleOnly */ false);
for (int activeSubId : activeSubIds) {
- if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid)
+ if (getCarrierPrivilegeStatus(context, activeSubId, uid)
== TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
return true;
}
@@ -683,18 +629,15 @@
return false;
}
- private static int getCarrierPrivilegeStatus(
- Supplier<ITelephony> telephonySupplier, int subId, int uid) {
- ITelephony telephony = telephonySupplier.get();
+ private static int getCarrierPrivilegeStatus(Context context, int subId, int uid) {
+ final long identity = Binder.clearCallingIdentity();
try {
- if (telephony != null) {
- return telephony.getCarrierPrivilegeStatusForUid(subId, uid);
- }
- } catch (RemoteException e) {
- // Fallback below.
+ TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
+ Context.TELEPHONY_SERVICE);
+ return telephonyManager.createForSubscriptionId(subId).getCarrierPrivilegeStatus(uid);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- Log.e(LOG_TAG, "Phone process is down, cannot check carrier privileges");
- return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
}
/**
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index 0498d7c..2abcc76 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -28,6 +28,7 @@
import android.os.SystemProperties;
import java.io.PrintWriter;
+import java.util.function.Supplier;
/**
* This class provides various util functions
@@ -75,6 +76,42 @@
}
/**
+ * Convenience method for running the provided action enclosed in
+ * {@link Binder#clearCallingIdentity}/{@link Binder#restoreCallingIdentity}
+ *
+ * Any exception thrown by the given action will need to be handled by caller.
+ *
+ */
+ public static void runWithCleanCallingIdentity(
+ @NonNull Runnable action) {
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ action.run();
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+
+ /**
+ * Convenience method for running the provided action enclosed in
+ * {@link Binder#clearCallingIdentity}/{@link Binder#restoreCallingIdentity} and return
+ * the result.
+ *
+ * Any exception thrown by the given action will need to be handled by caller.
+ *
+ */
+ public static <T> T runWithCleanCallingIdentity(
+ @NonNull Supplier<T> action) {
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ return action.get();
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ /**
* Filter values in bundle to only basic types.
*/
public static Bundle filterValues(Bundle bundle) {
diff --git a/telephony/common/com/google/android/mms/ContentType.java b/telephony/common/com/google/android/mms/ContentType.java
index 12e4b7e..4a971dd 100644
--- a/telephony/common/com/google/android/mms/ContentType.java
+++ b/telephony/common/com/google/android/mms/ContentType.java
@@ -17,7 +17,7 @@
package com.google.android.mms;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import java.util.ArrayList;
diff --git a/telephony/common/com/google/android/mms/InvalidHeaderValueException.java b/telephony/common/com/google/android/mms/InvalidHeaderValueException.java
index 2836c30..55087ff 100644
--- a/telephony/common/com/google/android/mms/InvalidHeaderValueException.java
+++ b/telephony/common/com/google/android/mms/InvalidHeaderValueException.java
@@ -17,7 +17,7 @@
package com.google.android.mms;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* Thrown when an invalid header value was set.
diff --git a/telephony/common/com/google/android/mms/MmsException.java b/telephony/common/com/google/android/mms/MmsException.java
index 5be33ed..24bceb3 100644
--- a/telephony/common/com/google/android/mms/MmsException.java
+++ b/telephony/common/com/google/android/mms/MmsException.java
@@ -17,7 +17,7 @@
package com.google.android.mms;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
/**
* A generic exception that is thrown by the Mms client.
diff --git a/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java b/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java
index ae447d7..8693385 100644
--- a/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java
+++ b/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/Base64.java b/telephony/common/com/google/android/mms/pdu/Base64.java
index 483fa7f..0d6a46a 100644
--- a/telephony/common/com/google/android/mms/pdu/Base64.java
+++ b/telephony/common/com/google/android/mms/pdu/Base64.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
public class Base64 {
/**
diff --git a/telephony/common/com/google/android/mms/pdu/CharacterSets.java b/telephony/common/com/google/android/mms/pdu/CharacterSets.java
index 27da35e..5172b7b 100644
--- a/telephony/common/com/google/android/mms/pdu/CharacterSets.java
+++ b/telephony/common/com/google/android/mms/pdu/CharacterSets.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
diff --git a/telephony/common/com/google/android/mms/pdu/DeliveryInd.java b/telephony/common/com/google/android/mms/pdu/DeliveryInd.java
index 7093ac6..8fb6a75 100644
--- a/telephony/common/com/google/android/mms/pdu/DeliveryInd.java
+++ b/telephony/common/com/google/android/mms/pdu/DeliveryInd.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java
index 4166275..8c0380f 100644
--- a/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java
+++ b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java
@@ -17,10 +17,9 @@
package com.google.android.mms.pdu;
+import android.compat.annotation.UnsupportedAppUsage;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
diff --git a/telephony/common/com/google/android/mms/pdu/GenericPdu.java b/telephony/common/com/google/android/mms/pdu/GenericPdu.java
index ebf16ac..320b13f 100644
--- a/telephony/common/com/google/android/mms/pdu/GenericPdu.java
+++ b/telephony/common/com/google/android/mms/pdu/GenericPdu.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java b/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java
index e108f76..42a89c6 100644
--- a/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java
+++ b/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/NotificationInd.java b/telephony/common/com/google/android/mms/pdu/NotificationInd.java
index b561bd4..ca4615c 100644
--- a/telephony/common/com/google/android/mms/pdu/NotificationInd.java
+++ b/telephony/common/com/google/android/mms/pdu/NotificationInd.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java b/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java
index 3c70f86..ebd81af 100644
--- a/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java
+++ b/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/PduBody.java b/telephony/common/com/google/android/mms/pdu/PduBody.java
index 51914e4..f7f285f 100644
--- a/telephony/common/com/google/android/mms/pdu/PduBody.java
+++ b/telephony/common/com/google/android/mms/pdu/PduBody.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import java.util.HashMap;
import java.util.Map;
diff --git a/telephony/common/com/google/android/mms/pdu/PduComposer.java b/telephony/common/com/google/android/mms/pdu/PduComposer.java
index e24bf21..b8b212c 100644
--- a/telephony/common/com/google/android/mms/pdu/PduComposer.java
+++ b/telephony/common/com/google/android/mms/pdu/PduComposer.java
@@ -17,12 +17,11 @@
package com.google.android.mms.pdu;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.Context;
import android.text.TextUtils;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
diff --git a/telephony/common/com/google/android/mms/pdu/PduContentTypes.java b/telephony/common/com/google/android/mms/pdu/PduContentTypes.java
index 8551b2f..57141fe 100644
--- a/telephony/common/com/google/android/mms/pdu/PduContentTypes.java
+++ b/telephony/common/com/google/android/mms/pdu/PduContentTypes.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
public class PduContentTypes {
/**
diff --git a/telephony/common/com/google/android/mms/pdu/PduHeaders.java b/telephony/common/com/google/android/mms/pdu/PduHeaders.java
index b524464..3e62184 100644
--- a/telephony/common/com/google/android/mms/pdu/PduHeaders.java
+++ b/telephony/common/com/google/android/mms/pdu/PduHeaders.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/PduParser.java b/telephony/common/com/google/android/mms/pdu/PduParser.java
index f483994..5340245 100755
--- a/telephony/common/com/google/android/mms/pdu/PduParser.java
+++ b/telephony/common/com/google/android/mms/pdu/PduParser.java
@@ -17,10 +17,9 @@
package com.google.android.mms.pdu;
+import android.compat.annotation.UnsupportedAppUsage;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import com.google.android.mms.ContentType;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/PduPart.java b/telephony/common/com/google/android/mms/pdu/PduPart.java
index 09b7751..8dd976b 100644
--- a/telephony/common/com/google/android/mms/pdu/PduPart.java
+++ b/telephony/common/com/google/android/mms/pdu/PduPart.java
@@ -17,10 +17,9 @@
package com.google.android.mms.pdu;
+import android.compat.annotation.UnsupportedAppUsage;
import android.net.Uri;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.util.HashMap;
import java.util.Map;
diff --git a/telephony/common/com/google/android/mms/pdu/PduPersister.java b/telephony/common/com/google/android/mms/pdu/PduPersister.java
index 8efca0e..fcd5b8f 100755
--- a/telephony/common/com/google/android/mms/pdu/PduPersister.java
+++ b/telephony/common/com/google/android/mms/pdu/PduPersister.java
@@ -17,6 +17,7 @@
package com.google.android.mms.pdu;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -40,8 +41,6 @@
import android.text.TextUtils;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import com.google.android.mms.ContentType;
import com.google.android.mms.InvalidHeaderValueException;
import com.google.android.mms.MmsException;
diff --git a/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java b/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java
index 9d6535c..4e1d7f5 100644
--- a/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java
+++ b/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import java.io.ByteArrayOutputStream;
diff --git a/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java b/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java
index e38c62d..4ba3c71 100644
--- a/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java
+++ b/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/ReadRecInd.java b/telephony/common/com/google/android/mms/pdu/ReadRecInd.java
index 9696bc2..37ccfb9 100644
--- a/telephony/common/com/google/android/mms/pdu/ReadRecInd.java
+++ b/telephony/common/com/google/android/mms/pdu/ReadRecInd.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/RetrieveConf.java b/telephony/common/com/google/android/mms/pdu/RetrieveConf.java
index 03755af..260adfc 100644
--- a/telephony/common/com/google/android/mms/pdu/RetrieveConf.java
+++ b/telephony/common/com/google/android/mms/pdu/RetrieveConf.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/SendConf.java b/telephony/common/com/google/android/mms/pdu/SendConf.java
index b859827..7799238 100644
--- a/telephony/common/com/google/android/mms/pdu/SendConf.java
+++ b/telephony/common/com/google/android/mms/pdu/SendConf.java
@@ -17,7 +17,7 @@
package com.google.android.mms.pdu;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.InvalidHeaderValueException;
diff --git a/telephony/common/com/google/android/mms/pdu/SendReq.java b/telephony/common/com/google/android/mms/pdu/SendReq.java
index c1b7f93..6e2f2da 100644
--- a/telephony/common/com/google/android/mms/pdu/SendReq.java
+++ b/telephony/common/com/google/android/mms/pdu/SendReq.java
@@ -17,10 +17,9 @@
package com.google.android.mms.pdu;
+import android.compat.annotation.UnsupportedAppUsage;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import com.google.android.mms.InvalidHeaderValueException;
public class SendReq extends MultimediaMessagePdu {
diff --git a/telephony/common/com/google/android/mms/util/AbstractCache.java b/telephony/common/com/google/android/mms/util/AbstractCache.java
index ab5d48a..25862e7 100644
--- a/telephony/common/com/google/android/mms/util/AbstractCache.java
+++ b/telephony/common/com/google/android/mms/util/AbstractCache.java
@@ -17,10 +17,9 @@
package com.google.android.mms.util;
+import android.compat.annotation.UnsupportedAppUsage;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.util.HashMap;
public abstract class AbstractCache<K, V> {
diff --git a/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java b/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java
index 118de46..0f9390d 100644
--- a/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java
+++ b/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java
@@ -17,12 +17,11 @@
package com.google.android.mms.util;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.drm.DrmManagerClient;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
public class DownloadDrmHelper {
private static final String TAG = "DownloadDrmHelper";
diff --git a/telephony/common/com/google/android/mms/util/DrmConvertSession.java b/telephony/common/com/google/android/mms/util/DrmConvertSession.java
index 0e8ec91..156c7ad 100644
--- a/telephony/common/com/google/android/mms/util/DrmConvertSession.java
+++ b/telephony/common/com/google/android/mms/util/DrmConvertSession.java
@@ -16,14 +16,13 @@
*/
package com.google.android.mms.util;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.drm.DrmConvertedStatus;
import android.drm.DrmManagerClient;
import android.provider.Downloads;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
diff --git a/telephony/common/com/google/android/mms/util/PduCache.java b/telephony/common/com/google/android/mms/util/PduCache.java
index 94e3894..c380d6b 100644
--- a/telephony/common/com/google/android/mms/util/PduCache.java
+++ b/telephony/common/com/google/android/mms/util/PduCache.java
@@ -17,14 +17,13 @@
package com.google.android.mms.util;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentUris;
import android.content.UriMatcher;
import android.net.Uri;
import android.provider.Telephony.Mms;
import android.util.Log;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
import java.util.HashMap;
import java.util.HashSet;
diff --git a/telephony/common/com/google/android/mms/util/PduCacheEntry.java b/telephony/common/com/google/android/mms/util/PduCacheEntry.java
index 1ecd1bf..a4a25d2 100644
--- a/telephony/common/com/google/android/mms/util/PduCacheEntry.java
+++ b/telephony/common/com/google/android/mms/util/PduCacheEntry.java
@@ -17,7 +17,7 @@
package com.google.android.mms.util;
-import dalvik.annotation.compat.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import com.google.android.mms.pdu.GenericPdu;
diff --git a/telephony/common/com/google/android/mms/util/SqliteWrapper.java b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
index 2dd1dc1..31fe4d7 100644
--- a/telephony/common/com/google/android/mms/util/SqliteWrapper.java
+++ b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
@@ -18,6 +18,7 @@
package com.google.android.mms.util;
import android.app.ActivityManager;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
@@ -27,8 +28,6 @@
import android.util.Log;
import android.widget.Toast;
-import dalvik.annotation.compat.UnsupportedAppUsage;
-
public final class SqliteWrapper {
private static final String TAG = "SqliteWrapper";
private static final String SQLITE_EXCEPTION_DETAIL_MESSAGE
diff --git a/telephony/java/android/service/euicc/EuiccProfileInfo.java b/telephony/java/android/service/euicc/EuiccProfileInfo.java
index 6c357cc..8450a90 100644
--- a/telephony/java/android/service/euicc/EuiccProfileInfo.java
+++ b/telephony/java/android/service/euicc/EuiccProfileInfo.java
@@ -19,7 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.carrier.CarrierIdentifier;
diff --git a/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
index c7a9851..2382f65 100644
--- a/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
+++ b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
@@ -17,7 +17,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.euicc.DownloadableSubscription;
diff --git a/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
index abd4065..d0fb511 100644
--- a/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
+++ b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
@@ -17,7 +17,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.euicc.DownloadableSubscription;
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index bb28df2..610eef8 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -50,18 +50,12 @@
/**
* Transport type for Wireless Wide Area Networks (i.e. Cellular)
- * @hide
*/
- @SystemApi
- @TestApi
public static final int TRANSPORT_TYPE_WWAN = 1;
/**
* Transport type for Wireless Local Area Networks (i.e. Wifi)
- * @hide
*/
- @SystemApi
- @TestApi
public static final int TRANSPORT_TYPE_WLAN = 2;
/** @hide */
@@ -73,6 +67,22 @@
}
}
+ /**
+ * Access network type
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"RADIO_ACCESS_NETWORK_TYPE_"},
+ value = {
+ AccessNetworkType.UNKNOWN,
+ AccessNetworkType.GERAN,
+ AccessNetworkType.UTRAN,
+ AccessNetworkType.EUTRAN,
+ AccessNetworkType.CDMA2000,
+ AccessNetworkType.IWLAN,
+ AccessNetworkType.NGRAN})
+ public @interface RadioAccessNetworkType {}
+
public static final class AccessNetworkType {
public static final int UNKNOWN = 0;
public static final int GERAN = 1;
@@ -121,11 +131,11 @@
public static final int BAND_ER900 = 14;
/** @hide */
- private GeranBand() {};
+ private GeranBand() {}
}
/**
- * Frenquency bands for UTRAN.
+ * Frequency bands for UTRAN.
* http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf
*/
public static final class UtranBand {
@@ -152,12 +162,19 @@
public static final int BAND_25 = 25;
public static final int BAND_26 = 26;
+ /** Frequency bands for TD-SCDMA. Defined in 3GPP TS 25.102, Table 5.2. */
+ public static final int BAND_A = 101;
+ public static final int BAND_B = 102;
+ public static final int BAND_C = 103;
+ public static final int BAND_D = 104;
+ public static final int BAND_E = 105;
+ public static final int BAND_F = 106;
/** @hide */
- private UtranBand() {};
+ private UtranBand() {}
}
/**
- * Frenquency bands for EUTRAN.
+ * Frequency bands for EUTRAN.
* http://www.etsi.org/deliver/etsi_ts/136100_136199/136101/14.03.00_60/ts_136101v140p.pdf
*/
public static final class EutranBand {
@@ -215,7 +232,7 @@
}
/**
- * Frenquency bands for CDMA2000.
+ * Frequency bands for CDMA2000.
* http://www.3gpp2.org/Public_html/Specs/C.S0057-E_v1.0_Bandclass_Specification.pdf
* @hide
*
@@ -246,7 +263,7 @@
public static final int BAND_21 = 22;
/** @hide */
- private CdmaBands() {};
+ private CdmaBands() {}
}
/**
@@ -300,8 +317,161 @@
public static final int BAND_260 = 260;
public static final int BAND_261 = 261;
+ /**
+ * NR Bands
+ *
+ * @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"BAND_"},
+ value = {BAND_1,
+ BAND_2,
+ BAND_3,
+ BAND_5,
+ BAND_7,
+ BAND_8,
+ BAND_12,
+ BAND_14,
+ BAND_18,
+ BAND_20,
+ BAND_25,
+ BAND_28,
+ BAND_29,
+ BAND_30,
+ BAND_34,
+ BAND_38,
+ BAND_39,
+ BAND_40,
+ BAND_41,
+ BAND_48,
+ BAND_50,
+ BAND_51,
+ BAND_65,
+ BAND_66,
+ BAND_70,
+ BAND_71,
+ BAND_74,
+ BAND_75,
+ BAND_76,
+ BAND_77,
+ BAND_78,
+ BAND_79,
+ BAND_80,
+ BAND_81,
+ BAND_82,
+ BAND_83,
+ BAND_84,
+ BAND_86,
+ BAND_90,
+ BAND_257,
+ BAND_258,
+ BAND_260,
+ BAND_261})
+ public @interface NgranBand {}
+
+ /**
+ * Unknown NR frequency.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final int FREQUENCY_RANGE_GROUP_UNKNOWN = 0;
+
+ /**
+ * NR frequency group 1 defined in 3GPP TS 38.101-1 table 5.2-1
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final int FREQUENCY_RANGE_GROUP_1 = 1;
+
+ /**
+ * NR frequency group 2 defined in 3GPP TS 38.101-2 table 5.2-1
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final int FREQUENCY_RANGE_GROUP_2 = 2;
+
+ /**
+ * Radio frequency range group
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"FREQUENCY_RANGE_GROUP_"},
+ value = {
+ FREQUENCY_RANGE_GROUP_UNKNOWN,
+ FREQUENCY_RANGE_GROUP_1,
+ FREQUENCY_RANGE_GROUP_2})
+ public @interface FrequencyRangeGroup {}
+
+ /**
+ * Get frequency range group
+ *
+ * @param band NR band
+ * @return The frequency range group
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static @FrequencyRangeGroup int getFrequencyRangeGroup(@NgranBand int band) {
+ switch (band) {
+ case BAND_1:
+ case BAND_2:
+ case BAND_3:
+ case BAND_5:
+ case BAND_7:
+ case BAND_8:
+ case BAND_12:
+ case BAND_14:
+ case BAND_18:
+ case BAND_20:
+ case BAND_25:
+ case BAND_28:
+ case BAND_29:
+ case BAND_30:
+ case BAND_34:
+ case BAND_38:
+ case BAND_39:
+ case BAND_40:
+ case BAND_41:
+ case BAND_48:
+ case BAND_50:
+ case BAND_51:
+ case BAND_65:
+ case BAND_66:
+ case BAND_70:
+ case BAND_71:
+ case BAND_74:
+ case BAND_75:
+ case BAND_76:
+ case BAND_77:
+ case BAND_78:
+ case BAND_79:
+ case BAND_80:
+ case BAND_81:
+ case BAND_82:
+ case BAND_83:
+ case BAND_84:
+ case BAND_86:
+ case BAND_90:
+ return FREQUENCY_RANGE_GROUP_1;
+ case BAND_257:
+ case BAND_258:
+ case BAND_260:
+ case BAND_261:
+ return FREQUENCY_RANGE_GROUP_2;
+ default:
+ return FREQUENCY_RANGE_GROUP_UNKNOWN;
+ }
+ };
+
/** @hide */
- private NgranBands() {};
+ private NgranBands() {}
}
/** @hide */
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 9e6dfef..db17a95 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -598,6 +598,48 @@
}
/**
+ * Call forwarding function status
+ */
+ @IntDef(prefix = { "STATUS_" }, value = {
+ CallForwardingInfo.STATUS_ACTIVE,
+ CallForwardingInfo.STATUS_INACTIVE,
+ CallForwardingInfo.STATUS_UNKNOWN_ERROR,
+ CallForwardingInfo.STATUS_NOT_SUPPORTED,
+ CallForwardingInfo.STATUS_FDN_CHECK_FAILURE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CallForwardingStatus {
+ }
+
+ /**
+ * Call forwarding reason types
+ */
+ @IntDef(flag = true, prefix = { "REASON_" }, value = {
+ CallForwardingInfo.REASON_UNCONDITIONAL,
+ CallForwardingInfo.REASON_BUSY,
+ CallForwardingInfo.REASON_NO_REPLY,
+ CallForwardingInfo.REASON_NOT_REACHABLE,
+ CallForwardingInfo.REASON_ALL,
+ CallForwardingInfo.REASON_ALL_CONDITIONAL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CallForwardingReason {
+ }
+
+ /**
+ * Call waiting function status
+ */
+ @IntDef(prefix = { "CALL_WAITING_STATUS_" }, value = {
+ TelephonyManager.CALL_WAITING_STATUS_ACTIVE,
+ TelephonyManager.CALL_WAITING_STATUS_INACTIVE,
+ TelephonyManager.CALL_WAITING_STATUS_NOT_SUPPORTED,
+ TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CallWaitingStatus {
+ }
+
+ /**
* UICC SIM Application Types
*/
@IntDef(prefix = { "APPTYPE_" }, value = {
diff --git a/core/java/android/net/NetworkMisc.aidl b/telephony/java/android/telephony/CallForwardingInfo.aidl
similarity index 75%
copy from core/java/android/net/NetworkMisc.aidl
copy to telephony/java/android/telephony/CallForwardingInfo.aidl
index c65583f..2019e07 100644
--- a/core/java/android/net/NetworkMisc.aidl
+++ b/telephony/java/android/telephony/CallForwardingInfo.aidl
@@ -1,11 +1,11 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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
+ * 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,
@@ -14,6 +14,6 @@
* limitations under the License.
*/
-package android.net;
+package android.telephony;
-parcelable NetworkMisc;
+parcelable CallForwardingInfo;
\ No newline at end of file
diff --git a/telephony/java/android/telephony/CallForwardingInfo.java b/telephony/java/android/telephony/CallForwardingInfo.java
new file mode 100644
index 0000000..33ad5e8
--- /dev/null
+++ b/telephony/java/android/telephony/CallForwardingInfo.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Annotation.CallForwardingReason;
+import android.telephony.Annotation.CallForwardingStatus;
+
+import java.util.Objects;
+
+/**
+ * Defines the call forwarding information.
+ * @hide
+ */
+@SystemApi
+public final class CallForwardingInfo implements Parcelable {
+ private static final String TAG = "CallForwardingInfo";
+
+ /**
+ * Indicates the call forwarding status is inactive.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int STATUS_INACTIVE = 0;
+
+ /**
+ * Indicates the call forwarding status is active.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int STATUS_ACTIVE = 1;
+
+ /**
+ * Indicates the call forwarding could not be enabled because the recipient is not on
+ * Fixed Dialing Number (FDN) list.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int STATUS_FDN_CHECK_FAILURE = 2;
+
+ /**
+ * Indicates the call forwarding status is with an unknown error.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int STATUS_UNKNOWN_ERROR = 3;
+
+ /**
+ * Indicates the call forwarding is not supported (e.g. called via CDMA).
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int STATUS_NOT_SUPPORTED = 4;
+
+ /**
+ * Indicates the call forwarding reason is "unconditional".
+ * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+ * and conditions +CCFC
+ * @hide
+ */
+ @SystemApi
+ public static final int REASON_UNCONDITIONAL = 0;
+
+ /**
+ * Indicates the call forwarding status is "busy".
+ * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+ * and conditions +CCFC
+ * @hide
+ */
+ @SystemApi
+ public static final int REASON_BUSY = 1;
+
+ /**
+ * Indicates the call forwarding reason is "no reply".
+ * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+ * and conditions +CCFC
+ * @hide
+ */
+ @SystemApi
+ public static final int REASON_NO_REPLY = 2;
+
+ /**
+ * Indicates the call forwarding reason is "not reachable".
+ * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+ * and conditions +CCFC
+ * @hide
+ */
+ @SystemApi
+ public static final int REASON_NOT_REACHABLE = 3;
+
+ /**
+ * Indicates the call forwarding reason is "all", for setting all call forwarding reasons
+ * simultaneously (unconditional, busy, no reply, and not reachable).
+ * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+ * and conditions +CCFC
+ * @hide
+ */
+ @SystemApi
+ public static final int REASON_ALL = 4;
+
+ /**
+ * Indicates the call forwarding reason is "all_conditional", for setting all conditional call
+ * forwarding reasons simultaneously (busy, no reply, and not reachable).
+ * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+ * and conditions +CCFC
+ * @hide
+ */
+ @SystemApi
+ public static final int REASON_ALL_CONDITIONAL = 5;
+
+ /**
+ * The call forwarding status.
+ */
+ private @CallForwardingStatus int mStatus;
+
+ /**
+ * The call forwarding reason indicates the condition under which calls will be forwarded.
+ * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+ * and conditions +CCFC
+ */
+ private @CallForwardingReason int mReason;
+
+ /**
+ * The phone number to which calls will be forwarded.
+ * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number
+ * and conditions +CCFC
+ */
+ private String mNumber;
+
+ /**
+ * Gets the timeout (in seconds) before the forwarding is attempted.
+ */
+ private int mTimeSeconds;
+
+ /**
+ * Construct a CallForwardingInfo.
+ *
+ * @param status the call forwarding status
+ * @param reason the call forwarding reason
+ * @param number the phone number to which calls will be forwarded
+ * @param timeSeconds the timeout (in seconds) before the forwarding is attempted
+ * @hide
+ */
+ @SystemApi
+ public CallForwardingInfo(@CallForwardingStatus int status, @CallForwardingReason int reason,
+ @Nullable String number, int timeSeconds) {
+ mStatus = status;
+ mReason = reason;
+ mNumber = number;
+ mTimeSeconds = timeSeconds;
+ }
+
+ /**
+ * Returns the call forwarding status.
+ *
+ * @return the call forwarding status.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @CallForwardingStatus int getStatus() {
+ return mStatus;
+ }
+
+ /**
+ * Returns the call forwarding reason. The call forwarding reason indicates the condition
+ * under which calls will be forwarded. For example, {@link #REASON_NO_REPLY} indicates
+ * that calls will be forward to {@link #getNumber()} when the user fails to answer the call.
+ *
+ * @return the call forwarding reason.
+ *
+ * @hide
+ */
+ @SystemApi
+ public @CallForwardingReason int getReason() {
+ return mReason;
+ }
+
+ /**
+ * Returns the phone number to which calls will be forwarded.
+ *
+ * @return the number calls will be forwarded to, or {@code null} if call forwarding
+ * is being disabled.
+ *
+ * @hide
+ */
+ @SystemApi
+ @Nullable
+ public String getNumber() {
+ return mNumber;
+ }
+
+ /**
+ * Gets the timeout (in seconds) before the forwarding is attempted. For example,
+ * if {@link #REASON_NO_REPLY} is the call forwarding reason, the device will wait this
+ * duration of time before forwarding the call to {@link #getNumber()}.
+ *
+ * Reference: 3GPP TS 27.007 version 10.3.0 Release 10
+ * 7.11 Call forwarding number and conditions +CCFC
+ *
+ * @return the timeout (in seconds) before the forwarding is attempted.
+ *
+ * @hide
+ */
+ @SystemApi
+ @SuppressLint("MethodNameUnits")
+ public int getTimeoutSeconds() {
+ return mTimeSeconds;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mNumber);
+ out.writeInt(mStatus);
+ out.writeInt(mReason);
+ out.writeInt(mTimeSeconds);
+ }
+
+ private CallForwardingInfo(Parcel in) {
+ mNumber = in.readString();
+ mStatus = in.readInt();
+ mReason = in.readInt();
+ mTimeSeconds = in.readInt();
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+
+ if (!(o instanceof CallForwardingInfo)) {
+ return false;
+ }
+
+ CallForwardingInfo other = (CallForwardingInfo) o;
+ return mStatus == other.mStatus
+ && mNumber == other.mNumber
+ && mReason == other.mReason
+ && mTimeSeconds == other.mTimeSeconds;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(mStatus, mNumber, mReason, mTimeSeconds);
+ }
+
+ public static final @NonNull Parcelable.Creator<CallForwardingInfo> CREATOR =
+ new Parcelable.Creator<CallForwardingInfo>() {
+ @Override
+ public CallForwardingInfo createFromParcel(Parcel in) {
+ return new CallForwardingInfo(in);
+ }
+
+ @Override
+ public CallForwardingInfo[] newArray(int size) {
+ return new CallForwardingInfo[size];
+ }
+ };
+
+ /**
+ * @hide
+ */
+ @Override
+ public String toString() {
+ return "[CallForwardingInfo: status=" + mStatus
+ + ", reason= " + mReason
+ + ", timeSec= " + mTimeSeconds + " seconds"
+ + ", number=" + Rlog.pii(TAG, mNumber) + "]";
+ }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 628a275..1eed0e0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -16,8 +16,6 @@
package android.telephony;
-import com.android.telephony.Rlog;
-
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,7 +24,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.os.PersistableBundle;
@@ -37,6 +35,7 @@
import android.telephony.ims.ImsReasonInfo;
import com.android.internal.telephony.ICarrierConfigLoader;
+import com.android.telephony.Rlog;
/**
* Provides access to telephony configuration values that are carrier-specific.
@@ -301,7 +300,6 @@
/**
* A string array containing numbers that shouldn't be included in the call log.
- * @hide
*/
public static final String KEY_UNLOGGABLE_NUMBERS_STRING_ARRAY =
"unloggable_numbers_string_array";
@@ -314,12 +312,11 @@
KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool";
/**
- * Do only allow auto selection in Advanced Network Settings when in home network.
+ * Only allow auto selection in Advanced Network Settings when in home network.
* Manual selection is allowed when in roaming network.
- * @hide
*/
- public static final String
- KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = "only_auto_select_in_home_network";
+ public static final String KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL =
+ "only_auto_select_in_home_network";
/**
* Control whether users receive a simplified network settings UI and improved network
@@ -583,9 +580,6 @@
* registration state to change. That is, turning on or off mobile data will not cause VT to be
* enabled or disabled.
* When {@code false}, disabling mobile data will cause VT to be de-registered.
- * <p>
- * See also {@link #KEY_VILTE_DATA_IS_METERED_BOOL}.
- * @hide
*/
public static final String KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS =
"ignore_data_enabled_changed_for_video_calls";
@@ -649,7 +643,6 @@
/**
* Default WFC_IMS_enabled: true VoWiFi by default is on
* false VoWiFi by default is off
- * @hide
*/
public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL =
"carrier_default_wfc_ims_enabled_bool";
@@ -721,9 +714,7 @@
*
* As of now, Verizon is the only carrier enforcing this dependency in their
* WFC awareness and activation requirements.
- *
- * @hide
- * */
+ */
public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL
= "carrier_volte_override_wfc_provisioning_bool";
@@ -1084,14 +1075,18 @@
*
* When {@code false}, the old behavior is used, where the toggle in accessibility settings is
* used to set the IMS stack's RTT enabled state.
- *
- * @deprecated -- this flag no longer does anything. Remove once the new behavior is verified.
- *
- * @hide
*/
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}.
@@ -1128,7 +1123,6 @@
* Determines whether the IMS conference merge process supports and returns its participants
* data. When {@code true}, on merge complete, conference call would have a list of its
* participants returned in XML format, {@code false otherwise}.
- * @hide
*/
public static final String KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL =
"support_ims_conference_event_package_bool";
@@ -1201,20 +1195,18 @@
public static final String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
/**
- * Determine whether user can switch Wi-Fi preferred or Cellular preferred in calling preference.
+ * Determine whether user can switch Wi-Fi preferred or Cellular preferred
+ * in calling preference.
* Some operators support Wi-Fi Calling only, not VoLTE.
* They don't need "Cellular preferred" option.
- * In this case, set uneditalbe attribute for preferred preference.
- * @hide
+ * In this case, set uneditable attribute for preferred preference.
*/
public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool";
- /**
- * Flag to indicate if Wi-Fi needs to be disabled in ECBM
- * @hide
- **/
- public static final String
- KEY_CONFIG_WIFI_DISABLE_IN_ECBM = "config_wifi_disable_in_ecbm";
+ /**
+ * Flag to indicate if Wi-Fi needs to be disabled in ECBM.
+ */
+ public static final String KEY_CONFIG_WIFI_DISABLE_IN_ECBM = "config_wifi_disable_in_ecbm";
/**
* List operator-specific error codes and indices of corresponding error strings in
@@ -1278,9 +1270,8 @@
public static final String KEY_WFC_SPN_USE_ROOT_LOCALE = "wfc_spn_use_root_locale";
/**
- * The Component Name of the activity that can setup the emergency addrees for WiFi Calling
+ * The Component Name of the activity that can setup the emergency address for WiFi Calling
* as per carrier requirement.
- * @hide
*/
public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING =
"wfc_emergency_address_carrier_app_string";
@@ -1444,22 +1435,19 @@
public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
/**
- * APN types that user is not allowed to modify
- * @hide
+ * APN types that user is not allowed to modify.
*/
public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY =
"read_only_apn_types_string_array";
/**
- * APN fields that user is not allowed to modify
- * @hide
+ * APN fields that user is not allowed to modify.
*/
public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY =
"read_only_apn_fields_string_array";
/**
* Default value of APN types field if not specified by user when adding/modifying an APN.
- * @hide
*/
public static final String KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY =
"apn_settings_default_apn_types_string_array";
@@ -1490,29 +1478,25 @@
"hide_digits_helper_text_on_stk_input_screen_bool";
/**
- * Boolean indicating if show data RAT icon on status bar even when data is disabled
- * @hide
+ * Boolean indicating if show data RAT icon on status bar even when data is disabled.
*/
public static final String KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL =
"always_show_data_rat_icon_bool";
/**
- * Boolean indicating if default data account should show LTE or 4G icon
- * @hide
+ * Boolean indicating if default data account should show LTE or 4G icon.
*/
public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL =
"show_4g_for_lte_data_icon_bool";
/**
* Boolean indicating if default data account should show 4G icon when in 3G.
- * @hide
*/
public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL =
"show_4g_for_3g_data_icon_bool";
/**
- * Boolean indicating if lte+ icon should be shown if available
- * @hide
+ * Boolean indicating if LTE+ icon should be shown if available.
*/
public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL =
"hide_lte_plus_data_icon_bool";
@@ -1527,10 +1511,8 @@
"operator_name_filter_pattern_string";
/**
- * The string is used to compare with operator name. If it matches the pattern then show
- * specific data icon.
- *
- * @hide
+ * The string is used to compare with operator name.
+ * If it matches the pattern then show specific data icon.
*/
public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING =
"show_carrier_data_icon_pattern_string";
@@ -1543,33 +1525,28 @@
"show_precise_failed_cause_bool";
/**
- * Boolean to decide whether lte is enabled.
- * @hide
+ * Boolean to decide whether LTE is enabled.
*/
public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool";
/**
* Boolean to decide whether TD-SCDMA is supported.
- * @hide
*/
public static final String KEY_SUPPORT_TDSCDMA_BOOL = "support_tdscdma_bool";
/**
* A list of mcc/mnc that support TD-SCDMA for device when connect to the roaming network.
- * @hide
*/
public static final String KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY =
"support_tdscdma_roaming_networks_string_array";
/**
* Boolean to decide whether world mode is enabled.
- * @hide
*/
public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool";
/**
* Flatten {@link android.content.ComponentName} of the carrier's settings activity.
- * @hide
*/
public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING =
"carrier_settings_activity_component_name_string";
@@ -1607,7 +1584,10 @@
public static final String KEY_MMS_UA_PROF_TAG_NAME_STRING = "uaProfTagName";
public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl";
public static final String KEY_MMS_USER_AGENT_STRING = "userAgent";
- /** @hide */
+ /**
+ * If true, add "Connection: close" header to MMS HTTP requests so the connection
+ * is immediately closed (disabling keep-alive).
+ */
public static final String KEY_MMS_CLOSE_CONNECTION_BOOL = "mmsCloseConnection";
/**
@@ -1623,25 +1603,23 @@
/**
* Defines carrier-specific actions which act upon
* com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED, used for customization of the
- * default carrier app
+ * default carrier app.
* Format: "CARRIER_ACTION_IDX, ..."
* Where {@code CARRIER_ACTION_IDX} is an integer defined in
- * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
+ * com.android.carrierdefaultapp.CarrierActionUtils
* Example:
- * {@link com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS
- * disable_metered_apns}
- * @hide
+ * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS
+ * disables metered APNs
*/
- @UnsupportedAppUsage
+ @SuppressLint("IntentName")
public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY =
"carrier_default_actions_on_redirection_string_array";
/**
- * Defines carrier-specific actions which act upon
- * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+ * Defines carrier-specific actions which act upon CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
* and configured signal args:
- * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_APN_TYPE_KEY apnType},
- * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_ERROR_CODE_KEY errorCode}
+ * android.telephony.TelephonyManager#EXTRA_APN_TYPE,
+ * android.telephony.TelephonyManager#EXTRA_ERROR_CODE
* used for customization of the default carrier app
* Format:
* {
@@ -1649,42 +1627,41 @@
* "APN_1, ERROR_CODE_2 : CARRIER_ACTION_IDX_1 "
* }
* Where {@code APN_1} is a string defined in
- * {@link com.android.internal.telephony.PhoneConstants PhoneConstants}
+ * com.android.internal.telephony.PhoneConstants
* Example: "default"
*
- * {@code ERROR_CODE_1} is an integer defined in
- * {@link DataFailCause DcFailure}
+ * {@code ERROR_CODE_1} is an integer defined in android.telephony.DataFailCause
* Example:
- * {@link DataFailCause#MISSING_UNKNOWN_APN}
+ * android.telephony.DataFailCause#MISSING_UNKNOWN_APN
*
* {@code CARRIER_ACTION_IDX_1} is an integer defined in
- * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
+ * com.android.carrierdefaultapp.CarrierActionUtils
* Example:
- * {@link com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS}
- * @hide
+ * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS
+ * disables metered APNs
*/
+ @SuppressLint("IntentName")
public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY =
"carrier_default_actions_on_dcfailure_string_array";
/**
- * Defines carrier-specific actions which act upon
- * com.android.internal.telephony.CARRIER_SIGNAL_RESET, used for customization of the
- * default carrier app
+ * Defines carrier-specific actions which act upon CARRIER_SIGNAL_RESET,
+ * used for customization of the default carrier app.
* Format: "CARRIER_ACTION_IDX, ..."
* Where {@code CARRIER_ACTION_IDX} is an integer defined in
- * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
+ * com.android.carrierdefaultapp.CarrierActionUtils
* Example:
- * {@link com.android.carrierdefaultapp.CarrierActionUtils
- * #CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS clear all notifications on reset}
- * @hide
+ * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS
+ * clears all notifications on reset
*/
+ @SuppressLint("IntentName")
public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET =
"carrier_default_actions_on_reset_string_array";
/**
* Defines carrier-specific actions which act upon
* com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE,
- * used for customization of the default carrier app
+ * used for customization of the default carrier app.
* Format:
* {
* "true : CARRIER_ACTION_IDX_1",
@@ -1692,17 +1669,17 @@
* }
* Where {@code true} is a boolean indicates default network available/unavailable
* Where {@code CARRIER_ACTION_IDX} is an integer defined in
- * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
+ * com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils
* Example:
- * {@link com.android.carrierdefaultapp.CarrierActionUtils
- * #CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER enable the app as the default URL handler}
- * @hide
+ * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER
+ * enables the app as the default URL handler
*/
+ @SuppressLint("IntentName")
public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE =
"carrier_default_actions_on_default_network_available_string_array";
+
/**
- * Defines a list of acceptable redirection url for default carrier app
- * @hides
+ * Defines a list of acceptable redirection url for default carrier app.
*/
public static final String KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY =
"carrier_default_redirection_url_string_array";
@@ -1830,10 +1807,10 @@
/**
* Determines whether to enable enhanced call blocking feature on the device.
- * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED
- * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE
- * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE
- * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN
+ * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED
+ * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE
+ * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE
+ * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN
*
* <p>
* 1. For Single SIM(SS) device, it can be customized in both carrier_config_mccmnc.xml
@@ -1843,7 +1820,6 @@
* function is used regardless of SIM.
* <p>
* If {@code true} enable enhanced call blocking feature on the device, {@code false} otherwise.
- * @hide
*/
public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL =
"support_enhanced_call_blocking_bool";
@@ -1946,7 +1922,6 @@
/**
* Flag indicating whether the carrier supports call deflection for an incoming IMS call.
- * @hide
*/
public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL =
"carrier_allow_deflect_ims_call_bool";
@@ -2011,8 +1986,6 @@
/**
* Whether system apps are allowed to use fallback if carrier video call is not available.
* Defaults to {@code true}.
- *
- * @hide
*/
public static final String KEY_ALLOW_VIDEO_CALLING_FALLBACK_BOOL =
"allow_video_calling_fallback_bool";
@@ -2050,9 +2023,8 @@
"enhanced_4g_lte_title_variant_bool";
/**
- * The index indicates the carrier specified title string of Enahnce 4G LTE Mode settings.
+ * The index indicates the carrier specified title string of Enhanced 4G LTE Mode settings.
* Default value is 0, which indicates the default title string.
- * @hide
*/
public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT =
"enhanced_4g_lte_title_variant_int";
@@ -2096,15 +2068,13 @@
* {@link #KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL} is false. If
* {@link #KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL} is true, this
* configuration is ignored and roaming preference cannot be changed.
- * @hide
*/
public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL =
"editable_wfc_roaming_mode_bool";
/**
- * Flag specifying wether to show blocking pay phone option in blocked numbers screen. Only show
- * the option if payphone call presentation represents in the carrier's region.
- * @hide
+ * Flag specifying whether to show blocking pay phone option in blocked numbers screen.
+ * Only show the option if payphone call presentation is present in the carrier's region.
*/
public static final java.lang.String KEY_SHOW_BLOCKING_PAY_PHONE_OPTION_BOOL =
"show_blocking_pay_phone_option_bool";
@@ -2114,7 +2084,6 @@
* {@code false} - roaming preference can be selected separately from the home preference.
* {@code true} - roaming preference is the same as home preference and
* {@link #KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT} is used as the default value.
- * @hide
*/
public static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL =
"use_wfc_home_network_mode_in_roaming_network_bool";
@@ -2148,7 +2117,6 @@
* while the device is registered over WFC. Default value is -1, which indicates
* that this notification is not pertinent for a particular carrier. We've added a delay
* to prevent false positives.
- * @hide
*/
public static final String KEY_EMERGENCY_NOTIFICATION_DELAY_INT =
"emergency_notification_delay_int";
@@ -2199,7 +2167,6 @@
/**
* Flag specifying whether to show an alert dialog for video call charges.
* By default this value is {@code false}.
- * @hide
*/
public static final String KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL =
"show_video_call_charges_alert_dialog_bool";
@@ -2486,10 +2453,9 @@
/**
* Identifies if the key is available for WLAN or EPDG or both. The value is a bitmask.
* 0 indicates that neither EPDG or WLAN is enabled.
- * 1 indicates that key type {@link TelephonyManager#KEY_TYPE_EPDG} is enabled.
- * 2 indicates that key type {@link TelephonyManager#KEY_TYPE_WLAN} is enabled.
+ * 1 indicates that key type TelephonyManager#KEY_TYPE_EPDG is enabled.
+ * 2 indicates that key type TelephonyManager#KEY_TYPE_WLAN is enabled.
* 3 indicates that both are enabled.
- * @hide
*/
public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int";
@@ -2508,7 +2474,6 @@
/**
* Flag specifying whether IMS registration state menu is shown in Status Info setting,
* default to false.
- * @hide
*/
public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL =
"show_ims_registration_status_bool";
@@ -2564,7 +2529,6 @@
/**
* The flag to disable the popup dialog which warns the user of data charges.
- * @hide
*/
public static final String KEY_DISABLE_CHARGE_INDICATION_BOOL =
"disable_charge_indication_bool";
@@ -2629,15 +2593,13 @@
/**
* Determines whether any carrier has been identified and its specific config has been applied,
* default to false.
- * @hide
*/
public static final String KEY_CARRIER_CONFIG_APPLIED_BOOL = "carrier_config_applied_bool";
/**
* Determines whether we should show a warning asking the user to check with their carrier
- * on pricing when the user enabled data roaming.
+ * on pricing when the user enabled data roaming,
* default to false.
- * @hide
*/
public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL =
"check_pricing_with_carrier_data_roaming_bool";
@@ -2789,10 +2751,10 @@
* Specifies a carrier-defined {@link android.telecom.CallRedirectionService} which Telecom
* will bind to for outgoing calls. An empty string indicates that no carrier-defined
* {@link android.telecom.CallRedirectionService} is specified.
- * @hide
*/
public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING =
"call_redirection_service_component_name_string";
+
/**
* Support for the original string display of CDMA MO call.
* By default, it is disabled.
@@ -2905,8 +2867,8 @@
"call_waiting_service_class_int";
/**
- * This configuration allow the system UI to display different 5G icon for different 5G
- * scenario.
+ * This configuration allows the system UI to display different 5G icons for different 5G
+ * scenarios.
*
* There are five 5G scenarios:
* 1. connected_mmwave: device currently connected to 5G cell as the secondary cell and using
@@ -2923,24 +2885,22 @@
* 5G cell as a secondary cell) but the use of 5G is restricted.
*
* The configured string contains multiple key-value pairs separated by comma. For each pair,
- * the key and value is separated by a colon. The key is corresponded to a 5G status above and
+ * the key and value are separated by a colon. The key corresponds to a 5G status above and
* the value is the icon name. Use "None" as the icon name if no icon should be shown in a
* specific 5G scenario. If the scenario is "None", config can skip this key and value.
*
* Icon name options: "5G_Plus", "5G".
*
* Here is an example:
- * UE want to display 5G_Plus icon for scenario#1, and 5G icon for scenario#2; otherwise no
+ * UE wants to display 5G_Plus icon for scenario#1, and 5G icon for scenario#2; otherwise not
* define.
* The configuration is: "connected_mmwave:5G_Plus,connected:5G"
- *
- * @hide
*/
public static final String KEY_5G_ICON_CONFIGURATION_STRING =
"5g_icon_configuration_string";
/**
- * Timeout in second for displaying 5G icon, default value is 0 which means the timer is
+ * Timeout in seconds for displaying 5G icon, default value is 0 which means the timer is
* disabled.
*
* System UI will show the 5G icon and start a timer with the timeout from this config when the
@@ -2949,8 +2909,6 @@
*
* If 5G is reacquired during this timer, the timer is canceled and restarted when 5G is next
* lost. Allows us to momentarily lose 5G without blinking the icon.
- *
- * @hide
*/
public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT =
"5g_icon_display_grace_period_sec_int";
@@ -3015,7 +2973,6 @@
/**
* Controls hysteresis time in milli seconds for which OpportunisticNetworkService
* will wait before switching data from opportunistic network to primary network.
- * @hide
*/
public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG =
"opportunistic_network_data_switch_exit_hysteresis_time_long";
@@ -3023,17 +2980,58 @@
/**
* Controls whether to do ping test before switching data to opportunistic network.
* This carrier config is used to disable this feature.
- * @hide
*/
public static final String KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL =
"ping_test_before_data_switch_bool";
/**
* Controls time in milliseconds until DcTracker reevaluates 5G connection state.
- * @hide
*/
public static final String KEY_5G_WATCHDOG_TIME_MS_LONG =
"5g_watchdog_time_long";
+ /**
+ * Controls whether to switch data to primary from opportunistic subscription
+ * if primary is out of service. This control only affects system or 1st party app
+ * initiated data switch, but will not override data switch initiated by privileged carrier apps
+ * This carrier config is used to disable this feature.
+ */
+ public static final String KEY_SWITCH_DATA_TO_PRIMARY_IF_PRIMARY_IS_OOS_BOOL =
+ "switch_data_to_primary_if_primary_is_oos_bool";
+
+ /**
+ * Controls the ping pong determination of opportunistic network.
+ * If opportunistic network is determined as out of service or below
+ * #KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT or
+ * #KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT within
+ * #KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG of switching to opportunistic network,
+ * it will be determined as ping pong situation by system app or 1st party app.
+ */
+ public static final String KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG =
+ "opportunistic_network_ping_pong_time_long";
+ /**
+ * Controls back off time in milli seconds for switching back to
+ * opportunistic subscription. This time will be added to
+ * {@link CarrierConfigManager#KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG} to
+ * determine hysteresis time if there is ping pong situation
+ * (determined by system app or 1st party app) between primary and opportunistic
+ * subscription. Ping ping situation is defined in
+ * #KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG.
+ * If ping pong situation continuous #KEY_OPPORTUNISTIC_NETWORK_BACKOFF_TIME_LONG
+ * will be added to previously determined hysteresis time.
+ */
+ public static final String KEY_OPPORTUNISTIC_NETWORK_BACKOFF_TIME_LONG =
+ "opportunistic_network_backoff_time_long";
+
+ /**
+ * Controls the max back off time in milli seconds for switching back to
+ * opportunistic subscription.
+ * This time will be the max hysteresis that can be determined irrespective of there is
+ * continuous ping pong situation or not as described in
+ * #KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG and
+ * #KEY_OPPORTUNISTIC_NETWORK_BACKOFF_TIME_LONG.
+ */
+ public static final String KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG =
+ "opportunistic_network_max_backoff_time_long";
/**
* Indicates zero or more emergency number prefix(es), because some carrier requires
@@ -3068,8 +3066,6 @@
* signal bar of primary network. By default it will be false, meaning whenever data
* is going over opportunistic network, signal bar will reflect signal strength and rat
* icon of that network.
- *
- * @hide
*/
public static final String KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN =
"always_show_primary_signal_bar_in_opportunistic_network_boolean";
@@ -3079,7 +3075,6 @@
* validation result, this value defines customized value of how long we wait for validation
* success before we fail and revoke the switch.
* Time out is in milliseconds.
- * @hide
*/
public static final String KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG =
"data_switch_validation_timeout_long";
@@ -3163,7 +3158,6 @@
* 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";
/**
@@ -3283,8 +3277,6 @@
/**
* Determines whether wifi calling location privacy policy is shown.
- *
- * @hide
*/
public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL =
"show_wfc_location_privacy_policy_bool";
@@ -3390,8 +3382,8 @@
"support_wps_over_ims_bool";
/**
- * Holds the list of carrier certificate hashes. Note that each carrier has its own certificates
- * @hide
+ * Holds the list of carrier certificate hashes.
+ * Note that each carrier has its own certificates.
*/
public static final String KEY_CARRIER_CERTIFICATE_STRING_ARRAY =
"carrier_certificate_string_array";
@@ -3575,8 +3567,9 @@
sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
sDefaults.putBoolean(KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL, false);
- sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, true);
+ 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);
@@ -3804,26 +3797,26 @@
sDefaults.putIntArray(KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY,
// Boundaries: [-140 dB, -44 dB]
new int[] {
- -125, /* SIGNAL_STRENGTH_POOR */
- -115, /* SIGNAL_STRENGTH_MODERATE */
- -105, /* SIGNAL_STRENGTH_GOOD */
- -95, /* SIGNAL_STRENGTH_GREAT */
+ -110, /* SIGNAL_STRENGTH_POOR */
+ -90, /* SIGNAL_STRENGTH_MODERATE */
+ -80, /* SIGNAL_STRENGTH_GOOD */
+ -65, /* SIGNAL_STRENGTH_GREAT */
});
sDefaults.putIntArray(KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY,
// Boundaries: [-20 dB, -3 dB]
new int[] {
- -14, /* SIGNAL_STRENGTH_POOR */
- -12, /* SIGNAL_STRENGTH_MODERATE */
- -10, /* SIGNAL_STRENGTH_GOOD */
- -8 /* SIGNAL_STRENGTH_GREAT */
+ -16, /* SIGNAL_STRENGTH_POOR */
+ -11, /* SIGNAL_STRENGTH_MODERATE */
+ -9, /* SIGNAL_STRENGTH_GOOD */
+ -7 /* SIGNAL_STRENGTH_GREAT */
});
sDefaults.putIntArray(KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY,
// Boundaries: [-23 dB, 40 dB]
new int[] {
- -8, /* SIGNAL_STRENGTH_POOR */
- 0, /* SIGNAL_STRENGTH_MODERATE */
- 8, /* SIGNAL_STRENGTH_GOOD */
- 16 /* SIGNAL_STRENGTH_GREAT */
+ -5, /* SIGNAL_STRENGTH_POOR */
+ 5, /* SIGNAL_STRENGTH_MODERATE */
+ 15, /* SIGNAL_STRENGTH_GOOD */
+ 30 /* SIGNAL_STRENGTH_GREAT */
});
sDefaults.putInt(KEY_PARAMETERS_USE_FOR_5G_NR_SIGNAL_BAR_INT,
CellSignalStrengthNr.USE_SSRSRP);
@@ -3862,6 +3855,13 @@
sDefaults.putBoolean(KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL, true);
/* Default value is 1 hour. */
sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000);
+ sDefaults.putBoolean(KEY_SWITCH_DATA_TO_PRIMARY_IF_PRIMARY_IS_OOS_BOOL, true);
+ /* Default value is 60 seconds. */
+ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_PING_PONG_TIME_LONG, 60000);
+ /* Default value is 10 seconds. */
+ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_BACKOFF_TIME_LONG, 10000);
+ /* Default value is 60 seconds. */
+ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG, 60000);
sDefaults.putAll(Gps.getDefaults());
sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
new int[] {
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 8e703fe..399b1a4 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -22,10 +22,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.hardware.radio.V1_0.CellInfoType;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.telephony.Rlog;
+
import java.util.Objects;
import java.util.UUID;
@@ -324,6 +327,86 @@
}
/** @hide */
+ public static CellIdentity create(android.hardware.radio.V1_0.CellIdentity cellIdentity) {
+ if (cellIdentity == null) return null;
+ switch(cellIdentity.cellInfoType) {
+ case CellInfoType.GSM: {
+ if (cellIdentity.cellIdentityGsm.size() == 1) {
+ return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0));
+ }
+ break;
+ }
+ case CellInfoType.WCDMA: {
+ if (cellIdentity.cellIdentityWcdma.size() == 1) {
+ return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0));
+ }
+ break;
+ }
+ case CellInfoType.TD_SCDMA: {
+ if (cellIdentity.cellIdentityTdscdma.size() == 1) {
+ return new CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0));
+ }
+ break;
+ }
+ case CellInfoType.LTE: {
+ if (cellIdentity.cellIdentityLte.size() == 1) {
+ return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0));
+ }
+ break;
+ }
+ case CellInfoType.CDMA: {
+ if (cellIdentity.cellIdentityCdma.size() == 1) {
+ return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0));
+ }
+ break;
+ }
+ case CellInfoType.NONE: break;
+ default: break;
+ }
+ return null;
+ }
+
+ /** @hide */
+ public static CellIdentity create(android.hardware.radio.V1_2.CellIdentity cellIdentity) {
+ if (cellIdentity == null) return null;
+ switch(cellIdentity.cellInfoType) {
+ case CellInfoType.GSM: {
+ if (cellIdentity.cellIdentityGsm.size() == 1) {
+ return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0));
+ }
+ break;
+ }
+ case CellInfoType.WCDMA: {
+ if (cellIdentity.cellIdentityWcdma.size() == 1) {
+ return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0));
+ }
+ break;
+ }
+ case CellInfoType.TD_SCDMA: {
+ if (cellIdentity.cellIdentityTdscdma.size() == 1) {
+ return new CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0));
+ }
+ break;
+ }
+ case CellInfoType.LTE: {
+ if (cellIdentity.cellIdentityLte.size() == 1) {
+ return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0));
+ }
+ break;
+ }
+ case CellInfoType.CDMA: {
+ if (cellIdentity.cellIdentityCdma.size() == 1) {
+ return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0));
+ }
+ break;
+ }
+ case CellInfoType.NONE: break;
+ default: break;
+ }
+ return null;
+ }
+
+ /** @hide */
public static CellIdentity create(android.hardware.radio.V1_5.CellIdentity ci) {
if (ci == null) return null;
switch (ci.getDiscriminator()) {
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 2ecdfce..dc73cbf 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -18,11 +18,13 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
/**
@@ -46,6 +48,9 @@
// 6-bit Base Station Identity Code
private final int mBsic;
+ // a list of additional PLMN-IDs reported for this cell
+ private final List<String> mAdditionalPlmns;
+
/**
* @hide
*/
@@ -56,6 +61,7 @@
mCid = CellInfo.UNAVAILABLE;
mArfcn = CellInfo.UNAVAILABLE;
mBsic = CellInfo.UNAVAILABLE;
+ mAdditionalPlmns = Collections.emptyList();
}
/**
@@ -68,35 +74,48 @@
* @param mncStr 2 or 3-digit Mobile Network Code in string format
* @param alphal long alpha Operator Name String or Enhanced Operator Name String
* @param alphas short alpha Operator Name String or Enhanced Operator Name String
+ * @param additionalPlmns a list of additional PLMN IDs broadcast by the cell
*
* @hide
*/
public CellIdentityGsm(int lac, int cid, int arfcn, int bsic, String mccStr,
- String mncStr, String alphal, String alphas) {
+ String mncStr, String alphal, String alphas,
+ List<String> additionalPlmns) {
super(TAG, CellInfo.TYPE_GSM, mccStr, mncStr, alphal, alphas);
mLac = inRangeOrUnavailable(lac, 0, MAX_LAC);
mCid = inRangeOrUnavailable(cid, 0, MAX_CID);
mArfcn = inRangeOrUnavailable(arfcn, 0, MAX_ARFCN);
mBsic = inRangeOrUnavailable(bsic, 0, MAX_BSIC);
+ mAdditionalPlmns = additionalPlmns;
}
/** @hide */
public CellIdentityGsm(android.hardware.radio.V1_0.CellIdentityGsm cid) {
this(cid.lac, cid.cid, cid.arfcn,
cid.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.bsic,
- cid.mcc, cid.mnc, "", "");
+ cid.mcc, cid.mnc, "", "", Collections.emptyList());
}
/** @hide */
public CellIdentityGsm(android.hardware.radio.V1_2.CellIdentityGsm cid) {
this(cid.base.lac, cid.base.cid, cid.base.arfcn,
cid.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.base.bsic, cid.base.mcc,
- cid.base.mnc, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort);
+ cid.base.mnc, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
+ Collections.emptyList());
+ }
+
+ /** @hide */
+ public CellIdentityGsm(android.hardware.radio.V1_5.CellIdentityGsm cid) {
+ this(cid.base.base.lac, cid.base.base.cid, cid.base.base.arfcn,
+ cid.base.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE
+ : cid.base.base.bsic, cid.base.base.mcc,
+ cid.base.base.mnc, cid.base.operatorNames.alphaLong,
+ cid.base.operatorNames.alphaShort, cid.additionalPlmns);
}
private CellIdentityGsm(CellIdentityGsm cid) {
this(cid.mLac, cid.mCid, cid.mArfcn, cid.mBsic, cid.mMccStr,
- cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort);
+ cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns);
}
CellIdentityGsm copy() {
@@ -107,7 +126,7 @@
@Override
public @NonNull CellIdentityGsm sanitizeLocationInfo() {
return new CellIdentityGsm(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
- CellInfo.UNAVAILABLE, mMccStr, mMncStr, mAlphaLong, mAlphaShort);
+ CellInfo.UNAVAILABLE, mMccStr, mMncStr, mAlphaLong, mAlphaShort, mAdditionalPlmns);
}
/**
@@ -193,6 +212,14 @@
}
/**
+ * @return a list of additional PLMN IDs supported by this cell.
+ */
+ @NonNull
+ public List<String> getAdditionalPlmns() {
+ return mAdditionalPlmns;
+ }
+
+ /**
* @deprecated Primary Scrambling Code is not applicable to GSM.
* @return {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} - undefined for GSM
*/
@@ -215,7 +242,7 @@
@Override
public int hashCode() {
- return Objects.hash(mLac, mCid, super.hashCode());
+ return Objects.hash(mLac, mCid, mAdditionalPlmns.hashCode(), super.hashCode());
}
@Override
@@ -235,6 +262,7 @@
&& mBsic == o.mBsic
&& TextUtils.equals(mMccStr, o.mMccStr)
&& TextUtils.equals(mMncStr, o.mMncStr)
+ && mAdditionalPlmns.equals(o.mAdditionalPlmns)
&& super.equals(other);
}
@@ -249,6 +277,7 @@
.append(" mMnc=").append(mMncStr)
.append(" mAlphaLong=").append(mAlphaLong)
.append(" mAlphaShort=").append(mAlphaShort)
+ .append(" mAdditionalPlmns=").append(mAdditionalPlmns)
.append("}").toString();
}
@@ -261,6 +290,7 @@
dest.writeInt(mCid);
dest.writeInt(mArfcn);
dest.writeInt(mBsic);
+ dest.writeList(mAdditionalPlmns);
}
/** Construct from Parcel, type has already been processed */
@@ -270,6 +300,7 @@
mCid = in.readInt();
mArfcn = in.readInt();
mBsic = in.readInt();
+ mAdditionalPlmns = in.readArrayList(null);
if (DBG) log(toString());
}
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 15c9175..cf8fe6a 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -18,12 +18,14 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
/**
@@ -50,6 +52,11 @@
// cell bandwidth, in kHz
private final int mBandwidth;
+ // a list of additional PLMN-IDs reported for this cell
+ private final List<String> mAdditionalPlmns;
+
+ private ClosedSubscriberGroupInfo mCsgInfo;
+
/**
* @hide
*/
@@ -61,6 +68,8 @@
mTac = CellInfo.UNAVAILABLE;
mEarfcn = CellInfo.UNAVAILABLE;
mBandwidth = CellInfo.UNAVAILABLE;
+ mAdditionalPlmns = Collections.emptyList();
+ mCsgInfo = null;
}
/**
@@ -76,7 +85,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public CellIdentityLte(int mcc, int mnc, int ci, int pci, int tac) {
this(ci, pci, tac, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, String.valueOf(mcc),
- String.valueOf(mnc), null, null);
+ String.valueOf(mnc), null, null, Collections.emptyList(), null);
}
/**
@@ -90,34 +99,49 @@
* @param mncStr 2 or 3-digit Mobile Network Code in string format
* @param alphal long alpha Operator Name String or Enhanced Operator Name String
* @param alphas short alpha Operator Name String or Enhanced Operator Name String
+ * @param additionalPlmns a list of additional PLMN IDs broadcast by the cell
+ * @param csgInfo info about the closed subscriber group broadcast by the cell
*
* @hide
*/
public CellIdentityLte(int ci, int pci, int tac, int earfcn, int bandwidth, String mccStr,
- String mncStr, String alphal, String alphas) {
+ String mncStr, String alphal, String alphas, List<String> additionalPlmns,
+ ClosedSubscriberGroupInfo csgInfo) {
super(TAG, CellInfo.TYPE_LTE, mccStr, mncStr, alphal, alphas);
mCi = inRangeOrUnavailable(ci, 0, MAX_CI);
mPci = inRangeOrUnavailable(pci, 0, MAX_PCI);
mTac = inRangeOrUnavailable(tac, 0, MAX_TAC);
mEarfcn = inRangeOrUnavailable(earfcn, 0, MAX_EARFCN);
mBandwidth = inRangeOrUnavailable(bandwidth, 0, MAX_BANDWIDTH);
+ mAdditionalPlmns = additionalPlmns;
+ mCsgInfo = csgInfo;
}
/** @hide */
public CellIdentityLte(android.hardware.radio.V1_0.CellIdentityLte cid) {
- this(cid.ci, cid.pci, cid.tac, cid.earfcn, CellInfo.UNAVAILABLE, cid.mcc, cid.mnc, "", "");
+ this(cid.ci, cid.pci, cid.tac, cid.earfcn,
+ CellInfo.UNAVAILABLE, cid.mcc, cid.mnc, "", "", Collections.emptyList(), null);
}
/** @hide */
public CellIdentityLte(android.hardware.radio.V1_2.CellIdentityLte cid) {
this(cid.base.ci, cid.base.pci, cid.base.tac, cid.base.earfcn, cid.bandwidth,
cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong,
- cid.operatorNames.alphaShort);
+ cid.operatorNames.alphaShort, Collections.emptyList(), null);
+ }
+
+ /** @hide */
+ public CellIdentityLte(android.hardware.radio.V1_5.CellIdentityLte cid) {
+ this(cid.base.base.ci, cid.base.base.pci, cid.base.base.tac, cid.base.base.earfcn,
+ cid.base.bandwidth, cid.base.base.mcc, cid.base.base.mnc,
+ cid.base.operatorNames.alphaLong, cid.base.operatorNames.alphaShort,
+ cid.additionalPlmns, cid.optionalCsgInfo.csgInfo() != null
+ ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo()) : null);
}
private CellIdentityLte(CellIdentityLte cid) {
this(cid.mCi, cid.mPci, cid.mTac, cid.mEarfcn, cid.mBandwidth, cid.mMccStr,
- cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort);
+ cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo);
}
/** @hide */
@@ -125,7 +149,7 @@
public @NonNull CellIdentityLte sanitizeLocationInfo() {
return new CellIdentityLte(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
- mMccStr, mMncStr, mAlphaLong, mAlphaShort);
+ mMccStr, mMncStr, mAlphaLong, mAlphaShort, mAdditionalPlmns, null);
}
CellIdentityLte copy() {
@@ -185,6 +209,19 @@
}
/**
+ * Get bands of the cell
+ *
+ * Reference: 3GPP TS 36.101 section 5.5
+ *
+ * @return List of band number or empty list if not available.
+ */
+ @NonNull
+ public List<Integer> getBands() {
+ // Todo: Add actual support
+ return Collections.emptyList();
+ }
+
+ /**
* @return Cell bandwidth in kHz,
* {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
*/
@@ -223,6 +260,22 @@
}
/**
+ * @return a list of additional PLMN IDs supported by this cell.
+ */
+ @NonNull
+ public List<String> getAdditionalPlmns() {
+ return mAdditionalPlmns;
+ }
+
+ /**
+ * @return closed subscriber group information about the cell if available, otherwise null.
+ */
+ @Nullable
+ public ClosedSubscriberGroupInfo getClosedSubscriberGroupInfo() {
+ return mCsgInfo;
+ }
+
+ /**
* A hack to allow tunneling of LTE information via GsmCellLocation
* so that older Network Location Providers can return some information
* on LTE only networks, see bug 9228974.
@@ -247,7 +300,8 @@
@Override
public int hashCode() {
- return Objects.hash(mCi, mPci, mTac, super.hashCode());
+ return Objects.hash(mCi, mPci, mTac,
+ mAdditionalPlmns.hashCode(), mCsgInfo, super.hashCode());
}
@Override
@@ -268,6 +322,8 @@
&& mBandwidth == o.mBandwidth
&& TextUtils.equals(mMccStr, o.mMccStr)
&& TextUtils.equals(mMncStr, o.mMncStr)
+ && mAdditionalPlmns.equals(o.mAdditionalPlmns)
+ && Objects.equals(mCsgInfo, o.mCsgInfo)
&& super.equals(other);
}
@@ -283,6 +339,8 @@
.append(" mMnc=").append(mMncStr)
.append(" mAlphaLong=").append(mAlphaLong)
.append(" mAlphaShort=").append(mAlphaShort)
+ .append(" mAdditionalPlmns=").append(mAdditionalPlmns)
+ .append(" mCsgInfo=").append(mCsgInfo)
.append("}").toString();
}
@@ -296,6 +354,8 @@
dest.writeInt(mTac);
dest.writeInt(mEarfcn);
dest.writeInt(mBandwidth);
+ dest.writeList(mAdditionalPlmns);
+ dest.writeParcelable(mCsgInfo, flags);
}
/** Construct from Parcel, type has already been processed */
@@ -306,7 +366,8 @@
mTac = in.readInt();
mEarfcn = in.readInt();
mBandwidth = in.readInt();
-
+ mAdditionalPlmns = in.readArrayList(null);
+ mCsgInfo = in.readParcelable(null);
if (DBG) log(toString());
}
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index f08a580..d4f181f 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -20,8 +20,12 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
+import android.telephony.AccessNetworkConstants.NgranBands.NgranBand;
import android.telephony.gsm.GsmCellLocation;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
/**
@@ -39,40 +43,58 @@
private final int mPci;
private final int mTac;
private final long mNci;
+ private final List<Integer> mBands;
+
+ // a list of additional PLMN-IDs reported for this cell
+ private final List<String> mAdditionalPlmns;
/**
*
* @param pci Physical Cell Id in range [0, 1007].
* @param tac 16-bit Tracking Area Code.
* @param nrArfcn NR Absolute Radio Frequency Channel Number, in range [0, 3279165].
+ * @param bands Bands used by the cell. Band number defined in 3GPP TS 38.101-1 and TS 38.101-2.
* @param mccStr 3-digit Mobile Country Code in string format.
* @param mncStr 2 or 3-digit Mobile Network Code in string format.
* @param nci The 36-bit NR Cell Identity in range [0, 68719476735].
* @param alphal long alpha Operator Name String or Enhanced Operator Name String.
* @param alphas short alpha Operator Name String or Enhanced Operator Name String.
+ * @param additionalPlmns a list of additional PLMN IDs broadcast by the cell
*
* @hide
*/
- public CellIdentityNr(int pci, int tac, int nrArfcn, String mccStr, String mncStr,
- long nci, String alphal, String alphas) {
+ public CellIdentityNr(int pci, int tac, int nrArfcn, @NgranBand List<Integer> bands,
+ String mccStr, String mncStr, long nci, String alphal, String alphas,
+ List<String> additionalPlmns) {
super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas);
mPci = inRangeOrUnavailable(pci, 0, MAX_PCI);
mTac = inRangeOrUnavailable(tac, 0, MAX_TAC);
mNrArfcn = inRangeOrUnavailable(nrArfcn, 0, MAX_NRARFCN);
+ mBands = new ArrayList<>(bands);
mNci = inRangeOrUnavailable(nci, 0, MAX_NCI);
+ mAdditionalPlmns = new ArrayList<>(additionalPlmns);
}
/** @hide */
public CellIdentityNr(android.hardware.radio.V1_4.CellIdentityNr cid) {
- this(cid.pci, cid.tac, cid.nrarfcn, cid.mcc, cid.mnc, cid.nci, cid.operatorNames.alphaLong,
- cid.operatorNames.alphaShort);
+ this(cid.pci, cid.tac, cid.nrarfcn, Collections.emptyList(), cid.mcc, cid.mnc, cid.nci,
+ cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
+ Collections.emptyList());
+ }
+
+ /** @hide */
+ public CellIdentityNr(android.hardware.radio.V1_5.CellIdentityNr cid) {
+ this(cid.base.pci, cid.base.tac, cid.base.nrarfcn, cid.bands, cid.base.mcc, cid.base.mnc,
+ cid.base.nci, cid.base.operatorNames.alphaLong,
+ cid.base.operatorNames.alphaShort, cid.additionalPlmns);
}
/** @hide */
@Override
public @NonNull CellIdentityNr sanitizeLocationInfo() {
- return new CellIdentityNr(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
- mMccStr, mMncStr, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort);
+ return new CellIdentityNr(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mNrArfcn,
+ mBands, mMccStr, mMncStr, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort,
+ mAdditionalPlmns);
}
/**
@@ -87,7 +109,8 @@
@Override
public int hashCode() {
- return Objects.hash(super.hashCode(), mPci, mTac, mNrArfcn, mNci);
+ return Objects.hash(super.hashCode(), mPci, mTac,
+ mNrArfcn, mBands.hashCode(), mNci, mAdditionalPlmns.hashCode());
}
@Override
@@ -98,7 +121,8 @@
CellIdentityNr o = (CellIdentityNr) other;
return super.equals(o) && mPci == o.mPci && mTac == o.mTac && mNrArfcn == o.mNrArfcn
- && mNci == o.mNci;
+ && mBands.equals(o.mBands) && mNci == o.mNci
+ && mAdditionalPlmns.equals(o.mAdditionalPlmns);
}
/**
@@ -125,6 +149,20 @@
}
/**
+ * Get bands of the cell
+ *
+ * Reference: TS 38.101-1 table 5.2-1
+ * Reference: TS 38.101-2 table 5.2-1
+ *
+ * @return List of band number or empty list if not available.
+ */
+ @NgranBand
+ @NonNull
+ public List<Integer> getBands() {
+ return Collections.unmodifiableList(mBands);
+ }
+
+ /**
* Get the physical cell id.
* @return Integer value in range [0, 1007] or {@link CellInfo#UNAVAILABLE} if unknown.
*/
@@ -158,17 +196,33 @@
return mMncStr;
}
+ /** @hide */
+ @Override
+ public int getChannelNumber() {
+ return mNrArfcn;
+ }
+
+ /**
+ * @return a list of additional PLMN IDs supported by this cell.
+ */
+ @NonNull
+ public List<String> getAdditionalPlmns() {
+ return Collections.unmodifiableList(mAdditionalPlmns);
+ }
+
@Override
public String toString() {
return new StringBuilder(TAG + ":{")
.append(" mPci = ").append(mPci)
.append(" mTac = ").append(mTac)
.append(" mNrArfcn = ").append(mNrArfcn)
+ .append(" mBands = ").append(mBands)
.append(" mMcc = ").append(mMccStr)
.append(" mMnc = ").append(mMncStr)
.append(" mNci = ").append(mNci)
.append(" mAlphaLong = ").append(mAlphaLong)
.append(" mAlphaShort = ").append(mAlphaShort)
+ .append(" mAdditionalPlmns = ").append(mAdditionalPlmns)
.append(" }")
.toString();
}
@@ -179,7 +233,9 @@
dest.writeInt(mPci);
dest.writeInt(mTac);
dest.writeInt(mNrArfcn);
+ dest.writeList(mBands);
dest.writeLong(mNci);
+ dest.writeList(mAdditionalPlmns);
}
/** Construct from Parcel, type has already been processed */
@@ -188,7 +244,9 @@
mPci = in.readInt();
mTac = in.readInt();
mNrArfcn = in.readInt();
+ mBands = in.readArrayList(null);
mNci = in.readLong();
+ mAdditionalPlmns = in.readArrayList(null);
}
/** Implement the Parcelable interface */
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 4bb3a95..2ff351c 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -21,6 +21,8 @@
import android.os.Parcel;
import android.telephony.gsm.GsmCellLocation;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
/**
@@ -46,6 +48,11 @@
// 16-bit UMTS Absolute RF Channel Number described in TS 25.101 sec. 5.4.3
private final int mUarfcn;
+ // a list of additional PLMN-IDs reported for this cell
+ private final List<String> mAdditionalPlmns;
+
+ private ClosedSubscriberGroupInfo mCsgInfo;
+
/**
* @hide
*/
@@ -55,6 +62,8 @@
mCid = CellInfo.UNAVAILABLE;
mCpid = CellInfo.UNAVAILABLE;
mUarfcn = CellInfo.UNAVAILABLE;
+ mAdditionalPlmns = Collections.emptyList();
+ mCsgInfo = null;
}
/**
@@ -68,39 +77,57 @@
* @param uarfcn 16-bit UMTS Absolute RF Channel Number described in TS 25.101 sec. 5.4.3
* @param alphal long alpha Operator Name String or Enhanced Operator Name String
* @param alphas short alpha Operator Name String or Enhanced Operator Name String
+ * @param additionalPlmns a list of additional PLMN IDs broadcast by the cell
+ * @param csgInfo info about the closed subscriber group broadcast by the cell
*
* @hide
*/
public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid, int uarfcn,
- String alphal, String alphas) {
+ String alphal, String alphas, @NonNull List<String> additionalPlmns,
+ ClosedSubscriberGroupInfo csgInfo) {
super(TAG, CellInfo.TYPE_TDSCDMA, mcc, mnc, alphal, alphas);
mLac = inRangeOrUnavailable(lac, 0, MAX_LAC);
mCid = inRangeOrUnavailable(cid, 0, MAX_CID);
mCpid = inRangeOrUnavailable(cpid, 0, MAX_CPID);
mUarfcn = inRangeOrUnavailable(uarfcn, 0, MAX_UARFCN);
+ mAdditionalPlmns = additionalPlmns;
+ mCsgInfo = csgInfo;
}
private CellIdentityTdscdma(CellIdentityTdscdma cid) {
this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid,
- cid.mCpid, cid.mUarfcn, cid.mAlphaLong, cid.mAlphaShort);
+ cid.mCpid, cid.mUarfcn, cid.mAlphaLong,
+ cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo);
}
/** @hide */
public CellIdentityTdscdma(android.hardware.radio.V1_0.CellIdentityTdscdma cid) {
- this(cid.mcc, cid.mnc, cid.lac, cid.cid, cid.cpid, CellInfo.UNAVAILABLE, "", "");
+ this(cid.mcc, cid.mnc, cid.lac, cid.cid, cid.cpid, CellInfo.UNAVAILABLE, "", "",
+ Collections.emptyList(), null);
}
/** @hide */
public CellIdentityTdscdma(android.hardware.radio.V1_2.CellIdentityTdscdma cid) {
this(cid.base.mcc, cid.base.mnc, cid.base.lac, cid.base.cid, cid.base.cpid,
- cid.uarfcn, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort);
+ cid.uarfcn, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort,
+ Collections.emptyList(), null);
+ }
+
+ /** @hide */
+ public CellIdentityTdscdma(android.hardware.radio.V1_5.CellIdentityTdscdma cid) {
+ this(cid.base.base.mcc, cid.base.base.mnc, cid.base.base.lac, cid.base.base.cid,
+ cid.base.base.cpid, cid.base.uarfcn, cid.base.operatorNames.alphaLong,
+ cid.base.operatorNames.alphaShort,
+ cid.additionalPlmns, cid.optionalCsgInfo.csgInfo() != null
+ ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo()) : null);
}
/** @hide */
@Override
public @NonNull CellIdentityTdscdma sanitizeLocationInfo() {
return new CellIdentityTdscdma(mMccStr, mMncStr, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
- CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort);
+ CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort,
+ mAdditionalPlmns, null);
}
CellIdentityTdscdma copy() {
@@ -171,6 +198,22 @@
return mUarfcn;
}
+ /**
+ * @return a list of additional PLMN IDs supported by this cell.
+ */
+ @NonNull
+ public List<String> getAdditionalPlmns() {
+ return mAdditionalPlmns;
+ }
+
+ /**
+ * @return closed subscriber group information about the cell if available, otherwise null.
+ */
+ @Nullable
+ public ClosedSubscriberGroupInfo getClosedSubscriberGroupInfo() {
+ return mCsgInfo;
+ }
+
/** @hide */
@NonNull
@Override
@@ -198,12 +241,15 @@
&& mCid == o.mCid
&& mCpid == o.mCpid
&& mUarfcn == o.mUarfcn
+ && mAdditionalPlmns.equals(o.mAdditionalPlmns)
+ && Objects.equals(mCsgInfo, o.mCsgInfo)
&& super.equals(other);
}
@Override
public int hashCode() {
- return Objects.hash(mLac, mCid, mCpid, mUarfcn, super.hashCode());
+ return Objects.hash(mLac, mCid, mCpid, mUarfcn,
+ mAdditionalPlmns.hashCode(), mCsgInfo, super.hashCode());
}
@Override
@@ -217,6 +263,8 @@
.append(" mCid=").append(mCid)
.append(" mCpid=").append(mCpid)
.append(" mUarfcn=").append(mUarfcn)
+ .append(" mAdditionalPlmns=").append(mAdditionalPlmns)
+ .append(" mCsgInfo=").append(mCsgInfo)
.append("}").toString();
}
@@ -235,6 +283,8 @@
dest.writeInt(mCid);
dest.writeInt(mCpid);
dest.writeInt(mUarfcn);
+ dest.writeList(mAdditionalPlmns);
+ dest.writeParcelable(mCsgInfo, flags);
}
/** Construct from Parcel, type has already been processed */
@@ -244,6 +294,8 @@
mCid = in.readInt();
mCpid = in.readInt();
mUarfcn = in.readInt();
+ mAdditionalPlmns = in.readArrayList(null);
+ mCsgInfo = in.readParcelable(null);
if (DBG) log(toString());
}
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 4ecd134..9be42a1 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -23,6 +23,8 @@
import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
/**
@@ -47,6 +49,12 @@
@UnsupportedAppUsage
private final int mUarfcn;
+ // a list of additional PLMN-IDs reported for this cell
+ private final List<String> mAdditionalPlmns;
+
+ @Nullable
+ private final ClosedSubscriberGroupInfo mCsgInfo;
+
/**
* @hide
*/
@@ -56,6 +64,8 @@
mCid = CellInfo.UNAVAILABLE;
mPsc = CellInfo.UNAVAILABLE;
mUarfcn = CellInfo.UNAVAILABLE;
+ mAdditionalPlmns = Collections.emptyList();
+ mCsgInfo = null;
}
/**
@@ -68,33 +78,49 @@
* @param mncStr 2 or 3-digit Mobile Network Code in string format
* @param alphal long alpha Operator Name String or Enhanced Operator Name String
* @param alphas short alpha Operator Name String or Enhanced Operator Name String
+ * @param additionalPlmns a list of additional PLMN IDs broadcast by the cell
+ * @param csgInfo info about the closed subscriber group broadcast by the cell
*
* @hide
*/
public CellIdentityWcdma (int lac, int cid, int psc, int uarfcn,
- String mccStr, String mncStr, String alphal, String alphas) {
+ String mccStr, String mncStr, String alphal, String alphas,
+ @NonNull List<String> additionalPlmns,
+ @Nullable ClosedSubscriberGroupInfo csgInfo) {
super(TAG, CellInfo.TYPE_WCDMA, mccStr, mncStr, alphal, alphas);
mLac = inRangeOrUnavailable(lac, 0, MAX_LAC);
mCid = inRangeOrUnavailable(cid, 0, MAX_CID);
mPsc = inRangeOrUnavailable(psc, 0, MAX_PSC);
mUarfcn = inRangeOrUnavailable(uarfcn, 0, MAX_UARFCN);
+ mAdditionalPlmns = additionalPlmns;
+ mCsgInfo = csgInfo;
}
/** @hide */
public CellIdentityWcdma(android.hardware.radio.V1_0.CellIdentityWcdma cid) {
- this(cid.lac, cid.cid, cid.psc, cid.uarfcn, cid.mcc, cid.mnc, "", "");
+ this(cid.lac, cid.cid, cid.psc, cid.uarfcn, cid.mcc, cid.mnc, "", "",
+ Collections.emptyList(), null);
}
/** @hide */
public CellIdentityWcdma(android.hardware.radio.V1_2.CellIdentityWcdma cid) {
this(cid.base.lac, cid.base.cid, cid.base.psc, cid.base.uarfcn,
cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong,
- cid.operatorNames.alphaShort);
+ cid.operatorNames.alphaShort, Collections.emptyList(), null);
+ }
+
+ /** @hide */
+ public CellIdentityWcdma(android.hardware.radio.V1_5.CellIdentityWcdma cid) {
+ this(cid.base.base.lac, cid.base.base.cid, cid.base.base.psc, cid.base.base.uarfcn,
+ cid.base.base.mcc, cid.base.base.mnc, cid.base.operatorNames.alphaLong,
+ cid.base.operatorNames.alphaShort, cid.additionalPlmns,
+ cid.optionalCsgInfo.csgInfo() != null
+ ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo()) : null);
}
private CellIdentityWcdma(CellIdentityWcdma cid) {
this(cid.mLac, cid.mCid, cid.mPsc, cid.mUarfcn, cid.mMccStr,
- cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort);
+ cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo);
}
/** @hide */
@@ -102,7 +128,7 @@
public @NonNull CellIdentityWcdma sanitizeLocationInfo() {
return new CellIdentityWcdma(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mMccStr, mMncStr,
- mAlphaLong, mAlphaShort);
+ mAlphaLong, mAlphaShort, mAdditionalPlmns, null);
}
CellIdentityWcdma copy() {
@@ -180,7 +206,7 @@
@Override
public int hashCode() {
- return Objects.hash(mLac, mCid, mPsc, super.hashCode());
+ return Objects.hash(mLac, mCid, mPsc, mAdditionalPlmns.hashCode(), super.hashCode());
}
/**
@@ -197,6 +223,22 @@
return mUarfcn;
}
+ /**
+ * @return a list of additional PLMN IDs supported by this cell.
+ */
+ @NonNull
+ public List<String> getAdditionalPlmns() {
+ return mAdditionalPlmns;
+ }
+
+ /**
+ * @return closed subscriber group information about the cell if available, otherwise null.
+ */
+ @Nullable
+ public ClosedSubscriberGroupInfo getClosedSubscriberGroupInfo() {
+ return mCsgInfo;
+ }
+
/** @hide */
@NonNull
@Override
@@ -228,6 +270,8 @@
&& mUarfcn == o.mUarfcn
&& TextUtils.equals(mMccStr, o.mMccStr)
&& TextUtils.equals(mMncStr, o.mMncStr)
+ && mAdditionalPlmns.equals(o.mAdditionalPlmns)
+ && Objects.equals(mCsgInfo, o.mCsgInfo)
&& super.equals(other);
}
@@ -242,6 +286,8 @@
.append(" mMnc=").append(mMncStr)
.append(" mAlphaLong=").append(mAlphaLong)
.append(" mAlphaShort=").append(mAlphaShort)
+ .append(" mAdditionalPlmns=").append(mAdditionalPlmns)
+ .append(" mCsgInfo=").append(mCsgInfo)
.append("}").toString();
}
@@ -254,6 +300,8 @@
dest.writeInt(mCid);
dest.writeInt(mPsc);
dest.writeInt(mUarfcn);
+ dest.writeList(mAdditionalPlmns);
+ dest.writeParcelable(mCsgInfo, flags);
}
/** Construct from Parcel, type has already been processed */
@@ -263,6 +311,8 @@
mCid = in.readInt();
mPsc = in.readInt();
mUarfcn = in.readInt();
+ mAdditionalPlmns = in.readArrayList(null);
+ mCsgInfo = in.readParcelable(null);
if (DBG) log(toString());
}
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index 475c99b..ec86c14 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
import android.compat.annotation.UnsupportedAppUsage;
import android.hardware.radio.V1_4.CellInfo.Info;
import android.os.Parcel;
@@ -179,6 +180,18 @@
*
* @return a time stamp in nanos since boot.
*/
+ @SuppressLint("MethodNameUnits")
+ public long getTimestampNanos() {
+ return mTimeStamp;
+ }
+
+ /**
+ * Approximate time this cell information was received from the modem.
+ *
+ * @return a time stamp in nanos since boot.
+ * @deprecated Use {@link #getTimestampNanos} instead.
+ */
+ @Deprecated
public long getTimeStamp() {
return mTimeStamp;
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 4d67bcf..f4c13ff 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -45,28 +45,28 @@
// Lifted from Default carrier configs and max range of SSRSRP
// Boundaries: [-140 dB, -44 dB]
private int[] mSsRsrpThresholds = new int[] {
- -125, /* SIGNAL_STRENGTH_POOR */
- -115, /* SIGNAL_STRENGTH_MODERATE */
- -105, /* SIGNAL_STRENGTH_GOOD */
- -95, /* SIGNAL_STRENGTH_GREAT */
+ -110, /* SIGNAL_STRENGTH_POOR */
+ -90, /* SIGNAL_STRENGTH_MODERATE */
+ -80, /* SIGNAL_STRENGTH_GOOD */
+ -65, /* SIGNAL_STRENGTH_GREAT */
};
// Lifted from Default carrier configs and max range of SSRSRQ
// Boundaries: [-20 dB, -3 dB]
private int[] mSsRsrqThresholds = new int[] {
- -14, /* SIGNAL_STRENGTH_POOR */
- -12, /* SIGNAL_STRENGTH_MODERATE */
- -10, /* SIGNAL_STRENGTH_GOOD */
- -8 /* SIGNAL_STRENGTH_GREAT */
+ -16, /* SIGNAL_STRENGTH_POOR */
+ -11, /* SIGNAL_STRENGTH_MODERATE */
+ -9, /* SIGNAL_STRENGTH_GOOD */
+ -7 /* SIGNAL_STRENGTH_GREAT */
};
// Lifted from Default carrier configs and max range of SSSINR
// Boundaries: [-23 dB, 40 dB]
private int[] mSsSinrThresholds = new int[] {
- -8, /* SIGNAL_STRENGTH_POOR */
- 0, /* SIGNAL_STRENGTH_MODERATE */
- 8, /* SIGNAL_STRENGTH_GOOD */
- 16 /* SIGNAL_STRENGTH_GREAT */
+ -5, /* SIGNAL_STRENGTH_POOR */
+ 5, /* SIGNAL_STRENGTH_MODERATE */
+ 15, /* SIGNAL_STRENGTH_GOOD */
+ 30 /* SIGNAL_STRENGTH_GREAT */
};
/**
diff --git a/telephony/java/android/telephony/ClosedSubscriberGroupInfo.aidl b/telephony/java/android/telephony/ClosedSubscriberGroupInfo.aidl
new file mode 100644
index 0000000..cbe7638
--- /dev/null
+++ b/telephony/java/android/telephony/ClosedSubscriberGroupInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2020, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable ClosedSubscriberGroupInfo;
diff --git a/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java b/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java
new file mode 100644
index 0000000..e7dfe634
--- /dev/null
+++ b/telephony/java/android/telephony/ClosedSubscriberGroupInfo.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Information to represent a closed subscriber group.
+ */
+public final class ClosedSubscriberGroupInfo implements Parcelable {
+ private static final String TAG = "ClosedSubscriberGroupInfo";
+
+ private final boolean mCsgIndicator;
+
+ private final String mHomeNodebName;
+
+ private final int mCsgIdentity;
+
+ /** @hide */
+ public ClosedSubscriberGroupInfo(boolean csgIndicator, @Nullable String homeNodebName,
+ int csgIdentity) {
+ mCsgIndicator = csgIndicator;
+ mHomeNodebName = (homeNodebName == null) ? "" : homeNodebName;
+ mCsgIdentity = csgIdentity;
+ }
+
+ /** @hide */
+ public ClosedSubscriberGroupInfo(
+ @NonNull android.hardware.radio.V1_5.ClosedSubscriberGroupInfo csgInfo) {
+ this(csgInfo.csgIndication, csgInfo.homeNodebName, csgInfo.csgIdentity);
+ }
+
+ /**
+ * Indicates whether the cell is restricted to only CSG members.
+ *
+ * A cell not broadcasting the CSG Indication but reporting CSG information is considered a
+ * Hybrid Cell.
+ * Refer to the "csg-Indication" field in 3GPP TS 36.331 section 6.2.2
+ * SystemInformationBlockType1.
+ * Also refer to "CSG Indicator" in 3GPP TS 25.331 section 10.2.48.8.1 and TS 25.304.
+ *
+ * @return true if the cell is restricted to group members only.
+ */
+ public boolean getCsgIndicator() {
+ return mCsgIndicator;
+ }
+
+ /**
+ * Returns human-readable name of the closed subscriber group operating this cell (Node-B).
+ *
+ * Refer to "hnb-Name" in TS 36.331 section 6.2.2 SystemInformationBlockType9.
+ * Also refer to "HNB Name" in 3GPP TS25.331 section 10.2.48.8.23 and TS 23.003 section 4.8.
+ *
+ * @return the home Node-B name if available.
+ */
+ public @NonNull String getHomeNodebName() {
+ return mHomeNodebName;
+ }
+
+ /**
+ * The identity of the closed subscriber group that the cell belongs to.
+ *
+ * Refer to "CSG-Identity" in TS 36.336 section 6.3.4.
+ * Also refer to "CSG Identity" in 3GPP TS 25.331 section 10.3.2.8 and TS 23.003 section 4.7.
+ *
+ * @return the unique 27-bit CSG Identity.
+ */
+ @IntRange(from = 0, to = 0x7FFFFFF)
+ public int getCsgIdentity() {
+ return mCsgIdentity;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mCsgIndicator, mHomeNodebName, mCsgIdentity);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof ClosedSubscriberGroupInfo)) {
+ return false;
+ }
+
+ ClosedSubscriberGroupInfo o = (ClosedSubscriberGroupInfo) other;
+ return mCsgIndicator == o.mCsgIndicator && mHomeNodebName == o.mHomeNodebName
+ && mCsgIdentity == o.mCsgIdentity;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder(TAG + ":{")
+ .append(" mCsgIndicator = ").append(mCsgIndicator)
+ .append(" mHomeNodebName = ").append(mHomeNodebName)
+ .append(" mCsgIdentity = ").append(mCsgIdentity)
+ .toString();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int type) {
+ dest.writeBoolean(mCsgIndicator);
+ dest.writeString(mHomeNodebName);
+ dest.writeInt(mCsgIdentity);
+ }
+
+ /** Construct from Parcel, type has already been processed */
+ private ClosedSubscriberGroupInfo(Parcel in) {
+ this(in.readBoolean(), in.readString(), in.readInt());
+ }
+
+ /**
+ * Implement the Parcelable interface
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ public static final @android.annotation.NonNull Creator<ClosedSubscriberGroupInfo> CREATOR =
+ new Creator<ClosedSubscriberGroupInfo>() {
+ @Override
+ public ClosedSubscriberGroupInfo createFromParcel(Parcel in) {
+ return createFromParcelBody(in);
+ }
+
+ @Override
+ public ClosedSubscriberGroupInfo[] newArray(int size) {
+ return new ClosedSubscriberGroupInfo[size];
+ }
+ };
+
+ /** @hide */
+ protected static ClosedSubscriberGroupInfo createFromParcelBody(Parcel in) {
+ return new ClosedSubscriberGroupInfo(in);
+ }
+}
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index c706d28..704e5aa 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -27,11 +27,7 @@
/**
* Provides access to information about Telephony IMS services on the device.
- *
- * @hide
*/
-@SystemApi
-@TestApi
@SystemService(Context.TELEPHONY_IMS_SERVICE)
public class ImsManager {
@@ -45,7 +41,10 @@
* <p class="note">
* Carrier applications may listen to this broadcast to be notified of possible IMS provisioning
* issues.
+ * @hide
*/
+ @SystemApi
+ @TestApi
// Moved from TelephonyIntents, need to keep backwards compatibility with OEM apps that have
// this value hard-coded in BroadcastReceiver.
@SuppressLint("ActionValue")
@@ -54,6 +53,43 @@
"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
*/
@@ -67,7 +103,10 @@
* @param subscriptionId The ID of the subscription that this ImsRcsManager will use.
* @throws IllegalArgumentException if the subscription is invalid.
* @return a ImsRcsManager instance with the specific subscription ID.
+ * @hide
*/
+ @SystemApi
+ @TestApi
@NonNull
public ImsRcsManager getImsRcsManager(int subscriptionId) {
if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) {
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index aee7cca..bd2375f 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -199,10 +199,10 @@
}
/**
+ * Indicate if the ModemActivityInfo is invalid due to modem's invalid reporting.
+ *
* @return {@code true} if this {@link ModemActivityInfo} record is valid,
* {@code false} otherwise.
- *
- * @hide
*/
public boolean isValid() {
for (TransmitPower powerInfo : getTransmitPowerInfo()) {
diff --git a/telephony/java/android/telephony/ModemInfo.java b/telephony/java/android/telephony/ModemInfo.java
deleted file mode 100644
index c0833af..0000000
--- a/telephony/java/android/telephony/ModemInfo.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * Information of a single logical modem indicating
- * its id, supported rats and whether it supports voice or data, etc.
- * @hide
- */
-public class ModemInfo implements Parcelable {
- public final int modemId;
- public final int rat; /* bitset */
- public final boolean isVoiceSupported;
- public final boolean isDataSupported;
-
- // TODO b/121394331: Clean up this class after V1_1.PhoneCapability cleanup.
- public ModemInfo(int modemId) {
- this(modemId, 0, true, true);
- }
-
- public ModemInfo(int modemId, int rat, boolean isVoiceSupported, boolean isDataSupported) {
- this.modemId = modemId;
- this.rat = rat;
- this.isVoiceSupported = isVoiceSupported;
- this.isDataSupported = isDataSupported;
- }
-
- public ModemInfo(Parcel in) {
- modemId = in.readInt();
- rat = in.readInt();
- isVoiceSupported = in.readBoolean();
- isDataSupported = in.readBoolean();
- }
-
- @Override
- public String toString() {
- return "modemId=" + modemId + " rat=" + rat + " isVoiceSupported:" + isVoiceSupported
- + " isDataSupported:" + isDataSupported;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(modemId, rat, isVoiceSupported, isDataSupported);
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == null || !(o instanceof ModemInfo) || hashCode() != o.hashCode()) {
- return false;
- }
-
- if (this == o) {
- return true;
- }
-
- ModemInfo s = (ModemInfo) o;
-
- return (modemId == s.modemId
- && rat == s.rat
- && isVoiceSupported == s.isVoiceSupported
- && isDataSupported == s.isDataSupported);
- }
-
- /**
- * {@link Parcelable#describeContents}
- */
- public @ContentsFlags int describeContents() {
- return 0;
- }
-
- /**
- * {@link Parcelable#writeToParcel}
- */
- public void writeToParcel(Parcel dest, @WriteFlags int flags) {
- dest.writeInt(modemId);
- dest.writeInt(rat);
- dest.writeBoolean(isVoiceSupported);
- dest.writeBoolean(isDataSupported);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<ModemInfo> CREATOR = new Parcelable.Creator() {
- public ModemInfo createFromParcel(Parcel in) {
- return new ModemInfo(in);
- }
-
- public ModemInfo[] newArray(int size) {
- return new ModemInfo[size];
- }
- };
-}
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index cbd5ed6..32ffb75 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -36,10 +36,7 @@
/**
* Description of a mobile network registration info
- * @hide
*/
-@SystemApi
-@TestApi
public final class NetworkRegistrationInfo implements Parcelable {
/**
* Network domain
@@ -51,9 +48,9 @@
/** Unknown / Unspecified domain */
public static final int DOMAIN_UNKNOWN = 0;
- /** Circuit switching domain */
+ /** Circuit switched domain */
public static final int DOMAIN_CS = android.hardware.radio.V1_5.Domain.CS;
- /** Packet switching domain */
+ /** Packet switched domain */
public static final int DOMAIN_PS = android.hardware.radio.V1_5.Domain.PS;
/** Applicable to both CS and PS Domain */
public static final int DOMAIN_CS_PS = DOMAIN_CS | DOMAIN_PS;
@@ -69,17 +66,41 @@
REGISTRATION_STATE_UNKNOWN, REGISTRATION_STATE_ROAMING})
public @interface RegistrationState {}
- /** Not registered. The device is not currently searching a new operator to register. */
+ /**
+ * Not registered. The device is not currently searching a new operator to register.
+ * @hide
+ */
+ @SystemApi @TestApi
public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0;
- /** Registered on home network. */
+ /**
+ * Registered on home network.
+ * @hide
+ */
+ @SystemApi @TestApi
public static final int REGISTRATION_STATE_HOME = 1;
- /** Not registered. The device is currently searching a new operator to register. */
+ /**
+ * Not registered. The device is currently searching a new operator to register.
+ * @hide
+ */
+ @SystemApi @TestApi
public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2;
- /** Registration denied. */
+ /**
+ * Registration denied.
+ * @hide
+ */
+ @SystemApi @TestApi
public static final int REGISTRATION_STATE_DENIED = 3;
- /** Registration state is unknown. */
+ /**
+ * Registration state is unknown.
+ * @hide
+ */
+ @SystemApi @TestApi
public static final int REGISTRATION_STATE_UNKNOWN = 4;
- /** Registered on roaming network. */
+ /**
+ * Registered on roaming network.
+ * @hide
+ */
+ @SystemApi @TestApi
public static final int REGISTRATION_STATE_ROAMING = 5;
/** @hide */
@@ -92,7 +113,6 @@
/**
* The device isn't camped on an LTE cell or the LTE cell doesn't support E-UTRA-NR
* Dual Connectivity(EN-DC).
- * @hide
*/
public static final int NR_STATE_NONE = 0;
@@ -100,7 +120,6 @@
* The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) but
* either the use of dual connectivity with NR(DCNR) is restricted or NR is not supported by
* the selected PLMN.
- * @hide
*/
public static final int NR_STATE_RESTRICTED = 1;
@@ -108,14 +127,12 @@
* The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and both
* the use of dual connectivity with NR(DCNR) is not restricted and NR is supported by the
* selected PLMN.
- * @hide
*/
public static final int NR_STATE_NOT_RESTRICTED = 2;
/**
* The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and
* also connected to at least one 5G cell as a secondary serving cell.
- * @hide
*/
public static final int NR_STATE_CONNECTED = 3;
@@ -129,22 +146,34 @@
SERVICE_TYPE_VIDEO, SERVICE_TYPE_EMERGENCY})
public @interface ServiceType {}
- /** Unkown service */
+ /**
+ * Unknown service
+ */
public static final int SERVICE_TYPE_UNKNOWN = 0;
- /** Voice service */
+ /**
+ * Voice service
+ */
public static final int SERVICE_TYPE_VOICE = 1;
- /** Data service */
+ /**
+ * Data service
+ */
public static final int SERVICE_TYPE_DATA = 2;
- /** SMS service */
+ /**
+ * SMS service
+ */
public static final int SERVICE_TYPE_SMS = 3;
- /** Video service */
+ /**
+ * Video service
+ */
public static final int SERVICE_TYPE_VIDEO = 4;
- /** Emergency service */
+ /**
+ * Emergency service
+ */
public static final int SERVICE_TYPE_EMERGENCY = 5;
@Domain
@@ -330,9 +359,7 @@
* Get the 5G NR connection state.
*
* @return the 5G NR connection state.
- * @hide
*/
- @SystemApi
public @NRState int getNrState() {
return mNrState;
}
@@ -344,7 +371,10 @@
/**
* @return The registration state.
+ *
+ * @hide
*/
+ @SystemApi @TestApi
public @RegistrationState int getRegistrationState() {
return mRegistrationState;
}
@@ -352,6 +382,21 @@
/**
* @return {@code true} if registered on roaming network, {@code false} otherwise.
*/
+ public boolean isRegistered() {
+ return mRegistrationState == REGISTRATION_STATE_HOME
+ || mRegistrationState == REGISTRATION_STATE_ROAMING;
+ }
+
+ /**
+ * @return {@code true} if registered on roaming network, {@code false} otherwise.
+ */
+ public boolean isSearching() {
+ return mRegistrationState == REGISTRATION_STATE_NOT_REGISTERED_SEARCHING;
+ }
+
+ /**
+ * @return {@code true} if registered on roaming network, {@code false} otherwise.
+ */
public boolean isRoaming() {
return mRoamingType != ServiceState.ROAMING_TYPE_NOT_ROAMING;
}
@@ -376,15 +421,18 @@
/**
* @return the current network roaming type.
+ * @hide
*/
-
+ @SystemApi @TestApi
public @ServiceState.RoamingType int getRoamingType() {
return mRoamingType;
}
/**
* @return Whether emergency is enabled.
+ * @hide
*/
+ @SystemApi @TestApi
public boolean isEmergencyEnabled() { return mEmergencyOnly; }
/**
@@ -422,7 +470,9 @@
* @return Reason for denial if the registration state is {@link #REGISTRATION_STATE_DENIED}.
* Depending on {@code accessNetworkTechnology}, the values are defined in 3GPP TS 24.008
* 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 A.S0001 6.2.2.44 for CDMA
+ * @hide
*/
+ @SystemApi @TestApi
public int getRejectCause() {
return mRejectCause;
}
@@ -445,8 +495,10 @@
/**
* @return Data registration related info
+ * @hide
*/
@Nullable
+ @SystemApi @TestApi
public DataSpecificRegistrationInfo getDataSpecificInfo() {
return mDataSpecificInfo;
}
@@ -571,7 +623,11 @@
&& mNrState == other.mNrState;
}
+ /**
+ * @hide
+ */
@Override
+ @SystemApi @TestApi
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mDomain);
dest.writeInt(mTransportType);
@@ -659,7 +715,9 @@
* .setRegistrationState(REGISTRATION_STATE_HOME)
* .build();
* </code></pre>
+ * @hide
*/
+ @SystemApi @TestApi
public static final class Builder {
@Domain
private int mDomain;
@@ -759,7 +817,9 @@
* @param emergencyOnly True if this network registration is for emergency use only.
*
* @return The same instance of the builder.
+ * @hide
*/
+ @SystemApi @TestApi
public @NonNull Builder setEmergencyOnly(boolean emergencyOnly) {
mEmergencyOnly = emergencyOnly;
return this;
@@ -771,7 +831,9 @@
* @param availableServices Available services.
*
* @return The same instance of the builder.
+ * @hide
*/
+ @SystemApi @TestApi
public @NonNull Builder setAvailableServices(
@NonNull @ServiceType List<Integer> availableServices) {
mAvailableServices = availableServices;
@@ -784,7 +846,9 @@
* @param cellIdentity The cell identity.
*
* @return The same instance of the builder.
+ * @hide
*/
+ @SystemApi @TestApi
public @NonNull Builder setCellIdentity(@Nullable CellIdentity cellIdentity) {
mCellIdentity = cellIdentity;
return this;
@@ -792,9 +856,10 @@
/**
* Build the NetworkRegistrationInfo.
- *
* @return the NetworkRegistrationInfo object.
+ * @hide
*/
+ @SystemApi @TestApi
public @NonNull NetworkRegistrationInfo build() {
return new NetworkRegistrationInfo(mDomain, mTransportType, mRegistrationState,
mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
diff --git a/telephony/java/android/telephony/NetworkScanRequest.java b/telephony/java/android/telephony/NetworkScanRequest.java
index 465b6aa..c8b8ffb 100644
--- a/telephony/java/android/telephony/NetworkScanRequest.java
+++ b/telephony/java/android/telephony/NetworkScanRequest.java
@@ -20,10 +20,10 @@
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
/**
* Defines a request to peform a network scan.
@@ -221,9 +221,15 @@
private NetworkScanRequest(Parcel in) {
mScanType = in.readInt();
- mSpecifiers = (RadioAccessSpecifier[]) in.readParcelableArray(
- Object.class.getClassLoader(),
- RadioAccessSpecifier.class);
+ Parcelable[] tempSpecifiers = in.readParcelableArray(Object.class.getClassLoader());
+ if (tempSpecifiers != null) {
+ mSpecifiers = new RadioAccessSpecifier[tempSpecifiers.length];
+ for (int i = 0; i < tempSpecifiers.length; i++) {
+ mSpecifiers[i] = (RadioAccessSpecifier) tempSpecifiers[i];
+ }
+ } else {
+ mSpecifiers = null;
+ }
mSearchPeriodicity = in.readInt();
mMaxSearchTime = in.readInt();
mIncrementalResults = in.readBoolean();
diff --git a/telephony/java/android/telephony/PhoneCapability.java b/telephony/java/android/telephony/PhoneCapability.java
index 8a75831..90244b3 100644
--- a/telephony/java/android/telephony/PhoneCapability.java
+++ b/telephony/java/android/telephony/PhoneCapability.java
@@ -16,13 +16,20 @@
package android.telephony;
+import android.annotation.LongDef;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.AccessNetworkConstants.RadioAccessNetworkType;
+import android.telephony.TelephonyManager.NetworkTypeBitMask;
+import com.android.internal.util.CollectionUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -31,68 +38,365 @@
* are shared between those modems defined by list of modem IDs.
*/
public final class PhoneCapability implements Parcelable {
- // Hardcoded default DSDS capability.
+ /** Modem feature indicating 3GPP2 capability. */
+ public static final long MODEM_FEATURE_3GPP2_REG = 1 << 0;
+ /** Modem feature indicating 3GPP capability. */
+ public static final long MODEM_FEATURE_3GPP_REG = 1 << 1;
+ /** Modem feature indicating CDMA 2000 with EHRPD capability. */
+ public static final long MODEM_FEATURE_CDMA2000_EHRPD_REG = 1 << 2;
+ /** Modem feature indicating GSM capability. */
+ public static final long MODEM_FEATURE_GERAN_REG = 1 << 3;
+ /** Modem feature indicating UMTS capability. */
+ public static final long MODEM_FEATURE_UTRAN_REG = 1 << 4;
+ /** Modem feature indicating LTE capability. */
+ public static final long MODEM_FEATURE_EUTRAN_REG = 1 << 5;
+ /** Modem feature indicating 5G capability.*/
+ public static final long MODEM_FEATURE_NGRAN_REG = 1 << 6;
+ /** Modem feature indicating EN-DC capability. */
+ public static final long MODEM_FEATURE_EUTRA_NR_DUAL_CONNECTIVITY_REG = 1 << 7;
+ /** Modem feature indicating VoLTE capability (IMS registered). */
+ public static final long MODEM_FEATURE_PS_VOICE_REG = 1 << 8;
+ /** Modem feature indicating CS voice call capability. */
+ public static final long MODEM_FEATURE_CS_VOICE_SESSION = 1 << 9;
+ /** Modem feature indicating Internet connection capability. */
+ public static final long MODEM_FEATURE_INTERACTIVE_DATA_SESSION = 1 << 10;
+ /**
+ * Modem feature indicating dedicated bearer capability.
+ * For services that require a high level QoS (eg. VoLTE), the network can create
+ * a dedicated bearer with the required QoS on top of an established default bearer.
+ * This will provide a dedicated tunnel for one or more specific traffic types.
+ */
+ public static final long MODEM_FEATURE_DEDICATED_BEARER = 1 << 11;
+ /** Modem feature indicating network scan capability. */
+ public static final long MODEM_FEATURE_NETWORK_SCAN = 1 << 12;
+ /** Modem feature indicating corresponding SIM has CDMA capability. */
+ public static final long MODEM_FEATURE_CSIM = 1 << 13;
+
/** @hide */
+ @LongDef(flag = true, prefix = {"MODEM_FEATURE_" }, value = {
+ MODEM_FEATURE_3GPP2_REG,
+ MODEM_FEATURE_3GPP_REG,
+ MODEM_FEATURE_CDMA2000_EHRPD_REG,
+ MODEM_FEATURE_GERAN_REG,
+ MODEM_FEATURE_UTRAN_REG,
+ MODEM_FEATURE_EUTRAN_REG,
+ MODEM_FEATURE_NGRAN_REG,
+ MODEM_FEATURE_EUTRA_NR_DUAL_CONNECTIVITY_REG,
+ MODEM_FEATURE_PS_VOICE_REG,
+ MODEM_FEATURE_CS_VOICE_SESSION,
+ MODEM_FEATURE_INTERACTIVE_DATA_SESSION,
+ MODEM_FEATURE_DEDICATED_BEARER,
+ MODEM_FEATURE_NETWORK_SCAN,
+ MODEM_FEATURE_CSIM,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ModemFeature {
+ }
+
+ /**
+ * Hardcoded default DSDS capability.
+ * @hide
+ */
public static final PhoneCapability DEFAULT_DSDS_CAPABILITY;
- // Hardcoded default Single SIM single standby capability.
- /** @hide */
+ /**
+ * Hardcoded default Single SIM single standby capability.
+ * @hide
+ */
public static final PhoneCapability DEFAULT_SSSS_CAPABILITY;
static {
- ModemInfo modemInfo1 = new ModemInfo(0, 0, true, true);
- ModemInfo modemInfo2 = new ModemInfo(1, 0, true, true);
+ List<List<Long>> capabilities = new ArrayList<>();
+ List<Long> modem1 = new ArrayList<>();
+ List<Long> modem2 = new ArrayList<>();
+ modem1.add(MODEM_FEATURE_GERAN_REG | MODEM_FEATURE_UTRAN_REG | MODEM_FEATURE_EUTRAN_REG
+ | MODEM_FEATURE_PS_VOICE_REG | MODEM_FEATURE_CS_VOICE_SESSION
+ | MODEM_FEATURE_INTERACTIVE_DATA_SESSION | MODEM_FEATURE_DEDICATED_BEARER);
+ modem2.add(MODEM_FEATURE_GERAN_REG | MODEM_FEATURE_UTRAN_REG | MODEM_FEATURE_EUTRAN_REG
+ | MODEM_FEATURE_PS_VOICE_REG | MODEM_FEATURE_INTERACTIVE_DATA_SESSION
+ | MODEM_FEATURE_DEDICATED_BEARER);
+ capabilities.add(modem1);
+ capabilities.add(modem2);
+ List<String> uuids = new ArrayList<>();
+ uuids.add("com.xxxx.lm0");
+ uuids.add("com.xxxx.lm1");
+ long rats = TelephonyManager.NETWORK_TYPE_BITMASK_GSM
+ | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS
+ | TelephonyManager.NETWORK_TYPE_BITMASK_EDGE
+ | TelephonyManager.NETWORK_TYPE_BITMASK_UMTS
+ | TelephonyManager.NETWORK_TYPE_BITMASK_LTE;
+ DEFAULT_DSDS_CAPABILITY = new PhoneCapability(0, 0, 0, 0, 0, rats, null, null, null, null,
+ uuids, null, capabilities);
- List<ModemInfo> logicalModemList = new ArrayList<>();
- logicalModemList.add(modemInfo1);
- logicalModemList.add(modemInfo2);
- DEFAULT_DSDS_CAPABILITY = new PhoneCapability(1, 1, 0, logicalModemList, false);
-
- logicalModemList = new ArrayList<>();
- logicalModemList.add(modemInfo1);
- DEFAULT_SSSS_CAPABILITY = new PhoneCapability(1, 1, 0, logicalModemList, false);
+ capabilities = new ArrayList<>();
+ capabilities.add(modem1);
+ uuids = new ArrayList<>();
+ uuids.add("com.xxxx.lm0");
+ DEFAULT_SSSS_CAPABILITY = new PhoneCapability(0, 0, 0, 0, 0, rats, null, null, null, null,
+ uuids, null, capabilities);
}
- /** @hide */
- public final int maxActiveVoiceCalls;
- /** @hide */
- public final int maxActiveData;
- /** @hide */
- public final int max5G;
- /** @hide */
- public final boolean validationBeforeSwitchSupported;
- /** @hide */
- public final List<ModemInfo> logicalModemList;
- /** @hide */
- public PhoneCapability(int maxActiveVoiceCalls, int maxActiveData, int max5G,
- List<ModemInfo> logicalModemList, boolean validationBeforeSwitchSupported) {
- this.maxActiveVoiceCalls = maxActiveVoiceCalls;
- this.maxActiveData = maxActiveData;
- this.max5G = max5G;
- // Make sure it's not null.
- this.logicalModemList = logicalModemList == null ? new ArrayList<>() : logicalModemList;
- this.validationBeforeSwitchSupported = validationBeforeSwitchSupported;
+ private final int mUtranUeCategoryDl;
+ private final int mUtranUeCategoryUl;
+ private final int mEutranUeCategoryDl;
+ private final int mEutranUeCategoryUl;
+ private final long mPsDataConnectionLingerTimeMillis;
+ private final @NetworkTypeBitMask long mSupportedRats;
+ private final List<Integer> mGeranBands;
+ private final List<Integer> mUtranBands;
+ private final List<Integer> mEutranBands;
+ private final List<Integer> mNgranBands;
+ private final List<String> mLogicalModemUuids;
+ private final List<SimSlotCapability> mSimSlotCapabilities;
+ private final @ModemFeature List<List<Long>> mConcurrentFeaturesSupport;
+
+ /**
+ * Default constructor to create a PhoneCapability object.
+ * @param utranUeCategoryDl 3GPP UE category for UTRAN downlink.
+ * @param utranUeCategoryUl 3GPP UE category for UTRAN uplink.
+ * @param eutranUeCategoryDl 3GPP UE category for EUTRAN downlink.
+ * @param eutranUeCategoryUl 3GPP UE category for EUTRAN uplink.
+ * @param psDataConnectionLingerTimeMillis length of the grace period to allow a smooth
+ * "handover" between data connections.
+ * @param supportedRats all radio access technologies this phone is capable of supporting.
+ * @param geranBands list of supported {@link AccessNetworkConstants.GeranBand}.
+ * @param utranBands list of supported {@link AccessNetworkConstants.UtranBand}.
+ * @param eutranBands list of supported {@link AccessNetworkConstants.EutranBand}.
+ * @param ngranBands list of supported {@link AccessNetworkConstants.NgranBands}.
+ * @param logicalModemUuids list of logical modem UUIDs, typically of the form
+ * "com.xxxx.lmX", where X is the logical modem ID.
+ * @param simSlotCapabilities list of {@link SimSlotCapability} for the device
+ * @param concurrentFeaturesSupport list of list of concurrently supportable modem feature sets.
+ * @hide
+ */
+ public PhoneCapability(int utranUeCategoryDl, int utranUeCategoryUl, int eutranUeCategoryDl,
+ int eutranUeCategoryUl, long psDataConnectionLingerTimeMillis,
+ @NetworkTypeBitMask long supportedRats, @Nullable List<Integer> geranBands,
+ @Nullable List<Integer> utranBands, @Nullable List<Integer> eutranBands,
+ @Nullable List<Integer> ngranBands, @Nullable List<String> logicalModemUuids,
+ @Nullable List<SimSlotCapability> simSlotCapabilities,
+ @Nullable @ModemFeature List<List<Long>> concurrentFeaturesSupport) {
+ this.mUtranUeCategoryDl = utranUeCategoryDl;
+ this.mUtranUeCategoryUl = utranUeCategoryUl;
+ this.mEutranUeCategoryDl = eutranUeCategoryDl;
+ this.mEutranUeCategoryUl = eutranUeCategoryUl;
+ this.mPsDataConnectionLingerTimeMillis = psDataConnectionLingerTimeMillis;
+ this.mSupportedRats = supportedRats;
+ this.mGeranBands = CollectionUtils.emptyIfNull(geranBands);
+ this.mUtranBands = CollectionUtils.emptyIfNull(utranBands);
+ this.mEutranBands = CollectionUtils.emptyIfNull(eutranBands);
+ this.mNgranBands = CollectionUtils.emptyIfNull(ngranBands);
+ this.mLogicalModemUuids = CollectionUtils.emptyIfNull(logicalModemUuids);
+ this.mSimSlotCapabilities = CollectionUtils.emptyIfNull(simSlotCapabilities);
+ this.mConcurrentFeaturesSupport = CollectionUtils.emptyIfNull(concurrentFeaturesSupport);
+ }
+
+ private PhoneCapability(Parcel in) {
+ mUtranUeCategoryDl = in.readInt();
+ mUtranUeCategoryUl = in.readInt();
+ mEutranUeCategoryDl = in.readInt();
+ mEutranUeCategoryUl = in.readInt();
+ mPsDataConnectionLingerTimeMillis = in.readLong();
+ mSupportedRats = in.readLong();
+ mGeranBands = new ArrayList<>();
+ in.readList(mGeranBands, Integer.class.getClassLoader());
+ mUtranBands = new ArrayList<>();
+ in.readList(mUtranBands, Integer.class.getClassLoader());
+ mEutranBands = new ArrayList<>();
+ in.readList(mEutranBands, Integer.class.getClassLoader());
+ mNgranBands = new ArrayList<>();
+ in.readList(mNgranBands, Integer.class.getClassLoader());
+ mLogicalModemUuids = in.createStringArrayList();
+ mSimSlotCapabilities = in.createTypedArrayList(SimSlotCapability.CREATOR);
+ int length = in.readInt();
+ mConcurrentFeaturesSupport = new ArrayList<>();
+ for (int i = 0; i < length; i++) {
+ ArrayList<Long> feature = new ArrayList<>();
+ in.readList(feature, Long.class.getClassLoader());
+ mConcurrentFeaturesSupport.add(feature);
+ }
+ }
+
+ /**
+ * 3GPP UE category for a given Radio Access Network and direction.
+ *
+ * References are:
+ * TS 25.306 Table 4.1a EUTRAN downlink
+ * TS 25.306 Table 5.1a-2 EUTRAN uplink
+ * TS 25.306 Table 5.1a UTRAN downlink
+ * TS 25.306 Table 5.1g UTRAN uplink
+ *
+ * @param uplink true for uplink direction and false for downlink direction.
+ * @param accessNetworkType accessNetworkType, defined in {@link AccessNetworkType}.
+ * @return the UE category, or -1 if it is not supported.
+ */
+ public int getUeCategory(boolean uplink, @RadioAccessNetworkType int accessNetworkType) {
+ if (uplink) {
+ switch (accessNetworkType) {
+ case AccessNetworkType.UTRAN: return mUtranUeCategoryUl;
+ case AccessNetworkType.EUTRAN: return mEutranUeCategoryUl;
+ default: return -1;
+ }
+ } else {
+ switch (accessNetworkType) {
+ case AccessNetworkType.UTRAN: return mUtranUeCategoryDl;
+ case AccessNetworkType.EUTRAN: return mEutranUeCategoryDl;
+ default: return -1;
+ }
+ }
+ }
+
+ /**
+ * In cellular devices that support a greater number of logical modems than
+ * Internet connections, some devices support a grace period to allow a smooth "handover"
+ * between those connections. If that feature is supported, then this API will provide
+ * the length of that grace period in milliseconds. If it is not supported, the default value
+ * for the grace period is 0.
+ * @return handover linger time in milliseconds, or 0 if it is not supported.
+ */
+ public long getPsDataConnectionLingerTimeMillis() {
+ return mPsDataConnectionLingerTimeMillis;
+ }
+
+ /**
+ * The radio access technologies this device is capable of supporting.
+ * @return a bitfield of all supported network types, defined in {@link TelephonyManager}
+ */
+ public @NetworkTypeBitMask long getSupportedRats() {
+ return mSupportedRats;
+ }
+
+ /**
+ * List of supported cellular bands for the given accessNetworkType.
+ * @param accessNetworkType accessNetworkType, defined in {@link AccessNetworkType}.
+ * @return a list of bands, or an empty list if the access network type is unsupported.
+ */
+ public @NonNull List<Integer> getBands(@RadioAccessNetworkType int accessNetworkType) {
+ switch (accessNetworkType) {
+ case AccessNetworkType.GERAN: return mGeranBands;
+ case AccessNetworkType.UTRAN: return mUtranBands;
+ case AccessNetworkType.EUTRAN: return mEutranBands;
+ case AccessNetworkType.NGRAN: return mNgranBands;
+ default: return new ArrayList<>();
+ }
+ }
+
+ /**
+ * List of logical modem UUIDs, each typically "com.xxxx.lmX", where X is the logical modem ID.
+ * @return a list of modem UUIDs, one for every logical modem the device has.
+ */
+ public @NonNull List<String> getLogicalModemUuids() {
+ return mLogicalModemUuids;
+ }
+
+ /**
+ * List of {@link SimSlotCapability} for the device. The order of SIMs corresponds to the
+ * order of modems in {@link #getLogicalModemUuids}.
+ * @return a list of SIM slot capabilities, one for every SIM slot the device has.
+ */
+ public @NonNull List<SimSlotCapability> getSimSlotCapabilities() {
+ return mSimSlotCapabilities;
+ }
+
+ /**
+ * A List of Lists of concurrently supportable modem feature sets.
+ *
+ * Each entry in the top-level list is an independent configuration across all modems
+ * that describes the capabilities of the device as a whole.
+ *
+ * Each entry in the second-level list is a bitfield of ModemFeatures that describes
+ * the capabilities for a single modem. In the second-level list, the order of the modems
+ * corresponds to order of the UUIDs in {@link #getLogicalModemUuids}.
+ *
+ * For symmetric capabilities that can only be active on one modem at a time, there will be
+ * multiple configurations (equal to the number of modems) that shows it active on each modem.
+ * For asymmetric capabilities that are only available on one of the modems, all configurations
+ * will have that capability on just that one modem.
+ *
+ * The example below shows the concurrentFeaturesSupport for a 3-modem device with
+ * theoretical capabilities SYMMETRIC (available on all modems, but only one at a time) and
+ * ASYMMETRIC (only available on the first modem):
+ * {
+ * Configuration 1: ASYMMETRIC and SYMMETRIC on modem 1, modem 2 empty, modem 3 empty
+ * {(ASYMMETRIC | SYMMETRIC), (), ()},
+ *
+ * Configuration 2: ASYMMETRIC on modem 1, SYMMETRIC on modem 2, modem 3 empty
+ * {(ASYMMETRIC), (SYMMETRIC), ()},
+ *
+ * Configuration 3: ASYMMETRIC on modem 1, modem 2 empty, SYMMETRIC on modem 3
+ * {(ASYMMETRIC), (), (SYMMETRIC)}
+ * }
+ *
+ * @return List of all concurrently supportable modem features.
+ */
+ public @NonNull @ModemFeature List<List<Long>> getConcurrentFeaturesSupport() {
+ return mConcurrentFeaturesSupport;
+ }
+
+ /**
+ * How many modems can simultaneously have PS attached.
+ * @return maximum number of active PS voice connections.
+ */
+ public int getMaxActivePsVoice() {
+ return countFeature(MODEM_FEATURE_PS_VOICE_REG);
+ }
+
+ /**
+ * How many modems can simultaneously support active data connections.
+ * For DSDS, this will be 1, and for DSDA this will be 2.
+ * @return maximum number of active Internet data sessions.
+ */
+ public int getMaxActiveInternetData() {
+ return countFeature(MODEM_FEATURE_INTERACTIVE_DATA_SESSION);
+ }
+
+ /**
+ * How many modems can simultaneously have dedicated bearer capability.
+ * @return maximum number of active dedicated bearers.
+ */
+ public int getMaxActiveDedicatedBearers() {
+ return countFeature(MODEM_FEATURE_DEDICATED_BEARER);
+ }
+
+ /**
+ * Whether the CBRS band 48 is supported or not.
+ * @return true if any RadioAccessNetwork supports CBRS and false if none do.
+ * @hide
+ */
+ public boolean isCbrsSupported() {
+ return mEutranBands.contains(AccessNetworkConstants.EutranBand.BAND_48)
+ || mNgranBands.contains(AccessNetworkConstants.NgranBands.BAND_48);
+ }
+
+ private int countFeature(@ModemFeature long feature) {
+ int count = 0;
+ for (long featureSet : mConcurrentFeaturesSupport.get(0)) {
+ if ((featureSet & feature) != 0) {
+ count++;
+ }
+ }
+ return count;
}
@Override
public String toString() {
- return "maxActiveVoiceCalls=" + maxActiveVoiceCalls + " maxActiveData=" + maxActiveData
- + " max5G=" + max5G + "logicalModemList:"
- + Arrays.toString(logicalModemList.toArray());
- }
-
- private PhoneCapability(Parcel in) {
- maxActiveVoiceCalls = in.readInt();
- maxActiveData = in.readInt();
- max5G = in.readInt();
- validationBeforeSwitchSupported = in.readBoolean();
- logicalModemList = new ArrayList<>();
- in.readList(logicalModemList, ModemInfo.class.getClassLoader());
+ return "utranUeCategoryDl=" + mUtranUeCategoryDl
+ + " utranUeCategoryUl=" + mUtranUeCategoryUl
+ + " eutranUeCategoryDl=" + mEutranUeCategoryDl
+ + " eutranUeCategoryUl=" + mEutranUeCategoryUl
+ + " psDataConnectionLingerTimeMillis=" + mPsDataConnectionLingerTimeMillis
+ + " supportedRats=" + mSupportedRats + " geranBands=" + mGeranBands
+ + " utranBands=" + mUtranBands + " eutranBands=" + mEutranBands
+ + " ngranBands=" + mNgranBands + " logicalModemUuids=" + mLogicalModemUuids
+ + " simSlotCapabilities=" + mSimSlotCapabilities
+ + " concurrentFeaturesSupport=" + mConcurrentFeaturesSupport;
}
@Override
public int hashCode() {
- return Objects.hash(maxActiveVoiceCalls, maxActiveData, max5G, logicalModemList,
- validationBeforeSwitchSupported);
+ return Objects.hash(mUtranUeCategoryDl, mUtranUeCategoryUl, mEutranUeCategoryDl,
+ mEutranUeCategoryUl, mPsDataConnectionLingerTimeMillis, mSupportedRats, mGeranBands,
+ mUtranBands, mEutranBands, mNgranBands, mLogicalModemUuids, mSimSlotCapabilities,
+ mConcurrentFeaturesSupport);
}
@Override
@@ -107,11 +411,19 @@
PhoneCapability s = (PhoneCapability) o;
- return (maxActiveVoiceCalls == s.maxActiveVoiceCalls
- && maxActiveData == s.maxActiveData
- && max5G == s.max5G
- && validationBeforeSwitchSupported == s.validationBeforeSwitchSupported
- && logicalModemList.equals(s.logicalModemList));
+ return (mUtranUeCategoryDl == s.mUtranUeCategoryDl
+ && mUtranUeCategoryUl == s.mUtranUeCategoryUl
+ && mEutranUeCategoryDl == s.mEutranUeCategoryDl
+ && mEutranUeCategoryUl == s.mEutranUeCategoryUl
+ && mPsDataConnectionLingerTimeMillis == s.mPsDataConnectionLingerTimeMillis
+ && mSupportedRats == s.mSupportedRats
+ && mGeranBands.equals(s.mGeranBands)
+ && mUtranBands.equals(s.mUtranBands)
+ && mEutranBands.equals(s.mEutranBands)
+ && mNgranBands.equals(s.mNgranBands)
+ && mLogicalModemUuids.equals(s.mLogicalModemUuids)
+ && mSimSlotCapabilities.equals(s.mSimSlotCapabilities)
+ && mConcurrentFeaturesSupport.equals(s.mConcurrentFeaturesSupport));
}
/**
@@ -125,20 +437,32 @@
* {@link Parcelable#writeToParcel}
*/
public void writeToParcel(@NonNull Parcel dest, @Parcelable.WriteFlags int flags) {
- dest.writeInt(maxActiveVoiceCalls);
- dest.writeInt(maxActiveData);
- dest.writeInt(max5G);
- dest.writeBoolean(validationBeforeSwitchSupported);
- dest.writeList(logicalModemList);
+ dest.writeInt(mUtranUeCategoryDl);
+ dest.writeInt(mUtranUeCategoryUl);
+ dest.writeInt(mEutranUeCategoryDl);
+ dest.writeInt(mEutranUeCategoryUl);
+ dest.writeLong(mPsDataConnectionLingerTimeMillis);
+ dest.writeLong(mSupportedRats);
+ dest.writeList(mGeranBands);
+ dest.writeList(mUtranBands);
+ dest.writeList(mEutranBands);
+ dest.writeList(mNgranBands);
+ dest.writeStringList(mLogicalModemUuids);
+ dest.writeTypedList(mSimSlotCapabilities);
+ dest.writeInt(mConcurrentFeaturesSupport.size());
+ for (List<Long> feature : mConcurrentFeaturesSupport) {
+ dest.writeList(feature);
+ }
}
- public static final @android.annotation.NonNull Parcelable.Creator<PhoneCapability> CREATOR = new Parcelable.Creator() {
- public PhoneCapability createFromParcel(Parcel in) {
- return new PhoneCapability(in);
- }
+ public static final @NonNull Parcelable.Creator<PhoneCapability> CREATOR =
+ new Parcelable.Creator() {
+ public PhoneCapability createFromParcel(Parcel in) {
+ return new PhoneCapability(in);
+ }
- public PhoneCapability[] newArray(int size) {
- return new PhoneCapability[size];
- }
- };
+ public PhoneCapability[] newArray(int size) {
+ return new PhoneCapability[size];
+ }
+ };
}
diff --git a/telephony/java/android/telephony/PhoneNumberRange.java b/telephony/java/android/telephony/PhoneNumberRange.java
index e6f107e..2b199d2 100644
--- a/telephony/java/android/telephony/PhoneNumberRange.java
+++ b/telephony/java/android/telephony/PhoneNumberRange.java
@@ -85,18 +85,18 @@
}
private PhoneNumberRange(Parcel in) {
- mCountryCode = in.readStringNoHelper();
- mPrefix = in.readStringNoHelper();
- mLowerBound = in.readStringNoHelper();
- mUpperBound = in.readStringNoHelper();
+ mCountryCode = in.readString();
+ mPrefix = in.readString();
+ mLowerBound = in.readString();
+ mUpperBound = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeStringNoHelper(mCountryCode);
- dest.writeStringNoHelper(mPrefix);
- dest.writeStringNoHelper(mLowerBound);
- dest.writeStringNoHelper(mUpperBound);
+ dest.writeString(mCountryCode);
+ dest.writeString(mPrefix);
+ dest.writeString(mLowerBound);
+ dest.writeString(mUpperBound);
}
@Override
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 2f9e6ac..0074772 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -28,7 +28,6 @@
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 @@
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 @@
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/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index 4c090b8..0cfb8c5 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -20,6 +20,9 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.LinkProperties;
import android.os.Build;
@@ -31,8 +34,6 @@
import android.telephony.Annotation.NetworkType;
import android.telephony.data.ApnSetting;
-import dalvik.system.VMRuntime;
-
import java.util.Objects;
@@ -81,18 +82,20 @@
/**
- * Constructor
+ * Constructor of PreciseDataConnectionState
*
* @param state the state of the data connection
* @param networkType the access network that is/would carry this data connection
* @param apnTypes the APN types that this data connection carries
- * @param apnSetting if there is a valid APN for this Data Connection, then the APN Settings;
- * if there is no valid APN setting for the specific type, then this will be null
+ * @param apn the APN of this data connection
* @param linkProperties if the data connection is connected, the properties of the connection
* @param failCause in case a procedure related to this data connection fails, a non-zero error
* code indicating the cause of the failure.
+ * @param apnSetting if there is a valid APN for this Data Connection, then the APN Settings;
+ * if there is no valid APN setting for the specific type, then this will be null
* @hide
*/
+ @SystemApi
public PreciseDataConnectionState(@DataState int state,
@NetworkType int networkType,
@ApnType int apnTypes, @NonNull String apn,
@@ -132,6 +135,13 @@
}
/**
+ * To check the SDK version for {@link PreciseDataConnectionState#getDataConnectionState}.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+ private static final long GET_DATA_CONNECTION_STATE_CODE_CHANGE = 147600208L;
+
+ /**
* Returns the state of data connection that supported the apn types returned by
* {@link #getDataConnectionApnTypeBitMask()}
*
@@ -142,7 +152,7 @@
@SystemApi
public @DataState int getDataConnectionState() {
if (mState == TelephonyManager.DATA_DISCONNECTING
- && VMRuntime.getRuntime().getTargetSdkVersion() < Build.VERSION_CODES.R) {
+ && !Compatibility.isChangeEnabled(GET_DATA_CONNECTION_STATE_CODE_CHANGE)) {
return TelephonyManager.DATA_CONNECTED;
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 2c62d06..ed003ed 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -16,8 +16,6 @@
package android.telephony;
-import com.android.telephony.Rlog;
-
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -36,6 +34,8 @@
import android.telephony.NetworkRegistrationInfo.NRState;
import android.text.TextUtils;
+import com.android.telephony.Rlog;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -584,8 +584,8 @@
*/
@DuplexMode
public int getDuplexMode() {
- // only support LTE duplex mode
- if (!isLte(getRilDataRadioTechnology())) {
+ // support LTE/NR duplex mode
+ if (!isPsOnlyTech(getRilDataRadioTechnology())) {
return DUPLEX_MODE_UNKNOWN;
}
@@ -1624,7 +1624,8 @@
* @return Current data network type
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @SystemApi
+ @TestApi
public @NetworkType int getDataNetworkType() {
final NetworkRegistrationInfo iwlanRegInfo = getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
@@ -1717,9 +1718,10 @@
}
/** @hide */
- public static boolean isLte(int radioTechnology) {
- return radioTechnology == RIL_RADIO_TECHNOLOGY_LTE ||
- radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA;
+ public static boolean isPsOnlyTech(int radioTechnology) {
+ return radioTechnology == RIL_RADIO_TECHNOLOGY_LTE
+ || radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA
+ || radioTechnology == RIL_RADIO_TECHNOLOGY_NR;
}
/** @hide */
@@ -1835,10 +1837,8 @@
* Get all of the available network registration info.
*
* @return List of {@link NetworkRegistrationInfo}
- * @hide
*/
@NonNull
- @SystemApi
public List<NetworkRegistrationInfo> getNetworkRegistrationInfoList() {
synchronized (mNetworkRegistrationInfos) {
List<NetworkRegistrationInfo> newList = new ArrayList<>();
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 4ff1aab..483ccc4 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -16,15 +16,18 @@
package android.telephony;
-import com.android.telephony.Rlog;
-
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
+import android.os.SystemClock;
+
+import com.android.telephony.Rlog;
import java.util.ArrayList;
import java.util.List;
@@ -76,6 +79,9 @@
/* The type of signal measurement */
private static final String MEASUREMENT_TYPE_RSCP = "rscp";
+ // timeStamp of signalStrength in nanoseconds since boot
+ private long mTimestamp = Long.MAX_VALUE;
+
CellSignalStrengthCdma mCdma;
CellSignalStrengthGsm mGsm;
CellSignalStrengthWcdma mWcdma;
@@ -134,6 +140,7 @@
mTdscdma = tdscdma;
mLte = lte;
mNr = nr;
+ mTimestamp = SystemClock.elapsedRealtimeNanos();
}
/**
@@ -268,6 +275,7 @@
mTdscdma.updateLevel(cc, ss);
mLte.updateLevel(cc, ss);
mNr.updateLevel(cc, ss);
+ mTimestamp = SystemClock.elapsedRealtimeNanos();
}
/**
@@ -277,8 +285,8 @@
*
* @hide
*/
- @UnsupportedAppUsage
- public SignalStrength(SignalStrength s) {
+ @SystemApi
+ public SignalStrength(@NonNull SignalStrength s) {
copyFrom(s);
}
@@ -293,6 +301,7 @@
mTdscdma = new CellSignalStrengthTdscdma(s.mTdscdma);
mLte = new CellSignalStrengthLte(s.mLte);
mNr = new CellSignalStrengthNr(s.mNr);
+ mTimestamp = s.getTimestampNanos();
}
/**
@@ -310,6 +319,7 @@
mTdscdma = in.readParcelable(CellSignalStrengthTdscdma.class.getClassLoader());
mLte = in.readParcelable(CellSignalStrengthLte.class.getClassLoader());
mNr = in.readParcelable(CellSignalStrengthLte.class.getClassLoader());
+ mTimestamp = in.readLong();
}
/**
@@ -322,9 +332,18 @@
out.writeParcelable(mTdscdma, flags);
out.writeParcelable(mLte, flags);
out.writeParcelable(mNr, flags);
+ out.writeLong(mTimestamp);
}
/**
+ * @return mTimestamp in nanoseconds
+ */
+ @SuppressLint("MethodNameUnits")
+ public long getTimestampNanos() {
+ return mTimestamp;
+ }
+
+ /**
* {@link Parcelable#describeContents}
*/
public int describeContents() {
diff --git a/telephony/java/android/telephony/SimSlotCapability.java b/telephony/java/android/telephony/SimSlotCapability.java
new file mode 100644
index 0000000..3d38d04
--- /dev/null
+++ b/telephony/java/android/telephony/SimSlotCapability.java
@@ -0,0 +1,130 @@
+/*
+ * 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.telephony;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Capabilities for a SIM Slot.
+ */
+public final class SimSlotCapability implements Parcelable {
+ /** Slot type for UICC (removable SIM). */
+ public static final int SLOT_TYPE_UICC = 1;
+ /** Slot type for iUICC/iSIM (integrated SIM). */
+ public static final int SLOT_TYPE_IUICC = 2;
+ /** Slot type for eUICC/eSIM (embedded SIM). */
+ public static final int SLOT_TYPE_EUICC = 3;
+ /** Slot type for soft SIM (no physical SIM). */
+ public static final int SLOT_TYPE_SOFT_SIM = 4;
+
+ /** @hide */
+ @IntDef(prefix = {"SLOT_TYPE_" }, value = {
+ SLOT_TYPE_UICC,
+ SLOT_TYPE_IUICC,
+ SLOT_TYPE_EUICC,
+ SLOT_TYPE_SOFT_SIM,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SlotType {
+ }
+
+ private final int mPhysicalSlotIndex;
+ private final int mSlotType;
+
+ /** @hide */
+ public SimSlotCapability(int physicalSlotId, int slotType) {
+ this.mPhysicalSlotIndex = physicalSlotId;
+ this.mSlotType = slotType;
+ }
+
+ private SimSlotCapability(Parcel in) {
+ mPhysicalSlotIndex = in.readInt();
+ mSlotType = in.readInt();
+ }
+
+ /**
+ * @return physical SIM slot index
+ */
+ public int getPhysicalSlotIndex() {
+ return mPhysicalSlotIndex;
+ }
+
+ /**
+ * @return type of SIM {@link SlotType}
+ */
+ public @SlotType int getSlotType() {
+ return mSlotType;
+ }
+
+ @Override
+ public String toString() {
+ return "mPhysicalSlotIndex=" + mPhysicalSlotIndex + " slotType=" + mSlotType;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPhysicalSlotIndex, mSlotType);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || !(o instanceof SimSlotCapability) || hashCode() != o.hashCode()) {
+ return false;
+ }
+
+ if (this == o) {
+ return true;
+ }
+
+ SimSlotCapability s = (SimSlotCapability) o;
+
+ return (mPhysicalSlotIndex == s.mPhysicalSlotIndex && mSlotType == s.mSlotType);
+ }
+
+ /**
+ * {@link Parcelable#describeContents}
+ */
+ public @ContentsFlags int describeContents() {
+ return 0;
+ }
+
+ /**
+ * {@link Parcelable#writeToParcel}
+ */
+ public void writeToParcel(@NonNull Parcel dest, @WriteFlags int flags) {
+ dest.writeInt(mPhysicalSlotIndex);
+ dest.writeInt(mSlotType);
+ }
+
+ public static final @NonNull Parcelable.Creator<SimSlotCapability> CREATOR =
+ new Parcelable.Creator() {
+ public SimSlotCapability createFromParcel(Parcel in) {
+ return new SimSlotCapability(in);
+ }
+
+ public SimSlotCapability[] newArray(int size) {
+ return new SimSlotCapability[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index db90550..e7b2613 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -25,11 +25,12 @@
import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.app.ActivityThread;
import android.app.PendingIntent;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.database.CursorWindow;
import android.net.Uri;
import android.os.Build;
@@ -388,7 +389,7 @@
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- true /* persistMessage*/, ActivityThread.currentPackageName());
+ true /* persistMessage*/, null);
}
/**
@@ -598,7 +599,7 @@
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- false /* persistMessage */, ActivityThread.currentPackageName());
+ false /* persistMessage */, null);
}
private void sendTextMessageInternal(
@@ -641,7 +642,7 @@
ISms iSms = getISmsServiceOrThrow();
if (iSms != null) {
iSms.sendTextForSubscriberWithOptions(subId,
- ActivityThread.currentPackageName(), destinationAddress,
+ null, destinationAddress,
scAddress,
text, sentIntent, deliveryIntent, persistMessage, finalPriority,
expectMore, finalValidity);
@@ -663,7 +664,7 @@
ISms iSms = getISmsServiceOrThrow();
if (iSms != null) {
iSms.sendTextForSubscriberWithOptions(getSubscriptionId(),
- ActivityThread.currentPackageName(), destinationAddress,
+ null, destinationAddress,
scAddress,
text, sentIntent, deliveryIntent, persistMessage, finalPriority,
expectMore, finalValidity);
@@ -881,7 +882,7 @@
String destinationAddress, String scAddress, ArrayList<String> parts,
ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, true /* persistMessage*/, ActivityThread.currentPackageName());
+ deliveryIntents, true /* persistMessage*/, null);
}
/**
@@ -898,8 +899,9 @@
* subscription.
* </p>
*
- * @param packageName serves as the default package name if
- * {@link ActivityThread#currentPackageName()} is null.
+ * @param packageName serves as the default package name if the package name that is
+ * associated with the user id is null.
+ *
* @hide
*/
@SystemApi
@@ -909,9 +911,7 @@
@NonNull List<String> parts, @Nullable List<PendingIntent> sentIntents,
@Nullable List<PendingIntent> deliveryIntents, @NonNull String packageName) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, true /* persistMessage*/,
- ActivityThread.currentPackageName() == null
- ? packageName : ActivityThread.currentPackageName());
+ deliveryIntents, true /* persistMessage*/, packageName);
}
private void sendMultipartTextMessageInternal(
@@ -1012,7 +1012,7 @@
String destinationAddress, String scAddress, List<String> parts,
List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, false /* persistMessage*/, ActivityThread.currentPackageName());
+ deliveryIntents, false /* persistMessage*/, null);
}
/**
@@ -1174,7 +1174,7 @@
ISms iSms = getISmsServiceOrThrow();
if (iSms != null) {
iSms.sendMultipartTextForSubscriberWithOptions(subId,
- ActivityThread.currentPackageName(), destinationAddress,
+ null, destinationAddress,
scAddress, parts, sentIntents, deliveryIntents,
persistMessage, finalPriority, expectMore, finalValidity);
}
@@ -1196,7 +1196,7 @@
ISms iSms = getISmsServiceOrThrow();
if (iSms != null) {
iSms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(),
- ActivityThread.currentPackageName(), destinationAddress,
+ null, destinationAddress,
scAddress, parts, sentIntents, deliveryIntents,
persistMessage, finalPriority, expectMore, finalValidity);
}
@@ -1327,7 +1327,7 @@
public void onSuccess(int subId) {
try {
ISms iSms = getISmsServiceOrThrow();
- iSms.sendDataForSubscriber(subId, ActivityThread.currentPackageName(),
+ iSms.sendDataForSubscriber(subId, null,
destinationAddress, scAddress, destinationPort & 0xFFFF, data,
sentIntent, deliveryIntent);
} catch (RemoteException e) {
@@ -1453,7 +1453,6 @@
private void resolveSubscriptionForOperation(SubscriptionResolverResult resolverResult) {
int subId = getSubscriptionId();
boolean isSmsSimPickActivityNeeded = false;
- final Context context = ActivityThread.currentApplication().getApplicationContext();
try {
ISms iSms = getISmsService();
if (iSms != null) {
@@ -1475,14 +1474,14 @@
return;
}
// We need to ask the user pick an appropriate subid for the operation.
- Log.d(TAG, "resolveSubscriptionForOperation isSmsSimPickActivityNeeded is true for package "
- + context.getPackageName());
+ Log.d(TAG, "resolveSubscriptionForOperation isSmsSimPickActivityNeeded is true for calling"
+ + " package. ");
try {
// Create the SMS pick activity and call back once the activity is complete. Can't do
// it here because we do not have access to the activity context that is performing this
// operation.
// Requires that the calling process has the SEND_SMS permission.
- getITelephony().enqueueSmsPickResult(context.getOpPackageName(),
+ getITelephony().enqueueSmsPickResult(null,
new IIntegerConsumer.Stub() {
@Override
public void accept(int subId) {
@@ -1500,6 +1499,13 @@
}
}
+ /**
+ * To check the SDK version for SmsManager.sendResolverResult method.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P)
+ private static final long GET_TARGET_SDK_VERSION_CODE_CHANGE = 145147528L;
+
private void sendResolverResult(SubscriptionResolverResult resolverResult, int subId,
boolean pickActivityShown) {
if (SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -1507,7 +1513,8 @@
return;
}
- if (getTargetSdkVersion() <= Build.VERSION_CODES.P && !pickActivityShown) {
+ if (!Compatibility.isChangeEnabled(GET_TARGET_SDK_VERSION_CODE_CHANGE)
+ && !pickActivityShown) {
// Do not fail, return a success with an INVALID subid for apps targeting P or below
// that tried to perform an operation and the SMS disambiguation dialog was never shown,
// as these applications may not have been written to handle the failure case properly.
@@ -1520,19 +1527,6 @@
}
}
- private static int getTargetSdkVersion() {
- final Context context = ActivityThread.currentApplication().getApplicationContext();
- int targetSdk;
- try {
- targetSdk = context.getPackageManager().getApplicationInfo(
- context.getOpPackageName(), 0).targetSdkVersion;
- } catch (PackageManager.NameNotFoundException e) {
- // Default to old behavior if we can not find this.
- targetSdk = -1;
- }
- return targetSdk;
- }
-
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
ServiceManager.getService(Context.TELEPHONY_SERVICE));
@@ -1577,7 +1571,7 @@
}
/**
- * 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,27 +1585,32 @@
* 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();
if (iSms != null) {
success = iSms.copyMessageToIccEfForSubscriber(getSubscriptionId(),
- ActivityThread.currentPackageName(),
+ null,
status, pdu, smsc);
}
} catch (RemoteException ex) {
@@ -1622,7 +1621,7 @@
}
/**
- * 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.
*
@@ -1652,7 +1651,7 @@
ISms iSms = getISmsService();
if (iSms != null) {
success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
- ActivityThread.currentPackageName(),
+ null,
messageIndex, STATUS_ON_ICC_FREE, null /* pdu */);
}
} catch (RemoteException ex) {
@@ -1695,7 +1694,7 @@
ISms iSms = getISmsService();
if (iSms != null) {
success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
- ActivityThread.currentPackageName(),
+ null,
messageIndex, newStatus, pdu);
}
} catch (RemoteException ex) {
@@ -1706,7 +1705,7 @@
}
/**
- * 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.
*
@@ -1747,7 +1746,7 @@
if (iSms != null) {
records = iSms.getAllMessagesFromIccEfForSubscriber(
getSubscriptionId(),
- ActivityThread.currentPackageName());
+ null);
}
} catch (RemoteException ex) {
// ignore it
@@ -1872,8 +1871,7 @@
}
/**
- * 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 +1883,7 @@
* 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 +1894,7 @@
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 +2034,17 @@
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). */
@@ -2425,16 +2433,6 @@
/** Intent extra name for HTTP status code for MMS HTTP failure in integer type */
public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
- /** Represents the received SMS message for importing {@hide} */
- public static final int SMS_TYPE_INCOMING = 0;
- /** Represents the sent SMS message for importing {@hide} */
- public static final int SMS_TYPE_OUTGOING = 1;
-
- /** Message status property: whether the message has been seen. 1 means seen, 0 not {@hide} */
- public static final String MESSAGE_STATUS_SEEN = "seen";
- /** Message status property: whether the message has been read. 1 means read, 0 not {@hide} */
- public static final String MESSAGE_STATUS_READ = "read";
-
/**
* Get carrier-dependent MMS configuration values.
*
@@ -2491,7 +2489,7 @@
try {
ISms iccSms = getISmsServiceOrThrow();
return iccSms.createAppSpecificSmsToken(getSubscriptionId(),
- ActivityThread.currentPackageName(), intent);
+ null, intent);
} catch (RemoteException ex) {
ex.rethrowFromSystemServer();
@@ -2611,7 +2609,7 @@
try {
ISms iccSms = getISmsServiceOrThrow();
return iccSms.createAppSpecificSmsTokenWithPackageInfo(getSubscriptionId(),
- ActivityThread.currentPackageName(), prefixes, intent);
+ null, prefixes, intent);
} catch (RemoteException ex) {
ex.rethrowFromSystemServer();
@@ -2702,7 +2700,7 @@
ISms iccISms = getISmsServiceOrThrow();
if (iccISms != null) {
return iccISms.checkSmsShortCodeDestination(getSubscriptionId(),
- ActivityThread.currentPackageName(), null, destAddress, countryIso);
+ null, null, destAddress, countryIso);
}
} catch (RemoteException e) {
Log.e(TAG, "checkSmsShortCodeDestination() RemoteException", e);
@@ -2738,7 +2736,7 @@
ISms iSms = getISmsService();
if (iSms != null) {
smsc = iSms.getSmscAddressFromIccEfForSubscriber(
- getSubscriptionId(), ActivityThread.currentPackageName());
+ getSubscriptionId(), null);
}
} catch (RemoteException ex) {
// ignore it
@@ -2772,7 +2770,7 @@
ISms iSms = getISmsService();
if (iSms != null) {
return iSms.setSmscAddressOnIccEfForSubscriber(
- smsc, getSubscriptionId(), ActivityThread.currentPackageName());
+ smsc, getSubscriptionId(), null);
}
} catch (RemoteException ex) {
// ignore it
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index b708b3f..8d9b1dd 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -278,41 +278,24 @@
}
/**
- * 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
@@ -332,6 +315,34 @@
}
/**
+ * Create an SmsMessage from a native SMS-Submit PDU, specified by Bluetooth Message Access
+ * Profile Specification v1.4.2 5.8.
+ * This is used by Bluetooth MAP profile to decode message when sending non UTF-8 SMS messages.
+ *
+ * @param data Message data.
+ * @param isCdma Indicates weather the type of the SMS is CDMA.
+ * @return An SmsMessage representing the message.
+ *
+ * @hide
+ */
+ @SystemApi
+ @Nullable
+ public static SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) {
+ SmsMessageBase wrappedMessage;
+
+ if (isCdma) {
+ wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord(
+ 0, data);
+ } else {
+ // Bluetooth uses its own method to decode GSM PDU so this part is not called.
+ wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord(
+ 0, data);
+ }
+
+ return wrappedMessage != null ? new SmsMessage(wrappedMessage) : null;
+ }
+
+ /**
* Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the
* length in bytes (not hex chars) less the SMSC header
*
@@ -574,13 +585,15 @@
*/
/**
- * 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) {
@@ -593,17 +606,16 @@
}
/**
- * 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,
@@ -621,17 +633,16 @@
}
/**
- * Get an SMS-SUBMIT PDU for a data message to a destination address & port.
+ * Gets an SMS-SUBMIT PDU for a data message to a destination address & 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,
@@ -649,6 +660,55 @@
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/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 2d8e237..832771d 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -16,8 +16,6 @@
package android.telephony;
-import com.android.telephony.Rlog;
-
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -40,6 +38,7 @@
import android.util.Log;
import com.android.internal.telephony.util.TelephonyUtils;
+import com.android.telephony.Rlog;
import java.util.ArrayList;
import java.util.Arrays;
@@ -685,8 +684,8 @@
int id = source.readInt();
String iccId = source.readString();
int simSlotIndex = source.readInt();
- CharSequence displayName = source.readCharSequence();
- CharSequence carrierName = source.readCharSequence();
+ CharSequence displayName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
+ CharSequence carrierName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
int nameSource = source.readInt();
int iconTint = source.readInt();
String number = source.readString();
@@ -705,8 +704,8 @@
int carrierid = source.readInt();
int profileClass = source.readInt();
int subType = source.readInt();
- String[] ehplmns = source.readStringArray();
- String[] hplmns = source.readStringArray();
+ String[] ehplmns = source.createStringArray();
+ String[] hplmns = source.createStringArray();
String groupOwner = source.readString();
UiccAccessRule[] carrierConfigAccessRules = source.createTypedArray(
UiccAccessRule.CREATOR);
@@ -732,8 +731,8 @@
dest.writeInt(mId);
dest.writeString(mIccId);
dest.writeInt(mSimSlotIndex);
- dest.writeCharSequence(mDisplayName);
- dest.writeCharSequence(mCarrierName);
+ TextUtils.writeToParcel(mDisplayName, dest, 0);
+ TextUtils.writeToParcel(mCarrierName, dest, 0);
dest.writeInt(mNameSource);
dest.writeInt(mIconTint);
dest.writeString(mNumber);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index d4ab04cc..ea95aac 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -266,7 +266,7 @@
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id";
+ public static final String UNIQUE_KEY_SUBSCRIPTION_ID = SimInfo.UNIQUE_KEY_SUBSCRIPTION_ID;
/**
* TelephonyProvider column name for a unique identifier for the subscription within the
@@ -275,18 +275,18 @@
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String ICC_ID = "icc_id";
+ public static final String ICC_ID = SimInfo.ICC_ID;
/**
* TelephonyProvider column name for user SIM_SlOT_INDEX
* <P>Type: INTEGER (int)</P>
*/
/** @hide */
- public static final String SIM_SLOT_INDEX = "sim_id";
+ public static final String SIM_SLOT_INDEX = SimInfo.SIM_SLOT_INDEX;
/** SIM is not inserted */
/** @hide */
- public static final int SIM_NOT_INSERTED = -1;
+ public static final int SIM_NOT_INSERTED = SimInfo.SIM_NOT_INSERTED;
/**
* The slot-index for Bluetooth Remote-SIM subscriptions
@@ -301,23 +301,7 @@
* Default value is 0.
*/
/** @hide */
- public static final String SUBSCRIPTION_TYPE = "subscription_type";
-
- /**
- * TelephonyProvider column name white_listed_apn_data.
- * It's a bitmask of APN types that will be allowed on this subscription even if it's metered
- * and mobile data is turned off by the user.
- * <P>Type: INTEGER (int)</P> For example, if TYPE_MMS is is true, Telephony will allow MMS
- * data connection to setup even if MMS is metered and mobile_data is turned off on that
- * subscription.
- *
- * Default value is 0.
- *
- * @deprecated Replaced by {@link #DATA_ENABLED_OVERRIDE_RULES}
- * @hide
- */
- @Deprecated
- public static final String WHITE_LISTED_APN_DATA = "white_listed_apn_data";
+ public static final String SUBSCRIPTION_TYPE = SimInfo.SUBSCRIPTION_TYPE;
/**
* TelephonyProvider column name data_enabled_override_rules.
@@ -330,7 +314,15 @@
*
* @hide
*/
- public static final String DATA_ENABLED_OVERRIDE_RULES = "data_enabled_override_rules";
+ public static final String DATA_ENABLED_OVERRIDE_RULES = SimInfo.DATA_ENABLED_OVERRIDE_RULES;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"SUBSCRIPTION_TYPE_"},
+ value = {
+ SUBSCRIPTION_TYPE_LOCAL_SIM,
+ SUBSCRIPTION_TYPE_REMOTE_SIM})
+ public @interface SubscriptionType {}
/**
* This constant is to designate a subscription as a Local-SIM Subscription.
@@ -338,7 +330,7 @@
* device.
* </p>
*/
- public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = 0;
+ public static final int SUBSCRIPTION_TYPE_LOCAL_SIM = SimInfo.SUBSCRIPTION_TYPE_LOCAL_SIM;
/**
* This constant is to designate a subscription as a Remote-SIM Subscription.
@@ -364,29 +356,21 @@
* was never seen before.
* </p>
*/
- public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = 1;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = {"SUBSCRIPTION_TYPE_"},
- value = {
- SUBSCRIPTION_TYPE_LOCAL_SIM,
- SUBSCRIPTION_TYPE_REMOTE_SIM})
- public @interface SubscriptionType {}
+ public static final int SUBSCRIPTION_TYPE_REMOTE_SIM = SimInfo.SUBSCRIPTION_TYPE_REMOTE_SIM;
/**
* TelephonyProvider column name for user displayed name.
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String DISPLAY_NAME = "display_name";
+ public static final String DISPLAY_NAME = SimInfo.DISPLAY_NAME;
/**
* TelephonyProvider column name for the service provider name for the SIM.
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String CARRIER_NAME = "carrier_name";
+ public static final String CARRIER_NAME = SimInfo.CARRIER_NAME;
/**
* Default name resource
@@ -400,44 +384,44 @@
*
* @hide
*/
- public static final String NAME_SOURCE = "name_source";
+ public static final String NAME_SOURCE = SimInfo.NAME_SOURCE;
/**
* The name_source is the default, which is from the carrier id.
* @hide
*/
- public static final int NAME_SOURCE_DEFAULT_SOURCE = 0;
+ public static final int NAME_SOURCE_DEFAULT = SimInfo.NAME_SOURCE_DEFAULT;
/**
* The name_source is from SIM EF_SPN.
* @hide
*/
- public static final int NAME_SOURCE_SIM_SPN = 1;
+ public static final int NAME_SOURCE_SIM_SPN = SimInfo.NAME_SOURCE_SIM_SPN;
/**
* The name_source is from user input
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public static final int NAME_SOURCE_USER_INPUT = 2;
+ public static final int NAME_SOURCE_USER_INPUT = SimInfo.NAME_SOURCE_USER_INPUT;
/**
* The name_source is carrier (carrier app, carrier config, etc.)
* @hide
*/
- public static final int NAME_SOURCE_CARRIER = 3;
+ public static final int NAME_SOURCE_CARRIER = SimInfo.NAME_SOURCE_CARRIER;
/**
* The name_source is from SIM EF_PNN.
* @hide
*/
- public static final int NAME_SOURCE_SIM_PNN = 4;
+ public static final int NAME_SOURCE_SIM_PNN = SimInfo.NAME_SOURCE_SIM_PNN;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"NAME_SOURCE_"},
value = {
- NAME_SOURCE_DEFAULT_SOURCE,
+ NAME_SOURCE_DEFAULT,
NAME_SOURCE_SIM_SPN,
NAME_SOURCE_USER_INPUT,
NAME_SOURCE_CARRIER,
@@ -450,67 +434,30 @@
* <P>Type: INTEGER (int)</P>
*/
/** @hide */
- public static final String COLOR = "color";
-
- /** @hide */
- public static final int COLOR_1 = 0;
-
- /** @hide */
- public static final int COLOR_2 = 1;
-
- /** @hide */
- public static final int COLOR_3 = 2;
-
- /** @hide */
- public static final int COLOR_4 = 3;
-
- /** @hide */
- public static final int COLOR_DEFAULT = COLOR_1;
+ public static final String COLOR = SimInfo.COLOR;
/**
* TelephonyProvider column name for the phone number of a SIM.
* <P>Type: TEXT (String)</P>
*/
/** @hide */
- public static final String NUMBER = "number";
+ public static final String NUMBER = SimInfo.NUMBER;
/**
- * TelephonyProvider column name for the number display format of a SIM.
+ * TelephonyProvider column name for whether data roaming is enabled.
* <P>Type: INTEGER (int)</P>
*/
/** @hide */
- public static final String DISPLAY_NUMBER_FORMAT = "display_number_format";
-
- /** @hide */
- public static final int DISPLAY_NUMBER_NONE = 0;
-
- /** @hide */
- public static final int DISPLAY_NUMBER_FIRST = 1;
-
- /** @hide */
- public static final int DISPLAY_NUMBER_LAST = 2;
-
- /** @hide */
- public static final int DISPLAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST;
-
- /**
- * TelephonyProvider column name for permission for data roaming of a SIM.
- * <P>Type: INTEGER (int)</P>
- */
- /** @hide */
- public static final String DATA_ROAMING = "data_roaming";
+ public static final String DATA_ROAMING = SimInfo.DATA_ROAMING;
/** Indicates that data roaming is enabled for a subscription */
- public static final int DATA_ROAMING_ENABLE = 1;
+ public static final int DATA_ROAMING_ENABLE = SimInfo.DATA_ROAMING_ENABLE;
/** Indicates that data roaming is disabled for a subscription */
- public static final int DATA_ROAMING_DISABLE = 0;
+ public static final int DATA_ROAMING_DISABLE = SimInfo.DATA_ROAMING_DISABLE;
/** @hide */
- public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
-
- /** @hide */
- public static final int SIM_PROVISIONED = 0;
+ public static final int DATA_ROAMING_DEFAULT = SimInfo.DATA_ROAMING_DEFAULT;
/**
* TelephonyProvider column name for subscription carrier id.
@@ -518,61 +465,61 @@
* <p>Type: INTEGER (int) </p>
* @hide
*/
- public static final String CARRIER_ID = "carrier_id";
+ public static final String CARRIER_ID = SimInfo.CARRIER_ID;
/**
* @hide A comma-separated list of EHPLMNs associated with the subscription
* <P>Type: TEXT (String)</P>
*/
- public static final String EHPLMNS = "ehplmns";
+ public static final String EHPLMNS = SimInfo.EHPLMNS;
/**
* @hide A comma-separated list of HPLMNs associated with the subscription
* <P>Type: TEXT (String)</P>
*/
- public static final String HPLMNS = "hplmns";
+ public static final String HPLMNS = SimInfo.HPLMNS;
/**
* TelephonyProvider column name for the MCC associated with a SIM, stored as a string.
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String MCC_STRING = "mcc_string";
+ public static final String MCC_STRING = SimInfo.MCC_STRING;
/**
* TelephonyProvider column name for the MNC associated with a SIM, stored as a string.
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String MNC_STRING = "mnc_string";
+ public static final String MNC_STRING = SimInfo.MNC_STRING;
/**
* TelephonyProvider column name for the MCC associated with a SIM.
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String MCC = "mcc";
+ public static final String MCC = SimInfo.MCC;
/**
* TelephonyProvider column name for the MNC associated with a SIM.
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String MNC = "mnc";
+ public static final String MNC = SimInfo.MNC;
/**
* TelephonyProvider column name for the iso country code associated with a SIM.
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String ISO_COUNTRY_CODE = "iso_country_code";
+ public static final String ISO_COUNTRY_CODE = SimInfo.ISO_COUNTRY_CODE;
/**
* TelephonyProvider column name for the sim provisioning status associated with a SIM.
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status";
+ public static final String SIM_PROVISIONING_STATUS = SimInfo.SIM_PROVISIONING_STATUS;
/**
* TelephonyProvider column name for whether a subscription is embedded (that is, present on an
@@ -580,7 +527,7 @@
* <p>Type: INTEGER (int), 1 for embedded or 0 for non-embedded.
* @hide
*/
- public static final String IS_EMBEDDED = "is_embedded";
+ public static final String IS_EMBEDDED = SimInfo.IS_EMBEDDED;
/**
* TelephonyProvider column name for SIM card identifier. For UICC card it is the ICCID of the
@@ -588,7 +535,7 @@
* <P>Type: TEXT (String)</P>
* @hide
*/
- public static final String CARD_ID = "card_id";
+ public static final String CARD_ID = SimInfo.CARD_ID;
/**
* TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
@@ -596,7 +543,7 @@
* <p>TYPE: BLOB
* @hide
*/
- public static final String ACCESS_RULES = "access_rules";
+ public static final String ACCESS_RULES = SimInfo.ACCESS_RULES;
/**
* TelephonyProvider column name for the encoded {@link UiccAccessRule}s from
@@ -606,7 +553,7 @@
* @hide
*/
public static final String ACCESS_RULES_FROM_CARRIER_CONFIGS =
- "access_rules_from_carrier_configs";
+ SimInfo.ACCESS_RULES_FROM_CARRIER_CONFIGS;
/**
* TelephonyProvider column name identifying whether an embedded subscription is on a removable
@@ -616,79 +563,79 @@
* <p>TYPE: INTEGER (int), 1 for removable or 0 for non-removable.
* @hide
*/
- public static final String IS_REMOVABLE = "is_removable";
+ public static final String IS_REMOVABLE = SimInfo.IS_REMOVABLE;
/**
* TelephonyProvider column name for extreme threat in CB settings
* @hide
*/
- public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts";
+ public static final String CB_EXTREME_THREAT_ALERT = SimInfo.CB_EXTREME_THREAT_ALERT;
/**
* TelephonyProvider column name for severe threat in CB settings
*@hide
*/
- public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts";
+ public static final String CB_SEVERE_THREAT_ALERT = SimInfo.CB_SEVERE_THREAT_ALERT;
/**
* TelephonyProvider column name for amber alert in CB settings
*@hide
*/
- public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts";
+ public static final String CB_AMBER_ALERT = SimInfo.CB_AMBER_ALERT;
/**
* TelephonyProvider column name for emergency alert in CB settings
*@hide
*/
- public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts";
+ public static final String CB_EMERGENCY_ALERT = SimInfo.CB_EMERGENCY_ALERT;
/**
* TelephonyProvider column name for alert sound duration in CB settings
*@hide
*/
- public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration";
+ public static final String CB_ALERT_SOUND_DURATION = SimInfo.CB_ALERT_SOUND_DURATION;
/**
* TelephonyProvider column name for alert reminder interval in CB settings
*@hide
*/
- public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval";
+ public static final String CB_ALERT_REMINDER_INTERVAL = SimInfo.CB_ALERT_REMINDER_INTERVAL;
/**
* TelephonyProvider column name for enabling vibrate in CB settings
*@hide
*/
- public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate";
+ public static final String CB_ALERT_VIBRATE = SimInfo.CB_ALERT_VIBRATE;
/**
* TelephonyProvider column name for enabling alert speech in CB settings
*@hide
*/
- public static final String CB_ALERT_SPEECH = "enable_alert_speech";
+ public static final String CB_ALERT_SPEECH = SimInfo.CB_ALERT_SPEECH;
/**
* TelephonyProvider column name for ETWS test alert in CB settings
*@hide
*/
- public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts";
+ public static final String CB_ETWS_TEST_ALERT = SimInfo.CB_ETWS_TEST_ALERT;
/**
* TelephonyProvider column name for enable channel50 alert in CB settings
*@hide
*/
- public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts";
+ public static final String CB_CHANNEL_50_ALERT = SimInfo.CB_CHANNEL_50_ALERT;
/**
* TelephonyProvider column name for CMAS test alert in CB settings
*@hide
*/
- public static final String CB_CMAS_TEST_ALERT= "enable_cmas_test_alerts";
+ public static final String CB_CMAS_TEST_ALERT = SimInfo.CB_CMAS_TEST_ALERT;
/**
* TelephonyProvider column name for Opt out dialog in CB settings
*@hide
*/
- public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog";
+ public static final String CB_OPT_OUT_DIALOG = SimInfo.CB_OPT_OUT_DIALOG;
/**
* TelephonyProvider column name for enable Volte.
@@ -697,37 +644,44 @@
* {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}.
*@hide
*/
- public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
+ public static final String ENHANCED_4G_MODE_ENABLED = SimInfo.ENHANCED_4G_MODE_ENABLED;
/**
* TelephonyProvider column name for enable VT (Video Telephony over IMS)
*@hide
*/
- public static final String VT_IMS_ENABLED = "vt_ims_enabled";
+ public static final String VT_IMS_ENABLED = SimInfo.VT_IMS_ENABLED;
/**
* TelephonyProvider column name for enable Wifi calling
*@hide
*/
- public static final String WFC_IMS_ENABLED = "wfc_ims_enabled";
+ public static final String WFC_IMS_ENABLED = SimInfo.WFC_IMS_ENABLED;
/**
* TelephonyProvider column name for Wifi calling mode
*@hide
*/
- public static final String WFC_IMS_MODE = "wfc_ims_mode";
+ public static final String WFC_IMS_MODE = SimInfo.WFC_IMS_MODE;
/**
* TelephonyProvider column name for Wifi calling mode in roaming
*@hide
*/
- public static final String WFC_IMS_ROAMING_MODE = "wfc_ims_roaming_mode";
+ public static final String WFC_IMS_ROAMING_MODE = SimInfo.WFC_IMS_ROAMING_MODE;
/**
* TelephonyProvider column name for enable Wifi calling in roaming
*@hide
*/
- public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
+ public static final String WFC_IMS_ROAMING_ENABLED = SimInfo.WFC_IMS_ROAMING_ENABLED;
+
+ /**
+ * Determines if the user has enabled IMS RCS User Capability Exchange (UCE) for this
+ * subscription.
+ * @hide
+ */
+ public static final String IMS_RCS_UCE_ENABLED = SimInfo.IMS_RCS_UCE_ENABLED;
/**
* TelephonyProvider column name for whether a subscription is opportunistic, that is,
@@ -736,7 +690,7 @@
* <p>Type: INTEGER (int), 1 for opportunistic or 0 for non-opportunistic.
* @hide
*/
- public static final String IS_OPPORTUNISTIC = "is_opportunistic";
+ public static final String IS_OPPORTUNISTIC = SimInfo.IS_OPPORTUNISTIC;
/**
* TelephonyProvider column name for group ID. Subscriptions with same group ID
@@ -745,7 +699,7 @@
*
* @hide
*/
- public static final String GROUP_UUID = "group_uuid";
+ public static final String GROUP_UUID = SimInfo.GROUP_UUID;
/**
* TelephonyProvider column name for group owner. It's the package name who created
@@ -753,14 +707,7 @@
*
* @hide
*/
- public static final String GROUP_OWNER = "group_owner";
-
- /**
- * TelephonyProvider column name for whether a subscription is metered or not, that is, whether
- * the network it connects to charges for subscription or not. For example, paid CBRS or unpaid.
- * @hide
- */
- public static final String IS_METERED = "is_metered";
+ public static final String GROUP_OWNER = SimInfo.GROUP_OWNER;
/**
* TelephonyProvider column name for the profile class of a subscription
@@ -768,7 +715,7 @@
* <P>Type: INTEGER (int)</P>
* @hide
*/
- public static final String PROFILE_CLASS = "profile_class";
+ public static final String PROFILE_CLASS = SimInfo.PROFILE_CLASS;
/**
* Profile class of the subscription
@@ -776,11 +723,11 @@
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "PROFILE_CLASS_" }, value = {
- PROFILE_CLASS_TESTING,
- PROFILE_CLASS_PROVISIONING,
- PROFILE_CLASS_OPERATIONAL,
- PROFILE_CLASS_UNSET,
- PROFILE_CLASS_DEFAULT
+ SimInfo.PROFILE_CLASS_TESTING,
+ SimInfo.PROFILE_CLASS_PROVISIONING,
+ SimInfo.PROFILE_CLASS_OPERATIONAL,
+ SimInfo.PROFILE_CLASS_UNSET,
+ SimInfo.PROFILE_CLASS_DEFAULT
})
public @interface ProfileClass {}
@@ -792,7 +739,7 @@
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_TESTING = 0;
+ public static final int PROFILE_CLASS_TESTING = SimInfo.PROFILE_CLASS_TESTING;
/**
* A provisioning profile is pre-loaded onto the eUICC and
@@ -801,7 +748,7 @@
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_PROVISIONING = 1;
+ public static final int PROFILE_CLASS_PROVISIONING = SimInfo.PROFILE_CLASS_PROVISIONING;
/**
* An operational profile can be pre-loaded or downloaded
@@ -810,7 +757,7 @@
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_OPERATIONAL = 2;
+ public static final int PROFILE_CLASS_OPERATIONAL = SimInfo.PROFILE_CLASS_OPERATIONAL;
/**
* The profile class is unset. This occurs when profile class
@@ -819,14 +766,14 @@
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_UNSET = -1;
+ public static final int PROFILE_CLASS_UNSET = SimInfo.PROFILE_CLASS_UNSET;
/**
* Default profile class
* @hide
*/
@SystemApi
- public static final int PROFILE_CLASS_DEFAULT = PROFILE_CLASS_UNSET;
+ public static final int PROFILE_CLASS_DEFAULT = SimInfo.PROFILE_CLASS_DEFAULT;
/**
* IMSI (International Mobile Subscriber Identity).
@@ -834,13 +781,19 @@
* @hide
*/
//TODO: add @SystemApi
- public static final String IMSI = "imsi";
+ public static final String IMSI = SimInfo.IMSI;
/**
* Whether uicc applications is set to be enabled or disabled. By default it's enabled.
* @hide
*/
- public static final String UICC_APPLICATIONS_ENABLED = "uicc_applications_enabled";
+ public static final String UICC_APPLICATIONS_ENABLED = SimInfo.UICC_APPLICATIONS_ENABLED;
+
+ /**
+ * Indicate which network type is allowed. By default it's enabled.
+ * @hide
+ */
+ public static final String ALLOWED_NETWORK_TYPES = SimInfo.ALLOWED_NETWORK_TYPES;
/**
* Broadcast Action: The user has changed one of the default subs related to
@@ -2353,7 +2306,28 @@
try {
return Integer.parseInt(result);
} catch (NumberFormatException err) {
- logd("getBooleanSubscriptionProperty NumberFormat exception");
+ logd("getIntegerSubscriptionProperty NumberFormat exception");
+ }
+ }
+ return defValue;
+ }
+
+ /**
+ * Returns long value corresponding to query result.
+ * @param subId Subscription Id of Subscription
+ * @param propKey Column name in SubscriptionInfo database
+ * @param defValue Default long value to be returned
+ * @return long result value to be returned
+ * @hide
+ */
+ public static long getLongSubscriptionProperty(int subId, String propKey, long defValue,
+ Context context) {
+ String result = getSubscriptionProperty(subId, propKey, context);
+ if (result != null) {
+ try {
+ return Long.parseLong(result);
+ } catch (NumberFormatException err) {
+ logd("getLongSubscriptionProperty NumberFormat exception");
}
}
return defValue;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 262cf1a..67e036d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -37,7 +37,6 @@
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.WorkerThread;
-import android.app.ActivityThread;
import android.app.PendingIntent;
import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
@@ -72,7 +71,9 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.CallForwardingReason;
import android.telephony.Annotation.CallState;
+import android.telephony.Annotation.CallWaitingStatus;
import android.telephony.Annotation.NetworkType;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SimActivationState;
@@ -109,8 +110,6 @@
import com.android.internal.telephony.SmsApplication;
import com.android.telephony.Rlog;
-import dalvik.system.VMRuntime;
-
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.annotation.Retention;
@@ -196,11 +195,8 @@
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 */
@@ -377,8 +373,17 @@
// effort and get the context from the current activity thread.
if (mContext != null) {
return mContext.getOpPackageName();
+ } else {
+ ITelephony telephony = getITelephony();
+ if (telephony == null) return null;
+ try {
+ return telephony.getCurrentPackageName();
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ return null;
+ }
}
- return ActivityThread.currentOpPackageName();
}
private String getFeatureId() {
@@ -1225,6 +1230,80 @@
public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
/**
+ * Broadcast Action: The Service Provider string(s) have been updated. Activities or
+ * services that use these strings should update their display.
+ *
+ * <p>The intent will have the following extra values:
+ * <dl>
+ * <dt>{@link #EXTRA_SHOW_PLMN}</dt>
+ * <dd>Boolean that indicates whether the PLMN should be shown.</dd>
+ * <dt>{@link #EXTRA_PLMN}</dt>
+ * <dd>The operator name of the registered network, as a string.</dd>
+ * <dt>{@link #EXTRA_SHOW_SPN}</dt>
+ * <dd>Boolean that indicates whether the SPN should be shown.</dd>
+ * <dt>{@link #EXTRA_SPN}</dt>
+ * <dd>The service provider name, as a string.</dd>
+ * <dt>{@link #EXTRA_DATA_SPN}</dt>
+ * <dd>The service provider name for data service, as a string.</dd>
+ * </dl>
+ *
+ * Note that {@link #EXTRA_SHOW_PLMN} may indicate that {@link #EXTRA_PLMN} should be displayed,
+ * even though the value for {@link #EXTRA_PLMN} is null. This can happen, for example, if the
+ * phone has not registered to a network yet. In this case the receiver may substitute an
+ * appropriate placeholder string (eg, "No service").
+ *
+ * It is recommended to display {@link #EXTRA_PLMN} before / above {@link #EXTRA_SPN} if
+ * both are displayed.
+ *
+ * <p>Note: this is a protected intent that can only be sent by the system.
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SERVICE_PROVIDERS_UPDATED =
+ "android.telephony.action.SERVICE_PROVIDERS_UPDATED";
+
+ /**
+ * String intent extra to be used with {@link ACTION_SERVICE_PROVIDERS_UPDATED} to indicate
+ * whether the PLMN should be shown.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_SHOW_PLMN = "android.telephony.extra.SHOW_PLMN";
+
+ /**
+ * String intent extra to be used with {@link ACTION_SERVICE_PROVIDERS_UPDATED} to indicate
+ * the operator name of the registered network.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_PLMN = "android.telephony.extra.PLMN";
+
+ /**
+ * String intent extra to be used with {@link ACTION_SERVICE_PROVIDERS_UPDATED} to indicate
+ * whether the PLMN should be shown.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_SHOW_SPN = "android.telephony.extra.SHOW_SPN";
+
+ /**
+ * String intent extra to be used with {@link ACTION_SERVICE_PROVIDERS_UPDATED} to indicate
+ * the service provider name.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_SPN = "android.telephony.extra.SPN";
+
+ /**
+ * String intent extra to be used with {@link ACTION_SERVICE_PROVIDERS_UPDATED} to indicate
+ * the service provider name for data service.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_DATA_SPN = "android.telephony.extra.DATA_SPN";
+
+ /**
* Broadcast intent action indicating that when data stall recovery is attempted by Telephony,
* intended for report every data stall recovery step attempted.
*
@@ -1443,6 +1522,24 @@
//
/**
+ * Returns the {@link PhoneCapability} for the device or null if it is not available.
+ * <p>
+ * Requires Permission: READ_PHONE_STATE or that the calling app has
+ * carrier privileges (see {@link #hasCarrierPrivileges}).
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @Nullable
+ public PhoneCapability getPhoneCapability() {
+ try {
+ ITelephony telephony = getITelephony();
+ return telephony == null ? null :
+ telephony.getPhoneCapability(getSubId(), getOpPackageName(), getFeatureId());
+ } catch (RemoteException ex) {
+ return null;
+ }
+ }
+
+ /**
* Returns the software version number for the device, for example,
* the IMEI/SV for GSM phones. Return null if the software version is
* not available.
@@ -1950,6 +2047,16 @@
public static final int PHONE_TYPE_CDMA = PhoneConstants.PHONE_TYPE_CDMA;
/** Phone is via SIP. */
public static final int PHONE_TYPE_SIP = PhoneConstants.PHONE_TYPE_SIP;
+ /** Phone is via IMS. */
+ public static final int PHONE_TYPE_IMS = PhoneConstants.PHONE_TYPE_IMS;
+
+ /**
+ * Phone is via Third Party.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int PHONE_TYPE_THIRD_PARTY = PhoneConstants.PHONE_TYPE_THIRD_PARTY;
/**
* Returns the current phone type.
@@ -2339,7 +2446,7 @@
@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);
}
/**
@@ -5102,6 +5209,13 @@
public static final int DATA_DISCONNECTING = 4;
/**
+ * To check the SDK version for {@link TelephonyManager#getDataState}.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+ private static final long GET_DATA_STATE_CODE_CHANGE = 147600208L;
+
+ /**
* Returns a constant indicating the current data connection state
* (cellular).
*
@@ -5119,7 +5233,7 @@
int state = telephony.getDataStateForSubId(
getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
if (state == TelephonyManager.DATA_DISCONNECTING
- && VMRuntime.getRuntime().getTargetSdkVersion() < Build.VERSION_CODES.R) {
+ && !Compatibility.isChangeEnabled(GET_DATA_STATE_CODE_CHANGE)) {
return TelephonyManager.DATA_CONNECTED;
}
@@ -5172,6 +5286,13 @@
//
/**
+ * To check the SDK version for {@link TelephonyManager#listen}.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P)
+ private static final long LISTEN_CODE_CHANGE = 147600208L;
+
+ /**
* Registers a listener object to receive notification of changes
* in specified telephony states.
* <p>
@@ -5210,7 +5331,7 @@
// subId from PhoneStateListener is deprecated Q on forward, use the subId from
// TelephonyManager instance. keep using subId from PhoneStateListener for pre-Q.
int subId = mSubId;
- if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q) {
+ if (Compatibility.isChangeEnabled(LISTEN_CODE_CHANGE)) {
// since mSubId in PhoneStateListener is deprecated from Q on forward, this is
// the only place to set mSubId and its for "informational" only.
// TODO: remove this once we completely get rid of mSubId in PhoneStateListener
@@ -6871,6 +6992,30 @@
}
}
+
+ /**
+ * Resets the {@link android.telephony.ims.ImsService} associated with the specified sim slot.
+ * Used by diagnostic apps to force the IMS stack to be disabled and re-enabled in an effort to
+ * recover from scenarios where the {@link android.telephony.ims.ImsService} gets in to a bad
+ * state.
+ *
+ * @param slotIndex the sim slot to reset the IMS stack on.
+ * @hide */
+ @SystemApi
+ @WorkerThread
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void resetIms(int slotIndex) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.resetIms(slotIndex);
+ }
+ } catch (RemoteException e) {
+ Rlog.e(TAG, "toggleImsOnOff, RemoteException: "
+ + e.getMessage());
+ }
+ }
+
/**
* Enables IMS for the framework. This will trigger IMS registration and ImsFeature capability
* status updates, if not already enabled.
@@ -7279,7 +7424,9 @@
*
* @return the preferred network type.
* @hide
+ * @deprecated Use {@link #getPreferredNetworkTypeBitmask} instead.
*/
+ @Deprecated
@RequiresPermission((android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE))
@UnsupportedAppUsage
public @PrefNetworkMode int getPreferredNetworkType(int subId) {
@@ -7324,6 +7471,30 @@
}
/**
+ * Get the allowed network types.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+ * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @return the allowed network type bitmask
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @SystemApi
+ public @NetworkTypeBitMask long getAllowedNetworkTypes() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getAllowedNetworkTypes(getSubId());
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getAllowedNetworkTypes RemoteException", ex);
+ }
+ return -1;
+ }
+
+ /**
* Sets the network selection mode to automatic.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
@@ -7486,6 +7657,36 @@
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
* app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
+ * @param operatorNumeric the PLMN ID of the network to select.
+ * @param ran the initial suggested radio access network type.
+ * If registration fails, the RAN is not available after, the RAN is not within the
+ * network types specified by {@link #setPreferredNetworkTypeBitmask}, or the value is
+ * {@link AccessNetworkConstants.AccessNetworkType#UNKNOWN}, modem will select
+ * the next best RAN for network registration.
+ * @param persistSelection whether the selection will persist until reboot.
+ * If true, only allows attaching to the selected PLMN until reboot; otherwise,
+ * attach to the chosen PLMN and resume normal network selection next time.
+ * @return {@code true} on success; {@code false} on any failure.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @SystemApi
+ public boolean setNetworkSelectionModeManual(@NonNull String operatorNumeric,
+ @AccessNetworkConstants.RadioAccessNetworkType int ran, boolean persistSelection) {
+ return setNetworkSelectionModeManual(new OperatorInfo("" /* operatorAlphaLong */,
+ "" /* operatorAlphaShort */, operatorNumeric, ran), persistSelection);
+ }
+
+ /**
+ * Ask the radio to connect to the input network and change selection mode to manual.
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling
+ * app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
* @param operatorInfo included the PLMN id, long name, short name of the operator to attach to.
* @param persistSelection whether the selection will persist until reboot. If true, only allows
* attaching to the selected PLMN until reboot; otherwise, attach to the chosen PLMN and resume
@@ -7514,14 +7715,18 @@
*
* <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();
@@ -7574,7 +7779,9 @@
* @param networkType the preferred network type
* @return true on success; false on any failure.
* @hide
+ * @deprecated Use {@link #setPreferredNetworkTypeBitmask} instead.
*/
+ @Deprecated
@UnsupportedAppUsage
public boolean setPreferredNetworkType(int subId, @PrefNetworkMode int networkType) {
try {
@@ -7589,7 +7796,8 @@
}
/**
- * Set the preferred network type bitmask.
+ * Set the preferred network type bitmask but if {@link #setAllowedNetworkTypes} has been set,
+ * only the allowed network type will set to the modem.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
* given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
@@ -7619,6 +7827,29 @@
}
/**
+ * Set the allowed network types of the device. This is for carrier or privileged apps to
+ * enable/disable certain network types on the device. The user preferred network types should
+ * be set through {@link #setPreferredNetworkTypeBitmask}.
+ *
+ * @param allowedNetworkTypes The bitmask of allowed network types.
+ * @return true on success; false on any failure.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ @SystemApi
+ public boolean setAllowedNetworkTypes(@NetworkTypeBitMask long allowedNetworkTypes) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.setAllowedNetworkTypes(getSubId(), allowedNetworkTypes);
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "setAllowedNetworkTypes RemoteException", ex);
+ }
+ return false;
+ }
+
+ /**
* Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
*
* <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
@@ -9093,15 +9324,20 @@
}
/**
- * Requested state of SIM
- *
- * CARD_POWER_DOWN
* Powers down the SIM. SIM must be up prior.
- *
- * CARD_POWER_UP
+ * @hide
+ */
+ @SystemApi
+ public static final int CARD_POWER_DOWN = 0;
+
+ /**
* Powers up the SIM normally. SIM must be down prior.
- *
- * CARD_POWER_UP_PASS_THROUGH
+ * @hide
+ */
+ @SystemApi
+ public static final int CARD_POWER_UP = 1;
+
+ /**
* Powers up the SIM in PASS_THROUGH mode. SIM must be down prior.
* When SIM is powered up in PASS_THOUGH mode, the modem does not send
* any command to it (for example SELECT of MF, or TERMINAL CAPABILITY),
@@ -9114,12 +9350,9 @@
* is activated, and normal behavior occurs at the next SIM initialization,
* unless PASS_THROUGH mode is requested again. Hence, the last power-up mode
* is NOT persistent across boots. On reboot, SIM will power up normally.
+ * @hide
*/
- /** @hide */
- public static final int CARD_POWER_DOWN = 0;
- /** @hide */
- public static final int CARD_POWER_UP = 1;
- /** @hide */
+ @SystemApi
public static final int CARD_POWER_UP_PASS_THROUGH = 2;
/**
@@ -9634,7 +9867,8 @@
* {@link android.telephony.ModemActivityInfo} object.
* @hide
*/
- public void requestModemActivityInfo(ResultReceiver result) {
+ @SystemApi
+ public void requestModemActivityInfo(@NonNull ResultReceiver result) {
try {
ITelephony service = getITelephony();
if (service != null) {
@@ -10272,6 +10506,7 @@
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
*
* @param enabled control enable or disable carrier data.
+ * @see #resetAllCarrierActions()
* @hide
*/
@SystemApi
@@ -10298,6 +10533,7 @@
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
*
* @param enabled control enable or disable radio.
+ * @see #resetAllCarrierActions()
* @hide
*/
@SystemApi
@@ -10324,6 +10560,7 @@
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
*
* @param report control start/stop reporting network status.
+ * @see #resetAllCarrierActions()
* @hide
*/
@SystemApi
@@ -10485,6 +10722,27 @@
}
/**
+ * Enable or disable signal strength changes from radio will always be reported in any
+ * condition (e.g. screen is off). This is only allowed for System caller.
+ *
+ * @param isEnabled {@code true} for enabling; {@code false} for disabling.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public void setAlwaysReportSignalStrength(boolean isEnabled) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.setAlwaysReportSignalStrength(getSubId(), isEnabled);
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "setAlwaysReportSignalStrength RemoteException", ex);
+ ex.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
* Get the most recently available signal strength information.
*
* Get the most recent SignalStrength information reported by the modem. Due
@@ -11750,6 +12008,32 @@
}
/**
+ * Get the calling application status about carrier privileges for the subscription created
+ * in TelephonyManager. Used by Telephony Module for permission checking.
+ *
+ * @param uid Uid to check.
+ * @return any value of {@link #CARRIER_PRIVILEGE_STATUS_HAS_ACCESS},
+ * {@link #CARRIER_PRIVILEGE_STATUS_NO_ACCESS},
+ * {@link #CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED}, or
+ * {@link #CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES}
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public int getCarrierPrivilegeStatus(int uid) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getCarrierPrivilegeStatusForUid(getSubId(), uid);
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "getCarrierPrivilegeStatus RemoteException", ex);
+ }
+ return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
+ }
+
+ /**
* Returns a list of APNs set as overrides by the device policy manager via
* {@link #addDevicePolicyOverrideApn}.
* This method must only be called from the system or phone processes.
@@ -11920,6 +12204,191 @@
}
/**
+ * Gets the voice call forwarding info {@link CallForwardingInfo}, given the call forward
+ * reason.
+ *
+ * @param callForwardingReason the call forwarding reasons
+ *
+ * @throws IllegalArgumentException if callForwardingReason is not any of
+ * {@link CallForwardingInfo.REASON_UNCONDITIONAL}, {@link CallForwardingInfo.REASON_BUSY},
+ * {@link CallForwardingInfo.REASON_NO_REPLY}, {@link CallForwardingInfo.REASON_NOT_REACHABLE},
+ * {@link CallForwardingInfo.REASON_ALL}, {@link CallForwardingInfo.REASON_ALL_CONDITIONAL}
+ *
+ * @return {@link CallForwardingInfo} with the status {@link CallForwardingInfo#STATUS_ACTIVE}
+ * or {@link CallForwardingInfo#STATUS_INACTIVE} and the target phone number to forward calls
+ * to, if it's available. Otherwise, it will return a {@link CallForwardingInfo} with status
+ * {@link CallForwardingInfo#STATUS_UNKNOWN_ERROR},
+ * {@link CallForwardingInfo#STATUS_NOT_SUPPORTED},
+ * or {@link CallForwardingInfo#STATUS_FDN_CHECK_FAILURE} depending on the situation.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @NonNull
+ public CallForwardingInfo getCallForwarding(@CallForwardingReason int callForwardingReason) {
+ if (callForwardingReason < CallForwardingInfo.REASON_UNCONDITIONAL
+ || callForwardingReason > CallForwardingInfo.REASON_ALL_CONDITIONAL) {
+ throw new IllegalArgumentException("callForwardingReason is out of range");
+ }
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getCallForwarding(getSubId(), callForwardingReason);
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getCallForwarding RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "getCallForwarding NPE", ex);
+ }
+ return new CallForwardingInfo(
+ CallForwardingInfo.STATUS_UNKNOWN_ERROR, 0 /* reason */, null /* number */,
+ 0 /* timeout */);
+ }
+
+ /**
+ * Sets the voice call forwarding info including status (enable/disable), call forwarding
+ * reason, the number to forward, and the timeout before the forwarding is attempted.
+ *
+ * @param callForwardingInfo {@link CallForwardingInfo} to setup the call forwarding.
+ * Enabling if {@link CallForwardingInfo#getStatus()} returns
+ * {@link CallForwardingInfo#STATUS_ACTIVE}; Disabling if
+ * {@link CallForwardingInfo#getStatus()} returns {@link CallForwardingInfo#STATUS_INACTIVE}.
+ *
+ * @throws IllegalArgumentException if any of the following for parameter callForwardingInfo:
+ * 0) it is {@code null}.
+ * 1) {@link CallForwardingInfo#getStatus()} returns neither
+ * {@link CallForwardingInfo#STATUS_ACTIVE} nor {@link CallForwardingInfo#STATUS_INACTIVE}.
+ * 2) {@link CallForwardingInfo#getReason()} is not any of
+ * {@link CallForwardingInfo.REASON_UNCONDITIONAL}, {@link CallForwardingInfo.REASON_BUSY},
+ * {@link CallForwardingInfo.REASON_NO_REPLY}, {@link CallForwardingInfo.REASON_NOT_REACHABLE},
+ * {@link CallForwardingInfo.REASON_ALL}, {@link CallForwardingInfo.REASON_ALL_CONDITIONAL}
+ * 3) {@link CallForwardingInfo#getNumber()} returns {@code null}.
+ * 4) {@link CallForwardingInfo#getTimeoutSeconds()} doesn't return a positive value.
+ *
+ * @return {@code true} to indicate it was set successfully; {@code false} otherwise.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public boolean setCallForwarding(@NonNull CallForwardingInfo callForwardingInfo) {
+ if (callForwardingInfo == null) {
+ throw new IllegalArgumentException("callForwardingInfo is null");
+ }
+ int callForwardingStatus = callForwardingInfo.getStatus();
+ if (callForwardingStatus != CallForwardingInfo.STATUS_ACTIVE
+ && callForwardingStatus != CallForwardingInfo.STATUS_INACTIVE) {
+ throw new IllegalArgumentException(
+ "callForwardingStatus is neither active nor inactive");
+ }
+ int callForwardingReason = callForwardingInfo.getReason();
+ if (callForwardingReason < CallForwardingInfo.REASON_UNCONDITIONAL
+ || callForwardingReason > CallForwardingInfo.REASON_ALL_CONDITIONAL) {
+ throw new IllegalArgumentException("callForwardingReason is out of range");
+ }
+ if (callForwardingInfo.getNumber() == null) {
+ throw new IllegalArgumentException("callForwarding number is null");
+ }
+ if (callForwardingInfo.getTimeoutSeconds() <= 0) {
+ throw new IllegalArgumentException("callForwarding timeout isn't positive");
+ }
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.setCallForwarding(getSubId(), callForwardingInfo);
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "setCallForwarding RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "setCallForwarding NPE", ex);
+ }
+ return false;
+ }
+
+ /**
+ * Indicates the call waiting status is active.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int CALL_WAITING_STATUS_ACTIVE = 1;
+
+ /**
+ * Indicates the call waiting status is inactive.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int CALL_WAITING_STATUS_INACTIVE = 2;
+
+ /**
+ * Indicates the call waiting status is with an unknown error.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int CALL_WAITING_STATUS_UNKNOWN_ERROR = 3;
+
+ /**
+ * Indicates the call waiting is not supported (e.g. called via CDMA).
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4;
+
+ /**
+ * Gets the status of voice call waiting function. Call waiting function enables the waiting
+ * for the incoming call when it reaches the user who is busy to make another call and allows
+ * users to decide whether to switch to the incoming call.
+ *
+ * @return the status of call waiting function.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public @CallWaitingStatus int getCallWaitingStatus() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.getCallWaitingStatus(getSubId());
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getCallWaitingStatus RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "getCallWaitingStatus NPE", ex);
+ }
+ return CALL_WAITING_STATUS_UNKNOWN_ERROR;
+ }
+
+ /**
+ * Sets the status for voice call waiting function. Call waiting function enables the waiting
+ * for the incoming call when it reaches the user who is busy to make another call and allows
+ * users to decide whether to switch to the incoming call.
+ *
+ * @param isEnable {@code true} to enable; {@code false} to disable.
+ * @return {@code true} to indicate it was set successfully; {@code false} otherwise.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public boolean setCallWaitingStatus(boolean isEnable) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.setCallWaitingStatus(getSubId(), isEnable);
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "setCallWaitingStatus RemoteException", ex);
+ } catch (NullPointerException ex) {
+ Rlog.e(TAG, "setCallWaitingStatus NPE", ex);
+ }
+ return false;
+ }
+
+ /**
* Set allowing mobile data during voice call.
*
* @param allow {@code true} if allowing using data during voice call, {@code false} if
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 49625bb..a116c07 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -78,6 +78,9 @@
private final List<InetAddress> mGatewayAddresses;
private final List<InetAddress> mPcscfAddresses;
private final int mMtu;
+ private final int mMtuV4;
+ private final int mMtuV6;
+ private final int mVersion;
/**
* @param cause Data call fail cause. {@link DataFailCause#NONE} indicates no error.
@@ -97,9 +100,8 @@
* "192.0.1.11 2001:db8::1". When null, the addresses represent point to point connections.
* @param pcscfAddresses A list of Proxy Call State Control Function address via PCO (Protocol
* Configuration Option) for IMS client.
- * @param mtu MTU (maximum transmission unit) in bytes received from network. Zero or negative
- * values means network has either not sent a value or sent an invalid value.
- * either not sent a value or sent an invalid value.
+ * @param mtu MTU (maximum transmission unit) in bytes received from network.
+ * Zero or negative values means network has either not sent a value or sent an invalid value.
*
* @removed Use the {@link Builder()} instead.
*/
@@ -125,6 +127,34 @@
mPcscfAddresses = (pcscfAddresses == null)
? new ArrayList<>() : new ArrayList<>(pcscfAddresses);
mMtu = mtu;
+ mMtuV4 = mMtuV6 = 0;
+ mVersion = 0;
+ }
+
+ /** @hide */
+ private DataCallResponse(@DataFailureCause int cause, int suggestedRetryTime, int id,
+ @LinkStatus int linkStatus, @ProtocolType int protocolType,
+ @Nullable String interfaceName, @Nullable List<LinkAddress> addresses,
+ @Nullable List<InetAddress> dnsAddresses, @Nullable List<InetAddress> gatewayAddresses,
+ @Nullable List<InetAddress> pcscfAddresses, int mtuV4, int mtuV6, int version) {
+ mCause = cause;
+ mSuggestedRetryTime = suggestedRetryTime;
+ mId = id;
+ mLinkStatus = linkStatus;
+ mProtocolType = protocolType;
+ mInterfaceName = (interfaceName == null) ? "" : interfaceName;
+ mAddresses = (addresses == null)
+ ? new ArrayList<>() : new ArrayList<>(addresses);
+ mDnsAddresses = (dnsAddresses == null)
+ ? new ArrayList<>() : new ArrayList<>(dnsAddresses);
+ mGatewayAddresses = (gatewayAddresses == null)
+ ? new ArrayList<>() : new ArrayList<>(gatewayAddresses);
+ mPcscfAddresses = (pcscfAddresses == null)
+ ? new ArrayList<>() : new ArrayList<>(pcscfAddresses);
+ mMtu = 0;
+ mMtuV4 = mtuV4;
+ mMtuV6 = mtuV6;
+ mVersion = version;
}
/** @hide */
@@ -145,6 +175,9 @@
mPcscfAddresses = new ArrayList<>();
source.readList(mPcscfAddresses, InetAddress.class.getClassLoader());
mMtu = source.readInt();
+ mMtuV4 = source.readInt();
+ mMtuV6 = source.readInt();
+ mVersion = source.readInt();
}
/**
@@ -210,8 +243,29 @@
/**
* @return MTU (maximum transmission unit) in bytes received from network. Zero or negative
* values means network has either not sent a value or sent an invalid value.
+ * @deprecated For IRadio 1.5 and up, use {@link #getMtuV4} or {@link #getMtuV6} instead.
*/
- public int getMtu() { return mMtu; }
+ @Deprecated
+ public int getMtu() {
+ return mVersion < 5 ? mMtu : 0;
+ }
+
+ /**
+ * This replaces the deprecated method getMtu.
+ * @return MTU (maximum transmission unit) in bytes received from network, for IPv4.
+ * Zero or negative values means network has either not sent a value or sent an invalid value.
+ */
+ public int getMtuV4() {
+ return mVersion < 5 ? 0 : mMtuV4;
+ }
+
+ /**
+ * @return MTU (maximum transmission unit) in bytes received from network, for IPv6.
+ * Zero or negative values means network has either not sent a value or sent an invalid value.
+ */
+ public int getMtuV6() {
+ return mVersion < 5 ? 0 : mMtuV6;
+ }
@NonNull
@Override
@@ -229,6 +283,9 @@
.append(" gateways=").append(mGatewayAddresses)
.append(" pcscf=").append(mPcscfAddresses)
.append(" mtu=").append(mMtu)
+ .append(" mtuV4=").append(mMtuV4)
+ .append(" mtuV6=").append(mMtuV6)
+ .append(" version=").append(mVersion)
.append("}");
return sb.toString();
}
@@ -256,14 +313,17 @@
&& mGatewayAddresses.containsAll(other.mGatewayAddresses)
&& mPcscfAddresses.size() == other.mPcscfAddresses.size()
&& mPcscfAddresses.containsAll(other.mPcscfAddresses)
- && mMtu == other.mMtu;
+ && mMtu == other.mMtu
+ && mMtuV4 == other.mMtuV4
+ && mMtuV6 == other.mMtuV6
+ && mVersion == other.mVersion;
}
@Override
public int hashCode() {
return Objects.hash(mCause, mSuggestedRetryTime, mId, mLinkStatus, mProtocolType,
mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses, mPcscfAddresses,
- mMtu);
+ mMtu, mMtuV4, mMtuV6, mVersion);
}
@Override
@@ -284,6 +344,9 @@
dest.writeList(mGatewayAddresses);
dest.writeList(mPcscfAddresses);
dest.writeInt(mMtu);
+ dest.writeInt(mMtuV4);
+ dest.writeInt(mMtuV6);
+ dest.writeInt(mVersion);
}
public static final @android.annotation.NonNull Parcelable.Creator<DataCallResponse> CREATOR =
@@ -336,6 +399,12 @@
private int mMtu;
+ private int mMtuV4;
+
+ private int mMtuV6;
+
+ private int mVersion;
+
/**
* Default constructor for Builder.
*/
@@ -460,6 +529,7 @@
* negative values means network has either not sent a value or sent an invalid value.
*
* @return The same instance of the builder.
+ * @deprecated For IRadio 1.5 and up, use {@link #setMtuV4} or {@link #setMtuV6} instead.
*/
public @NonNull Builder setMtu(int mtu) {
mMtu = mtu;
@@ -467,14 +537,55 @@
}
/**
+ * Set maximum transmission unit of the data connection, for IPv4.
+ *
+ * @param mtu MTU (maximum transmission unit) in bytes received from network. Zero or
+ * negative values means network has either not sent a value or sent an invalid value.
+ *
+ * @return The same instance of the builder.
+ */
+ public @NonNull Builder setMtuV4(int mtu) {
+ mMtuV4 = mtu;
+ return this;
+ }
+
+ /**
+ * Set maximum transmission unit of the data connection, for IPv6.
+ *
+ * @param mtu MTU (maximum transmission unit) in bytes received from network. Zero or
+ * negative values means network has either not sent a value or sent an invalid value.
+ *
+ * @return The same instance of the builder.
+ */
+ public @NonNull Builder setMtuV6(int mtu) {
+ mMtuV6 = mtu;
+ return this;
+ }
+
+ /**
+ * Set the IRadio version for this DataCallResponse
+ * @hide
+ */
+ public @NonNull Builder setVersion(int version) {
+ mVersion = version;
+ return this;
+ }
+
+ /**
* Build the DataCallResponse.
*
* @return the DataCallResponse object.
*/
public @NonNull DataCallResponse build() {
- return new DataCallResponse(mCause, mSuggestedRetryTime, mId, mLinkStatus,
- mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses,
- mPcscfAddresses, mMtu);
+ if (mVersion >= 5) {
+ return new DataCallResponse(mCause, mSuggestedRetryTime, mId, mLinkStatus,
+ mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses,
+ mPcscfAddresses, mMtuV4, mMtuV6, mVersion);
+ } else {
+ return new DataCallResponse(mCause, mSuggestedRetryTime, mId, mLinkStatus,
+ mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses,
+ mPcscfAddresses, mMtu);
+ }
}
}
}
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index 96a5a81..f2a1249 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -96,7 +96,9 @@
@NetworkTypeBitMask
private final int mBearerBitmask;
- private final int mMtu;
+ private final int mMtuV4;
+
+ private final int mMtuV6;
private final boolean mPersistent;
@@ -104,12 +106,11 @@
/** @hide */
private DataProfile(int profileId, String apn, @ProtocolType int protocolType, int authType,
- String userName, String password, int type, int maxConnectionsTime,
- int maxConnections, int waitTime, boolean enabled,
- @ApnType int supportedApnTypesBitmask,
- @ProtocolType int roamingProtocolType,
- @NetworkTypeBitMask int bearerBitmask, int mtu, boolean persistent,
- boolean preferred) {
+ String userName, String password, int type, int maxConnectionsTime,
+ int maxConnections, int waitTime, boolean enabled,
+ @ApnType int supportedApnTypesBitmask, @ProtocolType int roamingProtocolType,
+ @NetworkTypeBitMask int bearerBitmask, int mtuV4, int mtuV6, boolean persistent,
+ boolean preferred) {
this.mProfileId = profileId;
this.mApn = apn;
this.mProtocolType = protocolType;
@@ -128,7 +129,8 @@
this.mSupportedApnTypesBitmask = supportedApnTypesBitmask;
this.mRoamingProtocolType = roamingProtocolType;
this.mBearerBitmask = bearerBitmask;
- this.mMtu = mtu;
+ this.mMtuV4 = mtuV4;
+ this.mMtuV6 = mtuV6;
this.mPersistent = persistent;
this.mPreferred = preferred;
}
@@ -148,7 +150,8 @@
mSupportedApnTypesBitmask = source.readInt();
mRoamingProtocolType = source.readInt();
mBearerBitmask = source.readInt();
- mMtu = source.readInt();
+ mMtuV4 = source.readInt();
+ mMtuV6 = source.readInt();
mPersistent = source.readBoolean();
mPreferred = source.readBoolean();
}
@@ -237,8 +240,21 @@
/**
* @return The maximum transmission unit (MTU) size in bytes.
+ * @deprecated use {@link #getMtuV4} or {@link #getMtuV6} instead.
*/
- public int getMtu() { return mMtu; }
+ @Deprecated
+ public int getMtu() { return mMtuV4; }
+
+ /**
+ * This replaces the deprecated method getMtu.
+ * @return The maximum transmission unit (MTU) size in bytes, for IPv4.
+ */
+ public int getMtuV4() { return mMtuV4; }
+
+ /**
+ * @return The maximum transmission unit (MTU) size in bytes, for IPv6.
+ */
+ public int getMtuV6() { return mMtuV6; }
/**
* @return {@code true} if modem must persist this data profile.
@@ -265,8 +281,8 @@
(mApn + "/" + mUserName + "/" + mPassword)) + "/" + mType + "/"
+ mMaxConnectionsTime + "/" + mMaxConnections + "/"
+ mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmask + "/"
- + mRoamingProtocolType + "/" + mBearerBitmask + "/" + mMtu + "/" + mPersistent + "/"
- + mPreferred;
+ + mRoamingProtocolType + "/" + mBearerBitmask + "/" + mMtuV4 + "/" + mMtuV6 + "/"
+ + mPersistent + "/" + mPreferred;
}
@Override
@@ -285,7 +301,8 @@
dest.writeInt(mSupportedApnTypesBitmask);
dest.writeInt(mRoamingProtocolType);
dest.writeInt(mBearerBitmask);
- dest.writeInt(mMtu);
+ dest.writeInt(mMtuV4);
+ dest.writeInt(mMtuV6);
dest.writeBoolean(mPersistent);
dest.writeBoolean(mPreferred);
}
@@ -319,7 +336,8 @@
&& mSupportedApnTypesBitmask == that.mSupportedApnTypesBitmask
&& mRoamingProtocolType == that.mRoamingProtocolType
&& mBearerBitmask == that.mBearerBitmask
- && mMtu == that.mMtu
+ && mMtuV4 == that.mMtuV4
+ && mMtuV6 == that.mMtuV6
&& mPersistent == that.mPersistent
&& mPreferred == that.mPreferred
&& Objects.equals(mApn, that.mApn)
@@ -331,8 +349,8 @@
public int hashCode() {
return Objects.hash(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword, mType,
mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled,
- mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtu, mPersistent,
- mPreferred);
+ mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtuV4, mMtuV6,
+ mPersistent, mPreferred);
}
/**
@@ -384,7 +402,9 @@
@NetworkTypeBitMask
private int mBearerBitmask;
- private int mMtu;
+ private int mMtuV4;
+
+ private int mMtuV6;
private boolean mPersistent;
@@ -567,9 +587,33 @@
*
* @param mtu The maximum transmission unit (MTU) size in bytes.
* @return The same instance of the builder.
+ * @deprecated use {@link #setMtuV4} or {@link #setMtuV6} instead.
*/
public @NonNull Builder setMtu(int mtu) {
- mMtu = mtu;
+ mMtuV4 = mMtuV6 = mtu;
+ return this;
+ }
+
+ /**
+ * Set the maximum transmission unit (MTU) size in bytes, for IPv4.
+ * This replaces the deprecated method setMtu.
+ *
+ * @param mtu The maximum transmission unit (MTU) size in bytes.
+ * @return The same instance of the builder.
+ */
+ public @NonNull Builder setMtuV4(int mtu) {
+ mMtuV4 = mtu;
+ return this;
+ }
+
+ /**
+ * Set the maximum transmission unit (MTU) size in bytes, for IPv6.
+ *
+ * @param mtu The maximum transmission unit (MTU) size in bytes.
+ * @return The same instance of the builder.
+ */
+ public @NonNull Builder setMtuV6(int mtu) {
+ mMtuV6 = mtu;
return this;
}
@@ -606,7 +650,7 @@
public @NonNull DataProfile build() {
return new DataProfile(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword,
mType, mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled,
- mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtu,
+ mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtuV4, mMtuV6,
mPersistent, mPreferred);
}
}
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 998b39d..a7d553b 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -40,10 +41,11 @@
import java.util.List;
/**
- * Parcelable object to handle IMS call profile.
- * It is created from GSMA IR.92/IR.94, 3GPP TS 24.229/TS 26.114/TS26.111.
- * It provides the service and call type, the additional information related to the call.
- *
+ * A Parcelable object to handle the IMS call profile, which provides the service, call type, and
+ * additional information related to the call.
+ * <p>
+ * See the following specifications for more information about this class: GSMA IR.92/IR.94,
+ * 3GPP TS 24.229/TS 26.114/TS26.111.
* @hide
*/
@SystemApi
@@ -151,12 +153,13 @@
*/
public static final String EXTRA_CONFERENCE_AVAIL = "conference_avail";
- // Extra string for internal use only. OEMs should not use
- // this for packing extras.
/**
+ * Extra key used to store a Bundle containing proprietary extras to send to the ImsService.
+ * Use {@link #getProprietaryCallExtras()} instead.
* @hide
*/
- public static final String EXTRA_OEM_EXTRAS = "OemCallExtras";
+ @TestApi
+ public static final String EXTRA_OEM_EXTRAS = "android.telephony.ims.extra.OEM_EXTRAS";
/**
* Rule for originating identity (number) presentation, MO/MT.
@@ -291,15 +294,30 @@
* 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 */
@@ -679,6 +697,18 @@
return mCallExtras;
}
+ /**
+ * Get the proprietary extras set for this ImsCallProfile.
+ * @return A {@link Bundle} containing proprietary call extras that were not set by the
+ * platform.
+ */
+ public @Nullable Bundle getProprietaryCallExtras() {
+ if (mCallExtras == null) {
+ return null;
+ }
+ return mCallExtras.getBundle(EXTRA_OEM_EXTRAS);
+ }
+
public ImsStreamMediaProfile getMediaProfile() {
return mMediaProfile;
}
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index 5adc99e..1b583fd 100644
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -25,8 +25,6 @@
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 @@
}
/**
- * 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 @@
* 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 @@
* 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 @@
/**
* 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 @@
* 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 @@
* 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 e11886f..025721c 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 @@
* @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 @@
* @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 @@
* @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 39af2e7..643f452 100644
--- a/telephony/java/android/telephony/ims/ImsException.java
+++ b/telephony/java/android/telephony/ims/ImsException.java
@@ -30,10 +30,7 @@
/**
* 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 {
/**
@@ -64,7 +61,6 @@
* This is a configuration error and there should be no retry. The subscription used for this
* operation is either invalid or has become inactive. The active subscriptions can be queried
* with {@link SubscriptionManager#getActiveSubscriptionInfoList()}.
- * @hide
*/
public static final int CODE_ERROR_INVALID_SUBSCRIPTION = 3;
@@ -83,7 +79,10 @@
/**
* 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 +90,10 @@
/**
* 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 +104,10 @@
* {@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 5fd0af5..494009f 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -23,6 +23,8 @@
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;
@@ -55,11 +57,9 @@
* registration and MmTel capability status callbacks, as well as query/modify user settings for the
* associated subscription.
*
- * @see #createForSubscriptionId(int)
- * @hide
+ * Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an instance of this
+ * manager.
*/
-@SystemApi
-@TestApi
public class ImsMmTelManager implements RegistrationManager {
/**
@@ -94,9 +94,11 @@
* @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 +143,7 @@
/**
* 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)
@@ -161,9 +163,13 @@
public void onCapabilitiesStatusChanged(int config) {
if (mLocalCallback == null) return;
- Binder.withCleanCallingIdentity(() ->
- mExecutor.execute(() -> mLocalCallback.onCapabilitiesStatusChanged(
- new MmTelFeature.MmTelCapabilities(config))));
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mLocalCallback.onCapabilitiesStatusChanged(
+ new MmTelFeature.MmTelCapabilities(config)));
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
}
@Override
@@ -190,7 +196,7 @@
* 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 +224,25 @@
*
* @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.
+ * @deprecated Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an
+ * instance of this class.
+ * @hide
*/
+ @SystemApi
+ @TestApi
+ @Deprecated
+ @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");
@@ -229,7 +252,7 @@
}
/**
- * Only visible for testing, use {@link #createForSubscriptionId(int)} instead.
+ * Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead.
* @hide
*/
@VisibleForTesting
@@ -239,7 +262,7 @@
/**
* Registers a {@link RegistrationCallback} with the system, which will provide registration
- * updates for the subscription specified in {@link #createForSubscriptionId(int)}. Use
+ * updates for the subscription specified in {@link ImsManager#getImsMmTelManager(int)}. Use
* {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
* events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
*
@@ -258,8 +281,10 @@
* 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 +309,20 @@
}
}
- /**{@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 +353,10 @@
* @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 +369,20 @@
}
}
- /**{@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 +395,13 @@
}
}
- /**{@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 +422,19 @@
}
}
- /**{@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 +460,25 @@
/**
* 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 ImsManager#getImsMmTelManager(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 +494,10 @@
* 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 +529,27 @@
* 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 +571,19 @@
* <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 +595,10 @@
* 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 +636,10 @@
* @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 +670,15 @@
* {@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 +699,14 @@
* {@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 +731,9 @@
* 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 +762,32 @@
/**
* 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 +809,9 @@
* @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 +831,28 @@
/**
* @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 +875,9 @@
* 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 +897,30 @@
/**
* 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 +944,9 @@
* @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 +976,9 @@
* @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 +998,20 @@
/**
* 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 +1021,10 @@
* - {@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 +1050,9 @@
* @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 +1081,9 @@
* @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 +1112,9 @@
* @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 +1141,9 @@
* @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 +1163,29 @@
/**
* @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 +1212,9 @@
* 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/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 5aa37bb..917f91f 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -75,9 +75,13 @@
public void onCapabilitiesStatusChanged(int config) {
if (mLocalCallback == null) return;
- Binder.withCleanCallingIdentity(() ->
- mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged(
- new RcsFeature.RcsImsCapabilities(config))));
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged(
+ new RcsFeature.RcsImsCapabilities(config)));
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
}
@Override
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 62bc2ae..2b3072e 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -60,9 +60,10 @@
* The telephony framework will then bind to the ImsService you have defined in your manifest
* if you are either:
* 1) Defined as the default ImsService for the device in the device overlay using
- * "config_ims_package".
+ * "config_ims_mmtel_package" or "config_ims_rcs_package".
* 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using
- * {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}.
+ * {@link CarrierConfigManager#KEY_CONFIG_IMS_MMTEL_PACKAGE_OVERRIDE_STRING} or
+ * {@link CarrierConfigManager#KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING}.
*
* There are two ways to define to the platform which {@link ImsFeature}s this {@link ImsService}
* supports, dynamic or static definitions.
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 35a2a91..6125001 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -26,11 +26,10 @@
import android.annotation.TestApi;
import android.annotation.WorkerThread;
import android.content.Context;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.ims.aidl.IImsConfigCallback;
@@ -103,6 +102,101 @@
// 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>
@@ -118,6 +212,28 @@
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.
@@ -142,6 +258,43 @@
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>
@@ -224,7 +377,7 @@
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>
@@ -235,6 +388,14 @@
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.
@@ -272,6 +433,349 @@
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 {
@@ -287,17 +791,24 @@
@Override
public final void onIntConfigChanged(int item, int value) {
- Binder.withCleanCallingIdentity(() ->
- mExecutor.execute(() ->
- mLocalConfigurationCallback.onProvisioningIntChanged(item, value)));
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() ->
+ mLocalConfigurationCallback.onProvisioningIntChanged(item, value));
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
}
@Override
public final void onStringConfigChanged(int item, String value) {
- Binder.withCleanCallingIdentity(() ->
- mExecutor.execute(() ->
- mLocalConfigurationCallback.onProvisioningStringChanged(item,
- value)));
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() ->
+ mLocalConfigurationCallback.onProvisioningStringChanged(item, value));
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
}
private void setExecutor(Executor executor) {
@@ -376,13 +887,11 @@
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void registerProvisioningChangedCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull Callback callback) throws ImsException {
- if (!isImsAvailableOnDevice()) {
- throw new ImsException("IMS not available on device.",
- ImsException.CODE_ERROR_UNSUPPORTED_OPERATION);
- }
callback.setExecutor(executor);
try {
getITelephony().registerImsProvisioningChangedCallback(mSubId, callback.getBinder());
+ } catch (ServiceSpecificException e) {
+ throw new ImsException(e.getMessage(), e.errorCode);
} catch (RemoteException | IllegalStateException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
@@ -612,22 +1121,6 @@
}
- private static boolean isImsAvailableOnDevice() {
- IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
- if (pm == null) {
- // For some reason package manger is not available.. This will fail internally anyways,
- // so do not throw error and allow.
- return true;
- }
- try {
- return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS, 0);
- } catch (RemoteException e) {
- // For some reason package manger is not available.. This will fail internally anyways,
- // so do not throw error and allow.
- }
- return true;
- }
-
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(
ServiceManager.getService(Context.TELEPHONY_SERVICE));
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index 893a311..57b9b7a 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -16,10 +16,11 @@
package android.telephony.ims;
-import android.annotation.IntDef;
+import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -37,6 +38,7 @@
* @hide
*/
@SystemApi
+@TestApi
public final class RcsContactUceCapability implements Parcelable {
/** Supports 1-to-1 chat */
@@ -83,12 +85,32 @@
public static final int CAPABILITY_RCS_VOICE_CALL = (1 << 19);
/** Supports RCS video calling */
public static final int CAPABILITY_RCS_VIDEO_CALL = (1 << 20);
- /** Supports RCS video calling, where video media can not be dropped */
+ /** Supports RCS video calling, where video media can not be dropped. */
public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = (1 << 21);
+ /** Supports call composer, where outgoing calls can be enriched with pre-call content.*/
+ public static final int CAPABILITY_CALL_COMPOSER = (1 << 22);
+ /** Supports post call information that is included in the call if the call is missed.*/
+ public static final int CAPABILITY_POST_CALL = (1 << 23);
+ /** Supports sharing a map where the user can draw, share markers, and share their position. */
+ public static final int CAPABILITY_SHARED_MAP = (1 << 24);
+ /** Supports sharing a canvas, where users can draw, add images, and change background colors.*/
+ public static final int CAPABILITY_SHARED_SKETCH = (1 << 25);
+ /** Supports communication with Chatbots. */
+ public static final int CAPABILITY_CHAT_BOT = (1 << 26);
+ /** Supports Chatbot roles. */
+ public static final int CAPABILITY_CHAT_BOT_ROLE = (1 << 27);
+ /** Supports the unidirectional plug-ins framework. */
+ public static final int CAPABILITY_PLUG_IN = (1 << 28);
+ /** Supports standalone Chatbot communication. */
+ public static final int CAPABILITY_STANDALONE_CHAT_BOT = (1 << 29);
+ /** Supports MMTEL based call composer. */
+ public static final int CAPABILITY_MMTEL_CALL_COMPOSER = (1 << 30);
+
+
/** @hide*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = "CAPABILITY_", flag = true, value = {
+ @LongDef(prefix = "CAPABILITY_", flag = true, value = {
CAPABILITY_CHAT_STANDALONE,
CAPABILITY_CHAT_SESSION,
CAPABILITY_CHAT_SESSION_STORE_FORWARD,
@@ -110,7 +132,16 @@
CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER,
CAPABILITY_RCS_VOICE_CALL,
CAPABILITY_RCS_VIDEO_CALL,
- CAPABILITY_RCS_VIDEO_ONLY_CALL
+ CAPABILITY_RCS_VIDEO_ONLY_CALL,
+ CAPABILITY_CALL_COMPOSER,
+ CAPABILITY_POST_CALL,
+ CAPABILITY_SHARED_MAP,
+ CAPABILITY_SHARED_SKETCH,
+ CAPABILITY_CHAT_BOT,
+ CAPABILITY_CHAT_BOT_ROLE,
+ CAPABILITY_PLUG_IN,
+ CAPABILITY_STANDALONE_CHAT_BOT,
+ CAPABILITY_MMTEL_CALL_COMPOSER
})
public @interface CapabilityFlag {}
@@ -137,11 +168,11 @@
* @param type The capability to map to a service URI that is different from the contact's
* URI.
*/
- public @NonNull Builder add(@CapabilityFlag int type, @NonNull Uri serviceUri) {
+ public @NonNull Builder add(@CapabilityFlag long type, @NonNull Uri serviceUri) {
mCapabilities.mCapabilities |= type;
// Put each of these capabilities into the map separately.
- for (int shift = 0; shift < Integer.SIZE; shift++) {
- int cap = type & (1 << shift);
+ for (long shift = 0; shift < Integer.SIZE; shift++) {
+ long cap = type & (1 << shift);
if (cap != 0) {
mCapabilities.mServiceMap.put(cap, serviceUri);
// remove that capability from the field.
@@ -159,7 +190,7 @@
* Add a UCE capability flag that this contact supports.
* @param type the capability that the contact supports.
*/
- public @NonNull Builder add(@CapabilityFlag int type) {
+ public @NonNull Builder add(@CapabilityFlag long type) {
mCapabilities.mCapabilities |= type;
return this;
}
@@ -183,9 +214,9 @@
}
private final Uri mContactUri;
- private int mCapabilities;
+ private long mCapabilities;
private List<String> mExtensionTags = new ArrayList<>();
- private Map<Integer, Uri> mServiceMap = new HashMap<>();
+ private Map<Long, Uri> mServiceMap = new HashMap<>();
/**
* Use {@link Builder} to build an instance of this interface.
@@ -198,12 +229,12 @@
private RcsContactUceCapability(Parcel in) {
mContactUri = in.readParcelable(Uri.class.getClassLoader());
- mCapabilities = in.readInt();
+ mCapabilities = in.readLong();
in.readStringList(mExtensionTags);
// read mServiceMap as key,value pair
int mapSize = in.readInt();
for (int i = 0; i < mapSize; i++) {
- mServiceMap.put(in.readInt(), in.readParcelable(Uri.class.getClassLoader()));
+ mServiceMap.put(in.readLong(), in.readParcelable(Uri.class.getClassLoader()));
}
}
@@ -223,13 +254,13 @@
@Override
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeParcelable(mContactUri, 0);
- out.writeInt(mCapabilities);
+ out.writeLong(mCapabilities);
out.writeStringList(mExtensionTags);
// write mServiceMap as key,value pairs
int mapSize = mServiceMap.keySet().size();
out.writeInt(mapSize);
- for (int key : mServiceMap.keySet()) {
- out.writeInt(key);
+ for (long key : mServiceMap.keySet()) {
+ out.writeLong(key);
out.writeParcelable(mServiceMap.get(key), 0);
}
}
@@ -244,7 +275,7 @@
* @param type The capability flag to query.
* @return true if the capability flag specified is set, false otherwise.
*/
- public boolean isCapable(@CapabilityFlag int type) {
+ public boolean isCapable(@CapabilityFlag long type) {
return (mCapabilities & type) > 0;
}
@@ -268,13 +299,13 @@
* <p>
* This will typically be the contact {@link Uri} available via {@link #getContactUri()} unless
* a different service {@link Uri} was associated with this capability using
- * {@link Builder#add(int, Uri)}.
+ * {@link Builder#add(long, Uri)}.
*
* @return a String containing the {@link Uri} associated with the service tag or
* {@code null} if this capability is not set as capable.
- * @see #isCapable(int)
+ * @see #isCapable(long)
*/
- public @Nullable Uri getServiceUri(@CapabilityFlag int type) {
+ public @Nullable Uri getServiceUri(@CapabilityFlag long type) {
Uri result = mServiceMap.getOrDefault(type, null);
// If the capability is capable, but does not have a service URI associated, use the default
// contact URI.
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index b47bcb9..5e3847f 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -21,6 +21,8 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.content.Context;
import android.net.Uri;
import android.os.Binder;
@@ -29,6 +31,7 @@
import android.os.ServiceManager;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.aidl.IRcsUceControllerCallback;
+import android.telephony.ims.feature.RcsFeature;
import android.util.Log;
import java.lang.annotation.Retention;
@@ -42,6 +45,8 @@
* @see ImsRcsManager#getUceAdapter() for information on creating an instance of this class.
* @hide
*/
+@SystemApi
+@TestApi
public class RcsUceAdapter {
private static final String TAG = "RcsUceAdapter";
@@ -197,6 +202,7 @@
/**
* Not to be instantiated directly, use
* {@link ImsRcsManager#getUceAdapter()} to instantiate this manager class.
+ * @hide
*/
RcsUceAdapter(int subId) {
mSubId = subId;
@@ -222,7 +228,7 @@
* becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void requestCapabilities(@CallbackExecutor Executor executor,
+ public void requestCapabilities(@NonNull @CallbackExecutor Executor executor,
@NonNull List<Uri> contactNumbers,
@NonNull CapabilitiesCallback c) throws ImsException {
if (c == null) {
@@ -245,15 +251,22 @@
IRcsUceControllerCallback internalCallback = new IRcsUceControllerCallback.Stub() {
@Override
public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
- Binder.withCleanCallingIdentity(() ->
- executor.execute(() ->
- c.onCapabilitiesReceived(contactCapabilities)));
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() ->
+ c.onCapabilitiesReceived(contactCapabilities));
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
}
@Override
public void onError(int errorCode) {
- Binder.withCleanCallingIdentity(() ->
- executor.execute(() ->
- c.onError(errorCode)));
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> c.onError(errorCode));
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
}
};
@@ -299,7 +312,7 @@
* for the associated subscription.
*
* @return true if the user’s setting for UCE is enabled, false otherwise. If false,
- * {@link ImsRcsManager#isCapable(int)} will return false for
+ * {@link ImsRcsManager#isCapable(int, int)} will return false for
* {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} and
* {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE}
* @see #setUceSettingEnabled(boolean)
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index 99bb259..5c86ba7 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -22,8 +22,6 @@
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 @@
/**
* Manages IMS Service registration state for associated {@link ImsFeature}s.
- * @hide
*/
-@SystemApi
-@TestApi
public interface RegistrationManager {
/**
@@ -110,42 +105,62 @@
public void onRegistered(int imsRadioTech) {
if (mLocalCallback == null) return;
- Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
- mLocalCallback.onRegistered(getAccessType(imsRadioTech))));
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() ->
+ mLocalCallback.onRegistered(getAccessType(imsRadioTech)));
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
}
@Override
public void onRegistering(int imsRadioTech) {
if (mLocalCallback == null) return;
- Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
- mLocalCallback.onRegistering(getAccessType(imsRadioTech))));
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() ->
+ mLocalCallback.onRegistering(getAccessType(imsRadioTech)));
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
}
@Override
public void onDeregistered(ImsReasonInfo info) {
if (mLocalCallback == null) return;
- Binder.withCleanCallingIdentity(() ->
- mExecutor.execute(() -> mLocalCallback.onUnregistered(info)));
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mLocalCallback.onUnregistered(info));
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
}
@Override
public void onTechnologyChangeFailed(int imsRadioTech, ImsReasonInfo info) {
if (mLocalCallback == null) return;
- Binder.withCleanCallingIdentity(() ->
- mExecutor.execute(() -> mLocalCallback.onTechnologyChangeFailed(
- getAccessType(imsRadioTech), info)));
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mLocalCallback.onTechnologyChangeFailed(
+ getAccessType(imsRadioTech), info));
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
}
- @Override
public void onSubscriberAssociatedUriChanged(Uri[] uris) {
if (mLocalCallback == null) return;
- Binder.withCleanCallingIdentity(() ->
- mExecutor.execute(() ->
- mLocalCallback.onSubscriberAssociatedUriChanged(uris)));
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mLocalCallback.onSubscriberAssociatedUriChanged(uris));
+ } finally {
+ restoreCallingIdentity(callingIdentity);
+ }
}
private void setExecutor(Executor executor) {
@@ -225,7 +240,11 @@
/**
* 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 +294,10 @@
* 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 d64e67a..cc2ebb9 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
@@ -92,11 +92,11 @@
/**
* 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/aidl/IRcsFeatureListener.aidl b/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl
index 881b477..70cf651 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl
@@ -32,11 +32,11 @@
oneway void onNetworkResponse(int code, in String reason, int operationToken);
oneway void onCapabilityRequestResponsePresence(in List<RcsContactUceCapability> infos,
int operationToken);
- oneway void onNotifyUpdateCapabilities();
+ oneway void onNotifyUpdateCapabilities(int publishTriggerType);
oneway void onUnpublish();
// RcsSipOptionsImplBase specific
oneway void onCapabilityRequestResponseOptions(int code, in String reason,
in RcsContactUceCapability info, int operationToken);
oneway void onRemoteCapabilityRequest(in Uri contactUri, in RcsContactUceCapability remoteInfo,
int operationToken);
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
index acab738..75bd6a7 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.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 @@
@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 72390d0..e5779b3 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -22,7 +22,6 @@
import android.annotation.TestApi;
import android.content.Context;
import android.os.IInterface;
-import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.telephony.SubscriptionManager;
import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -31,6 +30,7 @@
import com.android.ims.internal.IImsFeatureStatusCallback;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.util.RemoteCallbackListExt;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -60,15 +60,21 @@
* 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 @@
* 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 @@
/**
* 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;
/**
@@ -310,12 +326,12 @@
/** @hide */
protected final Object mLock = new Object();
- private final RemoteCallbackList<IImsFeatureStatusCallback> mStatusCallbacks =
- new RemoteCallbackList<>();
+ private final RemoteCallbackListExt<IImsFeatureStatusCallback> mStatusCallbacks =
+ new RemoteCallbackListExt<>();
private @ImsState int mState = STATE_UNAVAILABLE;
private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
- private final RemoteCallbackList<IImsCapabilityCallback> mCapabilityCallbacks =
- new RemoteCallbackList<>();
+ private final RemoteCallbackListExt<IImsCapabilityCallback> mCapabilityCallbacks =
+ new RemoteCallbackListExt<>();
private Capabilities mCapabilityStatus = new Capabilities();
/**
@@ -331,17 +347,20 @@
*
* @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;
}
/**
- * @return The current state of the feature, defined as {@link #STATE_UNAVAILABLE},
- * {@link #STATE_INITIALIZING}, or {@link #STATE_READY}.
+ * @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
*/
- public int getFeatureState() {
+ @SystemApi @TestApi
+ public @ImsState int getFeatureState() {
synchronized (mLock) {
return mState;
}
@@ -352,7 +371,9 @@
* 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) {
@@ -391,7 +412,7 @@
* Internal method called by ImsFeature when setFeatureState has changed.
*/
private void notifyFeatureState(@ImsState int state) {
- mStatusCallbacks.broadcast((c) -> {
+ mStatusCallbacks.broadcastAction((c) -> {
try {
c.notifyImsFeatureStatus(state);
} catch (RemoteException e) {
@@ -470,7 +491,7 @@
synchronized (mLock) {
mCapabilityStatus = caps.copy();
}
- mCapabilityCallbacks.broadcast((callback) -> {
+ mCapabilityCallbacks.broadcastAction((callback) -> {
try {
callback.onCapabilitiesStatusChanged(caps.mCapabilities);
} catch (RemoteException e) {
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 56c8771..a3ce1b5 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -52,14 +52,18 @@
*
* 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 @@
* {@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 @@
* 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 @@
* 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,21 +293,36 @@
*/
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
public String toString() {
@@ -319,8 +349,10 @@
/**
* 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 +361,10 @@
* 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 +372,10 @@
/**
* 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 +384,22 @@
/**
* 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 +412,9 @@
* 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 +425,9 @@
* 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 +436,7 @@
/**
* @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 +455,11 @@
* 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 +471,9 @@
* 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 +486,9 @@
* @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 +513,9 @@
* @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 +554,9 @@
/**
* 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 +577,10 @@
* 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 +598,10 @@
* 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 +624,9 @@
* {@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 +647,9 @@
* {@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 +666,9 @@
* 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 +701,9 @@
/**
* @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 +712,9 @@
/**
* @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 +723,9 @@
/**
* @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 +751,9 @@
* // Remote side is dead
* }
* }
+ * @hide
*/
+ @SystemApi @TestApi
public void setUiTtyMode(int mode, @Nullable Message onCompleteMessage) {
// Base Implementation - Should be overridden
}
@@ -710,7 +787,9 @@
*
* @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 +798,22 @@
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/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 501e0e8..8e67621 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -22,7 +22,6 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.net.Uri;
-import android.os.Binder;
import android.os.RemoteException;
import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -33,7 +32,7 @@
import android.telephony.ims.stub.RcsSipOptionsImplBase;
import android.util.Log;
-import com.android.internal.util.FunctionalUtils;
+import com.android.internal.telephony.util.TelephonyUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -43,6 +42,7 @@
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
+import java.util.function.Supplier;
/**
* Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
@@ -150,13 +150,13 @@
// Call the methods with a clean calling identity on the executor and wait indefinitely for
// the future to return.
- private void executeMethodAsync(FunctionalUtils.ThrowingRunnable r, String errorLogName)
+ private void executeMethodAsync(Runnable r, String errorLogName)
throws RemoteException {
// call with a clean calling identity on the executor and wait indefinitely for the
// future to return.
try {
CompletableFuture.runAsync(
- () -> Binder.withCleanCallingIdentity(r), mExecutor).join();
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor).join();
} catch (CancellationException | CompletionException e) {
Log.w(LOG_TAG, "RcsFeatureBinder - " + errorLogName + " exception: "
+ e.getMessage());
@@ -164,12 +164,12 @@
}
}
- private <T> T executeMethodAsyncForResult(FunctionalUtils.ThrowingSupplier<T> r,
+ private <T> T executeMethodAsyncForResult(Supplier<T> r,
String errorLogName) throws RemoteException {
// call with a clean calling identity on the executor and wait indefinitely for the
// future to return.
CompletableFuture<T> future = CompletableFuture.supplyAsync(
- () -> Binder.withCleanCallingIdentity(r), mExecutor);
+ () -> TelephonyUtils.runWithCleanCallingIdentity(r), mExecutor);
try {
return future.get();
} catch (ExecutionException | InterruptedException e) {
@@ -349,9 +349,8 @@
*
* @return An instance of {@link RcsSipOptionsImplBase} that implements SIP options exchange if
* it is supported by the device.
- * @hide
*/
- public RcsSipOptionsImplBase getOptionsExchangeImpl() {
+ public @NonNull RcsSipOptionsImplBase getOptionsExchangeImpl() {
// Base Implementation, override to implement functionality
return new RcsSipOptionsImplBase();
}
@@ -365,9 +364,8 @@
*
* @return An instance of {@link RcsPresenceExchangeImplBase} that implements presence
* exchange if it is supported by the device.
- * @hide
*/
- public RcsPresenceExchangeImplBase getPresenceExchangeImpl() {
+ public @NonNull RcsPresenceExchangeImplBase getPresenceExchangeImpl() {
// Base Implementation, override to implement functionality.
return new RcsPresenceExchangeImplBase();
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
index f4367da..e8f69ea 100644
--- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -410,6 +410,13 @@
* Rejects an incoming call or session update.
*
* @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}.
+ * The {@link android.telecom.InCallService} (dialer app) can use the
+ * {@link android.telecom.Call#reject(int)} API to reject a call while specifying
+ * a user-indicated reason for rejecting the call.
+ * Normal call declines ({@link android.telecom.Call#REJECT_REASON_DECLINED}) will
+ * map to {@link ImsReasonInfo#CODE_USER_DECLINE}.
+ * Unwanted calls ({@link android.telecom.Call#REJECT_REASON_UNWANTED}) will map
+ * to {@link ImsReasonInfo#CODE_SIP_USER_MARKED_UNWANTED}.
* {@link ImsCallSession.Listener#callSessionStartFailed}
*/
public void reject(int reason) {
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index e0d576d..6a2638b 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -22,7 +22,6 @@
import android.annotation.TestApi;
import android.content.Context;
import android.os.PersistableBundle;
-import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.aidl.IImsConfig;
@@ -31,6 +30,7 @@
import com.android.ims.ImsConfig;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.util.RemoteCallbackListExt;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -257,7 +257,8 @@
})
public @interface SetConfigResult {}
- private final RemoteCallbackList<IImsConfigCallback> mCallbacks = new RemoteCallbackList<>();
+ private final RemoteCallbackListExt<IImsConfigCallback> mCallbacks =
+ new RemoteCallbackListExt<>();
ImsConfigStub mImsConfigStub;
/**
@@ -298,7 +299,7 @@
if (mCallbacks == null) {
return;
}
- mCallbacks.broadcast(c -> {
+ mCallbacks.broadcastAction(c -> {
try {
c.onIntConfigChanged(item, value);
} catch (RemoteException e) {
@@ -312,7 +313,7 @@
if (mCallbacks == null) {
return;
}
- mCallbacks.broadcast(c -> {
+ mCallbacks.broadcastAction(c -> {
try {
c.onStringConfigChanged(item, value);
} catch (RemoteException e) {
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index c0f16e5..14a64d2 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -20,7 +20,6 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.net.Uri;
-import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.RegistrationManager;
@@ -29,6 +28,7 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.util.RemoteCallbackListExt;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -94,8 +94,8 @@
}
};
- private final RemoteCallbackList<IImsRegistrationCallback> mCallbacks
- = new RemoteCallbackList<>();
+ private final RemoteCallbackListExt<IImsRegistrationCallback> mCallbacks =
+ new RemoteCallbackListExt<>();
private final Object mLock = new Object();
// Locked on mLock
private @ImsRegistrationTech
@@ -129,7 +129,7 @@
*/
public final void onRegistered(@ImsRegistrationTech int imsRadioTech) {
updateToState(imsRadioTech, RegistrationManager.REGISTRATION_STATE_REGISTERED);
- mCallbacks.broadcast((c) -> {
+ mCallbacks.broadcastAction((c) -> {
try {
c.onRegistered(imsRadioTech);
} catch (RemoteException e) {
@@ -147,7 +147,7 @@
*/
public final void onRegistering(@ImsRegistrationTech int imsRadioTech) {
updateToState(imsRadioTech, RegistrationManager.REGISTRATION_STATE_REGISTERING);
- mCallbacks.broadcast((c) -> {
+ mCallbacks.broadcastAction((c) -> {
try {
c.onRegistering(imsRadioTech);
} catch (RemoteException e) {
@@ -175,7 +175,7 @@
*/
public final void onDeregistered(ImsReasonInfo info) {
updateToDisconnectedState(info);
- mCallbacks.broadcast((c) -> {
+ mCallbacks.broadcastAction((c) -> {
try {
c.onDeregistered(info);
} catch (RemoteException e) {
@@ -194,7 +194,7 @@
*/
public final void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech,
ImsReasonInfo info) {
- mCallbacks.broadcast((c) -> {
+ mCallbacks.broadcastAction((c) -> {
try {
c.onTechnologyChangeFailed(imsRadioTech, info);
} catch (RemoteException e) {
@@ -210,7 +210,7 @@
* @param uris
*/
public final void onSubscriberAssociatedUriChanged(Uri[] uris) {
- mCallbacks.broadcast((c) -> {
+ mCallbacks.broadcastAction((c) -> {
try {
c.onSubscriberAssociatedUriChanged(uris);
} catch (RemoteException e) {
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index feac3c2..f13371c 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -16,6 +16,9 @@
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;
@@ -25,6 +28,9 @@
import com.android.ims.internal.IImsUt;
import com.android.ims.internal.IImsUtListener;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Base implementation of IMS UT interface, which implements stubs. Override these methods to
* implement functionality.
@@ -36,6 +42,70 @@
@SystemApi
@TestApi
public class ImsUtImplBase {
+ /**
+ * Bar all incoming calls. (See 3GPP TS 24.611)
+ */
+ public static final int CALL_BARRING_ALL_INCOMING = 1;
+
+ /**
+ * Bar all outgoing calls. (See 3GPP TS 24.611)
+ */
+ public static final int CALL_BARRING_ALL_OUTGOING = 2;
+
+ /**
+ * Bar all outgoing international calls. (See 3GPP TS 24.611)
+ */
+ public static final int CALL_BARRING_OUTGOING_INTL = 3;
+
+ /**
+ * Bar all outgoing international calls, excluding those to the home PLMN country
+ * (See 3GPP TS 24.611)
+ */
+ public static final int CALL_BARRING_OUTGOING_INTL_EXCL_HOME = 4;
+
+ /**
+ * Bar all incoming calls when roaming (See 3GPP TS 24.611)
+ */
+ public static final int CALL_BLOCKING_INCOMING_WHEN_ROAMING = 5;
+
+ /**
+ * Enable Anonymous Communication Rejection (See 3GPP TS 24.611)
+ */
+ public static final int CALL_BARRING_ANONYMOUS_INCOMING = 6;
+
+ /**
+ * Bar all incoming and outgoing calls. (See 3GPP TS 24.611)
+ */
+ public static final int CALL_BARRING_ALL = 7;
+
+ /**
+ * Bar all outgoing service requests, including calls. (See 3GPP TS 24.611)
+ */
+ public static final int CALL_BARRING_OUTGOING_ALL_SERVICES = 8;
+
+ /**
+ * Bar all incoming service requests, including calls. (See 3GPP TS 24.611)
+ */
+ public static final int CALL_BARRING_INCOMING_ALL_SERVICES = 9;
+
+ /**
+ * Bar specific incoming calls. (See 3GPP TS 24.611)
+ */
+ public static final int CALL_BARRING_SPECIFIC_INCOMING_CALLS = 10;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "CALL_BARRING_", value = {CALL_BARRING_ALL_INCOMING, CALL_BARRING_ALL_OUTGOING,
+ CALL_BARRING_OUTGOING_INTL, CALL_BARRING_OUTGOING_INTL_EXCL_HOME,
+ CALL_BLOCKING_INCOMING_WHEN_ROAMING, CALL_BARRING_ANONYMOUS_INCOMING,
+ CALL_BARRING_ALL, CALL_BARRING_OUTGOING_ALL_SERVICES,
+ CALL_BARRING_INCOMING_ALL_SERVICES, CALL_BARRING_SPECIFIC_INCOMING_CALLS})
+ public @interface CallBarringMode {}
+
+ /**
+ * Constant used to denote an invalid return value.
+ */
+ public static final int INVALID_RESULT = -1;
private IImsUt.Stub mServiceImpl = new IImsUt.Stub() {
@Override
@@ -138,6 +208,13 @@
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);
+ }
};
/**
@@ -247,15 +324,23 @@
/**
* Updates the configuration of the call barring.
*/
- public int updateCallBarring(int cbType, int action, String[] barrList) {
+ public int updateCallBarring(@CallBarringMode int cbType, int action, String[] barrList) {
return -1;
}
/**
* Updates the configuration of the call barring for specified service class.
*/
- public int updateCallBarringForServiceClass(int cbType, int action, String[] barrList,
- int serviceClass) {
+ public int updateCallBarringForServiceClass(@CallBarringMode int cbType, int action,
+ String[] barrList, int serviceClass) {
+ return -1;
+ }
+
+ /**
+ * 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;
}
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
index fda295a..a24af2f 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java
@@ -17,6 +17,8 @@
package android.telephony.ims.stub;
import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.RemoteException;
import android.telephony.ims.ImsException;
import android.telephony.ims.aidl.IRcsFeatureListener;
@@ -32,6 +34,8 @@
*
* @hide
*/
+@SystemApi
+@TestApi
public class RcsCapabilityExchange {
/** Service is unknown. */
diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
index 055fca5..f200ea2 100644
--- a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java
@@ -18,6 +18,8 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.net.Uri;
import android.os.RemoteException;
import android.telephony.ims.ImsException;
@@ -37,6 +39,8 @@
*
* @hide
*/
+@SystemApi
+@TestApi
public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange {
private static final String LOG_TAG = "RcsPresenceExchangeIB";
@@ -113,6 +117,51 @@
})
public @interface PresenceResponseCode {}
+
+ /** A capability update has been requested due to the Entity Tag (ETag) expiring. */
+ public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0;
+ /** A capability update has been requested due to moving to LTE with VoPS disabled. */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1;
+ /** A capability update has been requested due to moving to LTE with VoPS enabled. */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2;
+ /** A capability update has been requested due to moving to eHRPD. */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3;
+ /** A capability update has been requested due to moving to HSPA+. */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4;
+ /** A capability update has been requested due to moving to 3G. */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5;
+ /** A capability update has been requested due to moving to 2G. */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6;
+ /** A capability update has been requested due to moving to WLAN */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7;
+ /** A capability update has been requested due to moving to IWLAN */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8;
+ /** A capability update has been requested but the reason is unknown. */
+ public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9;
+ /** A capability update has been requested due to moving to 5G NR with VoPS disabled. */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10;
+ /** A capability update has been requested due to moving to 5G NR with VoPS enabled. */
+ public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11;
+
+ /** @hide*/
+ @IntDef(value = {
+ CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN,
+ CAPABILITY_UPDATE_TRIGGER_UNKNOWN,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED,
+ CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED
+ }, prefix = "CAPABILITY_UPDATE_TRIGGER_")
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StackPublishTriggerType {
+ }
+
/**
* Provide the framework with a subsequent network response update to
* {@link #updateCapabilities(RcsContactUceCapability, int)} and
@@ -164,15 +213,18 @@
* This is typically used when trying to generate an initial PUBLISH for a new subscription to
* the network. The device will cache all presence publications after boot until this method is
* called once.
+ * @param publishTriggerType {@link StackPublishTriggerType} The reason for the capability
+ * update request.
* @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently
* connected to the framework. This can happen if the {@link RcsFeature} is not
* {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the
* {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the
* Telephony stack has crashed.
*/
- public final void onNotifyUpdateCapabilites() throws ImsException {
+ public final void onNotifyUpdateCapabilites(@StackPublishTriggerType int publishTriggerType)
+ throws ImsException {
try {
- getListener().onNotifyUpdateCapabilities();
+ getListener().onNotifyUpdateCapabilities(publishTriggerType);
} catch (RemoteException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
diff --git a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
index 1c68fc0..355c4dd 100644
--- a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java
@@ -19,6 +19,8 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.net.Uri;
import android.os.RemoteException;
import android.telephony.ims.ImsException;
@@ -35,6 +37,8 @@
*
* @hide
*/
+@SystemApi
+@TestApi
public class RcsSipOptionsImplBase extends RcsCapabilityExchange {
private static final String LOG_TAG = "RcsSipOptionsImplBase";
@@ -69,6 +73,11 @@
*/
public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4;
+ /**
+ * Indicates that the remote user responded with a 400 BAD REQUEST response.
+ */
+ public static final int RESPONSE_BAD_REQUEST = 5;
+
/** @hide*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "RESPONSE_", value = {
@@ -77,7 +86,8 @@
RESPONSE_TEMPORARILY_UNAVAILABLE,
RESPONSE_REQUEST_TIMEOUT,
RESPONSE_NOT_FOUND,
- RESPONSE_DOES_NOT_EXIST_ANYWHERE
+ RESPONSE_DOES_NOT_EXIST_ANYWHERE,
+ RESPONSE_BAD_REQUEST
})
public @interface SipResponseCode {}
@@ -188,7 +198,6 @@
* @param reason A non-null String containing the reason associated with the SIP code.
* @param operationToken The token provided by the framework when
* {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called.
- *
*/
public void respondToCapabilityRequestWithError(@NonNull Uri contactUri,
@SipResponseCode int code, @NonNull String reason, int operationToken) {
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index 0d86e2b..0f6ce13 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -135,374 +135,596 @@
/**
* 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 50b63bd..4a5380e 100644
--- a/telephony/java/com/android/ims/ImsUtInterface.java
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -21,6 +21,7 @@
import android.os.Message;
import android.telephony.ims.ImsCallForwardInfo;
import android.telephony.ims.ImsSsInfo;
+import android.telephony.ims.stub.ImsUtImplBase;
/**
* Provides APIs for the supplementary service settings using IMS (Ut interface).
@@ -58,47 +59,48 @@
* CDIV (Communication Diversion, 3GPP TS 24.604)
* actions: target, no reply timer
*/
- public static final int CDIV_CF_UNCONDITIONAL = 0;
- public static final int CDIV_CF_BUSY = 1;
- public static final int CDIV_CF_NO_REPLY = 2;
- public static final int CDIV_CF_NOT_REACHABLE = 3;
+ public static final int CDIV_CF_UNCONDITIONAL = ImsCallForwardInfo.CDIV_CF_REASON_UNCONDITIONAL;
+ public static final int CDIV_CF_BUSY = ImsCallForwardInfo.CDIV_CF_REASON_BUSY;
+ public static final int CDIV_CF_NO_REPLY = ImsCallForwardInfo.CDIV_CF_REASON_NO_REPLY;
+ public static final int CDIV_CF_NOT_REACHABLE = ImsCallForwardInfo.CDIV_CF_REASON_NOT_REACHABLE;
// For CS service code: 002
- public static final int CDIV_CF_ALL = 4;
+ public static final int CDIV_CF_ALL = ImsCallForwardInfo.CDIV_CF_REASON_ALL;
// For CS service code: 004
- public static final int CDIV_CF_ALL_CONDITIONAL = 5;
+ public static final int CDIV_CF_ALL_CONDITIONAL =
+ ImsCallForwardInfo.CDIV_CF_REASON_ALL_CONDITIONAL;
// It's only supported in the IMS service (CS does not define it).
// IR.92 recommends that an UE activates both the CFNRc and the CFNL
// (CDIV using condition not-registered) to the same target.
- public static final int CDIV_CF_NOT_LOGGED_IN = 6;
+ public static final int CDIV_CF_NOT_LOGGED_IN = ImsCallForwardInfo.CDIV_CF_REASON_NOT_LOGGED_IN;
/**
* CB (Communication Barring, 3GPP TS 24.611)
*/
// Barring of All Incoming Calls
- public static final int CB_BAIC = 1;
+ public static final int CB_BAIC = ImsUtImplBase.CALL_BARRING_ALL_INCOMING;
// Barring of All Outgoing Calls
- public static final int CB_BAOC = 2;
+ public static final int CB_BAOC = ImsUtImplBase.CALL_BARRING_ALL_OUTGOING;
// Barring of Outgoing International Calls
- public static final int CB_BOIC = 3;
+ public static final int CB_BOIC = ImsUtImplBase.CALL_BARRING_OUTGOING_INTL;
// Barring of Outgoing International Calls - excluding Home Country
- public static final int CB_BOIC_EXHC = 4;
+ public static final int CB_BOIC_EXHC = ImsUtImplBase.CALL_BARRING_OUTGOING_INTL_EXCL_HOME;
// Barring of Incoming Calls - when roaming
- public static final int CB_BIC_WR = 5;
+ public static final int CB_BIC_WR = ImsUtImplBase.CALL_BLOCKING_INCOMING_WHEN_ROAMING;
// Barring of Anonymous Communication Rejection (ACR) - a particular case of ICB service
- public static final int CB_BIC_ACR = 6;
+ public static final int CB_BIC_ACR = ImsUtImplBase.CALL_BARRING_ANONYMOUS_INCOMING;
// Barring of All Calls
- public static final int CB_BA_ALL = 7;
+ public static final int CB_BA_ALL = ImsUtImplBase.CALL_BARRING_ALL;
// Barring of Outgoing Services (Service Code 333 - 3GPP TS 22.030 Table B-1)
- public static final int CB_BA_MO = 8;
+ public static final int CB_BA_MO = ImsUtImplBase.CALL_BARRING_OUTGOING_ALL_SERVICES;
// Barring of Incoming Services (Service Code 353 - 3GPP TS 22.030 Table B-1)
- public static final int CB_BA_MT = 9;
+ public static final int CB_BA_MT = ImsUtImplBase.CALL_BARRING_INCOMING_ALL_SERVICES;
// Barring of Specific Incoming calls
- public static final int CB_BS_MT = 10;
+ public static final int CB_BS_MT = ImsUtImplBase.CALL_BARRING_SPECIFIC_INCOMING_CALLS;
/**
* Invalid result value.
*/
- public static final int INVALID = (-1);
+ public static final int INVALID = ImsUtImplBase.INVALID_RESULT;
@@ -164,6 +166,12 @@
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 4f97cc5..302be65 100644
--- a/telephony/java/com/android/ims/internal/IImsUt.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUt.aidl
@@ -122,4 +122,10 @@
*/
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/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 1f84451..d7fbafb 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -29,6 +29,7 @@
import android.service.carrier.CarrierIdentifier;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
+import android.telephony.CallForwardingInfo;
import android.telephony.CarrierRestrictionRules;
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
@@ -38,6 +39,7 @@
import android.telephony.ModemActivityInfo;
import android.telephony.NeighboringCellInfo;
import android.telephony.NetworkScanRequest;
+import android.telephony.PhoneCapability;
import android.telephony.PhoneNumberRange;
import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
@@ -828,6 +830,11 @@
void disableIms(int slotId);
/**
+ * Toggle framework IMS disables and enables.
+ */
+ void resetIms(int slotIndex);
+
+ /**
* Get IImsMmTelFeature binder from ImsResolver that corresponds to the subId and MMTel feature
* as well as registering the MmTelFeature for callbacks using the IImsServiceFeatureCallback
* interface.
@@ -922,6 +929,23 @@
int subId, in OperatorInfo operatorInfo, boolean persisSelection);
/**
+ * Get the allowed network types that store in the telephony provider.
+ *
+ * @param subId the id of the subscription.
+ * @return allowedNetworkTypes the allowed network types.
+ */
+ long getAllowedNetworkTypes(int subId);
+
+ /**
+ * Set the allowed network types.
+ *
+ * @param subId the id of the subscription.
+ * @param allowedNetworkTypes the allowed network types.
+ * @return true on success; false on any failure.
+ */
+ boolean setAllowedNetworkTypes(int subId, long allowedNetworkTypes);
+
+ /**
* Set the preferred network type.
* Used for device configuration by some CDMA operators.
*
@@ -973,6 +997,11 @@
boolean isManualNetworkSelectionAllowed(int subId);
/**
+ * Enable or disable always reporting signal strength changes from radio.
+ */
+ void setAlwaysReportSignalStrength(int subId, boolean isEnable);
+
+ /**
* Get P-CSCF address from PCO after data connection is established or modified.
* @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
* @param callingPackage The package making the call.
@@ -1603,6 +1632,79 @@
NetworkStats getVtDataUsage(int subId, boolean perUidStats);
/**
+ * Gets the voice call forwarding info {@link CallForwardingInfo}, given the call forward
+ * reason.
+ *
+ * @param callForwardingReason the call forwarding reasons which are the bitwise-OR combination
+ * of the following constants:
+ * <ol>
+ * <li>{@link CallForwardingInfo#REASON_BUSY} </li>
+ * <li>{@link CallForwardingInfo#REASON_NO_REPLY} </li>
+ * <li>{@link CallForwardingInfo#REASON_NOT_REACHABLE} </li>
+ * </ol>
+ *
+ * @throws IllegalArgumentException if callForwardingReason is not a bitwise-OR combination
+ * of {@link CallForwardingInfo.REASON_BUSY}, {@link CallForwardingInfo.REASON_BUSY},
+ * {@link CallForwardingInfo.REASON_NOT_REACHABLE}
+ *
+ * @return {@link CallForwardingInfo} with the status {@link CallForwardingInfo#STATUS_ACTIVE}
+ * or {@link CallForwardingInfo#STATUS_INACTIVE} and the target phone number to forward calls
+ * to, if it's available. Otherwise, it will return a {@link CallForwardingInfo} with status
+ * {@link CallForwardingInfo#STATUS_NOT_SUPPORTED} or
+ * {@link CallForwardingInfo#STATUS_FDN_CHECK_FAILURE} depending on the situation.
+ *
+ * @hide
+ */
+ CallForwardingInfo getCallForwarding(int subId, int callForwardingReason);
+
+ /**
+ * Sets the voice call forwarding info including status (enable/disable), call forwarding
+ * reason, the number to forward, and the timeout before the forwarding is attempted.
+ *
+ * @param callForwardingInfo {@link CallForwardingInfo} to setup the call forwarding.
+ * Enabling if {@link CallForwardingInfo#getStatus()} returns
+ * {@link CallForwardingInfo#STATUS_ACTIVE}; Disabling if
+ * {@link CallForwardingInfo#getStatus()} returns {@link CallForwardingInfo#STATUS_INACTIVE}.
+ *
+ * @throws IllegalArgumentException if any of the following:
+ * 0) callForwardingInfo is null.
+ * 1) {@link CallForwardingInfo#getStatus()} for callForwardingInfo returns neither
+ * {@link CallForwardingInfo#STATUS_ACTIVE} nor {@link CallForwardingInfo#STATUS_INACTIVE}.
+ * 2) {@link CallForwardingInfo#getReason()} for callForwardingInfo doesn't return the
+ * bitwise-OR combination of {@link CallForwardingInfo.REASON_BUSY},
+ * {@link CallForwardingInfo.REASON_BUSY}, {@link CallForwardingInfo.REASON_NOT_REACHABLE}
+ * 3) {@link CallForwardingInfo#getNumber()} for callForwardingInfo returns null.
+ * 4) {@link CallForwardingInfo#getTimeout()} for callForwardingInfo returns nagetive value.
+ *
+ * @return {@code true} to indicate it was set successfully; {@code false} otherwise.
+ *
+ * @hide
+ */
+ boolean setCallForwarding(int subId, in CallForwardingInfo callForwardingInfo);
+
+ /**
+ * Gets the status of voice call waiting function. Call waiting function enables the waiting
+ * for the incoming call when it reaches the user who is busy to make another call and allows
+ * users to decide whether to switch to the incoming call.
+ *
+ * @return the status of call waiting function.
+ * @hide
+ */
+ int getCallWaitingStatus(int subId);
+
+ /**
+ * Sets the status for voice call waiting function. Call waiting function enables the waiting
+ * for the incoming call when it reaches the user who is busy to make another call and allows
+ * users to decide whether to switch to the incoming call.
+ *
+ * @param isEnable {@code true} to enable; {@code false} to disable.
+ * @return {@code true} to indicate it was set successfully; {@code false} otherwise.
+ *
+ * @hide
+ */
+ boolean setCallWaitingStatus(int subId, boolean isEnable);
+
+ /**
* Policy control of data connection. Usually used when data limit is passed.
* @param enabled True if enabling the data, otherwise disabling.
* @param subId Subscription index
@@ -1803,12 +1905,17 @@
/**
* Return the network selection mode on the subscription with id {@code subId}.
*/
- int getNetworkSelectionMode(int subId);
+ int getNetworkSelectionMode(int subId);
- /**
+ /**
+ * Return the PhoneCapability for the device.
+ */
+ PhoneCapability getPhoneCapability(int subId, String callingPackage, String callingFeatureId);
+
+ /**
* Return true if the device is in emergency sms mode, false otherwise.
*/
- boolean isInEmergencySmsMode();
+ boolean isInEmergencySmsMode();
/**
* Return the modem radio power state for slot index.
@@ -2087,6 +2194,11 @@
int getRadioHalVersion();
/**
+ * Get the current calling package name.
+ */
+ String getCurrentPackageName();
+
+ /**
* Returns true if the specified type of application (e.g. {@link #APPTYPE_CSIM} is present
* on the UICC card.
* @hide
diff --git a/telephony/java/com/android/internal/telephony/OperatorInfo.java b/telephony/java/com/android/internal/telephony/OperatorInfo.java
index 64d7863..2ca4598 100644
--- a/telephony/java/com/android/internal/telephony/OperatorInfo.java
+++ b/telephony/java/com/android/internal/telephony/OperatorInfo.java
@@ -20,6 +20,7 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
/**
* @hide
@@ -43,6 +44,7 @@
@UnsupportedAppUsage
private State mState = State.UNKNOWN;
+ private int mRan = AccessNetworkType.UNKNOWN;
@UnsupportedAppUsage
@@ -69,6 +71,10 @@
return mState;
}
+ public int getRan() {
+ return mRan;
+ }
+
@UnsupportedAppUsage
OperatorInfo(String operatorAlphaLong,
String operatorAlphaShort,
@@ -82,6 +88,14 @@
mState = state;
}
+ OperatorInfo(String operatorAlphaLong,
+ String operatorAlphaShort,
+ String operatorNumeric,
+ State state,
+ int ran) {
+ this (operatorAlphaLong, operatorAlphaShort, operatorNumeric, state);
+ mRan = ran;
+ }
@UnsupportedAppUsage
public OperatorInfo(String operatorAlphaLong,
@@ -92,6 +106,14 @@
operatorNumeric, rilStateToState(stateString));
}
+ public OperatorInfo(String operatorAlphaLong,
+ String operatorAlphaShort,
+ String operatorNumeric,
+ int ran) {
+ this (operatorAlphaLong, operatorAlphaShort, operatorNumeric);
+ mRan = ran;
+ }
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public OperatorInfo(String operatorAlphaLong,
String operatorAlphaShort,
@@ -124,7 +146,8 @@
return "OperatorInfo " + mOperatorAlphaLong
+ "/" + mOperatorAlphaShort
+ "/" + mOperatorNumeric
- + "/" + mState;
+ + "/" + mState
+ + "/" + mRan;
}
/**
@@ -150,6 +173,7 @@
dest.writeString(mOperatorAlphaShort);
dest.writeString(mOperatorNumeric);
dest.writeSerializable(mState);
+ dest.writeInt(mRan);
}
/**
@@ -158,20 +182,21 @@
*/
@UnsupportedAppUsage
public static final Creator<OperatorInfo> CREATOR =
- new Creator<OperatorInfo>() {
- @Override
- public OperatorInfo createFromParcel(Parcel in) {
- OperatorInfo opInfo = new OperatorInfo(
- in.readString(), /*operatorAlphaLong*/
- in.readString(), /*operatorAlphaShort*/
- in.readString(), /*operatorNumeric*/
- (State) in.readSerializable()); /*state*/
- return opInfo;
- }
+ new Creator<OperatorInfo>() {
+ @Override
+ public OperatorInfo createFromParcel(Parcel in) {
+ OperatorInfo opInfo = new OperatorInfo(
+ in.readString(), /*operatorAlphaLong*/
+ in.readString(), /*operatorAlphaShort*/
+ in.readString(), /*operatorNumeric*/
+ (State) in.readSerializable(), /*state*/
+ in.readInt()); /*ran*/
+ return opInfo;
+ }
- @Override
- public OperatorInfo[] newArray(int size) {
- return new OperatorInfo[size];
- }
- };
+ @Override
+ public OperatorInfo[] newArray(int size) {
+ return new OperatorInfo[size];
+ }
+ };
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 284544b..0e0a22ee 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -477,6 +477,7 @@
int RIL_REQUEST_STOP_KEEPALIVE = 145;
int RIL_REQUEST_ENABLE_MODEM = 146;
int RIL_REQUEST_GET_MODEM_STATUS = 147;
+ int RIL_REQUEST_CDMA_SEND_SMS_EXPECT_MORE = 148;
/* The following requests are not defined in RIL.h */
int RIL_REQUEST_HAL_NON_RIL_BASE = 200;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index b4d3ec9..eef96c4 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -205,8 +205,6 @@
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 832502c..d0c8024 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 & 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 @@
}
/**
- * Get an SMS-SUBMIT PDU for a data message to a destination address & port
+ * Gets an SMS-SUBMIT PDU for a data message to a destination address & 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 @@
}
/**
- * Get an SMS-SUBMIT PDU for a data message to a destination address & port
+ * Gets an SMS-SUBMIT PDU for a data message to a destination address & 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 @@
}
/**
+ * 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 ca03333..f4a96a6 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.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 @@
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 @@
}
}
+ 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 @@
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 f54da3b..4538193 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 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * Get an SMS-SUBMIT PDU for a data message to a destination address & port
+ * Gets an SMS-SUBMIT PDU for a data message to a destination address & 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 @@
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 @@
}
/**
- * 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 @@
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/telephony/java/com/android/internal/telephony/util/RemoteCallbackListExt.java b/telephony/java/com/android/internal/telephony/util/RemoteCallbackListExt.java
new file mode 100644
index 0000000..d66bda9
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/util/RemoteCallbackListExt.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.util;
+
+import android.os.IInterface;
+import android.os.RemoteCallbackList;
+
+import java.util.function.Consumer;
+
+/**
+ * Extension of RemoteCallbackList
+ * @param <E> defines the type of registered callbacks
+ */
+public class RemoteCallbackListExt<E extends IInterface> extends RemoteCallbackList<E> {
+ /**
+ * Performs {@code action} on each callback, calling
+ * {@link RemoteCallbackListExt#beginBroadcast()}
+ * /{@link RemoteCallbackListExt#finishBroadcast()} before/after looping
+ * @param action to be performed on each callback
+ *
+ */
+ public void broadcastAction(Consumer<E> action) {
+ int itemCount = beginBroadcast();
+ try {
+ for (int i = 0; i < itemCount; i++) {
+ action.accept(getBroadcastItem(i));
+ }
+ } finally {
+ finishBroadcast();
+ }
+ }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java
index 42cafd4..5a66e80 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ChangeAppRotationTest.java
@@ -66,7 +66,7 @@
@Parameters(name = "{0}-{1}")
public static Collection<Object[]> getParams() {
int[] supportedRotations =
- {Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_270};
+ {Surface.ROTATION_0, Surface.ROTATION_90};
Collection<Object[]> params = new ArrayList<>();
for (int begin : supportedRotations) {
for (int end : supportedRotations) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java
index fc6719e..f740af9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java
@@ -25,6 +25,7 @@
import org.junit.Before;
import org.junit.FixMethodOrder;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
@@ -62,6 +63,7 @@
.forAllEntries());
}
+ @Ignore("Flaky")
@Test
public void checkVisibility_imeLayerBecomesInvisible() {
checkResults(result -> LayersTraceSubject.assertThat(result)
@@ -71,6 +73,7 @@
.forAllEntries());
}
+ @Ignore("Flaky")
@Test
public void checkVisibility_imeAppLayerBecomesInvisible() {
checkResults(result -> LayersTraceSubject.assertThat(result)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
index ae55a75..37d7c4c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
@@ -30,10 +30,12 @@
import android.view.Surface;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
import androidx.test.filters.LargeTest;
import org.junit.Before;
import org.junit.FixMethodOrder;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
@@ -50,6 +52,8 @@
@LargeTest
@RunWith(Parameterized.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@FlakyTest(bugId = 147659548)
+@Ignore("Waiting bug feedback")
public class SeamlessAppRotationTest extends FlickerTestBase {
private int mBeginRotation;
private int mEndRotation;
@@ -65,7 +69,7 @@
@Parameters(name = "{0}")
public static Collection<Object[]> getParams() {
int[] supportedRotations =
- {Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_270};
+ {Surface.ROTATION_0, Surface.ROTATION_90};
Collection<Object[]> params = new ArrayList<>();
ArrayList<Intent> testIntents = new ArrayList<>();
@@ -108,7 +112,7 @@
super.runTransition(
changeAppRotation(mIntent, intentId, InstrumentationRegistry.getContext(),
- mUiDevice, mBeginRotation, mEndRotation).repeat(5).build());
+ mUiDevice, mBeginRotation, mEndRotation).build());
}
@Test
diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp
index 5e9ef8e..609896e 100644
--- a/tests/PlatformCompatGating/Android.bp
+++ b/tests/PlatformCompatGating/Android.bp
@@ -18,7 +18,6 @@
name: "PlatformCompatGating",
// Only compile source java files in this apk.
srcs: ["src/**/*.java"],
- certificate: "platform",
libs: [
"android.test.runner",
"android.test.base",
diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
index 932ec64..c00aa2a 100644
--- a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
+++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
@@ -16,7 +16,9 @@
package android.compat.testing;
+import android.Manifest;
import android.app.Instrumentation;
+import android.app.UiAutomation;
import android.compat.Compatibility;
import android.compat.Compatibility.ChangeConfig;
import android.content.Context;
@@ -83,12 +85,16 @@
@Override
public void evaluate() throws Throwable {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ UiAutomation uiAutomation = instrumentation.getUiAutomation();
String packageName = instrumentation.getTargetContext().getPackageName();
IPlatformCompat platformCompat = IPlatformCompat.Stub
.asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
if (platformCompat == null) {
throw new IllegalStateException("Could not get IPlatformCompat service!");
}
+ uiAutomation.adoptShellPermissionIdentity(
+ Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
+ Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG);
Compatibility.setOverrides(mConfig);
try {
platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig),
@@ -101,6 +107,7 @@
} catch (RemoteException e) {
throw new RuntimeException("Could not call IPlatformCompat binder method!", e);
} finally {
+ uiAutomation.dropShellPermissionIdentity();
Compatibility.clearOverrides();
}
}
diff --git a/tests/libs-permissions/Android.bp b/tests/libs-permissions/Android.bp
index 330bfc9..66a1f83 100644
--- a/tests/libs-permissions/Android.bp
+++ b/tests/libs-permissions/Android.bp
@@ -2,6 +2,7 @@
name: "com.android.test.libs.product",
installable: true,
product_specific: true,
+ sdk_version: "current",
srcs: ["product/java/**/*.java"],
required: ["com.android.test.libs.product.xml"],
}
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
index b2e573b..06c6301 100644
--- a/tests/net/common/java/android/net/LinkAddressTest.java
+++ b/tests/net/common/java/android/net/LinkAddressTest.java
@@ -38,6 +38,8 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.os.SystemClock;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -316,9 +318,76 @@
l = new LinkAddress(V6_ADDRESS, 64, 123, 456);
assertParcelingIsLossless(l);
+ l = new LinkAddress(V6_ADDRESS, 64, 123, 456,
+ 1L, 3600000L);
+ assertParcelingIsLossless(l);
l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
- assertParcelSane(l, 4);
+ assertParcelSane(l, 6);
+ }
+
+ @Test
+ public void testDeprecationTime() {
+ try {
+ new LinkAddress(V6_ADDRESS, 64, 0, 456,
+ LinkAddress.LIFETIME_UNKNOWN, 100000L);
+ fail("Only one time provided should cause exception");
+ } catch (IllegalArgumentException expected) { }
+
+ try {
+ new LinkAddress(V6_ADDRESS, 64, 0, 456,
+ 200000L, 100000L);
+ fail("deprecation time later than expiration time should cause exception");
+ } catch (IllegalArgumentException expected) { }
+
+ try {
+ new LinkAddress(V6_ADDRESS, 64, 0, 456,
+ -2, 100000L);
+ fail("negative deprecation time should cause exception");
+ } catch (IllegalArgumentException expected) { }
+ }
+
+ @Test
+ public void testExpirationTime() {
+ try {
+ new LinkAddress(V6_ADDRESS, 64, 0, 456,
+ 200000L, LinkAddress.LIFETIME_UNKNOWN);
+ fail("Only one time provided should cause exception");
+ } catch (IllegalArgumentException expected) { }
+
+ try {
+ new LinkAddress(V6_ADDRESS, 64, 0, 456,
+ 100000L, -2);
+ fail("negative expiration time should cause exception");
+ } catch (IllegalArgumentException expected) { }
+ }
+
+ @Test
+ public void testGetFlags() {
+ LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, RT_SCOPE_HOST);
+ assertEquals(123, l.getFlags());
+
+ // Test if deprecated bit was added/remove automatically based on the provided deprecation
+ // time
+ l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST,
+ 1L, LinkAddress.LIFETIME_PERMANENT);
+ // Check if the flag is added automatically.
+ assertTrue((l.getFlags() & IFA_F_DEPRECATED) != 0);
+
+ l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
+ SystemClock.elapsedRealtime() + 100000L, LinkAddress.LIFETIME_PERMANENT);
+ // Check if the flag is removed automatically.
+ assertTrue((l.getFlags() & IFA_F_DEPRECATED) == 0);
+
+ l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_HOST,
+ LinkAddress.LIFETIME_PERMANENT, LinkAddress.LIFETIME_PERMANENT);
+ // Check if the permanent flag is added.
+ assertTrue((l.getFlags() & IFA_F_PERMANENT) != 0);
+
+ l = new LinkAddress(V6_ADDRESS, 64, IFA_F_PERMANENT, RT_SCOPE_HOST,
+ 1000L, SystemClock.elapsedRealtime() + 100000L);
+ // Check if the permanent flag is removed
+ assertTrue((l.getFlags() & IFA_F_PERMANENT) == 0);
}
private void assertGlobalPreferred(LinkAddress l, String msg) {
@@ -389,5 +458,12 @@
(IFA_F_TEMPORARY|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC),
RT_SCOPE_UNIVERSE);
assertGlobalPreferred(l, "v6,global,tempaddr+optimistic");
+
+ l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED,
+ RT_SCOPE_UNIVERSE, SystemClock.elapsedRealtime() + 100000,
+ SystemClock.elapsedRealtime() + 200000);
+ // Although the deprecated bit is set, but the deprecation time is in the future, test
+ // if the flag is removed automatically.
+ assertGlobalPreferred(l, "v6,global,tempaddr+deprecated in the future");
}
}
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index a7328ac..3f311c9 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -75,6 +75,9 @@
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 @@
assertFalse(lp.isIpv6Provisioned());
assertFalse(lp.isPrivateDnsActive());
assertFalse(lp.isWakeOnLanSupported());
+ assertNull(lp.getCaptivePortalApiUrl());
+ assertNull(lp.getCaptivePortalData());
}
private LinkProperties makeTestObject() {
@@ -124,6 +129,8 @@
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 @@
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 @@
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 @@
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 @@
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/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 1569112..3e4f3d8 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -269,9 +269,10 @@
.setUids(uids)
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.setOwnerUid(123);
assertParcelingIsLossless(netCap);
netCap.setSSID(TEST_SSID);
- assertParcelSane(netCap, 12);
+ assertParcelSane(netCap, 13);
}
@Test
diff --git a/tests/net/common/java/android/net/RouteInfoTest.java b/tests/net/common/java/android/net/RouteInfoTest.java
index 5ce8436..fe51b3a 100644
--- a/tests/net/common/java/android/net/RouteInfoTest.java
+++ b/tests/net/common/java/android/net/RouteInfoTest.java
@@ -258,6 +258,16 @@
assertParcelingIsLossless(r);
r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
- assertParcelSane(r, 6);
+ assertParcelSane(r, 7);
+ }
+
+ public void testMtu() {
+ RouteInfo r;
+ r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0",
+ RouteInfo.RTN_UNICAST, 1500);
+ assertEquals(1500, r.getMtu());
+
+ r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0");
+ assertEquals(0, r.getMtu());
}
}
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index 18474a8..1c69209 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.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 @@
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 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 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 @@
@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 0000000..0071438
--- /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 0000000..7ab4b56
--- /dev/null
+++ b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java
@@ -0,0 +1,248 @@
+/*
+ * 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.ConnectivityDiagnosticsBinder;
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
+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 static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.os.PersistableBundle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+
+import java.util.concurrent.Executor;
+
+@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 static final Executor INLINE_EXECUTOR = x -> x.run();
+
+ @Mock private ConnectivityDiagnosticsCallback mCb;
+
+ private ConnectivityDiagnosticsBinder mBinder;
+
+ @Before
+ public void setUp() {
+ mCb = mock(ConnectivityDiagnosticsCallback.class);
+
+ mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR);
+ }
+
+ 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);
+ }
+
+ @Test
+ public void testConnectivityDiagnosticsCallbackOnConnectivityReport() {
+ mBinder.onConnectivityReport(createSampleConnectivityReport());
+
+ // The callback will be invoked synchronously by inline executor. Immediately check the
+ // latch without waiting.
+ verify(mCb).onConnectivityReport(eq(createSampleConnectivityReport()));
+ }
+
+ @Test
+ public void testConnectivityDiagnosticsCallbackOnDataStallSuspected() {
+ mBinder.onDataStallSuspected(createSampleDataStallReport());
+
+ // The callback will be invoked synchronously by inline executor. Immediately check the
+ // latch without waiting.
+ verify(mCb).onDataStallSuspected(eq(createSampleDataStallReport()));
+ }
+
+ @Test
+ public void testConnectivityDiagnosticsCallbackOnNetworkConnectivityReported() {
+ final Network n = new Network(NET_ID);
+ final boolean connectivity = true;
+
+ mBinder.onNetworkConnectivityReported(n, connectivity);
+
+ // The callback will be invoked synchronously by inline executor. Immediately check the
+ // latch without waiting.
+ verify(mCb).onNetworkConnectivityReported(eq(n), eq(connectivity));
+ }
+}
diff --git a/tests/net/java/android/net/Ikev2VpnProfileTest.java b/tests/net/java/android/net/Ikev2VpnProfileTest.java
new file mode 100644
index 0000000..d6a2176
--- /dev/null
+++ b/tests/net/java/android/net/Ikev2VpnProfileTest.java
@@ -0,0 +1,360 @@
+/*
+ * 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 static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+
+import android.test.mock.MockContext;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.net.VpnProfile;
+import com.android.org.bouncycastle.x509.X509V1CertificateGenerator;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+import javax.security.auth.x500.X500Principal;
+
+/** Unit tests for {@link Ikev2VpnProfile.Builder}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class Ikev2VpnProfileTest {
+ private static final String SERVER_ADDR_STRING = "1.2.3.4";
+ private static final String IDENTITY_STRING = "Identity";
+ private static final String USERNAME_STRING = "username";
+ private static final String PASSWORD_STRING = "pa55w0rd";
+ private static final String EXCL_LIST = "exclList";
+ private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
+ private static final int TEST_MTU = 1300;
+
+ private final MockContext mMockContext =
+ new MockContext() {
+ @Override
+ public String getOpPackageName() {
+ return "fooPackage";
+ }
+ };
+ private final ProxyInfo mProxy = new ProxyInfo(SERVER_ADDR_STRING, -1, EXCL_LIST);
+
+ private X509Certificate mUserCert;
+ private X509Certificate mServerRootCa;
+ private PrivateKey mPrivateKey;
+
+ @Before
+ public void setUp() throws Exception {
+ mServerRootCa = generateRandomCertAndKeyPair().cert;
+
+ final CertificateAndKey userCertKey = generateRandomCertAndKeyPair();
+ mUserCert = userCertKey.cert;
+ mPrivateKey = userCertKey.key;
+ }
+
+ private Ikev2VpnProfile.Builder getBuilderWithDefaultOptions() {
+ final Ikev2VpnProfile.Builder builder =
+ new Ikev2VpnProfile.Builder(SERVER_ADDR_STRING, IDENTITY_STRING);
+
+ builder.setBypassable(true);
+ builder.setProxy(mProxy);
+ builder.setMaxMtu(TEST_MTU);
+ builder.setMetered(true);
+
+ return builder;
+ }
+
+ @Test
+ public void testBuildValidProfileWithOptions() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
+ final Ikev2VpnProfile profile = builder.build();
+ assertNotNull(profile);
+
+ // Check non-auth parameters correctly stored
+ assertEquals(SERVER_ADDR_STRING, profile.getServerAddr());
+ assertEquals(IDENTITY_STRING, profile.getUserIdentity());
+ assertEquals(mProxy, profile.getProxyInfo());
+ assertTrue(profile.isBypassable());
+ assertTrue(profile.isMetered());
+ assertEquals(TEST_MTU, profile.getMaxMtu());
+ }
+
+ @Test
+ public void testBuildUsernamePasswordProfile() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
+ final Ikev2VpnProfile profile = builder.build();
+ assertNotNull(profile);
+
+ assertEquals(USERNAME_STRING, profile.getUsername());
+ assertEquals(PASSWORD_STRING, profile.getPassword());
+ assertEquals(mServerRootCa, profile.getServerRootCaCert());
+
+ assertNull(profile.getPresharedKey());
+ assertNull(profile.getRsaPrivateKey());
+ assertNull(profile.getUserCert());
+ }
+
+ @Test
+ public void testBuildDigitalSignatureProfile() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
+ final Ikev2VpnProfile profile = builder.build();
+ assertNotNull(profile);
+
+ assertEquals(profile.getUserCert(), mUserCert);
+ assertEquals(mPrivateKey, profile.getRsaPrivateKey());
+ assertEquals(profile.getServerRootCaCert(), mServerRootCa);
+
+ assertNull(profile.getPresharedKey());
+ assertNull(profile.getUsername());
+ assertNull(profile.getPassword());
+ }
+
+ @Test
+ public void testBuildPresharedKeyProfile() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthPsk(PSK_BYTES);
+ final Ikev2VpnProfile profile = builder.build();
+ assertNotNull(profile);
+
+ assertArrayEquals(PSK_BYTES, profile.getPresharedKey());
+
+ assertNull(profile.getServerRootCaCert());
+ assertNull(profile.getUsername());
+ assertNull(profile.getPassword());
+ assertNull(profile.getRsaPrivateKey());
+ assertNull(profile.getUserCert());
+ }
+
+ @Test
+ public void testBuildNoAuthMethodSet() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ try {
+ builder.build();
+ fail("Expected exception due to lack of auth method");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testBuildInvalidMtu() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ try {
+ builder.setMaxMtu(500);
+ fail("Expected exception due to too-small MTU");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ private void verifyVpnProfileCommon(VpnProfile profile) {
+ assertEquals(SERVER_ADDR_STRING, profile.server);
+ assertEquals(IDENTITY_STRING, profile.ipsecIdentifier);
+ assertEquals(mProxy, profile.proxy);
+ assertTrue(profile.isBypassable);
+ assertTrue(profile.isMetered);
+ assertEquals(TEST_MTU, profile.maxMtu);
+ }
+
+ @Test
+ public void testPskConvertToVpnProfile() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthPsk(PSK_BYTES);
+ final VpnProfile profile = builder.build().toVpnProfile();
+
+ verifyVpnProfileCommon(profile);
+ assertEquals(Ikev2VpnProfile.encodeForIpsecSecret(PSK_BYTES), profile.ipsecSecret);
+
+ // Check nothing else is set
+ assertEquals("", profile.username);
+ assertEquals("", profile.password);
+ assertEquals("", profile.ipsecUserCert);
+ assertEquals("", profile.ipsecCaCert);
+ }
+
+ @Test
+ public void testUsernamePasswordConvertToVpnProfile() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
+ final VpnProfile profile = builder.build().toVpnProfile();
+
+ verifyVpnProfileCommon(profile);
+ assertEquals(USERNAME_STRING, profile.username);
+ assertEquals(PASSWORD_STRING, profile.password);
+ assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
+
+ // Check nothing else is set
+ assertEquals("", profile.ipsecUserCert);
+ assertEquals("", profile.ipsecSecret);
+ }
+
+ @Test
+ public void testRsaConvertToVpnProfile() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
+ final VpnProfile profile = builder.build().toVpnProfile();
+
+ verifyVpnProfileCommon(profile);
+ assertEquals(Ikev2VpnProfile.certificateToPemString(mUserCert), profile.ipsecUserCert);
+ assertEquals(
+ Ikev2VpnProfile.encodeForIpsecSecret(mPrivateKey.getEncoded()),
+ profile.ipsecSecret);
+ assertEquals(Ikev2VpnProfile.certificateToPemString(mServerRootCa), profile.ipsecCaCert);
+
+ // Check nothing else is set
+ assertEquals("", profile.username);
+ assertEquals("", profile.password);
+ }
+
+ @Test
+ public void testPskFromVpnProfileDiscardsIrrelevantValues() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthPsk(PSK_BYTES);
+ final VpnProfile profile = builder.build().toVpnProfile();
+ profile.username = USERNAME_STRING;
+ profile.password = PASSWORD_STRING;
+ profile.ipsecCaCert = Ikev2VpnProfile.certificateToPemString(mServerRootCa);
+ profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
+
+ final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
+ assertNull(result.getUsername());
+ assertNull(result.getPassword());
+ assertNull(result.getUserCert());
+ assertNull(result.getRsaPrivateKey());
+ assertNull(result.getServerRootCaCert());
+ }
+
+ @Test
+ public void testUsernamePasswordFromVpnProfileDiscardsIrrelevantValues() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
+ final VpnProfile profile = builder.build().toVpnProfile();
+ profile.ipsecSecret = new String(PSK_BYTES);
+ profile.ipsecUserCert = Ikev2VpnProfile.certificateToPemString(mUserCert);
+
+ final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
+ assertNull(result.getPresharedKey());
+ assertNull(result.getUserCert());
+ assertNull(result.getRsaPrivateKey());
+ }
+
+ @Test
+ public void testRsaFromVpnProfileDiscardsIrrelevantValues() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
+ final VpnProfile profile = builder.build().toVpnProfile();
+ profile.username = USERNAME_STRING;
+ profile.password = PASSWORD_STRING;
+
+ final Ikev2VpnProfile result = Ikev2VpnProfile.fromVpnProfile(profile);
+ assertNull(result.getUsername());
+ assertNull(result.getPassword());
+ assertNull(result.getPresharedKey());
+ }
+
+ @Test
+ public void testPskConversionIsLossless() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthPsk(PSK_BYTES);
+ final Ikev2VpnProfile ikeProfile = builder.build();
+
+ assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
+ }
+
+ @Test
+ public void testUsernamePasswordConversionIsLossless() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthUsernamePassword(USERNAME_STRING, PASSWORD_STRING, mServerRootCa);
+ final Ikev2VpnProfile ikeProfile = builder.build();
+
+ assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
+ }
+
+ @Test
+ public void testRsaConversionIsLossless() throws Exception {
+ final Ikev2VpnProfile.Builder builder = getBuilderWithDefaultOptions();
+
+ builder.setAuthDigitalSignature(mUserCert, mPrivateKey, mServerRootCa);
+ final Ikev2VpnProfile ikeProfile = builder.build();
+
+ assertEquals(ikeProfile, Ikev2VpnProfile.fromVpnProfile(ikeProfile.toVpnProfile()));
+ }
+
+ private static class CertificateAndKey {
+ public final X509Certificate cert;
+ public final PrivateKey key;
+
+ CertificateAndKey(X509Certificate cert, PrivateKey key) {
+ this.cert = cert;
+ this.key = key;
+ }
+ }
+
+ private static CertificateAndKey generateRandomCertAndKeyPair() throws Exception {
+ final Date validityBeginDate =
+ new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1L));
+ final Date validityEndDate =
+ new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1L));
+
+ // Generate a keypair
+ final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(512);
+ final KeyPair keyPair = keyPairGenerator.generateKeyPair();
+
+ final X500Principal dnName = new X500Principal("CN=test.android.com");
+ final X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
+ certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
+ certGen.setSubjectDN(dnName);
+ certGen.setIssuerDN(dnName);
+ certGen.setNotBefore(validityBeginDate);
+ certGen.setNotAfter(validityEndDate);
+ certGen.setPublicKey(keyPair.getPublic());
+ certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
+
+ final X509Certificate cert = certGen.generate(keyPair.getPrivate(), "AndroidOpenSSL");
+ return new CertificateAndKey(cert, keyPair.getPrivate());
+ }
+}
diff --git a/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java b/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java
new file mode 100644
index 0000000..47afed4
--- /dev/null
+++ b/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+
+import android.telephony.SubscriptionManager;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Unit test for {@link android.net.TelephonyNetworkSpecifier}.
+ */
+@SmallTest
+public class TelephonyNetworkSpecifierTest {
+ private static final int TEST_SUBID = 5;
+
+ /**
+ * Validate that IllegalArgumentException will be thrown if build TelephonyNetworkSpecifier
+ * without calling {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}.
+ */
+ @Test
+ public void testBuilderBuildWithDefault() {
+ try {
+ new TelephonyNetworkSpecifier.Builder().build();
+ } catch (IllegalArgumentException iae) {
+ // expected, test pass
+ }
+ }
+
+ /**
+ * Validate that no exception will be thrown even if pass invalid subscription id to
+ * {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}.
+ */
+ @Test
+ public void testBuilderBuildWithInvalidSubId() {
+ TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
+ .setSubscriptionId(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ .build();
+ assertEquals(specifier.getSubscriptionId(), SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ }
+
+ /**
+ * Validate the correctness of TelephonyNetworkSpecifier when provide valid subId.
+ */
+ @Test
+ public void testBuilderBuildWithValidSubId() {
+ final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
+ .setSubscriptionId(TEST_SUBID)
+ .build();
+ assertEquals(TEST_SUBID, specifier.getSubscriptionId());
+ }
+
+ /**
+ * Validate that parcel marshalling/unmarshalling works.
+ */
+ @Test
+ public void testParcel() {
+ TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder()
+ .setSubscriptionId(TEST_SUBID)
+ .build();
+ assertParcelSane(specifier, 1 /* fieldCount */);
+ }
+}
diff --git a/tests/net/java/android/net/VpnManagerTest.java b/tests/net/java/android/net/VpnManagerTest.java
new file mode 100644
index 0000000..655c4d1
--- /dev/null
+++ b/tests/net/java/android/net/VpnManagerTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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 static org.mockito.Mockito.mock;
+
+import android.test.mock.MockContext;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link VpnManager}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class VpnManagerTest {
+ private static final String VPN_PROFILE_KEY = "KEY";
+
+ private IConnectivityManager mMockCs;
+ private VpnManager mVpnManager;
+ private final MockContext mMockContext =
+ new MockContext() {
+ @Override
+ public String getOpPackageName() {
+ return "fooPackage";
+ }
+ };
+
+ @Before
+ public void setUp() throws Exception {
+ mMockCs = mock(IConnectivityManager.class);
+ mVpnManager = new VpnManager(mMockContext, mMockCs);
+ }
+
+ @Test
+ public void testProvisionVpnProfile() throws Exception {
+ try {
+ mVpnManager.provisionVpnProfile(mock(PlatformVpnProfile.class));
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+
+ @Test
+ public void testDeleteProvisionedVpnProfile() throws Exception {
+ try {
+ mVpnManager.deleteProvisionedVpnProfile();
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+
+ @Test
+ public void testStartProvisionedVpnProfile() throws Exception {
+ try {
+ mVpnManager.startProvisionedVpnProfile();
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+
+ @Test
+ public void testStopProvisionedVpnProfile() throws Exception {
+ try {
+ mVpnManager.stopProvisionedVpnProfile();
+ } catch (UnsupportedOperationException expected) {
+ }
+ }
+}
diff --git a/tests/net/java/com/android/internal/net/VpnProfileTest.java b/tests/net/java/com/android/internal/net/VpnProfileTest.java
new file mode 100644
index 0000000..8a4b533
--- /dev/null
+++ b/tests/net/java/com/android/internal/net/VpnProfileTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.net;
+
+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.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.net.IpSecAlgorithm;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+
+/** Unit tests for {@link VpnProfile}. */
+@SmallTest
+@RunWith(JUnit4.class)
+public class VpnProfileTest {
+ private static final String DUMMY_PROFILE_KEY = "Test";
+
+ @Test
+ public void testDefaults() throws Exception {
+ final VpnProfile p = new VpnProfile(DUMMY_PROFILE_KEY);
+
+ assertEquals(DUMMY_PROFILE_KEY, p.key);
+ assertEquals("", p.name);
+ assertEquals(VpnProfile.TYPE_PPTP, p.type);
+ assertEquals("", p.server);
+ assertEquals("", p.username);
+ assertEquals("", p.password);
+ assertEquals("", p.dnsServers);
+ assertEquals("", p.searchDomains);
+ assertEquals("", p.routes);
+ assertTrue(p.mppe);
+ assertEquals("", p.l2tpSecret);
+ assertEquals("", p.ipsecIdentifier);
+ assertEquals("", p.ipsecSecret);
+ assertEquals("", p.ipsecUserCert);
+ assertEquals("", p.ipsecCaCert);
+ assertEquals("", p.ipsecServerCert);
+ assertEquals(null, p.proxy);
+ assertTrue(p.getAllowedAlgorithms() != null && p.getAllowedAlgorithms().isEmpty());
+ assertFalse(p.isBypassable);
+ assertFalse(p.isMetered);
+ assertEquals(1400, p.maxMtu);
+ assertFalse(p.areAuthParamsInline);
+ }
+
+ private VpnProfile getSampleIkev2Profile(String key) {
+ final VpnProfile p = new VpnProfile(key);
+
+ p.name = "foo";
+ p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
+ p.server = "bar";
+ p.username = "baz";
+ p.password = "qux";
+ p.dnsServers = "8.8.8.8";
+ p.searchDomains = "";
+ p.routes = "0.0.0.0/0";
+ p.mppe = false;
+ p.l2tpSecret = "";
+ p.ipsecIdentifier = "quux";
+ p.ipsecSecret = "quuz";
+ p.ipsecUserCert = "corge";
+ p.ipsecCaCert = "grault";
+ p.ipsecServerCert = "garply";
+ p.proxy = null;
+ p.setAllowedAlgorithms(
+ Arrays.asList(
+ IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
+ IpSecAlgorithm.AUTH_HMAC_SHA512,
+ IpSecAlgorithm.CRYPT_AES_CBC));
+ p.isBypassable = true;
+ p.isMetered = true;
+ p.maxMtu = 1350;
+ p.areAuthParamsInline = true;
+
+ // Not saved, but also not compared.
+ p.saveLogin = true;
+
+ return p;
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(
+ getSampleIkev2Profile(DUMMY_PROFILE_KEY), getSampleIkev2Profile(DUMMY_PROFILE_KEY));
+
+ final VpnProfile modified = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+ modified.maxMtu--;
+ assertNotEquals(getSampleIkev2Profile(DUMMY_PROFILE_KEY), modified);
+ }
+
+ @Test
+ public void testParcelUnparcel() {
+ assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 22);
+ }
+
+ @Test
+ public void testSetInvalidAlgorithmValueDelimiter() {
+ final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+
+ try {
+ profile.setAllowedAlgorithms(
+ Arrays.asList("test" + VpnProfile.VALUE_DELIMITER + "test"));
+ fail("Expected failure due to value separator in algorithm name");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testSetInvalidAlgorithmListDelimiter() {
+ final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+
+ try {
+ profile.setAllowedAlgorithms(
+ Arrays.asList("test" + VpnProfile.LIST_DELIMITER + "test"));
+ fail("Expected failure due to value separator in algorithm name");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testEncodeDecode() {
+ final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+ final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, profile.encode());
+ assertEquals(profile, decoded);
+ }
+
+ @Test
+ public void testEncodeDecodeTooManyValues() {
+ final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+ final byte[] tooManyValues =
+ (new String(profile.encode()) + VpnProfile.VALUE_DELIMITER + "invalid").getBytes();
+
+ assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooManyValues));
+ }
+
+ @Test
+ public void testEncodeDecodeInvalidNumberOfValues() {
+ final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+ final String encoded = new String(profile.encode());
+ final byte[] tooFewValues =
+ encoded.substring(0, encoded.lastIndexOf(VpnProfile.VALUE_DELIMITER)).getBytes();
+
+ assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues));
+ }
+
+ @Test
+ public void testEncodeDecodeLoginsNotSaved() {
+ final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
+ profile.saveLogin = false;
+
+ final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, profile.encode());
+ assertNotEquals(profile, decoded);
+
+ // Add the username/password back, everything else must be equal.
+ decoded.username = profile.username;
+ decoded.password = profile.password;
+ assertEquals(profile, decoded);
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b2d363e..e80b7c9 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.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.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.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.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.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 @@
@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 @@
}
@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 @@
}
};
- assertEquals(na.netId, nmNetworkCaptor.getValue().netId);
+ assertEquals(na.network.netId, nmNetworkCaptor.getValue().netId);
mNmCallbacks = nmCbCaptor.getValue();
mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor);
@@ -1750,6 +1785,66 @@
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 @@
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());
@@ -6216,12 +6313,24 @@
assertEquals(wifiLp, mService.getActiveLinkProperties());
}
+ @Test
+ public void testNetworkCapabilitiesRestrictedForCallerPermissions() {
+ int callerUid = Process.myUid();
+ final NetworkCapabilities originalNc = new NetworkCapabilities();
+ originalNc.setOwnerUid(callerUid);
- private TestNetworkAgentWrapper establishVpn(LinkProperties lp, int establishingUid,
- Set<UidRange> vpnRange) throws Exception {
+ final NetworkCapabilities newNc =
+ mService.networkCapabilitiesRestrictedForCallerPermissions(
+ originalNc, Process.myPid(), callerUid);
+
+ assertEquals(Process.INVALID_UID, newNc.getOwnerUid());
+ }
+
+ private TestNetworkAgentWrapper establishVpn(
+ LinkProperties lp, int ownerUid, Set<UidRange> vpnRange) throws Exception {
final TestNetworkAgentWrapper
vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp);
- vpnNetworkAgent.getNetworkCapabilities().setEstablishingVpnAppUid(establishingUid);
+ vpnNetworkAgent.getNetworkCapabilities().setOwnerUid(ownerUid);
mMockVpn.setNetworkAgent(vpnNetworkAgent);
mMockVpn.connect();
mMockVpn.setUids(vpnRange);
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 82cb193..e863266 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.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 @@
@Mock INetd mNetd;
@Mock INetworkManagementService mNMS;
@Mock Context mCtx;
- @Mock NetworkMisc mMisc;
@Mock NetworkNotificationManager mNotifier;
@Mock Resources mResources;
@@ -358,7 +356,7 @@
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/MultipathPolicyTrackerTest.java b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
index b783467..de1028c 100644
--- a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
+++ b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
@@ -51,6 +51,7 @@
import android.net.NetworkPolicyManager;
import android.net.NetworkTemplate;
import android.net.StringNetworkSpecifier;
+import android.net.TelephonyNetworkSpecifier;
import android.os.Handler;
import android.provider.Settings;
import android.telephony.TelephonyManager;
@@ -229,7 +230,7 @@
verify(mCM).registerNetworkCallback(any(), networkCallback.capture(), any());
// Simulate callback after capability changes
- final NetworkCapabilities capabilities = new NetworkCapabilities()
+ NetworkCapabilities capabilities = new NetworkCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
.addTransportType(TRANSPORT_CELLULAR)
.setNetworkSpecifier(new StringNetworkSpecifier("234"));
@@ -239,6 +240,19 @@
networkCallback.getValue().onCapabilitiesChanged(
TEST_NETWORK,
capabilities);
+
+ // make sure it also works with the new introduced TelephonyNetworkSpecifier
+ capabilities = new NetworkCapabilities()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addTransportType(TRANSPORT_CELLULAR)
+ .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+ .setSubscriptionId(234).build());
+ if (!roaming) {
+ capabilities.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ }
+ networkCallback.getValue().onCapabilitiesChanged(
+ TEST_NETWORK,
+ capabilities);
}
@Test
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index b709af1..9b24887 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.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 @@
static final int NETID = 42;
@Mock ConnectivityService mConnectivity;
- @Mock NetworkMisc mMisc;
@Mock IDnsResolver mDnsResolver;
@Mock INetd mNetd;
@Mock INetworkManagementService mNms;
@@ -72,6 +71,7 @@
TestLooper mLooper;
Handler mHandler;
+ NetworkAgentConfig mAgentConfig = new NetworkAgentConfig();
Nat464Xlat makeNat464Xlat() {
return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) {
@@ -93,7 +93,7 @@
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 @@
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 @@
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 @@
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);
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 45cea81..40eae54 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -1643,8 +1643,14 @@
ParsedResource* out_resource) {
out_resource->name.type = ResourceType::kStyleable;
- // Declare-styleable is kPrivate by default, because it technically only exists in R.java.
- out_resource->visibility_level = Visibility::Level::kPublic;
+ if (!options_.preserve_visibility_of_styleables) {
+ // This was added in change Idd21b5de4d20be06c6f8c8eb5a22ccd68afc4927 to mimic aapt1, but no one
+ // knows exactly what for.
+ //
+ // FWIW, styleables only appear in generated R classes. For custom views these should always be
+ // package-private (to be used only by the view class); themes are a different story.
+ out_resource->visibility_level = Visibility::Level::kPublic;
+ }
// Declare-styleable only ends up in default config;
if (out_resource->config != ConfigDescription::DefaultConfig()) {
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 06bb0c9..9d3ecc8 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -46,6 +46,12 @@
*/
bool error_on_positional_arguments = true;
+ /**
+ * If true, apply the same visibility rules for styleables as are used for
+ * all other resources. Otherwise, all styleables will be made public.
+ */
+ bool preserve_visibility_of_styleables = false;
+
// If visibility was forced, we need to use it when creating a new resource and also error if we
// try to parse the <public>, <public-group>, <java-symbol> or <symbol> tags.
Maybe<Visibility::Level> visibility;
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 464225f..46ad7cb 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -611,6 +611,32 @@
EXPECT_THAT(styleable->entries[2].name, Eq(make_value(test::ParseNameOrDie("attr/baz"))));
}
+TEST_F(ResourceParserTest, ParseDeclareStyleablePreservingVisibility) {
+ StringInputStream input(R"(
+ <resources>
+ <declare-styleable name="foo">
+ <attr name="myattr" />
+ </declare-styleable>
+ <declare-styleable name="bar">
+ <attr name="myattr" />
+ </declare-styleable>
+ <public type="styleable" name="bar" />
+ </resources>)");
+ ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"},
+ ConfigDescription::DefaultConfig(),
+ ResourceParserOptions{.preserve_visibility_of_styleables = true});
+
+ xml::XmlPullParser xml_parser(&input);
+ ASSERT_TRUE(parser.Parse(&xml_parser));
+
+ EXPECT_EQ(
+ table_.FindResource(test::ParseNameOrDie("styleable/foo")).value().entry->visibility.level,
+ Visibility::Level::kUndefined);
+ EXPECT_EQ(
+ table_.FindResource(test::ParseNameOrDie("styleable/bar")).value().entry->visibility.level,
+ Visibility::Level::kPublic);
+}
+
TEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) {
std::string input = R"(
<declare-styleable xmlns:privAndroid="http://schemas.android.com/apk/prv/res/android"
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 9b81369f..2171970 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -159,6 +159,7 @@
ResourceParserOptions parser_options;
parser_options.error_on_positional_arguments = !options.legacy_mode;
+ parser_options.preserve_visibility_of_styleables = options.preserve_visibility_of_styleables;
parser_options.translatable = translatable_file;
// If visibility was forced, we need to use it when creating a new resource and also error if
diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h
index d3456b2..1752a1a 100644
--- a/tools/aapt2/cmd/Compile.h
+++ b/tools/aapt2/cmd/Compile.h
@@ -35,6 +35,8 @@
bool pseudolocalize = false;
bool no_png_crunch = false;
bool legacy_mode = false;
+ // See comments on aapt::ResourceParserOptions.
+ bool preserve_visibility_of_styleables = false;
bool verbose = false;
};
@@ -56,6 +58,11 @@
AddOptionalSwitch("--no-crunch", "Disables PNG processing", &options_.no_png_crunch);
AddOptionalSwitch("--legacy", "Treat errors that used to be valid in AAPT as warnings",
&options_.legacy_mode);
+ AddOptionalSwitch("--preserve-visibility-of-styleables",
+ "If specified, apply the same visibility rules for\n"
+ "styleables as are used for all other resources.\n"
+ "Otherwise, all stylesables will be made public.",
+ &options_.preserve_visibility_of_styleables);
AddOptionalFlag("--visibility",
"Sets the visibility of the compiled resources to the specified\n"
"level. Accepted levels: public, private, default", &visibility_);
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index fa55601..75deb01 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -434,7 +434,7 @@
AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
vector<java_type_t> nonChainedSignature;
if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
- auto it = atoms->non_chained_signatures_to_modules.find(signature);
+ auto it = atoms->non_chained_signatures_to_modules.find(nonChainedSignature);
if (it == atoms->non_chained_signatures_to_modules.end()) {
set<string> modules_non_chained;
if (atomDecl.hasModule) {
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index fef490c..c29936b 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -73,7 +73,7 @@
java_type_name(chainField.javaType), chainField.name.c_str());
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", SparseArray<Object> valueMap");
+ fprintf(out, ", android.util.SparseArray<Object> valueMap");
} else {
fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
}
@@ -85,8 +85,9 @@
string indent("");
if (supportQ) {
// TODO(b/146235828): Use just SDK_INT check once it is incremented from Q.
- fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q ||\n");
- fprintf(out, " Build.VERSION.CODENAME.equals(\"R\")) {\n");
+ fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q\n");
+ fprintf(out, " || (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q\n");
+ fprintf(out, " && Build.VERSION.PREVIEW_SDK_INT > 0)) {\n");
indent = " ";
}
@@ -141,16 +142,16 @@
fprintf(out,
"%s final int count = valueMap.size();\n", indent.c_str());
fprintf(out,
- "%s final SparseIntArray intMap = new SparseIntArray();\n",
+ "%s android.util.SparseIntArray intMap = null;\n",
indent.c_str());
fprintf(out,
- "%s final SparseLongArray longMap = new SparseLongArray();\n",
+ "%s android.util.SparseLongArray longMap = null;\n",
indent.c_str());
fprintf(out,
- "%s final SparseArray<String> stringMap = new SparseArray<>();\n",
+ "%s android.util.SparseArray<String> stringMap = null;\n",
indent.c_str());
fprintf(out,
- "%s final SparseArray<Float> floatMap = new SparseArray<>();\n",
+ "%s android.util.SparseArray<Float> floatMap = null;\n",
indent.c_str());
fprintf(out,
"%s for (int i = 0; i < count; i++) {\n", indent.c_str());
@@ -162,18 +163,42 @@
fprintf(out,
"%s if (value instanceof Integer) {\n", indent.c_str());
fprintf(out,
+ "%s if (null == intMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s intMap = new android.util.SparseIntArray();\n", indent.c_str());
+ fprintf(out,
+ "%s }\n", indent.c_str());
+ fprintf(out,
"%s intMap.put(key, (Integer) value);\n", indent.c_str());
fprintf(out,
"%s } else if (value instanceof Long) {\n", indent.c_str());
fprintf(out,
+ "%s if (null == longMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s longMap = new android.util.SparseLongArray();\n", indent.c_str());
+ fprintf(out,
+ "%s }\n", indent.c_str());
+ fprintf(out,
"%s longMap.put(key, (Long) value);\n", indent.c_str());
fprintf(out,
"%s } else if (value instanceof String) {\n", indent.c_str());
fprintf(out,
+ "%s if (null == stringMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s stringMap = new android.util.SparseArray<>();\n", indent.c_str());
+ fprintf(out,
+ "%s }\n", indent.c_str());
+ fprintf(out,
"%s stringMap.put(key, (String) value);\n", indent.c_str());
fprintf(out,
"%s } else if (value instanceof Float) {\n", indent.c_str());
fprintf(out,
+ "%s if (null == floatMap) {\n", indent.c_str());
+ fprintf(out,
+ "%s floatMap = new android.util.SparseArray<>();\n", indent.c_str());
+ fprintf(out,
+ "%s }\n", indent.c_str());
+ fprintf(out,
"%s floatMap.put(key, (Float) value);\n", indent.c_str());
fprintf(out,
"%s }\n", indent.c_str());
@@ -228,7 +253,8 @@
int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
const string& moduleName, const string& javaClass,
- const string& javaPackage, const bool supportQ) {
+ const string& javaPackage, const bool supportQ,
+ const bool supportWorkSource) {
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
@@ -240,25 +266,9 @@
fprintf(out, "import android.os.SystemClock;\n");
}
- if (DEFAULT_MODULE_NAME == moduleName) {
- // Mainline modules don't use WorkSource logging.
- fprintf(out, "import android.os.WorkSource;\n");
-
- // SparseArray is used for writing KeyValuePairs; not supported for Mainline modules.
- fprintf(out, "import android.util.SparseArray;\n");
- fprintf(out, "import android.util.SparseIntArray;\n");
- fprintf(out, "import android.util.SparseLongArray;\n");
- }
-
fprintf(out, "import android.util.StatsEvent;\n");
fprintf(out, "import android.util.StatsLog;\n");
- if (DEFAULT_MODULE_NAME == moduleName) {
- // List is used for WorkSource writing. Only needed for default module.
- fprintf(out, "\n");
- fprintf(out, "import java.util.ArrayList;\n");
- }
-
fprintf(out, "\n");
fprintf(out, "\n");
fprintf(out, "/**\n");
@@ -280,7 +290,7 @@
out, atoms.signatures_to_modules, attributionDecl, moduleName, supportQ);
errors += write_java_non_chained_methods(
out, atoms.non_chained_signatures_to_modules, moduleName);
- if (DEFAULT_MODULE_NAME == moduleName) {
+ if (supportWorkSource) {
errors += write_java_work_source_methods(out, atoms.signatures_to_modules, moduleName);
}
diff --git a/tools/stats_log_api_gen/java_writer.h b/tools/stats_log_api_gen/java_writer.h
index 9324b23..5b78f05 100644
--- a/tools/stats_log_api_gen/java_writer.h
+++ b/tools/stats_log_api_gen/java_writer.h
@@ -31,8 +31,9 @@
using namespace std;
int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
- const string& moduleName, const string& javaClass,
- const string& javaPackage, const bool supportQ);
+ const string& moduleName, const string& javaClass,
+ const string& javaPackage, const bool supportQ,
+ const bool supportWorkSource);
} // namespace stats_log_api_gen
} // namespace android
diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp
index d6899f6..db766b2 100644
--- a/tools/stats_log_api_gen/java_writer_q.cpp
+++ b/tools/stats_log_api_gen/java_writer_q.cpp
@@ -361,6 +361,50 @@
}
}
+// This method is called in main.cpp to generate StatsLog for modules that's compatible with
+// Q at compile-time.
+int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
+ const AtomDecl &attributionDecl, const string& moduleName,
+ const string& javaClass, const string& javaPackage,
+ const bool supportWorkSource) {
+ // Print prelude
+ fprintf(out, "// This file is autogenerated\n");
+ fprintf(out, "\n");
+ fprintf(out, "package %s;\n", javaPackage.c_str());
+ fprintf(out, "\n");
+ fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n");
+ fprintf(out, "\n");
+ fprintf(out, "import android.util.StatsLog;\n");
+ fprintf(out, "import android.os.SystemClock;\n");
+ fprintf(out, "\n");
+ fprintf(out, "\n");
+ fprintf(out, "/**\n");
+ fprintf(out, " * Utility class for logging statistics events.\n");
+ fprintf(out, " */\n");
+ fprintf(out, "public class %s {\n", javaClass.c_str());
+
+ write_java_q_logging_constants(out, " ");
+
+ write_java_atom_codes(out, atoms, moduleName);
+
+ write_java_enum_values(out, atoms, moduleName);
+
+ int errors = 0;
+ // Print write methods
+ fprintf(out, " // Write methods\n");
+ errors += write_java_methods_q_schema(out, atoms.signatures_to_modules, attributionDecl,
+ moduleName, " ");
+ errors += write_java_non_chained_methods(out, atoms.non_chained_signatures_to_modules,
+ moduleName);
+ if (supportWorkSource) {
+ errors += write_java_work_source_methods(out, atoms.signatures_to_modules, moduleName);
+ }
+
+ fprintf(out, "}\n");
+
+ return errors;
+}
+
#if defined(STATS_SCHEMA_LEGACY)
static void write_java_method(
FILE* out,
@@ -382,7 +426,7 @@
java_type_name(chainField.javaType), chainField.name.c_str());
}
} else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", SparseArray<Object> value_map");
+ fprintf(out, ", android.util.SparseArray<Object> value_map");
} else {
fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
}
@@ -393,16 +437,13 @@
}
}
-int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl) {
+int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
+ const bool supportWorkSource) {
// Print prelude
fprintf(out, "// This file is autogenerated\n");
fprintf(out, "\n");
fprintf(out, "package android.util;\n");
fprintf(out, "\n");
- fprintf(out, "import android.os.WorkSource;\n");
- fprintf(out, "import android.util.SparseArray;\n");
- fprintf(out, "import java.util.ArrayList;\n");
- fprintf(out, "\n");
fprintf(out, "\n");
fprintf(out, "/**\n");
fprintf(out, " * API For logging statistics events.\n");
@@ -418,52 +459,14 @@
write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl);
write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
attributionDecl);
- write_java_work_source_methods(out, atoms.signatures_to_modules, DEFAULT_MODULE_NAME);
+ if (supportWorkSource) {
+ write_java_work_source_methods(out, atoms.signatures_to_modules, DEFAULT_MODULE_NAME);
+ }
fprintf(out, "}\n");
return 0;
}
-
-int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
- const string& moduleName, const string& javaClass,
- const string& javaPackage) {
- // Print prelude
- fprintf(out, "// This file is autogenerated\n");
- fprintf(out, "\n");
- fprintf(out, "package %s;\n", javaPackage.c_str());
- fprintf(out, "\n");
- fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n");
- fprintf(out, "\n");
- fprintf(out, "import android.util.StatsLog;\n");
- fprintf(out, "import android.os.SystemClock;\n");
- fprintf(out, "\n");
- fprintf(out, "import java.util.ArrayList;\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "/**\n");
- fprintf(out, " * Utility class for logging statistics events.\n");
- fprintf(out, " */\n");
- fprintf(out, "public class %s {\n", javaClass.c_str());
-
- write_java_q_logging_constants(out, " ");
-
- write_java_atom_codes(out, atoms, moduleName);
-
- write_java_enum_values(out, atoms, moduleName);
-
- int errors = 0;
- // Print write methods
- fprintf(out, " // Write methods\n");
- errors += write_java_methods_q_schema(out, atoms.signatures_to_modules, attributionDecl,
- moduleName, " ");
- errors += write_java_non_chained_methods(out, atoms.non_chained_signatures_to_modules,
- moduleName);
-
- fprintf(out, "}\n");
-
- return errors;
-}
#endif
} // namespace stats_log_api_gen
diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h
index 96ac745..7d734df 100644
--- a/tools/stats_log_api_gen/java_writer_q.h
+++ b/tools/stats_log_api_gen/java_writer_q.h
@@ -45,12 +45,13 @@
const int requiredHelpers,
const string& indent);
-#if defined(STATS_SCHEMA_LEGACY)
-int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl);
-
int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
const AtomDecl &attributionDecl, const string& moduleName, const string& javaClass,
- const string& javaPackage);
+ const string& javaPackage, const bool supportWorkSource);
+
+#if defined(STATS_SCHEMA_LEGACY)
+int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
+ const bool supportWorkSource);
#endif
} // namespace stats_log_api_gen
} // namespace android
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 00a3704..ddbf22c 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -511,7 +511,10 @@
fprintf(stderr, " --javaClass CLASS the class name of the java class.\n");
fprintf(stderr, " Optional for Java with module.\n");
fprintf(stderr, " Default is \"StatsLogInternal\"\n");
- fprintf(stderr, " --supportQ Include support for Android Q.\n");
+ fprintf(stderr, " --supportQ Include runtime support for Android Q.\n");
+ fprintf(stderr, " --worksource Include support for logging WorkSource objects.\n");
+ fprintf(stderr, " --compileQ Include compile-time support for Android Q "
+ "(Java only).\n");
}
/**
@@ -534,6 +537,8 @@
string javaPackage = DEFAULT_JAVA_PACKAGE;
string javaClass = DEFAULT_JAVA_CLASS;
bool supportQ = false;
+ bool supportWorkSource = false;
+ bool compileQ = false;
int index = 1;
while (index < argc) {
@@ -626,6 +631,10 @@
atomsInfoCppHeaderImport = argv[index];
} else if (0 == strcmp("--supportQ", argv[index])) {
supportQ = true;
+ } else if (0 == strcmp("--worksource", argv[index])) {
+ supportWorkSource = true;
+ } else if (0 == strcmp("--compileQ", argv[index])) {
+ compileQ = true;
}
index++;
@@ -641,12 +650,18 @@
return 1;
}
- if (DEFAULT_MODULE_NAME == moduleName && supportQ) {
+ if (DEFAULT_MODULE_NAME == moduleName && (supportQ || compileQ)) {
// Support for Q schema is not needed for default module.
fprintf(stderr, "%s cannot support Q schema\n", moduleName.c_str());
return 1;
}
+ if (supportQ && compileQ) {
+ // Runtime Q support is redundant if compile-time Q support is required.
+ fprintf(stderr, "Cannot specify compileQ and supportQ simultaneously.\n");
+ return 1;
+ }
+
// Collate the parameters
Atoms atoms;
int errorCount = collate_atoms(Atom::descriptor(), &atoms);
@@ -728,19 +743,15 @@
fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
return 1;
}
- // If this is for a specific module, the java package must also be provided.
- if (moduleName != DEFAULT_MODULE_NAME && javaPackage== DEFAULT_JAVA_PACKAGE) {
- fprintf(stderr, "Must supply --javaPackage if supplying a specific module\n");
- return 1;
- }
#if defined(STATS_SCHEMA_LEGACY)
if (moduleName == DEFAULT_MODULE_NAME) {
errorCount = android::stats_log_api_gen::write_stats_log_java_q(
- out, atoms, attributionDecl);
+ out, atoms, attributionDecl, supportWorkSource);
} else {
errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
- out, atoms, attributionDecl, moduleName, javaClass, javaPackage);
+ out, atoms, attributionDecl, moduleName, javaClass, javaPackage,
+ supportWorkSource);
}
#else
@@ -748,8 +759,15 @@
javaClass = "StatsLogInternal";
javaPackage = "android.util";
}
- errorCount = android::stats_log_api_gen::write_stats_log_java(
- out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ);
+ if (compileQ) {
+ errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
+ out, atoms, attributionDecl, moduleName, javaClass, javaPackage,
+ supportWorkSource);
+ } else {
+ errorCount = android::stats_log_api_gen::write_stats_log_java(
+ out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ,
+ supportWorkSource);
+ }
#endif
fclose(out);
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
index 5b830ee..6414042 100644
--- a/tools/stats_log_api_gen/utils.cpp
+++ b/tools/stats_log_api_gen/utils.cpp
@@ -334,7 +334,7 @@
if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
fprintf(out, ", android.os.WorkSource workSource");
} else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", SparseArray<Object> value_map");
+ fprintf(out, ", android.util.SparseArray<Object> value_map");
} else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) {
fprintf(out, ", byte[] %s", field->name.c_str());
} else {
@@ -442,7 +442,7 @@
for (vector<java_type_t>::const_iterator arg = signature.begin();
arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- fprintf(out, ", WorkSource ws");
+ fprintf(out, ", android.os.WorkSource ws");
} else {
fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
}
@@ -464,9 +464,10 @@
fprintf(out, " }\n"); // close for-loop
// write() component.
- fprintf(out, " ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n");
+ fprintf(out, " java.util.ArrayList<android.os.WorkSource.WorkChain> workChains = "
+ "ws.getWorkChains();\n");
fprintf(out, " if (workChains != null) {\n");
- fprintf(out, " for (WorkSource.WorkChain wc : workChains) {\n");
+ fprintf(out, " for (android.os.WorkSource.WorkChain wc : workChains) {\n");
fprintf(out, " write(code");
for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
if (argIndex == attributionArg) {
diff --git a/wifi/java/android/net/wifi/ScanResult.aidl b/wifi/java/android/net/wifi/ScanResult.aidl
index bb66722..b30689c 100644
--- a/wifi/java/android/net/wifi/ScanResult.aidl
+++ b/wifi/java/android/net/wifi/ScanResult.aidl
@@ -16,4 +16,4 @@
package android.net.wifi;
-parcelable ScanResult;
+@JavaOnlyStableParcelable parcelable ScanResult;
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 2901bd8..2d0942d 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -16,13 +16,16 @@
package android.net.wifi;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -433,58 +436,100 @@
@UnsupportedAppUsage
public List<String> anqpLines;
- /** information elements from beacon
- * @hide
+ /**
+ * information elements from beacon.
*/
public static class InformationElement {
+ /** @hide */
@UnsupportedAppUsage
public static final int EID_SSID = 0;
+ /** @hide */
@UnsupportedAppUsage
public static final int EID_SUPPORTED_RATES = 1;
+ /** @hide */
@UnsupportedAppUsage
public static final int EID_TIM = 5;
+ /** @hide */
@UnsupportedAppUsage
public static final int EID_BSS_LOAD = 11;
+ /** @hide */
@UnsupportedAppUsage
public static final int EID_ERP = 42;
+ /** @hide */
public static final int EID_HT_CAPABILITIES = 45;
+ /** @hide */
@UnsupportedAppUsage
public static final int EID_RSN = 48;
+ /** @hide */
@UnsupportedAppUsage
public static final int EID_EXTENDED_SUPPORTED_RATES = 50;
+ /** @hide */
@UnsupportedAppUsage
public static final int EID_HT_OPERATION = 61;
+ /** @hide */
@UnsupportedAppUsage
public static final int EID_INTERWORKING = 107;
+ /** @hide */
@UnsupportedAppUsage
public static final int EID_ROAMING_CONSORTIUM = 111;
+ /** @hide */
@UnsupportedAppUsage
public static final int EID_EXTENDED_CAPS = 127;
+ /** @hide */
public static final int EID_VHT_CAPABILITIES = 191;
+ /** @hide */
@UnsupportedAppUsage
public static final int EID_VHT_OPERATION = 192;
+ /** @hide */
@UnsupportedAppUsage
public static final int EID_VSA = 221;
+ /** @hide */
@UnsupportedAppUsage
public int id;
+ /** @hide */
@UnsupportedAppUsage
public byte[] bytes;
+ /** @hide */
public InformationElement() {
}
- public InformationElement(InformationElement rhs) {
+ public InformationElement(@NonNull InformationElement rhs) {
this.id = rhs.id;
this.bytes = rhs.bytes.clone();
}
+
+ /**
+ * The element ID of the information element. Defined in the IEEE 802.11-2016 spec
+ * Table 9-77.
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Get the specific content of the information element.
+ */
+ @NonNull
+ public ByteBuffer getBytes() {
+ return ByteBuffer.wrap(bytes).asReadOnlyBuffer();
+ }
}
- /** information elements found in the beacon
+ /**
+ * information elements found in the beacon.
* @hide
*/
@UnsupportedAppUsage
public InformationElement[] informationElements;
+ /**
+ * Get all information elements found in the beacon.
+ */
+ @NonNull
+ public List<InformationElement> getInformationElements() {
+ return Collections.unmodifiableList(Arrays.asList(informationElements));
+ }
/** ANQP response elements.
* @hide
@@ -604,8 +649,8 @@
this.wifiSsid = wifiSsid;
}
- /** copy constructor {@hide} */
- public ScanResult(ScanResult source) {
+ /** copy constructor */
+ public ScanResult(@NonNull ScanResult source) {
if (source != null) {
wifiSsid = source.wifiSsid;
SSID = source.SSID;
@@ -759,9 +804,8 @@
}
}
- /** Implement the Parcelable interface {@hide} */
- @UnsupportedAppUsage
- public static final @android.annotation.NonNull Creator<ScanResult> CREATOR =
+ /** Implement the Parcelable interface */
+ public static final @NonNull Creator<ScanResult> CREATOR =
new Creator<ScanResult>() {
public ScanResult createFromParcel(Parcel in) {
WifiSsid wifiSsid = null;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index f85bb5f..b9eb3f2 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -3194,27 +3194,27 @@
* soft AP state and number of connected devices immediately after a successful call to this API
* via callback. Note that receiving an immediate WIFI_AP_STATE_FAILED value for soft AP state
* indicates that the latest attempt to start soft AP has failed. Caller can unregister a
- * previously registered callback using {@link unregisterSoftApCallback}
+ * previously registered callback using {@link #unregisterSoftApCallback}
* <p>
* Applications should have the
* {@link android.Manifest.permission#NETWORK_SETTINGS NETWORK_SETTINGS} permission. Callers
* without the permission will trigger a {@link java.lang.SecurityException}.
* <p>
*
- * @param executor The executor to execute the callbacks of the {@code executor}
- * object. If null, then the application's main executor will be used.
+ * @param executor The Executor on whose thread to execute the callbacks of the {@code callback}
+ * object.
* @param callback Callback for soft AP events
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
- public void registerSoftApCallback(@Nullable @CallbackExecutor Executor executor,
+ public void registerSoftApCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull SoftApCallback callback) {
+ if (executor == null) throw new IllegalArgumentException("executor cannot be null");
if (callback == null) throw new IllegalArgumentException("callback cannot be null");
Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", executor=" + executor);
- executor = (executor == null) ? mContext.getMainExecutor() : executor;
Binder binder = new Binder();
try {
mService.registerSoftApCallback(binder, new SoftApCallbackProxy(executor, callback),
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 4260c20..b130c17 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -693,6 +693,18 @@
}
/**
+ * Verify an IllegalArgumentException is thrown if executor is null.
+ */
+ @Test
+ public void registerSoftApCallbackThrowsIllegalArgumentExceptionOnNullArgumentForExecutor() {
+ try {
+ mWifiManager.registerSoftApCallback(null, mSoftApCallback);
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ /**
* Verify an IllegalArgumentException is thrown if callback is not provided.
*/
@Test
@@ -705,16 +717,6 @@
}
/**
- * Verify main looper is used when handler is not provided.
- */
- @Test
- public void registerSoftApCallbackUsesMainLooperOnNullArgumentForHandler() {
- when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
- mWifiManager.registerSoftApCallback(null, mSoftApCallback);
- verify(mContext).getMainExecutor();
- }
-
- /**
* Verify the call to registerSoftApCallback goes to WifiServiceImpl.
*/
@Test