Merge "Update test to not assume 2 max SIMs"
diff --git a/Android.bp b/Android.bp
index 3046b20..f97d307 100644
--- a/Android.bp
+++ b/Android.bp
@@ -658,7 +658,10 @@
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",
],
}
// Build ext.jar
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 bba6586..22f014e 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";
@@ -28691,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 {
@@ -28702,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 {
@@ -28859,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);
@@ -29087,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);
@@ -29096,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;
@@ -29205,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();
@@ -29485,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();
@@ -43500,6 +43570,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);
@@ -43515,6 +43586,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
@@ -43782,6 +43855,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();
@@ -46317,13 +46391,20 @@
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 @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getVoWiFiModeSetting();
diff --git a/api/system-current.txt b/api/system-current.txt
index 558907c..44a1c0d 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1590,7 +1590,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";
@@ -1641,6 +1640,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";
@@ -1945,6 +1945,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
@@ -4052,8 +4053,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;
}
@@ -4338,44 +4339,44 @@
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 InvalidPacketException extends java.lang.Exception {
@@ -4447,13 +4448,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 {
@@ -4533,9 +4539,11 @@
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
@@ -4708,19 +4716,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();
- method public boolean satisfiedBy(android.net.NetworkSpecifier);
- 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;
- }
-
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.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_INVALID = -1; // 0xffffffff
+ 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 {
method public static void setThreadStatsTagApp();
method public static void setThreadStatsTagBackup();
@@ -4910,7 +5002,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);
@@ -4919,6 +5011,7 @@
}
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();
@@ -4932,6 +5025,8 @@
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);
@@ -4945,6 +5040,14 @@
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 {
}
@@ -4966,6 +5069,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;
@@ -5013,7 +5119,7 @@
}
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 {
@@ -5030,33 +5136,33 @@
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 {
@@ -5540,7 +5646,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);
@@ -6957,6 +7063,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";
@@ -7076,7 +7183,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 {
@@ -7101,6 +7274,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 {
@@ -9274,6 +9455,7 @@
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 @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);
@@ -9347,9 +9529,11 @@
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 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);
@@ -9977,15 +10161,12 @@
}
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";
- 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 @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 int getVoWiFiRoamingModeSetting();
@@ -10353,8 +10534,8 @@
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
@@ -10376,6 +10557,7 @@
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
@@ -10384,6 +10566,7 @@
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;
@@ -10391,12 +10574,43 @@
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 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 RcsUceAdapter.CapabilitiesCallback {
+ ctor public RcsUceAdapter.CapabilitiesCallback();
+ method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>);
+ method public void onError(int);
+ }
+
}
package android.telephony.ims.feature {
@@ -10486,6 +10700,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();
@@ -10658,6 +10874,7 @@
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);
@@ -10677,6 +10894,71 @@
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
+ }
+
}
package android.telephony.mbms {
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 b5915d5..827ec34 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -657,7 +657,6 @@
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";
}
@@ -1404,9 +1403,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();
@@ -1506,6 +1508,99 @@
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_INVALID = -1; // 0xffffffff
+ 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();
@@ -3304,15 +3399,12 @@
}
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";
- 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 @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 int getVoWiFiRoamingModeSetting();
@@ -3672,6 +3764,87 @@
method public void onProvisioningStringChanged(int, @NonNull String);
}
+ 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 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);
+ }
+
}
package android.telephony.ims.feature {
@@ -3761,6 +3934,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();
@@ -3933,6 +4108,7 @@
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);
@@ -3952,6 +4128,71 @@
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
+ }
+
}
package android.telephony.mbms {
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/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 88976e1..81f6d28 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -98,6 +98,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 +113,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;
@@ -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,
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 bd0a39c..8415ecd 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3236,18 +3236,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.
@@ -3294,19 +3282,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/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/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 cd4af96..8fa00ab 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3296,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,
@@ -3880,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
*
@@ -4835,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 9cba7aa..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";
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/net/ConnectivityDiagnosticsManager.aidl b/core/java/android/net/ConnectivityDiagnosticsManager.aidl
new file mode 100644
index 0000000..82ba0ca
--- /dev/null
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.aidl
@@ -0,0 +1,21 @@
+/**
+ *
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable ConnectivityDiagnosticsManager.ConnectivityReport;
+parcelable ConnectivityDiagnosticsManager.DataStallReport;
\ No newline at end of file
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
index 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 11c1a9c..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.
@@ -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,
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 186196bd..3e9e7fa 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -18,6 +18,7 @@
import android.app.PendingIntent;
import android.net.ConnectionInfo;
+import android.net.IConnectivityDiagnosticsCallback;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkAgentConfig;
@@ -211,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/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 ec773ef..d25ee0e 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -80,7 +80,8 @@
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;
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 8ebd139..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;
}
@@ -1471,6 +1521,7 @@
public int describeContents() {
return 0;
}
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(mNetworkCapabilities);
@@ -1484,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 =
@@ -1504,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
@@ -1553,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/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/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/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/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/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/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/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 13d0c5c..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,6 +36,7 @@
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;
@@ -64,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);
@@ -398,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
@@ -410,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/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/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/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/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/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/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 1fb50a9..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
@@ -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/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/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 21585ed..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);
@@ -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/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/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/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl
new file mode 100644
index 0000000..0b279b8
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl
@@ -0,0 +1,18 @@
+/**
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+@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..8dacecc 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,6 +30,12 @@
import android.util.ArrayMap;
import android.util.Log;
+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;
/**
@@ -34,7 +45,8 @@
*
* @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;
@@ -44,7 +56,7 @@
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;
@@ -72,7 +84,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
@@ -118,35 +130,6 @@
*/
public static final int TETHERING_WIFI_P2P = 3;
- /**
- * Extra used for communicating with the TetherService. Includes the type of tethering to
- * enable if any.
- */
- 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.
- */
- 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 TETHER_ERROR_NO_ERROR = 0;
public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
@@ -160,12 +143,14 @@
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.
+ *
+ * {@hide}
*/
public TetheringManager(@NonNull final Context context, @NonNull final IBinder service) {
mContext = context;
@@ -229,10 +214,9 @@
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 +259,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) {
@@ -296,6 +282,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) {
@@ -320,6 +308,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) {
@@ -338,27 +328,171 @@
}
/**
+ * 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);
+ 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);
+ }
+ });
+ }
+ };
try {
- mConnector.startTethering(type, receiver, showProvisioningUi, callerPkg);
+ mConnector.startTethering(request.getParcel(), callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
}
/**
+ * 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);
@@ -375,11 +509,69 @@
}
/**
+ * 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,
@@ -396,25 +588,161 @@
}
/**
+ * 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 +750,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,11 +799,26 @@
});
}
- @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);
@@ -458,7 +835,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);
@@ -482,6 +863,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 +885,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 +899,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 +913,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 +925,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 +938,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 +957,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 +970,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,6 +984,7 @@
* due to device configuration.
*
* @return a boolean - {@code true} indicating Tethering is supported.
+ * @hide
*/
public boolean isTetheringSupported() {
final String callerPkg = mContext.getOpPackageName();
@@ -613,7 +1003,14 @@
/**
* 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);
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
new file mode 100644
index 0000000..bf19d85
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.LinkAddress;
+
+/**
+ * Configuration details for requesting tethering.
+ * @hide
+ */
+parcelable TetheringRequestParcel {
+ int tetheringType;
+ LinkAddress localIPv4Address;
+ boolean exemptFromEntitlementCheck;
+ boolean showProvisioningUi;
+}
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 5bf41ce..ce6a43f 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -66,6 +66,7 @@
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
+import android.net.IIntResultListener;
import android.net.INetd;
import android.net.ITetheringEventCallback;
import android.net.IpPrefix;
@@ -74,7 +75,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;
@@ -423,9 +426,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) {
@@ -437,29 +441,32 @@
* 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;
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) { }
}
}
@@ -485,12 +492,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;
}
@@ -519,7 +526,7 @@
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);
@@ -951,6 +958,7 @@
mWrapper.showTetheredNotification(
R.drawable.stat_sys_tether_general, false);
mWrapper.untetherAll();
+ // TODO(b/148139325): send tetheringSupported on restriction change
}
}
}
@@ -1844,9 +1852,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.
}
@@ -1881,6 +1893,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/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/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/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 affd691..e6a5521 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
@@ -86,7 +86,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;
@@ -467,6 +469,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);
@@ -572,7 +584,7 @@
.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);
@@ -818,7 +830,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);
@@ -845,7 +857,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);
@@ -922,7 +934,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);
@@ -1113,11 +1125,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
@@ -1188,7 +1199,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/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 76c119d..478b87c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -66,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;
@@ -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;
@@ -1624,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)) {
@@ -1634,9 +1637,24 @@
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();
@@ -1664,6 +1682,10 @@
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) {
@@ -5791,7 +5813,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
@@ -5990,7 +6012,7 @@
if (nc == null || lp == null) return false;
return nai.isVPN()
&& !nai.networkAgentConfig.allowBypass
- && nc.getEstablishingVpnAppUid() != Process.SYSTEM_UID
+ && nc.getOwnerUid() != Process.SYSTEM_UID
&& lp.getInterfaceName() != null
&& (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute());
}
@@ -6038,12 +6060,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!
@@ -7304,4 +7324,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/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 90b0c11..39ad354 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -2788,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/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/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 69ab47a..2933fab 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -950,7 +950,7 @@
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();
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/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/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/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/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index acf51f3..f54f8d1 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -265,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)
@@ -1520,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() {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index c934625..72c66d2 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -3037,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/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 440f044..00c2918 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -194,6 +194,7 @@
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;
@@ -450,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 {
@@ -1053,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,
@@ -1981,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();
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/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index 96f2483..4249dff 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -77,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/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/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 71aaa6e..71411d5 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3758,26 +3758,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);
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/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index 9b4292f..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")
@@ -104,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/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 ef631b8..173f84e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2346,7 +2346,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);
}
/**
@@ -6878,6 +6878,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.
@@ -7286,7 +7310,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) {
@@ -7331,6 +7357,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
@@ -7585,7 +7635,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 {
@@ -7600,7 +7652,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()}
@@ -7630,6 +7683,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}).
diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java
index cb3f0f9..643f452 100644
--- a/telephony/java/android/telephony/ims/ImsException.java
+++ b/telephony/java/android/telephony/ims/ImsException.java
@@ -61,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;
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index c66672f..ba8e90f 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -57,7 +57,8 @@
* registration and MmTel capability status callbacks, as well as query/modify user settings for the
* associated subscription.
*
- * @see #createForSubscriptionId(int)
+ * Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an instance of this
+ * manager.
*/
public class ImsMmTelManager implements RegistrationManager {
@@ -225,8 +226,13 @@
* (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,
@@ -242,7 +248,7 @@
}
/**
- * Only visible for testing, use {@link #createForSubscriptionId(int)} instead.
+ * Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead.
* @hide
*/
@VisibleForTesting
@@ -252,7 +258,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.
*
@@ -450,7 +456,7 @@
/**
* Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
* availability updates for the subscription specified in
- * {@link #createForSubscriptionId(int)}. The method {@see #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
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/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index 3e2903f..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 */
@@ -99,11 +101,16 @@
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,
@@ -132,7 +139,9 @@
CAPABILITY_SHARED_SKETCH,
CAPABILITY_CHAT_BOT,
CAPABILITY_CHAT_BOT_ROLE,
- CAPABILITY_PLUG_IN
+ CAPABILITY_PLUG_IN,
+ CAPABILITY_STANDALONE_CHAT_BOT,
+ CAPABILITY_MMTEL_CALL_COMPOSER
})
public @interface CapabilityFlag {}
@@ -159,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.
@@ -181,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;
}
@@ -207,7 +216,7 @@
private final Uri mContactUri;
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.
@@ -225,7 +234,7 @@
// 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()));
}
}
@@ -250,8 +259,8 @@
// 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);
}
}
@@ -266,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;
}
@@ -290,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..d3f393a 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) {
@@ -299,7 +305,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/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 0d5a979..a3ce1b5 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -325,7 +325,6 @@
*/
@NonNull
@Override
- @SystemApi @TestApi
public String toString() {
StringBuilder builder = new StringBuilder("MmTel Capabilities - [");
builder.append("Voice: ");
@@ -514,7 +513,7 @@
* @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
+ * @hide
*/
@SystemApi @TestApi
public final void notifyRejectedCall(@NonNull ImsCallProfile callProfile,
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 501e0e8..e4efc2043 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -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/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
index 3ec4f34..f13371c 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -17,6 +17,8 @@
package android.telephony.ims.stub;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.Bundle;
@@ -206,6 +208,13 @@
return ImsUtImplBase.this.updateCallBarringForServiceClass(
cbType, action, barrList, serviceClass);
}
+
+ @Override
+ public int updateCallBarringWithPassword(int cbType, int action, String[] barrList,
+ int serviceClass, String password) throws RemoteException {
+ return ImsUtImplBase.this.updateCallBarringWithPassword(
+ cbType, action, barrList, serviceClass, password);
+ }
};
/**
@@ -328,6 +337,14 @@
}
/**
+ * Updates the configuration of the call barring for specified service class with password.
+ */
+ public int updateCallBarringWithPassword(int cbType, int action, @Nullable String[] barrList,
+ int serviceClass, @NonNull String password) {
+ return -1;
+ }
+
+ /**
* Updates the configuration of the call forward.
*/
public int updateCallForward(int action, int condition, String number, int serviceClass,
diff --git a/telephony/java/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 bb03448..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";
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/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java
index 15f8371..4a5380e 100644
--- a/telephony/java/com/android/ims/ImsUtInterface.java
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -166,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..dfb4ee5 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -828,6 +828,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 +927,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.
*
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/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java
index ae55a75..8559cb9 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;
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/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/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/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 783f8d1..e80b7c9 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -6313,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/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