Merge "Enhance ImsManager tests to include tests for roaming setting"
diff --git a/Android.bp b/Android.bp
index 80070b7..8aea8ad 100644
--- a/Android.bp
+++ b/Android.bp
@@ -40,6 +40,8 @@
"src/java/**/*.logtags",
],
+ jarjar_rules: ":framework-hidl-jarjar",
+
libs: [
"voip-common",
"ims-common",
@@ -58,6 +60,7 @@
"android.hardware.radio.config-V1.2-java",
"android.hardware.radio.deprecated-V1.0-java",
"android.hidl.base-V1.0-java",
+ "android-support-annotations",
],
product_variables: {
diff --git a/proto/src/telephony.proto b/proto/src/telephony.proto
index 31d8ea8..9e1fa0c 100644
--- a/proto/src/telephony.proto
+++ b/proto/src/telephony.proto
@@ -599,6 +599,10 @@
PDP_TYPE_IPV4V6 = 3;
PDP_TYPE_PPP = 4;
+
+ PDP_TYPE_NON_IP = 5;
+
+ PDP_TYPE_UNSTRUCTURED = 6;
}
// The information about packet data connection
@@ -764,6 +768,8 @@
PDP_FAIL_PDP_WITHOUT_ACTIVE_TFT = 46;
+ PDP_FAIL_ACTIVATION_REJECTED_BCM_VIOLATION = 48;
+
PDP_FAIL_ONLY_IPV4_ALLOWED = 50;
PDP_FAIL_ONLY_IPV6_ALLOWED = 51;
@@ -776,6 +782,16 @@
PDP_FAIL_MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED = 55;
+ PDP_FAIL_COLLISION_WITH_NETWORK_INITIATED_REQUEST = 56;
+
+ PDP_FAIL_ONLY_IPV4V6_ALLOWED = 57;
+
+ PDP_FAIL_ONLY_NON_IP_ALLOWED = 58;
+
+ PDP_FAIL_UNSUPPORTED_QCI_VALUE = 59;
+
+ PDP_FAIL_BEARER_HANDLING_NOT_SUPPORTED = 60;
+
PDP_FAIL_MAX_ACTIVE_PDP_CONTEXT_REACHED = 65;
PDP_FAIL_UNSUPPORTED_APN_IN_CURRENT_PLMN = 66;
@@ -820,6 +836,518 @@
PDP_FAIL_AUTH_FAILURE_ON_EMERGENCY_CALL = 122;
+ PDP_FAIL_INVALID_DNS_ADDR = 123;
+
+ PDP_FAIL_INVALID_PCSCF_OR_DNS_ADDRESS = 124;
+
+ PDP_FAIL_CALL_PREEMPT_BY_EMERGENCY_APN = 127;
+
+ PDP_FAIL_UE_INITIATED_DETACH_OR_DISCONNECT = 128;
+
+ PDP_FAIL_MIP_FA_REASON_UNSPECIFIED = 2000;
+
+ PDP_FAIL_MIP_FA_ADMIN_PROHIBITED = 2001;
+
+ PDP_FAIL_MIP_FA_INSUFFICIENT_RESOURCES = 2002;
+
+ PDP_FAIL_MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2003;
+
+ PDP_FAIL_MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE = 2004;
+
+ PDP_FAIL_MIP_FA_REQUESTED_LIFETIME_TOO_LONG = 2005;
+
+ PDP_FAIL_MIP_FA_MALFORMED_REQUEST = 2006;
+
+ PDP_FAIL_MIP_FA_MALFORMED_REPLY = 2007;
+
+ PDP_FAIL_MIP_FA_ENCAPSULATION_UNAVAILABLE = 2008;
+
+ PDP_FAIL_MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE = 2009;
+
+ PDP_FAIL_MIP_FA_REVERSE_TUNNEL_UNAVAILABLE = 2010;
+
+ PDP_FAIL_MIP_FA_REVERSE_TUNNEL_IS_MANDATORY = 2011;
+
+ PDP_FAIL_MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED = 2012;
+
+ PDP_FAIL_MIP_FA_MISSING_NAI = 2013;
+
+ PDP_FAIL_MIP_FA_MISSING_HOME_AGENT = 2014;
+
+ PDP_FAIL_MIP_FA_MISSING_HOME_ADDRESS = 2015;
+
+ PDP_FAIL_MIP_FA_UNKNOWN_CHALLENGE = 2016;
+
+ PDP_FAIL_MIP_FA_MISSING_CHALLENGE = 2017;
+
+ PDP_FAIL_MIP_FA_STALE_CHALLENGE = 2018;
+
+ PDP_FAIL_MIP_HA_REASON_UNSPECIFIED = 2019;
+
+ PDP_FAIL_MIP_HA_ADMIN_PROHIBITED = 2020;
+
+ PDP_FAIL_MIP_HA_INSUFFICIENT_RESOURCES = 2021;
+
+ PDP_FAIL_MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE = 2022;
+
+ PDP_FAIL_MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE = 2023;
+
+ PDP_FAIL_MIP_HA_REGISTRATION_ID_MISMATCH = 2024;
+
+ PDP_FAIL_MIP_HA_MALFORMED_REQUEST = 2025;
+
+ PDP_FAIL_MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS = 2026;
+
+ PDP_FAIL_MIP_HA_REVERSE_TUNNEL_UNAVAILABLE = 2027;
+
+ PDP_FAIL_MIP_HA_REVERSE_TUNNEL_IS_MANDATORY = 2028;
+
+ PDP_FAIL_MIP_HA_ENCAPSULATION_UNAVAILABLE = 2029;
+
+ PDP_FAIL_CLOSE_IN_PROGRESS = 2030;
+
+ PDP_FAIL_NETWORK_INITIATED_TERMINATION = 2031;
+
+ PDP_FAIL_MODEM_APP_PREEMPTED = 2032;
+
+ PDP_FAIL_PDN_IPV4_CALL_DISALLOWED = 2033;
+
+ PDP_FAIL_PDN_IPV4_CALL_THROTTLED = 2034;
+
+ PDP_FAIL_PDN_IPV6_CALL_DISALLOWED = 2035;
+
+ PDP_FAIL_PDN_IPV6_CALL_THROTTLED = 2036;
+
+ PDP_FAIL_MODEM_RESTART = 2037;
+
+ PDP_FAIL_PDP_PPP_NOT_SUPPORTED = 2038;
+
+ PDP_FAIL_UNPREFERRED_RAT = 2039;
+
+ PDP_FAIL_PHYSICAL_LINK_CLOSE_IN_PROGRESS = 2040;
+
+ PDP_FAIL_APN_PENDING_HANDOVER = 2041;
+
+ PDP_FAIL_PROFILE_BEARER_INCOMPATIBLE = 2042;
+
+ PDP_FAIL_SIM_CARD_CHANGED = 2043;
+
+ PDP_FAIL_LOW_POWER_MODE_OR_POWERING_DOWN = 2044;
+
+ PDP_FAIL_APN_DISABLED = 2045;
+
+ PDP_FAIL_MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046;
+
+ PDP_FAIL_IPV6_ADDRESS_TRANSFER_FAILED = 2047;
+
+ PDP_FAIL_TRAT_SWAP_FAILED = 2048;
+
+ PDP_FAIL_EHRPD_TO_HRPD_FALLBACK = 2049;
+
+ PDP_FAIL_MIP_CONFIG_FAILURE = 2050;
+
+ PDP_FAIL_PDN_INACTIVITY_TIMER_EXPIRED = 2051;
+
+ PDP_FAIL_MAX_IPV4_CONNECTIONS = 2052;
+
+ PDP_FAIL_MAX_IPV6_CONNECTIONS = 2053;
+
+ PDP_FAIL_APN_MISMATCH = 2054;
+
+ PDP_FAIL_IP_VERSION_MISMATCH = 2055;
+
+ PDP_FAIL_DUN_CALL_DISALLOWED = 2056;
+
+ PDP_FAIL_INTERNAL_EPC_NONEPC_TRANSITION = 2057;
+
+ PDP_FAIL_INTERFACE_IN_USE = 2058;
+
+ PDP_FAIL_APN_DISALLOWED_ON_ROAMING = 2059;
+
+ PDP_FAIL_APN_PARAMETERS_CHANGED = 2060;
+
+ PDP_FAIL_NULL_APN_DISALLOWED = 2061;
+
+ PDP_FAIL_THERMAL_MITIGATION = 2062;
+
+ PDP_FAIL_DATA_SETTINGS_DISABLED = 2063;
+
+ PDP_FAIL_DATA_ROAMING_SETTINGS_DISABLED = 2064;
+
+ PDP_FAIL_DDS_SWITCHED = 2065;
+
+ PDP_FAIL_FORBIDDEN_APN_NAME = 2066;
+
+ PDP_FAIL_DDS_SWITCH_IN_PROGRESS = 2067;
+
+ PDP_FAIL_CALL_DISALLOWED_IN_ROAMING = 2068;
+
+ PDP_FAIL_NON_IP_NOT_SUPPORTED = 2069;
+
+ PDP_FAIL_PDN_NON_IP_CALL_THROTTLED = 2070;
+
+ PDP_FAIL_PDN_NON_IP_CALL_DISALLOWED = 2071;
+
+ PDP_FAIL_CDMA_LOCK = 2072;
+
+ PDP_FAIL_CDMA_INTERCEPT = 2073;
+
+ PDP_FAIL_CDMA_REORDER = 2074;
+
+ PDP_FAIL_CDMA_RELEASE_DUE_TO_SO_REJECTION = 2075;
+
+ PDP_FAIL_CDMA_INCOMING_CALL = 2076;
+
+ PDP_FAIL_CDMA_ALERT_STOP = 2077;
+
+ PDP_FAIL_CHANNEL_ACQUISITION_FAILURE = 2078;
+
+ PDP_FAIL_MAX_ACCESS_PROBE = 2079;
+
+ PDP_FAIL_CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 2080;
+
+ PDP_FAIL_NO_RESPONSE_FROM_BASE_STATION = 2081;
+
+ PDP_FAIL_REJECTED_BY_BASE_STATION = 2082;
+
+ PDP_FAIL_CONCURRENT_SERVICES_INCOMPATIBLE = 2083;
+
+ PDP_FAIL_NO_CDMA_SERVICE = 2084;
+
+ PDP_FAIL_RUIM_NOT_PRESENT = 2085;
+
+ PDP_FAIL_CDMA_RETRY_ORDER = 2086;
+
+ PDP_FAIL_ACCESS_BLOCK = 2087;
+
+ PDP_FAIL_ACCESS_BLOCK_ALL = 2088;
+
+ PDP_FAIL_IS707B_MAX_ACCESS_PROBES = 2089;
+
+ PDP_FAIL_THERMAL_EMERGENCY = 2090;
+
+ PDP_FAIL_CONCURRENT_SERVICES_NOT_ALLOWED = 2091;
+
+ PDP_FAIL_INCOMING_CALL_REJECTED = 2092;
+
+ PDP_FAIL_NO_SERVICE_ON_GATEWAY = 2093;
+
+ PDP_FAIL_NO_GPRS_CONTEXT = 2094;
+
+ PDP_FAIL_ILLEGAL_MS = 2095;
+
+ PDP_FAIL_ILLEGAL_ME = 2096;
+
+ PDP_FAIL_GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED = 2097;
+
+ PDP_FAIL_GPRS_SERVICES_NOT_ALLOWED = 2098;
+
+ PDP_FAIL_MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK = 2099;
+
+ PDP_FAIL_IMPLICITLY_DETACHED = 2100;
+
+ PDP_FAIL_PLMN_NOT_ALLOWED = 2101;
+
+ PDP_FAIL_LOCATION_AREA_NOT_ALLOWED = 2102;
+
+ PDP_FAIL_GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN = 2103;
+
+ PDP_FAIL_PDP_DUPLICATE = 2104;
+
+ PDP_FAIL_UE_RAT_CHANGE = 2105;
+
+ PDP_FAIL_CONGESTION = 2106;
+
+ PDP_FAIL_NO_PDP_CONTEXT_ACTIVATED = 2107;
+
+ PDP_FAIL_ACCESS_CLASS_DSAC_REJECTION = 2108;
+
+ PDP_FAIL_PDP_ACTIVATE_MAX_RETRY_FAILED = 2109;
+
+ PDP_FAIL_RADIO_ACCESS_BEARER_FAILURE = 2110;
+
+ PDP_FAIL_ESM_UNKNOWN_EPS_BEARER_CONTEXT = 2111;
+
+ PDP_FAIL_DRB_RELEASED_BY_RRC = 2112;
+
+ PDP_FAIL_CONNECTION_RELEASED = 2113;
+
+ PDP_FAIL_EMM_DETACHED = 2114;
+
+ PDP_FAIL_EMM_ATTACH_FAILED = 2115;
+
+ PDP_FAIL_EMM_ATTACH_STARTED = 2116;
+
+ PDP_FAIL_LTE_NAS_SERVICE_REQUEST_FAILED = 2117;
+
+ PDP_FAIL_DUPLICATE_BEARER_ID = 2118;
+
+ PDP_FAIL_ESM_COLLISION_SCENARIOS = 2119;
+
+ PDP_FAIL_ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK = 2120;
+
+ PDP_FAIL_ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER = 2121;
+
+ PDP_FAIL_ESM_BAD_OTA_MESSAGE = 2122;
+
+ PDP_FAIL_ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL = 2123;
+
+ PDP_FAIL_ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT = 2124;
+
+ PDP_FAIL_DS_EXPLICIT_DEACTIVATION = 2125;
+
+ PDP_FAIL_ESM_LOCAL_CAUSE_NONE = 2126;
+
+ PDP_FAIL_LTE_THROTTLING_NOT_REQUIRED = 2127;
+
+ PDP_FAIL_ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128;
+
+ PDP_FAIL_SERVICE_NOT_ALLOWED_ON_PLMN = 2129;
+
+ PDP_FAIL_EMM_T3417_EXPIRED = 2130;
+
+ PDP_FAIL_EMM_T3417_EXT_EXPIRED = 2131;
+
+ PDP_FAIL_RRC_UPLINK_DATA_TRANSMISSION_FAILURE = 2132;
+
+ PDP_FAIL_RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER = 2133;
+
+ PDP_FAIL_RRC_UPLINK_CONNECTION_RELEASE = 2134;
+
+ PDP_FAIL_RRC_UPLINK_RADIO_LINK_FAILURE = 2135;
+
+ PDP_FAIL_RRC_UPLINK_ERROR_REQUEST_FROM_NAS = 2136;
+
+ PDP_FAIL_RRC_CONNECTION_ACCESS_STRATUM_FAILURE = 2137;
+
+ PDP_FAIL_RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS = 2138;
+
+ PDP_FAIL_RRC_CONNECTION_ACCESS_BARRED = 2139;
+
+ PDP_FAIL_RRC_CONNECTION_CELL_RESELECTION = 2140;
+
+ PDP_FAIL_RRC_CONNECTION_CONFIG_FAILURE = 2141;
+
+ PDP_FAIL_RRC_CONNECTION_TIMER_EXPIRED = 2142;
+
+ PDP_FAIL_RRC_CONNECTION_LINK_FAILURE = 2143;
+
+ PDP_FAIL_RRC_CONNECTION_CELL_NOT_CAMPED = 2144;
+
+ PDP_FAIL_RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE = 2145;
+
+ PDP_FAIL_RRC_CONNECTION_REJECT_BY_NETWORK = 2146;
+
+ PDP_FAIL_RRC_CONNECTION_NORMAL_RELEASE = 2147;
+
+ PDP_FAIL_RRC_CONNECTION_RADIO_LINK_FAILURE = 2148;
+
+ PDP_FAIL_RRC_CONNECTION_REESTABLISHMENT_FAILURE = 2149;
+
+ PDP_FAIL_RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER = 2150;
+
+ PDP_FAIL_RRC_CONNECTION_ABORT_REQUEST = 2151;
+
+ PDP_FAIL_RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR = 2152;
+
+ PDP_FAIL_NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH = 2153;
+
+ PDP_FAIL_NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH = 2154;
+
+ PDP_FAIL_ESM_PROCEDURE_TIME_OUT = 2155;
+
+ PDP_FAIL_INVALID_CONNECTION_ID = 2156;
+
+ PDP_FAIL_MAXIMIUM_NSAPIS_EXCEEDED = 2157;
+
+ PDP_FAIL_INVALID_PRIMARY_NSAPI = 2158;
+
+ PDP_FAIL_CANNOT_ENCODE_OTA_MESSAGE = 2159;
+
+ PDP_FAIL_RADIO_ACCESS_BEARER_SETUP_FAILURE = 2160;
+
+ PDP_FAIL_PDP_ESTABLISH_TIMEOUT_EXPIRED = 2161;
+
+ PDP_FAIL_PDP_MODIFY_TIMEOUT_EXPIRED = 2162;
+
+ PDP_FAIL_PDP_INACTIVE_TIMEOUT_EXPIRED = 2163;
+
+ PDP_FAIL_PDP_LOWERLAYER_ERROR = 2164;
+
+ PDP_FAIL_PDP_MODIFY_COLLISION = 2165;
+
+ PDP_FAIL_MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166;
+
+ PDP_FAIL_NAS_REQUEST_REJECTED_BY_NETWORK = 2167;
+
+ PDP_FAIL_RRC_CONNECTION_INVALID_REQUEST = 2168;
+
+ PDP_FAIL_RRC_CONNECTION_TRACKING_AREA_ID_CHANGED = 2169;
+
+ PDP_FAIL_RRC_CONNECTION_RF_UNAVAILABLE = 2170;
+
+ PDP_FAIL_RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE = 2171;
+
+ PDP_FAIL_RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE = 2172;
+
+ PDP_FAIL_RRC_CONNECTION_ABORTED_AFTER_HANDOVER = 2173;
+
+ PDP_FAIL_RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE = 2174;
+
+ PDP_FAIL_RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE = 2175;
+
+ PDP_FAIL_IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER = 2176;
+
+ PDP_FAIL_IMEI_NOT_ACCEPTED = 2177;
+
+ PDP_FAIL_EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED = 2178;
+
+ PDP_FAIL_EPS_SERVICES_NOT_ALLOWED_IN_PLMN = 2179;
+
+ PDP_FAIL_MSC_TEMPORARILY_NOT_REACHABLE = 2180;
+
+ PDP_FAIL_CS_DOMAIN_NOT_AVAILABLE = 2181;
+
+ PDP_FAIL_ESM_FAILURE = 2182;
+
+ PDP_FAIL_MAC_FAILURE = 2183;
+
+ PDP_FAIL_SYNCHRONIZATION_FAILURE = 2184;
+
+ PDP_FAIL_UE_SECURITY_CAPABILITIES_MISMATCH = 2185;
+
+ PDP_FAIL_SECURITY_MODE_REJECTED = 2186;
+
+ PDP_FAIL_UNACCEPTABLE_NON_EPS_AUTHENTICATION = 2187;
+
+ PDP_FAIL_CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED = 2188;
+
+ PDP_FAIL_NO_EPS_BEARER_CONTEXT_ACTIVATED = 2189;
+
+ PDP_FAIL_INVALID_EMM_STATE = 2190;
+
+ PDP_FAIL_NAS_LAYER_FAILURE = 2191;
+
+ PDP_FAIL_MULTIPLE_PDP_CALL_NOT_ALLOWED = 2192;
+
+ PDP_FAIL_EMBMS_NOT_ENABLED = 2193;
+
+ PDP_FAIL_IRAT_HANDOVER_FAILED = 2194;
+
+ PDP_FAIL_EMBMS_REGULAR_DEACTIVATION = 2195;
+
+ PDP_FAIL_TEST_LOOPBACK_REGULAR_DEACTIVATION = 2196;
+
+ PDP_FAIL_LOWER_LAYER_REGISTRATION_FAILURE = 2197;
+
+ PDP_FAIL_DATA_PLAN_EXPIRED = 2198;
+
+ PDP_FAIL_UMTS_HANDOVER_TO_IWLAN = 2199;
+
+ PDP_FAIL_EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY = 2200;
+
+ PDP_FAIL_EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE = 2201;
+
+ PDP_FAIL_EVDO_HDR_CHANGED = 2202;
+
+ PDP_FAIL_EVDO_HDR_EXITED = 2203;
+
+ PDP_FAIL_EVDO_HDR_NO_SESSION = 2204;
+
+ PDP_FAIL_EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL = 2205;
+
+ PDP_FAIL_EVDO_HDR_CONNECTION_SETUP_TIMEOUT = 2206;
+
+ PDP_FAIL_FAILED_TO_ACQUIRE_COLOCATED_HDR = 2207;
+
+ PDP_FAIL_OTASP_COMMIT_IN_PROGRESS = 2208;
+
+ PDP_FAIL_NO_HYBRID_HDR_SERVICE = 2209;
+
+ PDP_FAIL_HDR_NO_LOCK_GRANTED = 2210;
+
+ PDP_FAIL_DBM_OR_SMS_IN_PROGRESS = 2211;
+
+ PDP_FAIL_HDR_FADE = 2212;
+
+ PDP_FAIL_HDR_ACCESS_FAILURE = 2213;
+
+ PDP_FAIL_UNSUPPORTED_1X_PREV = 2214;
+
+ PDP_FAIL_LOCAL_END = 2215;
+
+ PDP_FAIL_NO_SERVICE = 2216;
+
+ PDP_FAIL_FADE = 2217;
+
+ PDP_FAIL_NORMAL_RELEASE = 2218;
+
+ PDP_FAIL_ACCESS_ATTEMPT_ALREADY_IN_PROGRESS = 2219;
+
+ PDP_FAIL_REDIRECTION_OR_HANDOFF_IN_PROGRESS = 2220;
+
+ PDP_FAIL_EMERGENCY_MODE = 2221;
+
+ PDP_FAIL_PHONE_IN_USE = 2222;
+
+ PDP_FAIL_INVALID_MODE = 2223;
+
+ PDP_FAIL_INVALID_SIM_STATE = 2224;
+
+ PDP_FAIL_NO_COLLOCATED_HDR = 2225;
+
+ PDP_FAIL_UE_IS_ENTERING_POWERSAVE_MODE = 2226;
+
+ PDP_FAIL_DUAL_SWITCH = 2227;
+
+ PDP_FAIL_PPP_TIMEOUT = 2228;
+
+ PDP_FAIL_PPP_AUTH_FAILURE = 2229;
+
+ PDP_FAIL_PPP_OPTION_MISMATCH = 2230;
+
+ PDP_FAIL_PPP_PAP_FAILURE = 2231;
+
+ PDP_FAIL_PPP_CHAP_FAILURE = 2232;
+
+ PDP_FAIL_PPP_CLOSE_IN_PROGRESS = 2233;
+
+ PDP_FAIL_LIMITED_TO_IPV4 = 2234;
+
+ PDP_FAIL_LIMITED_TO_IPV6 = 2235;
+
+ PDP_FAIL_VSNCP_TIMEOUT = 2236;
+
+ PDP_FAIL_VSNCP_GEN_ERROR = 2237;
+
+ PDP_FAIL_VSNCP_APN_UNATHORIZED = 2238;
+
+ PDP_FAIL_VSNCP_PDN_LIMIT_EXCEEDED = 2239;
+
+ PDP_FAIL_VSNCP_NO_PDN_GATEWAY_ADDRESS = 2240;
+
+ PDP_FAIL_VSNCP_PDN_GATEWAY_UNREACHABLE = 2241;
+
+ PDP_FAIL_VSNCP_PDN_GATEWAY_REJECT = 2242;
+
+ PDP_FAIL_VSNCP_INSUFFICIENT_PARAMETERS = 2243;
+
+ PDP_FAIL_VSNCP_RESOURCE_UNAVAILABLE = 2244;
+
+ PDP_FAIL_VSNCP_ADMINISTRATIVELY_PROHIBITED = 2245;
+
+ PDP_FAIL_VSNCP_PDN_ID_IN_USE = 2246;
+
+ PDP_FAIL_VSNCP_SUBSCRIBER_LIMITATION = 2247;
+
+ PDP_FAIL_VSNCP_PDN_EXISTS_FOR_THIS_APN = 2248;
+
+ PDP_FAIL_VSNCP_RECONNECT_NOT_ALLOWED = 2249;
+
+ PDP_FAIL_IPV6_PREFIX_UNAVAILABLE = 2250;
+
+ PDP_FAIL_HANDOFF_PREFERENCE_CHANGED = 2251;
+
// Not mentioned in the specification
PDP_FAIL_VOICE_REGISTRATION_FAIL = -1;
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index bcc8e1a..73b0e7d 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -21,7 +21,7 @@
import android.os.Handler;
import android.os.Message;
import android.os.WorkSource;
-import android.service.carrier.CarrierIdentifier;
+import android.telephony.CarrierRestrictionRules;
import android.telephony.ClientRequestStats;
import android.telephony.ImsiEncryptionInfo;
import android.telephony.NetworkScanRequest;
@@ -2067,11 +2067,11 @@
* Set allowed carriers
*
* @param carriers Allowed carriers
- * @param result Callback message contains the number of carriers set successfully
+ * @param result Callback message contains the result of the operation
* @param workSource calling WorkSource
*/
- default void setAllowedCarriers(List<CarrierIdentifier> carriers, Message result,
- WorkSource workSource) {}
+ default void setAllowedCarriers(CarrierRestrictionRules carrierRestrictionRules,
+ Message result, WorkSource workSource) {}
/**
* Get allowed carriers
@@ -2258,6 +2258,14 @@
*/
void stopNattKeepalive(int sessionHandle, Message result);
+ /**
+ * Enable or disable the logical modem.
+ *
+ * @param enable whether to enable or disable the modem
+ * @param result a Message to return to the requester
+ */
+ default void enableModem(boolean enable, Message result) {};
+
default List<ClientRequestStats> getClientRequestStats() {
return null;
}
diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index e85db77..4a2fac4 100644
--- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -21,6 +21,7 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.telephony.CallQuality;
import android.telephony.CellInfo;
import android.telephony.CellLocation;
import android.telephony.DataFailCause;
@@ -270,7 +271,8 @@
mRegistry.notifyPreciseCallState(
convertPreciseCallState(ringingCall.getState()),
convertPreciseCallState(foregroundCall.getState()),
- convertPreciseCallState(backgroundCall.getState()));
+ convertPreciseCallState(backgroundCall.getState()),
+ sender.getPhoneId());
} catch (RemoteException ex) {
// system process is dead
}
@@ -373,6 +375,17 @@
}
}
+ @Override
+ public void notifyCallQualityChanged(Phone sender, CallQuality callQuality) {
+ try {
+ if (mRegistry != null) {
+ mRegistry.notifyCallQualityChanged(callQuality, sender.getPhoneId());
+ }
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
/**
* Convert the {@link Phone.DataActivityState} enum into the TelephonyManager.DATA_* constants
* for the public API.
diff --git a/src/java/com/android/internal/telephony/NetworkRegistrationManager.java b/src/java/com/android/internal/telephony/NetworkRegistrationManager.java
index 04d09a5..072181b 100644
--- a/src/java/com/android/internal/telephony/NetworkRegistrationManager.java
+++ b/src/java/com/android/internal/telephony/NetworkRegistrationManager.java
@@ -84,12 +84,13 @@
private final Map<NetworkRegStateCallback, Message> mCallbackTable = new Hashtable();
- public void getNetworkRegistrationState(int domain, Message onCompleteMessage) {
+ public void getNetworkRegistrationState(@NetworkRegistrationState.Domain int domain,
+ Message onCompleteMessage) {
if (onCompleteMessage == null) return;
- logd("getNetworkRegistrationState domain " + domain);
if (!isServiceConnected()) {
- logd("service not connected.");
+ loge("service not connected. Domain = "
+ + ((domain == NetworkRegistrationState.DOMAIN_CS) ? "CS" : "PS"));
onCompleteMessage.obj = new AsyncResult(onCompleteMessage.obj, null,
new IllegalStateException("Service not connected."));
onCompleteMessage.sendToTarget();
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 9d084dd..8951cd7 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -39,10 +39,10 @@
import android.os.WorkSource;
import android.preference.PreferenceManager;
import android.provider.Settings;
-import android.service.carrier.CarrierIdentifier;
import android.telecom.VideoProfile;
import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.CarrierConfigManager;
+import android.telephony.CarrierRestrictionRules;
import android.telephony.CellInfo;
import android.telephony.CellLocation;
import android.telephony.ClientRequestStats;
@@ -3658,9 +3658,9 @@
/**
* Set allowed carriers
*/
- public void setAllowedCarriers(List<CarrierIdentifier> carriers, Message response,
- WorkSource workSource) {
- mCi.setAllowedCarriers(carriers, response, workSource);
+ public void setAllowedCarriers(CarrierRestrictionRules carrierRestrictionRules,
+ Message response, WorkSource workSource) {
+ mCi.setAllowedCarriers(carrierRestrictionRules, response, workSource);
}
/** Sets the SignalStrength reporting criteria. */
diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
index bf85c18..20d11e7 100644
--- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
+++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
@@ -17,6 +17,7 @@
package com.android.internal.telephony;
import android.content.Context;
+import android.os.Message;
import android.telephony.PhoneCapability;
import android.telephony.Rlog;
import android.telephony.TelephonyManager;
@@ -82,23 +83,16 @@
/**
* Enable or disable phone
*
- * @param phoneId which phone to operate on
+ * @param phone which phone to operate on
* @param enable true or false
- *
+ * @param result the message to sent back when it's done.
*/
- public void enablePhone(int phoneId, boolean enable) {
- // TODO: send command to modem once interface is ready.
- }
-
- /**
- * Enable or disable phone
- *
- * @param phoneId which phone to operate on
- * @param enable true or false
- *
- */
- public void enablePhone(int[] phoneId, boolean[] enable) {
- // TODO: send command to modem once interface is ready.
+ public void enablePhone(Phone phone, boolean enable, Message result) {
+ if (phone == null) {
+ log("enablePhone failed phone is null");
+ return;
+ }
+ phone.mCi.enableModem(enable, result);
}
/**
diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java
index ce03ad8..a1c1186 100644
--- a/src/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/PhoneNotifier.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony;
+import android.telephony.CallQuality;
import android.telephony.CellInfo;
import android.telephony.CellLocation;
import android.telephony.DataFailCause;
@@ -80,4 +81,7 @@
/** Notify of change to EmergencyNumberList. */
void notifyEmergencyNumberList();
+
+ /** Notify of a change to the call quality of an active foreground call. */
+ void notifyCallQualityChanged(Phone sender, CallQuality callQuality);
}
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 7df50ea..7d2a3ce 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -48,10 +48,14 @@
import android.hardware.radio.V1_0.SmsWriteArgs;
import android.hardware.radio.V1_0.UusInfo;
import android.hardware.radio.V1_2.AccessNetwork;
+import android.hardware.radio.V1_4.CarrierRestrictionsWithPriority;
+import android.hardware.radio.V1_4.SimLockMultiSimPolicy;
import android.hardware.radio.deprecated.V1_0.IOemHook;
import android.net.ConnectivityManager;
import android.net.KeepalivePacketData;
+import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NetworkUtils;
import android.os.AsyncResult;
import android.os.Build;
import android.os.Handler;
@@ -65,6 +69,7 @@
import android.os.WorkSource;
import android.service.carrier.CarrierIdentifier;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.CarrierRestrictionRules;
import android.telephony.CellInfo;
import android.telephony.ClientRequestStats;
import android.telephony.ImsiEncryptionInfo;
@@ -80,6 +85,7 @@
import android.telephony.TelephonyHistogram;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
+import android.telephony.data.DataCallResponse;
import android.telephony.data.DataProfile;
import android.telephony.data.DataService;
import android.telephony.emergency.EmergencyNumber;
@@ -612,7 +618,7 @@
resetProxyAndRequestList();
}
- private String convertNullToEmptyString(String string) {
+ private static String convertNullToEmptyString(String string) {
return string != null ? string : "";
}
@@ -864,6 +870,38 @@
}
@Override
+ public void enableModem(boolean enable, Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (mRadioVersion.less(RADIO_HAL_VERSION_1_3)) {
+ if (RILJ_LOGV) riljLog("enableModem: not supported.");
+ if (result != null) {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+ result.sendToTarget();
+ }
+ return;
+ }
+
+ android.hardware.radio.V1_3.IRadio radioProxy13 =
+ (android.hardware.radio.V1_3.IRadio) radioProxy;
+ if (radioProxy13 != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_ENABLE_MODEM, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " enable = "
+ + enable);
+ }
+
+ try {
+ radioProxy13.enableModem(rr.mSerial, enable);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "enableModem", e);
+ }
+ }
+ }
+
+ @Override
public void dial(String address, boolean isEmergencyCall, EmergencyNumber emergencyNumberInfo,
int clirMode, UUSInfo uusInfo, Message result) {
if (isEmergencyCall && mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4)) {
@@ -1399,7 +1437,7 @@
radioProxy12.setupDataCall_1_2(rr.mSerial, accessNetworkType, dpi,
dataProfile.isPersistent(), allowRoaming, isRoaming, reason,
addresses, dnses);
- } else if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_0)) {
+ } else {
// IRadio V1.0 and IRadio V1.1
// Convert to HAL data profile
@@ -1931,8 +1969,6 @@
IRadio radioProxy = getRadioProxy(result);
if (radioProxy != null) {
if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_2)) {
- android.hardware.radio.V1_2.IRadio radioProxy12 =
- (android.hardware.radio.V1_2.IRadio) radioProxy;
android.hardware.radio.V1_2.NetworkScanRequest request =
new android.hardware.radio.V1_2.NetworkScanRequest();
@@ -1962,7 +1998,15 @@
}
try {
- radioProxy12.startNetworkScan_1_2(rr.mSerial, request);
+ if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4)) {
+ android.hardware.radio.V1_4.IRadio radioProxy14 =
+ (android.hardware.radio.V1_4.IRadio) radioProxy;
+ radioProxy14.startNetworkScan_1_4(rr.mSerial, request);
+ } else {
+ android.hardware.radio.V1_2.IRadio radioProxy12 =
+ (android.hardware.radio.V1_2.IRadio) radioProxy;
+ radioProxy12.startNetworkScan_1_2(rr.mSerial, request);
+ }
} catch (RemoteException | RuntimeException e) {
handleRadioProxyExceptionForRR(rr, "startNetworkScan", e);
}
@@ -3843,62 +3887,121 @@
}
+ /**
+ * Convert a list of CarrierIdentifier into a list of Carrier defined in 1.0/types.hal.
+ * @param carriers List of CarrierIdentifier
+ * @return List of converted objects
+ */
+ @VisibleForTesting
+ public static ArrayList<Carrier> createCarrierRestrictionList(
+ List<CarrierIdentifier> carriers) {
+ ArrayList<Carrier> result = new ArrayList<>();
+ for (CarrierIdentifier ci : carriers) {
+ Carrier c = new Carrier();
+ c.mcc = convertNullToEmptyString(ci.getMcc());
+ c.mnc = convertNullToEmptyString(ci.getMnc());
+ int matchType = CarrierIdentifier.MatchType.ALL;
+ String matchData = null;
+ if (!TextUtils.isEmpty(ci.getSpn())) {
+ matchType = CarrierIdentifier.MatchType.SPN;
+ matchData = ci.getSpn();
+ } else if (!TextUtils.isEmpty(ci.getImsi())) {
+ matchType = CarrierIdentifier.MatchType.IMSI_PREFIX;
+ matchData = ci.getImsi();
+ } else if (!TextUtils.isEmpty(ci.getGid1())) {
+ matchType = CarrierIdentifier.MatchType.GID1;
+ matchData = ci.getGid1();
+ } else if (!TextUtils.isEmpty(ci.getGid2())) {
+ matchType = CarrierIdentifier.MatchType.GID2;
+ matchData = ci.getGid2();
+ }
+ c.matchType = matchType;
+ c.matchData = convertNullToEmptyString(matchData);
+ result.add(c);
+ }
+ return result;
+ }
+
@Override
- public void setAllowedCarriers(List<CarrierIdentifier> carriers, Message result,
- WorkSource workSource) {
- checkNotNull(carriers, "Allowed carriers list cannot be null.");
+ public void setAllowedCarriers(CarrierRestrictionRules carrierRestrictionRules,
+ Message result, WorkSource workSource) {
+ riljLog("RIL.java - setAllowedCarriers");
+
+ checkNotNull(carrierRestrictionRules, "Carrier restriction cannot be null.");
workSource = getDeafultWorkSourceIfInvalid(workSource);
IRadio radioProxy = getRadioProxy(result);
- if (radioProxy != null) {
- RILRequest rr = obtainRequest(RIL_REQUEST_SET_ALLOWED_CARRIERS, result,
- workSource);
+ if (radioProxy == null) {
+ return;
+ }
- if (RILJ_LOGD) {
- String logStr = "";
- for (int i = 0; i < carriers.size(); i++) {
- logStr = logStr + carriers.get(i) + " ";
- }
- riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " carriers = "
- + logStr);
- }
+ RILRequest rr = obtainRequest(RIL_REQUEST_SET_ALLOWED_CARRIERS, result, workSource);
- boolean allAllowed;
- if (carriers.size() == 0) {
- allAllowed = true;
- } else {
- allAllowed = false;
- }
- CarrierRestrictions carrierList = new CarrierRestrictions();
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " params: "
+ + carrierRestrictionRules);
+ }
- for (CarrierIdentifier ci : carriers) { /* allowed carriers */
- Carrier c = new Carrier();
- c.mcc = convertNullToEmptyString(ci.getMcc());
- c.mnc = convertNullToEmptyString(ci.getMnc());
- int matchType = CarrierIdentifier.MatchType.ALL;
- String matchData = null;
- if (!TextUtils.isEmpty(ci.getSpn())) {
- matchType = CarrierIdentifier.MatchType.SPN;
- matchData = ci.getSpn();
- } else if (!TextUtils.isEmpty(ci.getImsi())) {
- matchType = CarrierIdentifier.MatchType.IMSI_PREFIX;
- matchData = ci.getImsi();
- } else if (!TextUtils.isEmpty(ci.getGid1())) {
- matchType = CarrierIdentifier.MatchType.GID1;
- matchData = ci.getGid1();
- } else if (!TextUtils.isEmpty(ci.getGid2())) {
- matchType = CarrierIdentifier.MatchType.GID2;
- matchData = ci.getGid2();
- }
- c.matchType = matchType;
- c.matchData = convertNullToEmptyString(matchData);
- carrierList.allowedCarriers.add(c);
- }
+ // Extract multisim policy
+ int policy = SimLockMultiSimPolicy.NO_MULTISIM_POLICY;
+ switch (carrierRestrictionRules.getMultiSimPolicy()) {
+ case CarrierRestrictionRules.MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT:
+ policy = SimLockMultiSimPolicy.ONE_VALID_SIM_MUST_BE_PRESENT;
+ break;
+ }
- /* TODO: add excluded carriers */
+ if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4)) {
+ riljLog("RIL.java - Using IRadio 1.4 or greater");
+
+ android.hardware.radio.V1_4.IRadio radioProxy14 =
+ (android.hardware.radio.V1_4.IRadio) radioProxy;
+
+ // Prepare structure with allowed list, excluded list and priority
+ CarrierRestrictionsWithPriority carrierRestrictions =
+ new CarrierRestrictionsWithPriority();
+ carrierRestrictions.allowedCarriers =
+ createCarrierRestrictionList(carrierRestrictionRules.getAllowedCarriers());
+ carrierRestrictions.excludedCarriers =
+ createCarrierRestrictionList(carrierRestrictionRules.getExcludedCarriers());
+ carrierRestrictions.allowedCarriersPrioritized =
+ (carrierRestrictionRules.getDefaultCarrierRestriction()
+ == CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED);
try {
- radioProxy.setAllowedCarriers(rr.mSerial, allAllowed, carrierList);
+ radioProxy14.setAllowedCarriers_1_4(rr.mSerial, carrierRestrictions, policy);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "setAllowedCarriers_1_4", e);
+ }
+ } else {
+ boolean isAllCarriersAllowed = carrierRestrictionRules.isAllCarriersAllowed();
+
+ boolean supported = (isAllCarriersAllowed
+ || (carrierRestrictionRules.getExcludedCarriers().isEmpty()
+ && (carrierRestrictionRules.getDefaultCarrierRestriction()
+ == CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED)));
+ supported = supported && (policy == SimLockMultiSimPolicy.NO_MULTISIM_POLICY);
+
+ if (!supported) {
+ // Feature is not supported by IRadio interface
+ riljLoge("setAllowedCarriers does not support excluded list on IRadio version"
+ + " less than 1.4");
+ if (result != null) {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+ result.sendToTarget();
+ }
+ return;
+ }
+ riljLog("RIL.java - Using IRadio 1.3 or lower");
+
+ // Prepare structure with allowed list
+ CarrierRestrictions carrierRestrictions = new CarrierRestrictions();
+ carrierRestrictions.allowedCarriers =
+ createCarrierRestrictionList(carrierRestrictionRules.getAllowedCarriers());
+
+ try {
+ radioProxy.setAllowedCarriers(rr.mSerial, isAllCarriersAllowed,
+ carrierRestrictions);
} catch (RemoteException | RuntimeException e) {
handleRadioProxyExceptionForRR(rr, "setAllowedCarriers", e);
}
@@ -3910,13 +4013,30 @@
workSource = getDeafultWorkSourceIfInvalid(workSource);
IRadio radioProxy = getRadioProxy(result);
- if (radioProxy != null) {
- RILRequest rr = obtainRequest(RIL_REQUEST_GET_ALLOWED_CARRIERS, result,
- workSource);
+ if (radioProxy == null) {
+ return;
+ }
- if (RILJ_LOGD) {
- riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ RILRequest rr = obtainRequest(RIL_REQUEST_GET_ALLOWED_CARRIERS, result,
+ workSource);
+
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ }
+
+ if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4)) {
+ riljLog("RIL.java - Using IRadio 1.4 or greater");
+
+ android.hardware.radio.V1_4.IRadio radioProxy14 =
+ (android.hardware.radio.V1_4.IRadio) radioProxy;
+
+ try {
+ radioProxy14.getAllowedCarriers_1_4(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "getAllowedCarriers_1_4", e);
}
+ } else {
+ riljLog("RIL.java - Using IRadio 1.3 or lower");
try {
radioProxy.getAllowedCarriers(rr.mSerial);
@@ -5162,6 +5282,8 @@
return "RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA";
case RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA:
return "RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA";
+ case RIL_REQUEST_ENABLE_MODEM:
+ return "RIL_REQUEST_ENABLE_MODEM";
default: return "<unknown request>";
}
}
@@ -5510,6 +5632,136 @@
}
/**
+ * Convert SetupDataCallResult defined in 1.0 or 1.4/types.hal into DataCallResponse
+ * @param dcResult setup data call result
+ * @return converted DataCallResponse object
+ */
+ @VisibleForTesting
+ public static DataCallResponse convertDataCallResult(Object dcResult) {
+ if (dcResult == null) return null;
+
+ int status, suggestedRetryTime, cid, active, mtu;
+ String type, ifname;
+ String[] addresses = null;
+ String[] dnses = null;
+ String[] gateways = null;
+ List<String> pcscfs;
+ if (dcResult instanceof android.hardware.radio.V1_0.SetupDataCallResult) {
+ final android.hardware.radio.V1_0.SetupDataCallResult result =
+ (android.hardware.radio.V1_0.SetupDataCallResult) dcResult;
+ status = result.status;
+ suggestedRetryTime = result.suggestedRetryTime;
+ cid = result.cid;
+ active = result.active;
+ type = result.type;
+ ifname = result.ifname;
+ if (!TextUtils.isEmpty(result.addresses)) {
+ addresses = result.addresses.split("\\s+");
+ }
+ if (!TextUtils.isEmpty(result.dnses)) {
+ dnses = result.dnses.split("\\s+");
+ }
+ if (!TextUtils.isEmpty(result.gateways)) {
+ gateways = result.gateways.split("\\s+");
+ }
+ pcscfs = new ArrayList<>(Arrays.asList(result.pcscf.trim().split("\\s+")));
+ mtu = result.mtu;
+ } else if (dcResult instanceof android.hardware.radio.V1_4.SetupDataCallResult) {
+ final android.hardware.radio.V1_4.SetupDataCallResult result =
+ (android.hardware.radio.V1_4.SetupDataCallResult) dcResult;
+ status = result.cause;
+ suggestedRetryTime = result.suggestedRetryTime;
+ cid = result.cid;
+ active = result.active;
+ type = ApnSetting.getProtocolStringFromInt(result.type);
+ ifname = result.ifname;
+ addresses = result.addresses.stream().toArray(String[]::new);
+ dnses = result.dnses.stream().toArray(String[]::new);
+ gateways = result.gateways.stream().toArray(String[]::new);
+ pcscfs = result.pcscf;
+ mtu = result.mtu;
+ } else {
+ Rlog.e(RILJ_LOG_TAG, "Unsupported SetupDataCallResult " + dcResult);
+ return null;
+ }
+
+ // Process address
+ List<LinkAddress> laList = new ArrayList<>();
+ if (addresses != null) {
+ for (String address : addresses) {
+ address = address.trim();
+ if (address.isEmpty()) continue;
+
+ try {
+ LinkAddress la;
+ // Check if the address contains prefix length. If yes, LinkAddress
+ // can parse that.
+ if (address.split("/").length == 2) {
+ la = new LinkAddress(address);
+ } else {
+ InetAddress ia = NetworkUtils.numericToInetAddress(address);
+ la = new LinkAddress(ia, (ia instanceof Inet4Address) ? 32 : 128);
+ }
+
+ laList.add(la);
+ } catch (IllegalArgumentException e) {
+ Rlog.e(RILJ_LOG_TAG, "Unknown address: " + address, e);
+ }
+ }
+ }
+
+ // Process dns
+ List<InetAddress> dnsList = new ArrayList<>();
+ if (dnses != null) {
+ for (String dns : dnses) {
+ dns = dns.trim();
+ InetAddress ia;
+ try {
+ ia = NetworkUtils.numericToInetAddress(dns);
+ dnsList.add(ia);
+ } catch (IllegalArgumentException e) {
+ Rlog.e(RILJ_LOG_TAG, "Unknown dns: " + dns, e);
+ }
+ }
+ }
+
+ // Process gateway
+ List<InetAddress> gatewayList = new ArrayList<>();
+ if (gateways != null) {
+ for (String gateway : gateways) {
+ gateway = gateway.trim();
+ InetAddress ia;
+ try {
+ ia = NetworkUtils.numericToInetAddress(gateway);
+ gatewayList.add(ia);
+ } catch (IllegalArgumentException e) {
+ Rlog.e(RILJ_LOG_TAG, "Unknown gateway: " + gateway, e);
+ }
+ }
+ }
+
+ return new DataCallResponse(status, suggestedRetryTime, cid, active, type, ifname, laList,
+ dnsList, gatewayList, pcscfs, mtu);
+ }
+
+ /**
+ * Convert SetupDataCallResult defined in 1.0 or 1.4/types.hal into DataCallResponse
+ * @param dataCallResultList List of SetupDataCallResult defined in 1.0 or 1.4/types.hal
+ * @return List of converted DataCallResponse object
+ */
+ @VisibleForTesting
+ public static ArrayList<DataCallResponse> convertDataCallResultList(
+ List<? extends Object> dataCallResultList) {
+ ArrayList<DataCallResponse> response =
+ new ArrayList<DataCallResponse>(dataCallResultList.size());
+
+ for (Object obj : dataCallResultList) {
+ response.add(convertDataCallResult(obj));
+ }
+ return response;
+ }
+
+ /**
* @return The {@link IwlanOperationMode IWLAN operation mode}
*/
public @IwlanOperationMode int getIwlanOperationMode() {
diff --git a/src/java/com/android/internal/telephony/RadioConfig.java b/src/java/com/android/internal/telephony/RadioConfig.java
index b47b4f7..7314388 100644
--- a/src/java/com/android/internal/telephony/RadioConfig.java
+++ b/src/java/com/android/internal/telephony/RadioConfig.java
@@ -18,9 +18,11 @@
import static com.android.internal.telephony.RILConstants.RADIO_NOT_AVAILABLE;
import static com.android.internal.telephony.RILConstants.REQUEST_NOT_SUPPORTED;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_PHONE_CAPABILITY;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SLOT_STATUS;
import static com.android.internal.telephony.RILConstants
.RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_DATA_MODEM;
import android.content.Context;
import android.hardware.radio.V1_0.RadioResponseInfo;
@@ -298,8 +300,50 @@
CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
result.sendToTarget();
}
+ return;
}
- // TODO: call radioConfigProxy.setPreferredDataModem when it's ready.
+
+ RILRequest rr = obtainRequest(RIL_REQUEST_SET_PREFERRED_DATA_MODEM,
+ result, mDefaultWorkSource);
+
+ if (DBG) {
+ logd(rr.serialString() + "> " + requestToString(rr.mRequest));
+ }
+
+ try {
+ ((android.hardware.radio.config.V1_1.IRadioConfig) mRadioConfigProxy)
+ .setPreferredDataModem(rr.mSerial, (byte) modemId);
+ } catch (RemoteException | RuntimeException e) {
+ resetProxyAndRequestList("setPreferredDataModem", e);
+ }
+ }
+
+ /**
+ * Wrapper function for IRadioConfig.getPhoneCapability().
+ */
+ public void getPhoneCapability(Message result) {
+ IRadioConfig radioConfigProxy = getRadioConfigProxy(result);
+ if (radioConfigProxy == null || mRadioConfigVersion.less(RADIO_CONFIG_HAL_VERSION_1_1)) {
+ if (result != null) {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+ result.sendToTarget();
+ }
+ return;
+ }
+
+ RILRequest rr = obtainRequest(RIL_REQUEST_GET_PHONE_CAPABILITY, result, mDefaultWorkSource);
+
+ if (DBG) {
+ logd(rr.serialString() + "> " + requestToString(rr.mRequest));
+ }
+
+ try {
+ ((android.hardware.radio.config.V1_1.IRadioConfig) mRadioConfigProxy)
+ .getPhoneCapability(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ resetProxyAndRequestList("getPhoneCapability", e);
+ }
}
/**
@@ -309,8 +353,9 @@
* See PhoneSwitcher for more details.
*/
public boolean isSetPreferredDataCommandSupported() {
- // TODO: call radioConfigProxy.isSetPreferredDataCommandSupported when it's ready.
- return false;
+ IRadioConfig radioConfigProxy = getRadioConfigProxy(null);
+ return radioConfigProxy != null && mRadioConfigVersion
+ .greaterOrEqual(RADIO_CONFIG_HAL_VERSION_1_1);
}
/**
diff --git a/src/java/com/android/internal/telephony/RadioConfigResponse.java b/src/java/com/android/internal/telephony/RadioConfigResponse.java
index 3b333ae..d4b6778 100644
--- a/src/java/com/android/internal/telephony/RadioConfigResponse.java
+++ b/src/java/com/android/internal/telephony/RadioConfigResponse.java
@@ -18,13 +18,15 @@
import android.hardware.radio.V1_0.RadioError;
import android.hardware.radio.V1_0.RadioResponseInfo;
-import android.hardware.radio.config.V1_1.PhoneCapability;
import android.hardware.radio.config.V1_2.IRadioConfigResponse;
+import android.telephony.ModemInfo;
+import android.telephony.PhoneCapability;
import android.telephony.Rlog;
import com.android.internal.telephony.uicc.IccSlotStatus;
import java.util.ArrayList;
+import java.util.List;
/**
* This class is the implementation of IRadioConfigResponse interface.
@@ -111,16 +113,83 @@
}
}
+ private PhoneCapability convertHalPhoneCapability(
+ android.hardware.radio.config.V1_1.PhoneCapability phoneCapability) {
+ // TODO b/121394331: clean up V1_1.PhoneCapability fields.
+ int maxActiveVoiceCalls = 0;
+ int maxActiveData = phoneCapability.maxActiveData;
+ int max5G = 0;
+ List<ModemInfo> logicalModemList = new ArrayList();
+
+ for (android.hardware.radio.config.V1_1.ModemInfo
+ modemInfo : phoneCapability.logicalModemList) {
+ logicalModemList.add(new ModemInfo(modemInfo.modemId));
+ }
+
+ return new PhoneCapability(maxActiveVoiceCalls, maxActiveData, max5G, logicalModemList);
+ }
/**
* Response function for IRadioConfig.getPhoneCapability().
*/
- public void getPhoneCapabilityResponse(RadioResponseInfo info,
- PhoneCapability phoneCapability) {
+ public void getPhoneCapabilityResponse(RadioResponseInfo responseInfo,
+ android.hardware.radio.config.V1_1.PhoneCapability phoneCapability) {
+ RILRequest rr = mRadioConfig.processResponse(responseInfo);
+
+ if (rr != null) {
+ PhoneCapability ret = convertHalPhoneCapability(phoneCapability);
+ if (responseInfo.error == RadioError.NONE) {
+ // send response
+ RadioResponse.sendMessageResponse(rr.mResult, ret);
+ Rlog.d(TAG, rr.serialString() + "< "
+ + mRadioConfig.requestToString(rr.mRequest) + " " + ret.toString());
+ } else {
+ rr.onError(responseInfo.error, ret);
+ Rlog.e(TAG, rr.serialString() + "< "
+ + mRadioConfig.requestToString(rr.mRequest) + " error "
+ + responseInfo.error);
+ }
+ } else {
+ Rlog.e(TAG, "getPhoneCapabilityResponse: Error " + responseInfo.toString());
+ }
}
/**
* Response function for IRadioConfig.setPreferredDataModem().
*/
- public void setPreferredDataModemResponse(RadioResponseInfo info) {
+ public void setPreferredDataModemResponse(RadioResponseInfo responseInfo) {
+ RILRequest rr = mRadioConfig.processResponse(responseInfo);
+
+ if (rr != null) {
+ if (responseInfo.error == RadioError.NONE) {
+ // send response
+ RadioResponse.sendMessageResponse(rr.mResult, null);
+ Rlog.d(TAG, rr.serialString() + "< "
+ + mRadioConfig.requestToString(rr.mRequest));
+ } else {
+ rr.onError(responseInfo.error, null);
+ Rlog.e(TAG, rr.serialString() + "< "
+ + mRadioConfig.requestToString(rr.mRequest) + " error "
+ + responseInfo.error);
+ }
+ } else {
+ Rlog.e(TAG, "setPreferredDataModemResponse: Error " + responseInfo.toString());
+ }
+ }
+
+ /**
+ * Response function for IRadioConfig.setModemsConfigResponse()
+ *
+ */
+ public void setModemsConfigResponse(RadioResponseInfo info) {
+
+ }
+
+ /**
+ * Response function for IRadioConfig.getModemsConfigResponse()
+ *
+ */
+ public void getModemsConfigResponse(RadioResponseInfo info,
+ android.hardware.radio.config.V1_1.ModemsConfig modemsConfig) {
+
}
}
diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java
index 4719bae..7ad830e 100644
--- a/src/java/com/android/internal/telephony/RadioIndication.java
+++ b/src/java/com/android/internal/telephony/RadioIndication.java
@@ -78,21 +78,23 @@
import android.hardware.radio.V1_0.CfData;
import android.hardware.radio.V1_0.LceDataInfo;
import android.hardware.radio.V1_0.PcoDataInfo;
-import android.hardware.radio.V1_0.SetupDataCallResult;
import android.hardware.radio.V1_0.SimRefreshResult;
import android.hardware.radio.V1_0.SsInfoData;
import android.hardware.radio.V1_0.StkCcUnsolSsResult;
import android.hardware.radio.V1_0.SuppSvcNotification;
import android.hardware.radio.V1_2.CellConnectionStatus;
import android.hardware.radio.V1_2.IRadioIndication;
+import android.hardware.radio.V1_4.RadioFrequencyInfo.hidl_discriminator;
import android.os.AsyncResult;
import android.os.SystemProperties;
import android.telephony.CellInfo;
import android.telephony.PcoData;
import android.telephony.PhysicalChannelConfig;
+import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SmsMessage;
import android.telephony.TelephonyManager;
+import android.telephony.data.DataCallResponse;
import android.telephony.emergency.EmergencyNumber;
import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
@@ -275,37 +277,19 @@
/**
* Indicates current physical channel configuration.
*/
+ public void currentPhysicalChannelConfigs_1_4(int indicationType,
+ ArrayList<android.hardware.radio.V1_4.PhysicalChannelConfig> configs) {
+ mRil.processIndication(indicationType);
+ physicalChannelConfigsIndication(configs);
+ }
+
+ /**
+ * Indicates current physical channel configuration.
+ */
public void currentPhysicalChannelConfigs(int indicationType,
ArrayList<android.hardware.radio.V1_2.PhysicalChannelConfig> configs) {
- List<PhysicalChannelConfig> response = new ArrayList<>(configs.size());
-
- for (android.hardware.radio.V1_2.PhysicalChannelConfig config : configs) {
- int status;
- switch (config.status) {
- case CellConnectionStatus.PRIMARY_SERVING:
- status = PhysicalChannelConfig.CONNECTION_PRIMARY_SERVING;
- break;
- case CellConnectionStatus.SECONDARY_SERVING:
- status = PhysicalChannelConfig.CONNECTION_SECONDARY_SERVING;
- break;
- default:
- // only PRIMARY_SERVING and SECONDARY_SERVING are supported.
- mRil.riljLoge("Unsupported CellConnectionStatus in PhysicalChannelConfig: "
- + config.status);
- status = PhysicalChannelConfig.CONNECTION_UNKNOWN;
- break;
- }
-
- response.add(new PhysicalChannelConfig.Builder()
- .setCellConnectionStatus(status)
- .setCellBandwidthDownlinkKhz(config.cellBandwidthDownlink)
- .build());
- }
-
- if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG, response);
-
- mRil.mPhysicalChannelConfigurationRegistrants.notifyRegistrants(
- new AsyncResult(null, response, null));
+ mRil.processIndication(indicationType);
+ physicalChannelConfigsIndication(configs);
}
/**
@@ -330,13 +314,28 @@
new AsyncResult(null, response, null));
}
- public void dataCallListChanged(int indicationType, ArrayList<SetupDataCallResult> dcList) {
+ /** Indicates current data call list. */
+ public void dataCallListChanged(int indicationType,
+ ArrayList<android.hardware.radio.V1_0.SetupDataCallResult> dcList) {
mRil.processIndication(indicationType);
if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_DATA_CALL_LIST_CHANGED, dcList);
+ ArrayList<DataCallResponse> response = RIL.convertDataCallResultList(dcList);
mRil.mDataCallListChangedRegistrants.notifyRegistrants(
- new AsyncResult(null, dcList, null));
+ new AsyncResult(null, response, null));
+ }
+
+ /** Indicates current data call list with radio HAL 1.4. */
+ public void dataCallListChanged_1_4(int indicationType,
+ ArrayList<android.hardware.radio.V1_4.SetupDataCallResult> dcList) {
+ mRil.processIndication(indicationType);
+
+ if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_DATA_CALL_LIST_CHANGED, dcList);
+
+ ArrayList<DataCallResponse> response = RIL.convertDataCallResultList(dcList);
+ mRil.mDataCallListChangedRegistrants.notifyRegistrants(
+ new AsyncResult(null, response, null));
}
public void suppSvcNotify(int indicationType, SuppSvcNotification suppSvcNotification) {
@@ -752,13 +751,19 @@
/** Incremental network scan results */
public void networkScanResult(int indicationType,
android.hardware.radio.V1_1.NetworkScanResult result) {
- responseCellInfos(indicationType, result);
+ responseNetworkScan(indicationType, result);
}
/** Incremental network scan results with HAL V1_2 */
public void networkScanResult_1_2(int indicationType,
android.hardware.radio.V1_2.NetworkScanResult result) {
- responseCellInfos_1_2(indicationType, result);
+ responseNetworkScan_1_2(indicationType, result);
+ }
+
+ /** Incremental network scan results with HAL V1_4 */
+ public void networkScanResult_1_4(int indicationType,
+ android.hardware.radio.V1_4.NetworkScanResult result) {
+ responseNetworkScan_1_4(indicationType, result);
}
public void imsNetworkStateChanged(int indicationType) {
@@ -966,8 +971,79 @@
return state;
}
- private void responseCellInfos(int indicationType,
- android.hardware.radio.V1_1.NetworkScanResult result) {
+
+ /**
+ * Set the frequency range or channel number from the physical channel config. Only one of them
+ * is valid, we should set the other to the unknown value.
+ * @param builder the builder of {@link PhysicalChannelConfig}.
+ * @param config physical channel config from ril.
+ */
+ private void setFrequencyRangeOrChannelNumber(PhysicalChannelConfig.Builder builder,
+ android.hardware.radio.V1_4.PhysicalChannelConfig config) {
+
+ switch (config.rfInfo.getDiscriminator()) {
+ case hidl_discriminator.range:
+ builder.setFrequencyRange(config.rfInfo.range());
+ break;
+ case hidl_discriminator.channelNumber:
+ builder.setChannelNumber(config.rfInfo.channelNumber());
+ break;
+ default:
+ mRil.riljLoge("Unsupported frequency type " + config.rfInfo.getDiscriminator());
+ }
+ }
+
+ private int convertConnectionStatusFromCellConnectionStatus(int status) {
+ switch (status) {
+ case CellConnectionStatus.PRIMARY_SERVING:
+ return PhysicalChannelConfig.CONNECTION_PRIMARY_SERVING;
+ case CellConnectionStatus.SECONDARY_SERVING:
+ return PhysicalChannelConfig.CONNECTION_SECONDARY_SERVING;
+ default:
+ // only PRIMARY_SERVING and SECONDARY_SERVING are supported.
+ mRil.riljLoge("Unsupported CellConnectionStatus in PhysicalChannelConfig: "
+ + status);
+ return PhysicalChannelConfig.CONNECTION_UNKNOWN;
+ }
+ }
+
+ private void physicalChannelConfigsIndication(List<? extends Object> configs) {
+ List<PhysicalChannelConfig> response = new ArrayList<>(configs.size());
+ for (Object obj : configs) {
+ if (obj instanceof android.hardware.radio.V1_2.PhysicalChannelConfig) {
+ android.hardware.radio.V1_2.PhysicalChannelConfig config =
+ (android.hardware.radio.V1_2.PhysicalChannelConfig) obj;
+
+ response.add(new PhysicalChannelConfig.Builder()
+ .setCellConnectionStatus(
+ convertConnectionStatusFromCellConnectionStatus(config.status))
+ .setCellBandwidthDownlinkKhz(config.cellBandwidthDownlink)
+ .build());
+ } else if (obj instanceof android.hardware.radio.V1_4.PhysicalChannelConfig) {
+ android.hardware.radio.V1_4.PhysicalChannelConfig config =
+ (android.hardware.radio.V1_4.PhysicalChannelConfig) obj;
+ PhysicalChannelConfig.Builder builder = new PhysicalChannelConfig.Builder();
+ setFrequencyRangeOrChannelNumber(builder, config);
+ response.add(builder.setCellConnectionStatus(
+ convertConnectionStatusFromCellConnectionStatus(config.base.status))
+ .setCellBandwidthDownlinkKhz(config.base.cellBandwidthDownlink)
+ .setRat(ServiceState.rilRadioTechnologyToNetworkType(config.rat))
+ .setPhysicalCellId(config.physicalCellId)
+ .setContextIds(config.contextIds.stream().mapToInt(x -> x).toArray())
+ .build());
+ } else {
+ mRil.riljLoge("Unsupported PhysicalChannelConfig " + obj);
+ }
+ }
+
+ if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG, response);
+
+ mRil.mPhysicalChannelConfigurationRegistrants.notifyRegistrants(
+ new AsyncResult(null, response, null));
+ }
+
+ private void responseNetworkScan(int indicationType,
+ android.hardware.radio.V1_1.NetworkScanResult result) {
mRil.processIndication(indicationType);
NetworkScanResult nsr = null;
@@ -977,8 +1053,8 @@
mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null));
}
- private void responseCellInfos_1_2(int indicationType,
- android.hardware.radio.V1_2.NetworkScanResult result) {
+ private void responseNetworkScan_1_2(int indicationType,
+ android.hardware.radio.V1_2.NetworkScanResult result) {
mRil.processIndication(indicationType);
NetworkScanResult nsr = null;
@@ -987,4 +1063,14 @@
if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr);
mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null));
}
+
+ private void responseNetworkScan_1_4(int indicationType,
+ android.hardware.radio.V1_4.NetworkScanResult result) {
+ mRil.processIndication(indicationType);
+
+ ArrayList<CellInfo> cellInfos = RIL.convertHalCellInfoList_1_4(result.networkInfos);
+ NetworkScanResult nsr = new NetworkScanResult(result.status, result.error, cellInfos);
+ if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr);
+ mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null));
+ }
}
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index fedb45f..2d58e4d 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -20,6 +20,7 @@
import android.hardware.radio.V1_0.ActivityStatsInfo;
import android.hardware.radio.V1_0.AppStatus;
import android.hardware.radio.V1_0.CardStatus;
+import android.hardware.radio.V1_0.Carrier;
import android.hardware.radio.V1_0.CarrierRestrictions;
import android.hardware.radio.V1_0.CdmaBroadcastSmsConfigInfo;
import android.hardware.radio.V1_0.DataRegStateResult;
@@ -31,13 +32,15 @@
import android.hardware.radio.V1_0.RadioError;
import android.hardware.radio.V1_0.RadioResponseInfo;
import android.hardware.radio.V1_0.SendSmsResult;
-import android.hardware.radio.V1_0.SetupDataCallResult;
import android.hardware.radio.V1_0.VoiceRegStateResult;
import android.hardware.radio.V1_2.IRadioResponse;
+import android.hardware.radio.V1_4.CarrierRestrictionsWithPriority;
+import android.hardware.radio.V1_4.SimLockMultiSimPolicy;
import android.os.AsyncResult;
import android.os.Message;
import android.os.SystemClock;
import android.service.carrier.CarrierIdentifier;
+import android.telephony.CarrierRestrictionRules;
import android.telephony.CellInfo;
import android.telephony.ModemActivityInfo;
import android.telephony.NeighboringCellInfo;
@@ -46,6 +49,7 @@
import android.telephony.SignalStrength;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.data.DataCallResponse;
import android.text.TextUtils;
import com.android.internal.telephony.dataconnection.KeepaliveStatus;
@@ -417,7 +421,17 @@
* types.hal
*/
public void setupDataCallResponse(RadioResponseInfo responseInfo,
- SetupDataCallResult setupDataCallResult) {
+ android.hardware.radio.V1_0.SetupDataCallResult setupDataCallResult) {
+ responseSetupDataCall(responseInfo, setupDataCallResult);
+ }
+
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ * @param setupDataCallResult Response to data call setup as defined by setupDataCallResult in
+ * 1.4/types.hal
+ */
+ public void setupDataCallResponse_1_4(RadioResponseInfo responseInfo,
+ android.hardware.radio.V1_4.SetupDataCallResult setupDataCallResult) {
responseSetupDataCall(responseInfo, setupDataCallResult);
}
@@ -593,6 +607,16 @@
}
/**
+ * The same method as startNetworkScanResponse, except disallowing error codes
+ * OPERATION_NOT_ALLOWED and REQUEST_NOT_SUPPORTED.
+ *
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ */
+ public void startNetworkScanResponse_1_4(RadioResponseInfo responseInfo) {
+ responseScanStatus(responseInfo);
+ }
+
+ /**
*
* @param responseInfo Response info struct containing response type, serial no. and error
*/
@@ -661,7 +685,17 @@
* types.hal
*/
public void getDataCallListResponse(RadioResponseInfo responseInfo,
- ArrayList<SetupDataCallResult> dataCallResultList) {
+ ArrayList<android.hardware.radio.V1_0.SetupDataCallResult> dataCallResultList) {
+ responseDataCallList(responseInfo, dataCallResultList);
+ }
+
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ * @param dataCallResultList Response to get data call list as defined by setupDataCallResult in
+ * 1.4/types.hal
+ */
+ public void getDataCallListResponse_1_4(RadioResponseInfo responseInfo,
+ ArrayList<android.hardware.radio.V1_4.SetupDataCallResult> dataCallResultList) {
responseDataCallList(responseInfo, dataCallResultList);
}
@@ -1299,19 +1333,74 @@
* if Length of allowed carriers list is 0, numAllowed = 0.
*/
public void setAllowedCarriersResponse(RadioResponseInfo responseInfo, int numAllowed) {
- responseInts(responseInfo, numAllowed);
+ // The number of allowed carriers set correctly is not really useful. Even if one is
+ // missing, the operation has failed, as the list should be treated as a single
+ // configuration item. So, ignoring the value of numAllowed and considering only the
+ // value of the responseInfo.error.
+ int ret = TelephonyManager.SET_CARRIER_RESTRICTION_ERROR;
+ RILRequest rr = mRil.processResponse(responseInfo);
+ if (rr != null) {
+ mRil.riljLog("setAllowedCarriersResponse - error = " + responseInfo.error);
+
+ if (responseInfo.error == RadioError.NONE) {
+ ret = TelephonyManager.SET_CARRIER_RESTRICTION_SUCCESS;
+ sendMessageResponse(rr.mResult, ret);
+ } else if (responseInfo.error == RadioError.REQUEST_NOT_SUPPORTED) {
+ // Handle the case REQUEST_NOT_SUPPORTED as a valid response
+ responseInfo.error = RadioError.NONE;
+ ret = TelephonyManager.SET_CARRIER_RESTRICTION_NOT_SUPPORTED;
+ sendMessageResponse(rr.mResult, ret);
+ }
+ mRil.processResponseDone(rr, responseInfo, ret);
+ }
}
/**
*
* @param responseInfo Response info struct containing response type, serial no. and error
+ */
+ public void setAllowedCarriersResponse_1_4(RadioResponseInfo responseInfo) {
+ int ret = TelephonyManager.SET_CARRIER_RESTRICTION_ERROR;
+ RILRequest rr = mRil.processResponse(responseInfo);
+ if (rr != null) {
+ mRil.riljLog("setAllowedCarriersResponse_1_4 - error = " + responseInfo.error);
+
+ if (responseInfo.error == RadioError.NONE) {
+ ret = TelephonyManager.SET_CARRIER_RESTRICTION_SUCCESS;
+ sendMessageResponse(rr.mResult, ret);
+ }
+ mRil.processResponseDone(rr, responseInfo, ret);
+ }
+ }
+
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error
* @param allAllowed true only when all carriers are allowed. Ignore "carriers" struct.
* If false, consider "carriers" struct
* @param carriers Carrier restriction information.
*/
public void getAllowedCarriersResponse(RadioResponseInfo responseInfo, boolean allAllowed,
- CarrierRestrictions carriers) {
- responseCarrierIdentifiers(responseInfo, allAllowed, carriers);
+ CarrierRestrictions carriers) {
+ CarrierRestrictionsWithPriority carrierRestrictions = new CarrierRestrictionsWithPriority();
+ carrierRestrictions.allowedCarriers = carriers.allowedCarriers;
+ carrierRestrictions.excludedCarriers = carriers.excludedCarriers;
+ carrierRestrictions.allowedCarriersPrioritized = true;
+
+ responseCarrierRestrictions(responseInfo, allAllowed, carrierRestrictions,
+ SimLockMultiSimPolicy.NO_MULTISIM_POLICY);
+ }
+
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ * @param carrierRestrictions Carrier restriction information.
+ * @param multiSimPolicy Policy for multi-sim devices.
+ */
+ public void getAllowedCarriersResponse_1_4(RadioResponseInfo responseInfo,
+ CarrierRestrictionsWithPriority carrierRestrictions,
+ int multiSimPolicy) {
+ // The API in IRadio 1.4 does not support the flag allAllowed, so setting it to false, so
+ // that values in carrierRestrictions are used.
+ responseCarrierRestrictions(responseInfo, false, carrierRestrictions, multiSimPolicy);
}
/**
@@ -1812,14 +1901,15 @@
}
private void responseSetupDataCall(RadioResponseInfo responseInfo,
- SetupDataCallResult setupDataCallResult) {
+ Object setupDataCallResult) {
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
+ DataCallResponse response = RIL.convertDataCallResult(setupDataCallResult);
if (responseInfo.error == RadioError.NONE) {
- sendMessageResponse(rr.mResult, setupDataCallResult);
+ sendMessageResponse(rr.mResult, response);
}
- mRil.processResponseDone(rr, responseInfo, setupDataCallResult);
+ mRil.processResponseDone(rr, responseInfo, response);
}
}
@@ -1906,14 +1996,16 @@
}
private void responseDataCallList(RadioResponseInfo responseInfo,
- ArrayList<SetupDataCallResult> dataCallResultList) {
+ List<? extends Object> dataCallResultList) {
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
+ ArrayList<DataCallResponse> response =
+ RIL.convertDataCallResultList(dataCallResultList);
if (responseInfo.error == RadioError.NONE) {
- sendMessageResponse(rr.mResult, dataCallResultList);
+ sendMessageResponse(rr.mResult, response);
}
- mRil.processResponseDone(rr, responseInfo, dataCallResultList);
+ mRil.processResponseDone(rr, responseInfo, response);
}
}
@@ -2151,34 +2243,70 @@
}
}
- private void responseCarrierIdentifiers(RadioResponseInfo responseInfo, boolean allAllowed,
- CarrierRestrictions carriers) {
- RILRequest rr = mRil.processResponse(responseInfo);
-
- if (rr != null) {
- List<CarrierIdentifier> ret = new ArrayList<CarrierIdentifier>();
- for (int i = 0; i < carriers.allowedCarriers.size(); i++) {
- String mcc = carriers.allowedCarriers.get(i).mcc;
- String mnc = carriers.allowedCarriers.get(i).mnc;
- String spn = null, imsi = null, gid1 = null, gid2 = null;
- int matchType = carriers.allowedCarriers.get(i).matchType;
- String matchData = carriers.allowedCarriers.get(i).matchData;
- if (matchType == CarrierIdentifier.MatchType.SPN) {
- spn = matchData;
- } else if (matchType == CarrierIdentifier.MatchType.IMSI_PREFIX) {
- imsi = matchData;
- } else if (matchType == CarrierIdentifier.MatchType.GID1) {
- gid1 = matchData;
- } else if (matchType == CarrierIdentifier.MatchType.GID2) {
- gid2 = matchData;
- }
- ret.add(new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2));
+ private static List<CarrierIdentifier> convertCarrierList(List<Carrier> carrierList) {
+ List<CarrierIdentifier> ret = new ArrayList<>();
+ for (int i = 0; i < carrierList.size(); i++) {
+ String mcc = carrierList.get(i).mcc;
+ String mnc = carrierList.get(i).mnc;
+ String spn = null, imsi = null, gid1 = null, gid2 = null;
+ int matchType = carrierList.get(i).matchType;
+ String matchData = carrierList.get(i).matchData;
+ if (matchType == CarrierIdentifier.MatchType.SPN) {
+ spn = matchData;
+ } else if (matchType == CarrierIdentifier.MatchType.IMSI_PREFIX) {
+ imsi = matchData;
+ } else if (matchType == CarrierIdentifier.MatchType.GID1) {
+ gid1 = matchData;
+ } else if (matchType == CarrierIdentifier.MatchType.GID2) {
+ gid2 = matchData;
}
- if (responseInfo.error == RadioError.NONE) {
- /* TODO: Handle excluded carriers */
- sendMessageResponse(rr.mResult, ret);
- }
- mRil.processResponseDone(rr, responseInfo, ret);
+ ret.add(new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2));
}
+ return ret;
+ }
+
+ private void responseCarrierRestrictions(RadioResponseInfo responseInfo, boolean allAllowed,
+ CarrierRestrictionsWithPriority carriers,
+ int multiSimPolicy) {
+ RILRequest rr = mRil.processResponse(responseInfo);
+ if (rr == null) {
+ return;
+ }
+ CarrierRestrictionRules ret;
+
+ if (allAllowed) {
+ ret = CarrierRestrictionRules.newBuilder().setAllCarriersAllowed().build();
+ } else {
+ int policy = CarrierRestrictionRules.MULTISIM_POLICY_NONE;
+ if (multiSimPolicy == SimLockMultiSimPolicy.ONE_VALID_SIM_MUST_BE_PRESENT) {
+ policy = CarrierRestrictionRules.MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT;
+ }
+
+ int carrierRestrictionDefault =
+ CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED;
+ if (!carriers.allowedCarriersPrioritized) {
+ carrierRestrictionDefault =
+ CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_ALLOWED;
+ }
+
+ ret = CarrierRestrictionRules.newBuilder()
+ .setAllowedCarriers(convertCarrierList(carriers.allowedCarriers))
+ .setExcludedCarriers(convertCarrierList(carriers.excludedCarriers))
+ .setDefaultCarrierRestriction(carrierRestrictionDefault)
+ .setMultiSimPolicy(policy)
+ .build();
+ }
+
+ if (responseInfo.error == RadioError.NONE) {
+ sendMessageResponse(rr.mResult, ret);
+ }
+ mRil.processResponseDone(rr, responseInfo, ret);
+ }
+
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ */
+ public void enableModemResponse(RadioResponseInfo responseInfo) {
+ responseVoid(responseInfo);
}
}
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index abad3cf..46ffec6e 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -19,7 +19,6 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.Manifest;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -165,9 +164,8 @@
private AppOpsManager mAppOps;
- // FIXME: Does not allow for multiple subs in a slot and change to SparseArray
- private static Map<Integer, Integer> sSlotIndexToSubId =
- new ConcurrentHashMap<Integer, Integer>();
+ // Each slot can have multiple subs.
+ private static Map<Integer, ArrayList<Integer>> sSlotIndexToSubIds = new ConcurrentHashMap<>();
private static int mDefaultFallbackSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private static int mDefaultPhoneId = SubscriptionManager.DEFAULT_PHONE_INDEX;
@@ -226,7 +224,25 @@
}
private boolean isSubInfoReady() {
- return sSlotIndexToSubId.size() > 0;
+ if (VDBG) {
+ // make sure sSlotIndexToSubIds is consistent with cached subinfo list
+ int count = 0;
+ for (Integer i : sSlotIndexToSubIds.keySet()) {
+ count += sSlotIndexToSubIds.get(i).size();
+ }
+ if (count != mCacheActiveSubInfoList.size()) {
+ logdl("mismatch between map and list. list size = " + mCacheActiveSubInfoList.size()
+ + ", map size = " + count);
+ for (Integer i : sSlotIndexToSubIds.keySet()) {
+ logdl("From the Map, subs in map at slot index: " + i + " are: "
+ + sSlotIndexToSubIds.get(i));
+ }
+ for (SubscriptionInfo info : mCacheActiveSubInfoList) {
+ logdl("From the Cached list, subinfo is: " + info);
+ }
+ }
+ }
+ return sSlotIndexToSubIds.size() > 0;
}
private SubscriptionController(Phone phone) {
@@ -334,6 +350,8 @@
SubscriptionManager.IS_METERED)) == 1;
int profileClass = cursor.getInt(cursor.getColumnIndexOrThrow(
SubscriptionManager.PROFILE_CLASS));
+ int subType = cursor.getInt(cursor.getColumnIndexOrThrow(
+ SubscriptionManager.SUBSCRIPTION_TYPE));
if (VDBG) {
String iccIdToPrint = SubscriptionInfo.givePrintableIccid(iccId);
@@ -346,7 +364,8 @@
+ isEmbedded + " accessRules:" + Arrays.toString(accessRules)
+ " cardId:" + cardIdToPrint + " publicCardId:" + publicCardId
+ " isOpportunistic:" + isOpportunistic + " groupUUID:" + groupUUID
- + " isMetered:" + isMetered + " profileClass:" + profileClass);
+ + " isMetered:" + isMetered + " profileClass:" + profileClass
+ + " subscriptionType: " + subType);
}
// If line1number has been set to a different number, use it instead.
@@ -357,7 +376,7 @@
return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
isEmbedded, accessRules, cardId, publicCardId, isOpportunistic, groupUUID,
- isMetered, false /* isGroupDisabled */, carrierId, profileClass);
+ isMetered, false /* isGroupDisabled */, carrierId, profileClass, subType);
}
/**
@@ -367,7 +386,7 @@
* @return Array list of queried result from database
*/
private List<SubscriptionInfo> getSubInfo(String selection, Object queryKey) {
- if (VDBG) logd("selection:" + selection + " " + queryKey);
+ if (VDBG) logd("selection:" + selection + ", querykey: " + queryKey);
String[] selectionArgs = null;
if (queryKey != null) {
selectionArgs = new String[] {queryKey.toString()};
@@ -523,10 +542,11 @@
}
/**
- * Get the active SubscriptionInfo associated with the slotIndex
+ * Get the active SubscriptionInfo associated with the slotIndex.
+ * This API does not return details on Remote-SIM subscriptions.
* @param slotIndex the slot which the subscription is inserted
* @param callingPackage The package making the IPC.
- * @return SubscriptionInfo, maybe null if its not active
+ * @return SubscriptionInfo, null for Remote-SIMs or non-active slotIndex.
*/
@Override
public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex,
@@ -610,7 +630,8 @@
}
/**
- * Get the SubInfoRecord(s) of the currently inserted SIM(s)
+ * Get the SubInfoRecord(s) of the currently active SIM(s) - which include both local
+ * and remote SIMs.
* @param callingPackage The package making the IPC.
* @return Array list of currently inserted SubInfoRecord(s)
*/
@@ -620,7 +641,8 @@
}
/**
- * Refresh the cache of SubInfoRecord(s) of the currently inserted SIM(s)
+ * Refresh the cache of SubInfoRecord(s) of the currently available SIM(s) - including
+ * local & remote SIMs.
*/
@VisibleForTesting // For mockito to mock this method
public void refreshCachedActiveSubscriptionInfoList() {
@@ -637,7 +659,10 @@
synchronized (mSubInfoListLock) {
mCacheActiveSubInfoList.clear();
List<SubscriptionInfo> activeSubscriptionInfoList = getSubInfo(
- SubscriptionManager.SIM_SLOT_INDEX + ">=0", null);
+ SubscriptionManager.SIM_SLOT_INDEX + ">=0 OR "
+ + SubscriptionManager.SUBSCRIPTION_TYPE + "="
+ + SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM,
+ null);
if (activeSubscriptionInfoList != null) {
activeSubscriptionInfoList.sort(SUBSCRIPTION_INFO_COMPARATOR);
mCacheActiveSubInfoList.addAll(activeSubscriptionInfoList);
@@ -723,7 +748,7 @@
}
/**
- * @return the maximum number of subscriptions this device will support at any one time.
+ * @return the maximum number of local subscriptions this device will support at any one time.
*/
@Override
public int getActiveSubInfoCountMax() {
@@ -754,7 +779,10 @@
List<SubscriptionInfo> subList = getSubInfo(
SubscriptionManager.SIM_SLOT_INDEX + ">=0 OR "
- + SubscriptionManager.IS_EMBEDDED + "=1", null);
+ + SubscriptionManager.IS_EMBEDDED + "=1 OR "
+ + SubscriptionManager.SUBSCRIPTION_TYPE + "="
+ + SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM,
+ null);
if (subList != null) {
subList.sort(SUBSCRIPTION_INFO_COMPARATOR);
@@ -907,71 +935,114 @@
*/
@Override
public int addSubInfoRecord(String iccId, int slotIndex) {
- if (DBG) logdl("[addSubInfoRecord]+ iccId:" + SubscriptionInfo.givePrintableIccid(iccId) +
- " slotIndex:" + slotIndex);
+ return addSubInfo(iccId, null, slotIndex, SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
+ }
- enforceModifyPhoneState("addSubInfoRecord");
+ /**
+ * Add a new subscription info record, if needed.
+ * @param uniqueId This is the unique identifier for the subscription within the specific
+ * subscription type.
+ * @param displayName human-readable name of the device the subscription corresponds to.
+ * @param slotIndex value for {@link SubscriptionManager#SIM_SLOT_INDEX}
+ * @param subscriptionType the type of subscription to be added.
+ * @return 0 if success, < 0 on error.
+ */
+ @Override
+ public int addSubInfo(String uniqueId, String displayName, int slotIndex,
+ int subscriptionType) {
+ if (DBG) {
+ String iccIdStr = uniqueId;
+ if (!isSubscriptionForRemoteSim(subscriptionType)) {
+ iccIdStr = SubscriptionInfo.givePrintableIccid(uniqueId);
+ }
+ logdl("[addSubInfoRecord]+ iccid: " + iccIdStr
+ + ", slotIndex: " + slotIndex
+ + ", subscriptionType: " + subscriptionType);
+ }
+
+ enforceModifyPhoneState("addSubInfo");
// Now that all security checks passes, perform the operation as ourselves.
final long identity = Binder.clearCallingIdentity();
try {
- if (iccId == null) {
- if (DBG) logdl("[addSubInfoRecord]- null iccId");
+ if (uniqueId == null) {
+ if (DBG) logdl("[addSubInfo]- null iccId");
return -1;
}
ContentResolver resolver = mContext.getContentResolver();
+ String selection = SubscriptionManager.ICC_ID + "=?";
+ String[] args;
+ if (isSubscriptionForRemoteSim(subscriptionType)) {
+ selection += " AND " + SubscriptionManager.SUBSCRIPTION_TYPE + "=?";
+ args = new String[]{uniqueId, Integer.toString(subscriptionType)};
+ } else {
+ selection += " OR " + SubscriptionManager.ICC_ID + "=?";
+ args = new String[]{uniqueId, IccUtils.getDecimalSubstring(uniqueId)};
+ }
Cursor cursor = resolver.query(SubscriptionManager.CONTENT_URI,
new String[]{SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID,
SubscriptionManager.SIM_SLOT_INDEX, SubscriptionManager.NAME_SOURCE,
SubscriptionManager.ICC_ID, SubscriptionManager.CARD_ID},
- SubscriptionManager.ICC_ID + "=?" + " OR " + SubscriptionManager.ICC_ID + "=?",
- new String[]{iccId, IccUtils.getDecimalSubstring(iccId)}, null);
+ selection, args, null);
boolean setDisplayName = false;
try {
- if (cursor == null || !cursor.moveToFirst()) {
- setDisplayName = true;
- Uri uri = insertEmptySubInfoRecord(iccId, slotIndex);
- if (DBG) logdl("[addSubInfoRecord] New record created: " + uri);
- } else {
- int subId = cursor.getInt(0);
- int oldSimInfoId = cursor.getInt(1);
- int nameSource = cursor.getInt(2);
- String oldIccId = cursor.getString(3);
- String oldCardId = cursor.getString(4);
- ContentValues value = new ContentValues();
-
- if (slotIndex != oldSimInfoId) {
- value.put(SubscriptionManager.SIM_SLOT_INDEX, slotIndex);
+ boolean recordsDoNotExist = (cursor == null || !cursor.moveToFirst());
+ if (isSubscriptionForRemoteSim(subscriptionType)) {
+ if (recordsDoNotExist) {
+ // create a Subscription record
+ slotIndex = SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB;
+ Uri uri = insertEmptySubInfoRecord(uniqueId, displayName,
+ slotIndex, subscriptionType);
+ if (DBG) logd("[addSubInfoRecord] New record created: " + uri);
+ } else {
+ if (DBG) logdl("[addSubInfoRecord] Record already exists");
}
-
- if (nameSource != SubscriptionManager.NAME_SOURCE_USER_INPUT) {
+ } else { // Handle Local SIM devices
+ if (recordsDoNotExist) {
setDisplayName = true;
- }
+ Uri uri = insertEmptySubInfoRecord(uniqueId, slotIndex);
+ if (DBG) logdl("[addSubInfoRecord] New record created: " + uri);
+ } else { // there are matching records in the database for the given ICC_ID
+ int subId = cursor.getInt(0);
+ int oldSimInfoId = cursor.getInt(1);
+ int nameSource = cursor.getInt(2);
+ String oldIccId = cursor.getString(3);
+ String oldCardId = cursor.getString(4);
+ ContentValues value = new ContentValues();
- if (oldIccId != null && oldIccId.length() < iccId.length()
- && (oldIccId.equals(IccUtils.getDecimalSubstring(iccId)))) {
- value.put(SubscriptionManager.ICC_ID, iccId);
- }
-
- UiccCard card = UiccController.getInstance().getUiccCardForPhone(slotIndex);
- if (card != null) {
- String cardId = card.getCardId();
- if (cardId != null && cardId != oldCardId) {
- value.put(SubscriptionManager.CARD_ID, cardId);
+ if (slotIndex != oldSimInfoId) {
+ value.put(SubscriptionManager.SIM_SLOT_INDEX, slotIndex);
}
+
+ if (nameSource != SubscriptionManager.NAME_SOURCE_USER_INPUT) {
+ setDisplayName = true;
+ }
+
+ if (oldIccId != null && oldIccId.length() < uniqueId.length()
+ && (oldIccId.equals(IccUtils.getDecimalSubstring(uniqueId)))) {
+ value.put(SubscriptionManager.ICC_ID, uniqueId);
+ }
+
+ UiccCard card = UiccController.getInstance().getUiccCardForPhone(slotIndex);
+ if (card != null) {
+ String cardId = card.getCardId();
+ if (cardId != null && cardId != oldCardId) {
+ value.put(SubscriptionManager.CARD_ID, cardId);
+ }
+ }
+
+ if (value.size() > 0) {
+ resolver.update(SubscriptionManager.getUriForSubscriptionId(subId),
+ value, null, null);
+
+ // Refresh the Cache of Active Subscription Info List
+ refreshCachedActiveSubscriptionInfoList();
+ }
+
+ if (DBG) logdl("[addSubInfoRecord] Record already exists");
}
-
- if (value.size() > 0) {
- resolver.update(SubscriptionManager.getUriForSubscriptionId(subId),
- value, null, null);
-
- // Refresh the Cache of Active Subscription Info List
- refreshCachedActiveSubscriptionInfoList();
- }
-
- if (DBG) logdl("[addSubInfoRecord] Record already exists");
}
} finally {
if (cursor != null) {
@@ -979,57 +1050,69 @@
}
}
+ selection = SubscriptionManager.SIM_SLOT_INDEX + "=?";
+ args = new String[] {String.valueOf(slotIndex)};
+ if (isSubscriptionForRemoteSim(subscriptionType)) {
+ selection = SubscriptionManager.ICC_ID + "=? AND "
+ + SubscriptionManager.SUBSCRIPTION_TYPE + "=?";
+ args = new String[]{uniqueId, Integer.toString(subscriptionType)};
+ }
cursor = resolver.query(SubscriptionManager.CONTENT_URI, null,
- SubscriptionManager.SIM_SLOT_INDEX + "=?",
- new String[] {String.valueOf(slotIndex)}, null);
+ selection, args, null);
try {
if (cursor != null && cursor.moveToFirst()) {
do {
int subId = cursor.getInt(cursor.getColumnIndexOrThrow(
SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID));
- // If sSlotIndexToSubId already has the same subId for a slotIndex/phoneId,
+ // If sSlotIndexToSubIds already has the same subId for a slotIndex/phoneId,
// do not add it.
- Integer currentSubId = sSlotIndexToSubId.get(slotIndex);
- if (currentSubId == null
- || currentSubId != subId
- || !SubscriptionManager.isValidSubscriptionId(currentSubId)) {
+ if (addToSubIdList(slotIndex, subId, subscriptionType)) {
// TODO While two subs active, if user deactivats first
// one, need to update the default subId with second one.
// FIXME: Currently we assume phoneId == slotIndex which in the future
// may not be true, for instance with multiple subs per slot.
// But is true at the moment.
- sSlotIndexToSubId.put(slotIndex, subId);
int subIdCountMax = getActiveSubInfoCountMax();
int defaultSubId = getDefaultSubId();
if (DBG) {
logdl("[addSubInfoRecord]"
- + " sSlotIndexToSubId.size=" + sSlotIndexToSubId.size()
+ + " sSlotIndexToSubIds.size=" + sSlotIndexToSubIds.size()
+ " slotIndex=" + slotIndex + " subId=" + subId
- + " defaultSubId=" + defaultSubId + " simCount=" + subIdCountMax);
+ + " defaultSubId=" + defaultSubId
+ + " simCount=" + subIdCountMax);
}
// Set the default sub if not set or if single sim device
- if (!SubscriptionManager.isValidSubscriptionId(defaultSubId)
- || subIdCountMax == 1) {
- setDefaultFallbackSubId(subId);
- }
- // If single sim device, set this subscription as the default for everything
- if (subIdCountMax == 1) {
- if (DBG) {
- logdl("[addSubInfoRecord] one sim set defaults to subId=" + subId);
+ if (!isSubscriptionForRemoteSim(subscriptionType)) {
+ if (!SubscriptionManager.isValidSubscriptionId(defaultSubId)
+ || subIdCountMax == 1) {
+ logdl("setting default fallback subid to " + subId);
+ setDefaultFallbackSubId(subId, subscriptionType);
}
- setDefaultDataSubId(subId);
- setDefaultSmsSubId(subId);
- setDefaultVoiceSubId(subId);
+ // If single sim device, set this subscription as the default for
+ // everything
+ if (subIdCountMax == 1) {
+ if (DBG) {
+ logdl("[addSubInfoRecord] one sim set defaults to subId="
+ + subId);
+ }
+ setDefaultDataSubId(subId);
+ setDefaultSmsSubId(subId);
+ setDefaultVoiceSubId(subId);
+ }
+ } else {
+ updateDefaultSubIdsIfNeeded(subId, subscriptionType);
}
} else {
if (DBG) {
- logdl("[addSubInfoRecord] currentSubId != null"
- + " && currentSubId is valid, IGNORE");
+ logdl("[addSubInfoRecord] current SubId is already known, "
+ + "IGNORE");
}
}
- if (DBG) logdl("[addSubInfoRecord] hashmap(" + slotIndex + "," + subId + ")");
+ if (DBG) {
+ logdl("[addSubInfoRecord] hashmap(" + slotIndex + "," + subId + ")");
+ }
} while (cursor.moveToNext());
}
} finally {
@@ -1038,46 +1121,180 @@
}
}
- // Set Display name after sub id is set above so as to get valid simCarrierName
- int subId = getSubIdUsingPhoneId(slotIndex);
- if (!SubscriptionManager.isValidSubscriptionId(subId)) {
- if (DBG) {
- logdl("[addSubInfoRecord]- getSubId failed invalid subId = " + subId);
- }
- return -1;
- }
- if (setDisplayName) {
- String simCarrierName = mTelephonyManager.getSimOperatorName(subId);
- String nameToSet;
-
- if (!TextUtils.isEmpty(simCarrierName)) {
- nameToSet = simCarrierName;
- } else {
- nameToSet = "CARD " + Integer.toString(slotIndex + 1);
- }
-
- ContentValues value = new ContentValues();
- value.put(SubscriptionManager.DISPLAY_NAME, nameToSet);
- resolver.update(SubscriptionManager.getUriForSubscriptionId(subId), value,
- null, null);
-
- // Refresh the Cache of Active Subscription Info List
+ if (isSubscriptionForRemoteSim(subscriptionType)) {
refreshCachedActiveSubscriptionInfoList();
+ notifySubscriptionInfoChanged();
+ } else { // Handle Local SIM devices
+ // Set Display name after sub id is set above so as to get valid simCarrierName
+ int subId = getSubIdUsingPhoneId(slotIndex);
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ if (DBG) {
+ logdl("[addSubInfoRecord]- getSubId failed invalid subId = " + subId);
+ }
+ return -1;
+ }
+ if (setDisplayName) {
+ String simCarrierName = mTelephonyManager.getSimOperatorName(subId);
+ String nameToSet;
- if (DBG) logdl("[addSubInfoRecord] sim name = " + nameToSet);
+ if (!TextUtils.isEmpty(simCarrierName)) {
+ nameToSet = simCarrierName;
+ } else {
+ nameToSet = "CARD " + Integer.toString(slotIndex + 1);
+ }
+
+ ContentValues value = new ContentValues();
+ value.put(SubscriptionManager.DISPLAY_NAME, nameToSet);
+ resolver.update(SubscriptionManager.getUriForSubscriptionId(subId), value,
+ null, null);
+
+ // Refresh the Cache of Active Subscription Info List
+ refreshCachedActiveSubscriptionInfoList();
+
+ if (DBG) logdl("[addSubInfoRecord] sim name = " + nameToSet);
+ }
+
+ // Once the records are loaded, notify DcTracker
+ sPhones[slotIndex].updateDataConnectionTracker();
+
+ if (DBG) logdl("[addSubInfoRecord]- info size=" + sSlotIndexToSubIds.size());
}
- // Once the records are loaded, notify DcTracker
- sPhones[slotIndex].updateDataConnectionTracker();
-
- if (DBG) logdl("[addSubInfoRecord]- info size=" + sSlotIndexToSubId.size());
-
} finally {
Binder.restoreCallingIdentity(identity);
}
return 0;
}
+ private void updateDefaultSubIdsIfNeeded(int newDefault, int subscriptionType) {
+ if (DBG) {
+ logdl("[updateDefaultSubIdsIfNeeded] newDefault=" + newDefault
+ + ", subscriptionType=" + subscriptionType);
+ }
+ // Set the default ot new value only if the current default is invalid.
+ if (!isActiveSubscriptionId(getDefaultSubId())) {
+ // current default is not valid anylonger. set a new default
+ if (DBG) {
+ logdl("[updateDefaultSubIdsIfNeeded] set mDefaultFallbackSubId=" + newDefault);
+ }
+ setDefaultFallbackSubId(newDefault, subscriptionType);
+ }
+
+ int value = getDefaultSmsSubId();
+ if (!isActiveSubscriptionId(value)) {
+ // current default is not valid. set it to the given newDefault value
+ setDefaultSmsSubId(newDefault);
+ }
+ value = getDefaultDataSubId();
+ if (!isActiveSubscriptionId(value)) {
+ setDefaultDataSubId(newDefault);
+ }
+ value = getDefaultVoiceSubId();
+ if (!isActiveSubscriptionId(value)) {
+ setDefaultVoiceSubId(newDefault);
+ }
+ }
+
+ /**
+ * This method returns true if the given subId is among the list of currently active
+ * subscriptions.
+ */
+ private boolean isActiveSubscriptionId(int subId) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return false;
+ ArrayList<Integer> subIdList = getActiveSubIdArrayList();
+ if (subIdList.isEmpty()) return false;
+ return subIdList.contains(new Integer(subId));
+ }
+
+ /*
+ * Delete subscription info record for the given device.
+ * @param uniqueId This is the unique identifier for the subscription within the specific
+ * subscription type.
+ * @param subscriptionType the type of subscription to be removed
+ * @return 0 if success, < 0 on error.
+ */
+ @Override
+ public int removeSubInfo(String uniqueId, int subscriptionType) {
+ enforceModifyPhoneState("removeSubInfo");
+ if (DBG) {
+ logd("[removeSubInfo] uniqueId: " + uniqueId
+ + ", subscriptionType: " + subscriptionType);
+ }
+
+ // validate the given info - does it exist in the active subscription list
+ int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ int slotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+ for (SubscriptionInfo info : mCacheActiveSubInfoList) {
+ if ((info.getSubscriptionType() == subscriptionType)
+ && info.getIccId().equalsIgnoreCase(uniqueId)) {
+ subId = info.getSubscriptionId();
+ slotIndex = info.getSimSlotIndex();
+ break;
+ }
+ }
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ if (DBG) {
+ logd("Invalid subscription details: subscriptionType = " + subscriptionType
+ + ", uniqueId = " + uniqueId);
+ }
+ return -1;
+ }
+
+ if (DBG) logd("removing the subid : " + subId);
+
+ // Now that all security checks passes, perform the operation as ourselves.
+ int result = 0;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ ContentResolver resolver = mContext.getContentResolver();
+ result = resolver.delete(SubscriptionManager.CONTENT_URI,
+ SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=? AND "
+ + SubscriptionManager.SUBSCRIPTION_TYPE + "=?",
+ new String[]{Integer.toString(subId), Integer.toString(subscriptionType)});
+ if (result != 1) {
+ if (DBG) {
+ logd("found NO subscription to remove with subscriptionType = "
+ + subscriptionType + ", uniqueId = " + uniqueId);
+ }
+ return -1;
+ }
+ refreshCachedActiveSubscriptionInfoList();
+
+ // update sSlotIndexToSubIds struct
+ ArrayList<Integer> subIdsList = sSlotIndexToSubIds.get(slotIndex);
+ if (subIdsList == null) {
+ loge("sSlotIndexToSubIds has no entry for slotIndex = " + slotIndex);
+ } else {
+ if (subIdsList.contains(subId)) {
+ subIdsList.remove(new Integer(subId));
+ if (subIdsList.isEmpty()) {
+ sSlotIndexToSubIds.remove(slotIndex);
+ }
+ } else {
+ loge("sSlotIndexToSubIds has no subid: " + subId
+ + ", in index: " + slotIndex);
+ }
+ }
+ // Since a subscription is removed, if this one is set as default for any setting,
+ // set some other subid as the default.
+ int newDefault = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ SubscriptionInfo info = null;
+ final List<SubscriptionInfo> records = getActiveSubscriptionInfoList(
+ mContext.getOpPackageName());
+ if (!records.isEmpty()) {
+ // yes, we have more subscriptions. pick the first one.
+ // FIXME do we need a policy to figure out which one is to be next default
+ info = records.get(0);
+ }
+ updateDefaultSubIdsIfNeeded(info.getSubscriptionId(), info.getSubscriptionType());
+
+ notifySubscriptionInfoChanged();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return result;
+ }
+
/**
* Clear an subscriptionInfo to subinfo database if needed by updating slot index to invalid.
* @param slotIndex the slot which the SIM is removed
@@ -1101,7 +1318,7 @@
// Refresh the Cache of Active Subscription Info List
refreshCachedActiveSubscriptionInfoList();
- sSlotIndexToSubId.remove(slotIndex);
+ sSlotIndexToSubIds.remove(slotIndex);
// update default subId
clearDefaultsForInactiveSubIds();
@@ -1117,24 +1334,32 @@
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public Uri insertEmptySubInfoRecord(String iccId, int slotIndex) {
+ return insertEmptySubInfoRecord(iccId, null, slotIndex,
+ SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
+ }
+
+ Uri insertEmptySubInfoRecord(String uniqueId, String displayName, int slotIndex,
+ int subscriptionType) {
ContentResolver resolver = mContext.getContentResolver();
ContentValues value = new ContentValues();
- value.put(SubscriptionManager.ICC_ID, iccId);
+ value.put(SubscriptionManager.ICC_ID, uniqueId);
int color = getUnusedColor(mContext.getOpPackageName());
// default SIM color differs between slots
value.put(SubscriptionManager.COLOR, color);
value.put(SubscriptionManager.SIM_SLOT_INDEX, slotIndex);
value.put(SubscriptionManager.CARRIER_NAME, "");
- UiccCard card = UiccController.getInstance().getUiccCardForPhone(slotIndex);
- if (card != null) {
- String cardId = card.getCardId();
- if (cardId != null) {
- value.put(SubscriptionManager.CARD_ID, cardId);
- } else {
- value.put(SubscriptionManager.CARD_ID, iccId);
- }
+ value.put(SubscriptionManager.CARD_ID, uniqueId);
+ value.put(SubscriptionManager.SUBSCRIPTION_TYPE, subscriptionType);
+ if (isSubscriptionForRemoteSim(subscriptionType)) {
+ value.put(SubscriptionManager.DISPLAY_NAME, displayName);
} else {
- value.put(SubscriptionManager.CARD_ID, iccId);
+ UiccCard card = UiccController.getInstance().getUiccCardForPhone(slotIndex);
+ if (card != null) {
+ String cardId = card.getCardId();
+ if (cardId != null) {
+ value.put(SubscriptionManager.CARD_ID, cardId);
+ }
+ }
}
Uri uri = resolver.insert(SubscriptionManager.CONTENT_URI, value);
@@ -1501,20 +1726,18 @@
return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
}
- int size = sSlotIndexToSubId.size();
+ int size = sSlotIndexToSubIds.size();
- if (size == 0)
- {
+ if (size == 0) {
if (DBG) logd("[getSlotIndex]- size == 0, return SIM_NOT_INSERTED instead");
return SubscriptionManager.SIM_NOT_INSERTED;
}
- for (Entry<Integer, Integer> entry: sSlotIndexToSubId.entrySet()) {
+ for (Entry<Integer, ArrayList<Integer>> entry : sSlotIndexToSubIds.entrySet()) {
int sim = entry.getKey();
- int sub = entry.getValue();
+ ArrayList<Integer> subs = entry.getValue();
- if (subId == sub)
- {
+ if (subs != null && subs.contains(subId)) {
if (VDBG) logv("[getSlotIndex]- return = " + sim);
return sim;
}
@@ -1544,36 +1767,27 @@
}
// Check that we have a valid slotIndex
+ // TODO b/123300875 This check should probably be removed once tests are fixed
if (!SubscriptionManager.isValidSlotIndex(slotIndex)) {
if (DBG) logd("[getSubId]- invalid slotIndex=" + slotIndex);
return null;
}
// Check if we've got any SubscriptionInfo records using slotIndexToSubId as a surrogate.
- int size = sSlotIndexToSubId.size();
+ int size = sSlotIndexToSubIds.size();
if (size == 0) {
if (VDBG) {
- logd("[getSubId]- sSlotIndexToSubId.size == 0, return null slotIndex="
+ logd("[getSubId]- sSlotIndexToSubIds.size == 0, return null slotIndex="
+ slotIndex);
}
return null;
}
- // Create an array of subIds that are in this slot?
- ArrayList<Integer> subIds = new ArrayList<Integer>();
- for (Entry<Integer, Integer> entry: sSlotIndexToSubId.entrySet()) {
- int slot = entry.getKey();
- int sub = entry.getValue();
- if (slotIndex == slot) {
- subIds.add(sub);
- }
- }
-
// Convert ArrayList to array
- int numSubIds = subIds.size();
- if (numSubIds > 0) {
- int[] subIdArr = new int[numSubIds];
- for (int i = 0; i < numSubIds; i++) {
+ ArrayList<Integer> subIds = sSlotIndexToSubIds.get(slotIndex);
+ if (subIds != null && subIds.size() > 0) {
+ int[] subIdArr = new int[subIds.size()];
+ for (int i = 0; i < subIds.size(); i++) {
subIdArr[i] = subIds.get(i);
}
if (VDBG) logd("[getSubId]- subIdArr=" + subIdArr);
@@ -1602,7 +1816,7 @@
return SubscriptionManager.INVALID_PHONE_INDEX;
}
- int size = sSlotIndexToSubId.size();
+ int size = sSlotIndexToSubIds.size();
if (size == 0) {
phoneId = mDefaultPhoneId;
if (DBG) logdl("[getPhoneId]- no sims, returning default phoneId=" + phoneId);
@@ -1610,11 +1824,11 @@
}
// FIXME: Assumes phoneId == slotIndex
- for (Entry<Integer, Integer> entry: sSlotIndexToSubId.entrySet()) {
+ for (Entry<Integer, ArrayList<Integer>> entry: sSlotIndexToSubIds.entrySet()) {
int sim = entry.getKey();
- int sub = entry.getValue();
+ ArrayList<Integer> subs = entry.getValue();
- if (subId == sub) {
+ if (subs != null && subs.contains(subId)) {
if (VDBG) logdl("[getPhoneId]- found subId=" + subId + " phoneId=" + sim);
return sim;
}
@@ -1638,14 +1852,14 @@
// Now that all security checks passes, perform the operation as ourselves.
final long identity = Binder.clearCallingIdentity();
try {
- int size = sSlotIndexToSubId.size();
+ int size = sSlotIndexToSubIds.size();
if (size == 0) {
if (DBG) logdl("[clearSubInfo]- no simInfo size=" + size);
return 0;
}
- sSlotIndexToSubId.clear();
+ sSlotIndexToSubIds.clear();
if (DBG) logdl("[clearSubInfo]- clear size=" + size);
return size;
} finally {
@@ -1855,11 +2069,18 @@
* sub is set as default subId. If two or more sub's are active
* the first sub is set as default subscription
*/
- private void setDefaultFallbackSubId(int subId) {
+ private void setDefaultFallbackSubId(int subId, int subscriptionType) {
if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
throw new RuntimeException("setDefaultSubId called with DEFAULT_SUB_ID");
}
- if (DBG) logdl("[setDefaultFallbackSubId] subId=" + subId);
+ if (DBG) {
+ logdl("[setDefaultFallbackSubId] subId=" + subId + ", subscriptionType="
+ + subscriptionType);
+ }
+ if (isSubscriptionForRemoteSim(subscriptionType)) {
+ mDefaultFallbackSubId = subId;
+ return;
+ }
if (SubscriptionManager.isValidSubscriptionId(subId)) {
int phoneId = getPhoneId(subId);
if (phoneId >= 0 && (phoneId < mTelephonyManager.getPhoneCount()
@@ -1869,17 +2090,7 @@
// Update MCC MNC device configuration information
String defaultMccMnc = mTelephonyManager.getSimOperatorNumericForPhone(phoneId);
MccTable.updateMccMncConfiguration(mContext, defaultMccMnc);
-
- // Broadcast an Intent for default sub change
- Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
- | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId, subId);
- if (DBG) {
- logdl("[setDefaultFallbackSubId] broadcast default subId changed phoneId=" +
- phoneId + " subId=" + subId);
- }
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ sendDefaultChangedBroadcast(phoneId, subId);
} else {
if (DBG) {
logdl("[setDefaultFallbackSubId] not set invalid phoneId=" + phoneId
@@ -1889,6 +2100,19 @@
}
}
+ private void sendDefaultChangedBroadcast(int phoneId, int subId) {
+ // Broadcast an Intent for default sub change
+ Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId, subId);
+ if (DBG) {
+ logdl("[sendDefaultChangedBroadcast] broadcast default subId changed phoneId="
+ + phoneId + " subId=" + subId);
+ }
+ mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ }
+
@Override
public void clearDefaultsForInactiveSubIds() {
enforceModifyPhoneState("clearDefaultsForInactiveSubIds");
@@ -2006,18 +2230,38 @@
sPhones = phones;
}
+ private synchronized ArrayList<Integer> getActiveSubIdArrayList() {
+ // Clone the sub id list so it can't change out from under us while iterating
+ List<Entry<Integer, ArrayList<Integer>>> simInfoList =
+ new ArrayList<>(sSlotIndexToSubIds.entrySet());
+
+ // Put the set of sub ids in slot index order
+ Collections.sort(simInfoList, (x, y) -> x.getKey().compareTo(y.getKey()));
+
+ // Collect the sub ids for each slot in turn
+ ArrayList<Integer> allSubs = new ArrayList<>();
+ for (Entry<Integer, ArrayList<Integer>> slot : simInfoList) {
+ allSubs.addAll(slot.getValue());
+ }
+ return allSubs;
+ }
+
/**
* @return the list of subId's that are active, is never null but the length maybe 0.
*/
@Override
- public @NonNull int[] getActiveSubIdList() {
- int[] subIdArr = sSlotIndexToSubId.keySet().stream()
- .sorted()
- .mapToInt(slotId -> sSlotIndexToSubId.get(slotId))
- .toArray();
+ public int[] getActiveSubIdList() {
+ ArrayList<Integer> allSubs = getActiveSubIdArrayList();
+ int[] subIdArr = new int[allSubs.size()];
+ int i = 0;
+ for (int sub : allSubs) {
+ subIdArr[i] = sub;
+ i++;
+ }
if (VDBG) {
- logdl("[getActiveSubIdList] subIdArr=" + Arrays.toString(subIdArr));
+ logdl("[getActiveSubIdList] allSubs=" + allSubs + " subIdArr.length="
+ + subIdArr.length);
}
return subIdArr;
}
@@ -2039,14 +2283,15 @@
@Deprecated // This should be moved into isActiveSubId(int, String)
public boolean isActiveSubId(int subId) {
boolean retVal = SubscriptionManager.isValidSubscriptionId(subId)
- && sSlotIndexToSubId.containsValue(subId);
+ && getActiveSubIdArrayList().contains(subId);
if (VDBG) logdl("[isActiveSubId]- " + retVal);
return retVal;
}
/**
- * Get the SIM state for the slot index
+ * Get the SIM state for the slot index.
+ * For Remote-SIMs, this method returns {@link #IccCardConstants.State.UNKNOWN}
* @return SIM state as the ordinal of {@See IccCardConstants.State}
*/
@Override
@@ -2242,8 +2487,8 @@
.from(mContext).getDefaultSmsPhoneId());
pw.flush();
- for (Entry<Integer, Integer> entry : sSlotIndexToSubId.entrySet()) {
- pw.println(" sSlotIndexToSubId[" + entry.getKey() + "]: subId=" + entry.getValue());
+ for (Entry<Integer, ArrayList<Integer>> entry : sSlotIndexToSubIds.entrySet()) {
+ pw.println(" sSlotIndexToSubId[" + entry.getKey() + "]: subIds=" + entry);
}
pw.flush();
pw.println("++++++++++++++++++++++++++++++++");
@@ -2349,8 +2594,12 @@
long token = Binder.clearCallingIdentity();
try {
- return setSubscriptionProperty(subId, SubscriptionManager.IS_OPPORTUNISTIC,
+ int ret = setSubscriptionProperty(subId, SubscriptionManager.IS_OPPORTUNISTIC,
String.valueOf(opportunistic ? 1 : 0));
+
+ if (ret != 0) notifySubscriptionInfoChanged();
+
+ return ret;
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2380,8 +2629,12 @@
long token = Binder.clearCallingIdentity();
try {
- return setSubscriptionProperty(subId, SubscriptionManager.IS_METERED,
+ int ret = setSubscriptionProperty(subId, SubscriptionManager.IS_METERED,
String.valueOf(isMetered ? 1 : 0));
+
+ if (ret != 0) notifySubscriptionInfoChanged();
+
+ return ret;
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2721,6 +2974,53 @@
}
}
+ private synchronized boolean addToSubIdList(int slotIndex, int subId, int subscriptionType) {
+ ArrayList<Integer> subIdsList = sSlotIndexToSubIds.get(slotIndex);
+ if (subIdsList == null) {
+ subIdsList = new ArrayList<>();
+ sSlotIndexToSubIds.put(slotIndex, subIdsList);
+ }
+
+ // add the given subId unless it already exists
+ if (subIdsList.contains(subId)) {
+ logdl("slotIndex, subId combo already exists in the map. Not adding it again.");
+ return false;
+ }
+ if (isSubscriptionForRemoteSim(subscriptionType)) {
+ // For Remote SIM subscriptions, a slot can have multiple subscriptions.
+ subIdsList.add(subId);
+ } else {
+ // for all other types of subscriptions, a slot can have only one subscription at a time
+ subIdsList.clear();
+ subIdsList.add(subId);
+ }
+ if (DBG) logdl("slotIndex, subId combo is added to the map.");
+ return true;
+ }
+
+ private boolean isSubscriptionForRemoteSim(int subscriptionType) {
+ return subscriptionType == SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM;
+ }
+
+ /**
+ * This is only for testing
+ * @hide
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public Map<Integer, ArrayList<Integer>> getSlotIndexToSubIdsMap() {
+ return sSlotIndexToSubIds;
+ }
+
+ /**
+ * This is only for testing
+ * @hide
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public void resetStaticMembers() {
+ mDefaultFallbackSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ mDefaultPhoneId = SubscriptionManager.DEFAULT_PHONE_INDEX;
+ }
+
private void notifyOpportunisticSubscriptionInfoChanged() {
ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index 98ac9f5..5fbbbd3 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -549,21 +549,28 @@
List<SubscriptionInfo> subInfos = SubscriptionController.getInstance()
.getSubInfoUsingSlotIndexPrivileged(slotIndex, false);
if (subInfos != null) {
+ boolean changed = false;
for (int i = 0; i < subInfos.size(); i++) {
SubscriptionInfo temp = subInfos.get(i);
ContentValues value = new ContentValues(1);
String msisdn = TelephonyManager.getDefault().getLine1Number(
temp.getSubscriptionId());
- if (msisdn != null) {
+
+ UiccSlot uiccSlot = UiccController.getInstance().getUiccSlotForPhone(slotIndex);
+ boolean isEuicc = (uiccSlot != null && uiccSlot.isEuicc());
+ if (isEuicc != temp.isEmbedded() || !TextUtils.equals(msisdn, temp.getNumber())) {
+ value.put(SubscriptionManager.IS_EMBEDDED, isEuicc);
value.put(SubscriptionManager.NUMBER, msisdn);
mContext.getContentResolver().update(SubscriptionManager.getUriForSubscriptionId(
temp.getSubscriptionId()), value, null, null);
-
- // refresh Cached Active Subscription Info List
- SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList();
+ changed = true;
}
}
+ if (changed) {
+ // refresh Cached Active Subscription Info List
+ SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList();
+ }
}
// TODO investigate if we can update for each slot separately.
@@ -610,21 +617,25 @@
return false;
}
+ // If the returned result is not RESULT_OK or the profile list is null, don't update cache.
+ // Otherwise, update the cache.
final EuiccProfileInfo[] embeddedProfiles;
- if (result.getResult() == EuiccService.RESULT_OK) {
- List<EuiccProfileInfo> list = result.getProfiles();
- if (list == null || list.size() == 0) {
- embeddedProfiles = new EuiccProfileInfo[0];
- } else {
- embeddedProfiles = list.toArray(new EuiccProfileInfo[list.size()]);
+ List<EuiccProfileInfo> list = result.getProfiles();
+ if (result.getResult() == EuiccService.RESULT_OK && list != null) {
+ embeddedProfiles = list.toArray(new EuiccProfileInfo[list.size()]);
+ if (DBG) {
+ logd("blockingGetEuiccProfileInfoList: got " + result.getProfiles().size()
+ + " profiles");
}
} else {
- logd("updatedEmbeddedSubscriptions: error " + result.getResult() + " listing profiles");
- // If there's an error listing profiles, treat it equivalently to a successful
- // listing which returned no profiles under the assumption that none are currently
- // accessible.
- embeddedProfiles = new EuiccProfileInfo[0];
+ if (DBG) {
+ logd("blockingGetEuiccProfileInfoList returns an error. "
+ + "Result code=" + result.getResult()
+ + ". Null profile list=" + (result.getProfiles() == null));
+ }
+ return false;
}
+
final boolean isRemovable = result.getIsRemovable();
final String[] embeddedIccids = new String[embeddedProfiles.length];
diff --git a/src/java/com/android/internal/telephony/TransportManager.java b/src/java/com/android/internal/telephony/TransportManager.java
index a093b00..b161754 100644
--- a/src/java/com/android/internal/telephony/TransportManager.java
+++ b/src/java/com/android/internal/telephony/TransportManager.java
@@ -21,22 +21,27 @@
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
import android.telephony.data.ApnSetting.ApnType;
-import android.text.TextUtils;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.dataconnection.AccessNetworksManager.QualifiedNetworks;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
/**
* This class represents the transport manager which manages available transports (i.e. WWAN or
@@ -46,7 +51,17 @@
public class TransportManager extends Handler {
private static final String TAG = TransportManager.class.getSimpleName();
- private static final boolean DBG = true;
+ private static final Map<Integer, Integer> ACCESS_NETWORK_TRANSPORT_TYPE_MAP;
+
+ static {
+ ACCESS_NETWORK_TRANSPORT_TYPE_MAP = new HashMap<>();
+ ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.UNKNOWN, TransportType.WWAN);
+ ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.GERAN, TransportType.WWAN);
+ ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.UTRAN, TransportType.WWAN);
+ ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.EUTRAN, TransportType.WWAN);
+ ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.CDMA2000, TransportType.WWAN);
+ ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.IWLAN, TransportType.WLAN);
+ }
private static final int EVENT_QUALIFIED_NETWORKS_CHANGED = 1;
@@ -87,6 +102,12 @@
private final AccessNetworksManager mAccessNetworksManager;
+ /**
+ * Available networks. The key is the APN type, and the value is the available network list in
+ * the preferred order.
+ */
+ private final Map<Integer, int[]> mCurrentAvailableNetworks;
+
public TransportManager(Phone phone) {
mPhone = phone;
mAccessNetworksManager = new AccessNetworksManager(phone);
@@ -94,6 +115,8 @@
mAccessNetworksManager.registerForQualifiedNetworksChanged(this,
EVENT_QUALIFIED_NETWORKS_CHANGED);
+ mCurrentAvailableNetworks = new ConcurrentHashMap<>();
+
if (isInLegacyMode()) {
// For legacy mode, WWAN is the only transport to handle all data connections, even
// the IWLAN ones.
@@ -117,9 +140,11 @@
}
}
- private synchronized void updateAvailableNetworks(List<QualifiedNetworks> networks) {
- log("updateAvailableNetworks: " + networks);
- //TODO: Update available networks and transports.
+ private synchronized void updateAvailableNetworks(List<QualifiedNetworks> networksList) {
+ log("updateAvailableNetworks: " + networksList);
+ for (QualifiedNetworks networks : networksList) {
+ mCurrentAvailableNetworks.put(networks.apnType, networks.qualifiedNetworks);
+ }
}
/**
@@ -150,14 +175,33 @@
}
/**
- * Get the corresponding transport based on the APN type
+ * Get the transport based on the APN type
*
* @param apnType APN type
* @return The transport type
*/
public int getCurrentTransport(@ApnType int apnType) {
- // TODO: Look up the transport from the transport type map
- return TransportType.WWAN;
+ // In legacy mode, always route to cellular.
+ if (isInLegacyMode()) {
+ return TransportType.WWAN;
+ }
+
+ // If we can't find the available networks, always route to cellular.
+ if (!mCurrentAvailableNetworks.containsKey(apnType)) {
+ return TransportType.WWAN;
+ }
+
+ int[] availableNetworks = mCurrentAvailableNetworks.get(apnType);
+
+ // If the available networks list is empty, route to cellular.
+ if (ArrayUtils.isEmpty(availableNetworks)) {
+ return TransportType.WWAN;
+ }
+
+ // TODO: For now we choose the first network because it's the most preferred one. In the
+ // the future we should validate it to make sure this network does not violate carrier
+ // preference and user preference.
+ return ACCESS_NETWORK_TRANSPORT_TYPE_MAP.get(availableNetworks[0]);
}
/**
@@ -171,12 +215,11 @@
IndentingPrintWriter pw = new IndentingPrintWriter(printwriter, " ");
pw.println("TransportManager:");
pw.increaseIndent();
- pw.print("mAvailableTransports=");
- List<String> transportsStrings = new ArrayList<>();
- for (int i = 0; i < mAvailableTransports.length; i++) {
- transportsStrings.add(TransportType.toString(mAvailableTransports[i]));
- }
- pw.println("[" + TextUtils.join(",", transportsStrings) + "]");
+ pw.println("mAvailableTransports=[" + Arrays.stream(mAvailableTransports)
+ .mapToObj(type -> TransportType.toString(type))
+ .collect(Collectors.joining(",")) + "]");
+ pw.println("isInLegacy=" + isInLegacyMode());
+ pw.println("IWLAN operation mode=" + mPhone.mCi.getIwlanOperationMode());
mAccessNetworksManager.dump(fd, pw, args);
pw.decreaseIndent();
pw.flush();
diff --git a/src/java/com/android/internal/telephony/dataconnection/AccessNetworksManager.java b/src/java/com/android/internal/telephony/dataconnection/AccessNetworksManager.java
index a38cc8b..6a2b763 100644
--- a/src/java/com/android/internal/telephony/dataconnection/AccessNetworksManager.java
+++ b/src/java/com/android/internal/telephony/dataconnection/AccessNetworksManager.java
@@ -47,6 +47,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Access network manager manages the qualified/available networks for mobile data connection.
@@ -80,6 +81,7 @@
private QualifiedNetworksServiceConnection mServiceConnection;
+ // Available networks. Key is the APN type.
private final SparseArray<int[]> mAvailableNetworks = new SparseArray<>();
private final RegistrantList mQualifiedNetworksChangedRegistrants = new RegistrantList();
@@ -119,7 +121,9 @@
return "[QualifiedNetworks: apnType="
+ ApnSetting.getApnTypeString(apnType)
+ ", networks="
- + TextUtils.join(", ", accessNetworkStrings)
+ + Arrays.stream(qualifiedNetworks)
+ .mapToObj(type -> AccessNetworkType.toString(type))
+ .collect(Collectors.joining(","))
+ "]";
}
}
@@ -160,9 +164,11 @@
IQualifiedNetworksServiceCallback.Stub {
@Override
public void onQualifiedNetworkTypesChanged(int apnTypes, int[] qualifiedNetworkTypes) {
- log("onQualifiedNetworkTypesChanged. apnTypes = "
+ log("onQualifiedNetworkTypesChanged. apnTypes = ["
+ ApnSetting.getApnTypesStringFromBitmask(apnTypes)
- + ", networks = " + Arrays.toString(qualifiedNetworkTypes));
+ + "], networks = [" + Arrays.stream(qualifiedNetworkTypes)
+ .mapToObj(i -> AccessNetworkType.toString(i)).collect(Collectors.joining(","))
+ + "]");
List<QualifiedNetworks> qualifiedNetworksList = new ArrayList<>();
for (int supportedApnType : SUPPORTED_APN_TYPES) {
if ((apnTypes & supportedApnType) == supportedApnType) {
@@ -316,13 +322,10 @@
pw.increaseIndent();
for (int i = 0; i < mAvailableNetworks.size(); i++) {
- pw.print("APN type "
- + ApnSetting.getApnTypeString(mAvailableNetworks.keyAt(i)) + ": ");
- List<String> networksStrings = new ArrayList<>();
- for (int network : mAvailableNetworks.valueAt(i)) {
- networksStrings.add(AccessNetworkType.toString(network));
- }
- pw.println("[" + TextUtils.join(",", networksStrings) + "]");
+ pw.println("APN type " + ApnSetting.getApnTypeString(mAvailableNetworks.keyAt(i))
+ + ": [" + Arrays.stream(mAvailableNetworks.valueAt(i))
+ .mapToObj(type -> AccessNetworkType.toString(type))
+ .collect(Collectors.joining(",")) + "]");
}
pw.decreaseIndent();
pw.decreaseIndent();
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
index 0b4da48..471c9a6 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
@@ -32,12 +32,13 @@
import com.android.internal.telephony.DctConstants;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RetryManager;
+import com.android.internal.telephony.dataconnection.DcTracker.ReleaseNetworkType;
+import com.android.internal.telephony.dataconnection.DcTracker.RequestNetworkType;
import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -385,14 +386,7 @@
return mDataEnabled.get();
}
- public void setDependencyMet(boolean met) {
- if (DBG) {
- log("set mDependencyMet as " + met + " current state is " + mDependencyMet.get());
- }
- mDependencyMet.set(met);
- }
-
- public boolean getDependencyMet() {
+ public boolean isDependencyMet() {
return mDependencyMet.get();
}
@@ -419,19 +413,21 @@
}
}
- public void requestNetwork(NetworkRequest networkRequest, LocalLog log) {
+ public void requestNetwork(NetworkRequest networkRequest,
+ @RequestNetworkType int type, LocalLog log) {
synchronized (mRefCountLock) {
if (mLocalLogs.contains(log) || mNetworkRequests.contains(networkRequest)) {
log.log("ApnContext.requestNetwork has duplicate add - " + mNetworkRequests.size());
} else {
mLocalLogs.add(log);
mNetworkRequests.add(networkRequest);
- mDcTracker.setEnabled(ApnSetting.getApnTypesBitmaskFromString(mApnType), true);
+ mDcTracker.enableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type);
}
}
}
- public void releaseNetwork(NetworkRequest networkRequest, LocalLog log) {
+ public void releaseNetwork(NetworkRequest networkRequest, @ReleaseNetworkType int type,
+ LocalLog log) {
synchronized (mRefCountLock) {
if (mLocalLogs.contains(log) == false) {
log.log("ApnContext.releaseNetwork can't find this log");
@@ -445,19 +441,15 @@
mNetworkRequests.remove(networkRequest);
log.log("ApnContext.releaseNetwork left with " + mNetworkRequests.size() +
" requests.");
- if (mNetworkRequests.size() == 0) {
- mDcTracker.setEnabled(ApnSetting.getApnTypesBitmaskFromString(mApnType), false);
+ if (mNetworkRequests.size() == 0
+ || type == DcTracker.RELEASE_TYPE_DETACH
+ || type == DcTracker.RELEASE_TYPE_HANDOVER) {
+ mDcTracker.disableApn(ApnSetting.getApnTypesBitmaskFromString(mApnType), type);
}
}
}
}
- public List<NetworkRequest> getNetworkRequests() {
- synchronized (mRefCountLock) {
- return new ArrayList<NetworkRequest>(mNetworkRequests);
- }
- }
-
/**
* @param excludeDun True if excluding requests that have DUN capability
* @return True if the attached network requests contain restricted capability.
diff --git a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
index 555b6e9..ae69631 100644
--- a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
+++ b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
@@ -16,10 +16,7 @@
package com.android.internal.telephony.dataconnection;
-import android.hardware.radio.V1_0.SetupDataCallResult;
-import android.net.LinkAddress;
import android.net.LinkProperties;
-import android.net.NetworkUtils;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.HandlerThread;
@@ -31,16 +28,10 @@
import android.telephony.data.DataProfile;
import android.telephony.data.DataService;
import android.telephony.data.DataServiceCallback;
-import android.text.TextUtils;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -89,11 +80,11 @@
AsyncResult ar = (AsyncResult) message.obj;
switch (message.what) {
case SETUP_DATA_CALL_COMPLETE:
- SetupDataCallResult result = (SetupDataCallResult) ar.result;
+ DataCallResponse response = (DataCallResponse) ar.result;
callback.onSetupDataCallComplete(ar.exception != null
? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
: DataServiceCallback.RESULT_SUCCESS,
- convertDataCallResult(result));
+ response);
break;
case DEACTIVATE_DATA_ALL_COMPLETE:
callback.onDeactivateDataCallComplete(ar.exception != null
@@ -116,13 +107,11 @@
? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
: DataServiceCallback.RESULT_SUCCESS,
ar.exception != null
- ? null
- : getDataCallList((List<SetupDataCallResult>) ar.result)
+ ? null : (List<DataCallResponse>) ar.result
);
break;
case DATA_CALL_LIST_CHANGED:
- notifyDataCallListChanged(getDataCallList(
- (List<SetupDataCallResult>) ar.result));
+ notifyDataCallListChanged((List<DataCallResponse>) ar.result);
break;
default:
loge("Unexpected event: " + message.what);
@@ -135,14 +124,6 @@
mPhone.mCi.registerForDataCallListChanged(mHandler, DATA_CALL_LIST_CHANGED, null);
}
- private List<DataCallResponse> getDataCallList(List<SetupDataCallResult> dcList) {
- List<DataCallResponse> dcResponseList = new ArrayList<>();
- for (SetupDataCallResult dcResult : dcList) {
- dcResponseList.add(convertDataCallResult(dcResult));
- }
- return dcResponseList;
- }
-
@Override
public void setupDataCall(int radioTechnology, DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, LinkProperties linkProperties,
@@ -239,99 +220,6 @@
return new CellularDataServiceProvider(slotId);
}
- /**
- * Convert SetupDataCallResult defined in types.hal into DataCallResponse
- * @param dcResult setup data call result
- * @return converted DataCallResponse object
- */
- @VisibleForTesting
- public DataCallResponse convertDataCallResult(SetupDataCallResult dcResult) {
- if (dcResult == null) return null;
-
- // Process address
- String[] addresses = null;
- if (!TextUtils.isEmpty(dcResult.addresses)) {
- addresses = dcResult.addresses.split("\\s+");
- }
-
- List<LinkAddress> laList = new ArrayList<>();
- if (addresses != null) {
- for (String address : addresses) {
- address = address.trim();
- if (address.isEmpty()) continue;
-
- try {
- LinkAddress la;
- // Check if the address contains prefix length. If yes, LinkAddress
- // can parse that.
- if (address.split("/").length == 2) {
- la = new LinkAddress(address);
- } else {
- InetAddress ia = NetworkUtils.numericToInetAddress(address);
- la = new LinkAddress(ia, (ia instanceof Inet4Address) ? 32 : 128);
- }
-
- laList.add(la);
- } catch (IllegalArgumentException e) {
- loge("Unknown address: " + address + ", exception = " + e);
- }
- }
- }
-
- // Process dns
- String[] dnses = null;
- if (!TextUtils.isEmpty(dcResult.dnses)) {
- dnses = dcResult.dnses.split("\\s+");
- }
-
- List<InetAddress> dnsList = new ArrayList<>();
- if (dnses != null) {
- for (String dns : dnses) {
- dns = dns.trim();
- InetAddress ia;
- try {
- ia = NetworkUtils.numericToInetAddress(dns);
- dnsList.add(ia);
- } catch (IllegalArgumentException e) {
- loge("Unknown dns: " + dns + ", exception = " + e);
- }
- }
- }
-
- // Process gateway
- String[] gateways = null;
- if (!TextUtils.isEmpty(dcResult.gateways)) {
- gateways = dcResult.gateways.split("\\s+");
- }
-
- List<InetAddress> gatewayList = new ArrayList<>();
- if (gateways != null) {
- for (String gateway : gateways) {
- gateway = gateway.trim();
- InetAddress ia;
- try {
- ia = NetworkUtils.numericToInetAddress(gateway);
- gatewayList.add(ia);
- } catch (IllegalArgumentException e) {
- loge("Unknown gateway: " + gateway + ", exception = " + e);
- }
- }
- }
-
- return new DataCallResponse(dcResult.status,
- dcResult.suggestedRetryTime,
- dcResult.cid,
- dcResult.active,
- dcResult.type,
- dcResult.ifname,
- laList,
- dnsList,
- gatewayList,
- new ArrayList<>(Arrays.asList(dcResult.pcscf.trim().split("\\s+"))),
- dcResult.mtu
- );
- }
-
private void log(String s) {
Rlog.d(TAG, s);
}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 39b443a..7dfe6af 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -129,14 +129,16 @@
int mRilRat;
Message mOnCompletedMsg;
final int mConnectionGeneration;
+ final boolean mIsHandover;
ConnectionParams(ApnContext apnContext, int profileId, int rilRadioTechnology,
- Message onCompletedMsg, int connectionGeneration) {
+ Message onCompletedMsg, int connectionGeneration, boolean isHandover) {
mApnContext = apnContext;
mProfileId = profileId;
mRilRat = rilRadioTechnology;
mOnCompletedMsg = onCompletedMsg;
mConnectionGeneration = connectionGeneration;
+ mIsHandover = isHandover;
}
@Override
@@ -144,7 +146,9 @@
return "{mTag=" + mTag + " mApnContext=" + mApnContext
+ " mProfileId=" + mProfileId
+ " mRat=" + mRilRat
- + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}";
+ + " mOnCompletedMsg=" + msgToString(mOnCompletedMsg)
+ + " mIsHandover=" + mIsHandover
+ + "}";
}
}
@@ -155,11 +159,14 @@
int mTag;
public ApnContext mApnContext;
String mReason;
+ final boolean mIsHandover;
Message mOnCompletedMsg;
- DisconnectParams(ApnContext apnContext, String reason, Message onCompletedMsg) {
+ DisconnectParams(ApnContext apnContext, String reason, boolean isHandover,
+ Message onCompletedMsg) {
mApnContext = apnContext;
mReason = reason;
+ mIsHandover = isHandover;
mOnCompletedMsg = onCompletedMsg;
}
@@ -167,6 +174,7 @@
public String toString() {
return "{mTag=" + mTag + " mApnContext=" + mApnContext
+ " mReason=" + mReason
+ + " mIsHandover=" + mIsHandover
+ " mOnCompletedMsg=" + msgToString(mOnCompletedMsg) + "}";
}
}
@@ -286,9 +294,12 @@
DataServiceManager dataServiceManager,
DcTesterFailBringUpAll failBringUpAll,
DcController dcc) {
+ String transportType = (dataServiceManager.getTransportType() == TransportType.WWAN)
+ ? "C" // Cellular
+ : "I"; // IWLAN
DataConnection dc = new DataConnection(phone,
- "DC-" + mInstanceNumber.incrementAndGet(), id, dct, dataServiceManager,
- failBringUpAll, dcc);
+ "DC-" + transportType + "-" + mInstanceNumber.incrementAndGet(), id, dct,
+ dataServiceManager, failBringUpAll, dcc);
dc.start();
if (DBG) dc.log("Made " + dc.getName());
return dc;
@@ -499,20 +510,34 @@
}
/**
+ * Get the DcTracker for handover. There are multiple DcTrackers for different transports (e.g.
+ * WWAN, WLAN). For data handover, we need to handover the existing data connection from current
+ * DcTracker to the DcTracker on another transport.
+ */
+ private DcTracker getHandoverDcTracker() {
+ int transportType = mDataServiceManager.getTransportType();
+ // Get the DcTracker from the other transport.
+ return mPhone.getDcTracker(transportType == TransportType.WWAN
+ ? TransportType.WLAN : TransportType.WWAN);
+ }
+
+ /**
* Begin setting up a data connection, calls setupDataCall
* and the ConnectionParams will be returned with the
* EVENT_SETUP_DATA_CONNECTION_DONE
*
* @param cp is the connection parameters
+ *
+ * @return Fail cause if failed to setup data connection. {@link DataFailCause#NONE} if success.
*/
- private void onConnect(ConnectionParams cp) {
+ private @DataFailCause.FailCause int connect(ConnectionParams cp) {
if (DBG) {
- log("onConnect: carrier='" + mApnSetting.getEntryName()
+ log("connect: carrier='" + mApnSetting.getEntryName()
+ "' APN='" + mApnSetting.getApnName()
+ "' proxy='" + mApnSetting.getProxyAddressAsString()
+ "' port='" + mApnSetting.getProxyPort() + "'");
}
- if (cp.mApnContext != null) cp.mApnContext.requestLog("DataConnection.onConnect");
+ if (cp.mApnContext != null) cp.mApnContext.requestLog("DataConnection.connect");
// Check if we should fake an error.
if (mDcTesterFailBringUpAll.getDcFailBringUp().mCounter > 0) {
@@ -525,11 +550,11 @@
AsyncResult.forMessage(msg, response, null);
sendMessage(msg);
if (DBG) {
- log("onConnect: FailBringUpAll=" + mDcTesterFailBringUpAll.getDcFailBringUp()
+ log("connect: FailBringUpAll=" + mDcTesterFailBringUpAll.getDcFailBringUp()
+ " send error response=" + response);
}
mDcTesterFailBringUpAll.getDcFailBringUp().mCounter -= 1;
- return;
+ return DataFailCause.NONE;
}
mCreateTime = -1;
@@ -553,11 +578,46 @@
boolean allowRoaming = mPhone.getDataRoamingEnabled()
|| (isModemRoaming && !mPhone.getServiceState().getDataRoaming());
+ // Check if this data setup is a handover.
+ LinkProperties linkProperties = null;
+ int reason = DataService.REQUEST_REASON_NORMAL;
+ if (cp.mIsHandover) {
+ // If this is a data setup for handover, we need to pass the link properties
+ // of the existing data connection to the modem.
+ DcTracker dcTracker = getHandoverDcTracker();
+ if (dcTracker == null || cp.mApnContext == null) {
+ loge("connect: Handover failed. dcTracker=" + dcTracker + ", apnContext="
+ + cp.mApnContext);
+ return DataFailCause.HANDOVER_FAILED;
+ }
+
+ DataConnection dc = dcTracker.getDataConnectionByApnType(cp.mApnContext.getApnType());
+ if (dc == null) {
+ loge("connect: Can't find data connection for handover.");
+ return DataFailCause.HANDOVER_FAILED;
+ }
+
+ linkProperties = dc.getLinkProperties();
+ if (linkProperties == null) {
+ loge("connect: Can't find link properties of handover data connection. dc="
+ + dc);
+ return DataFailCause.HANDOVER_FAILED;
+ }
+
+ reason = DataService.REQUEST_REASON_HANDOVER;
+ }
+
mDataServiceManager.setupDataCall(
- ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat), dp, isModemRoaming,
- allowRoaming, DataService.REQUEST_REASON_NORMAL, null, msg);
+ ServiceState.rilRadioTechnologyToAccessNetworkType(cp.mRilRat),
+ dp,
+ isModemRoaming,
+ allowRoaming,
+ reason,
+ linkProperties,
+ msg);
TelephonyMetrics.getInstance().writeSetupDataCall(mPhone.getPhoneId(), cp.mRilRat,
dp.getProfileId(), dp.getApn(), dp.getProtocol());
+ return DataFailCause.NONE;
}
public void onSubscriptionOverride(int overrideMask, int overrideValue) {
@@ -581,6 +641,8 @@
if (TextUtils.equals(dp.mReason, Phone.REASON_RADIO_TURNED_OFF)
|| TextUtils.equals(dp.mReason, Phone.REASON_PDP_RESET)) {
discReason = DataService.REQUEST_REASON_SHUTDOWN;
+ } else if (dp.mIsHandover) {
+ discReason = DataService.REQUEST_REASON_HANDOVER;
}
}
@@ -599,7 +661,7 @@
if (apnContext == alreadySent) continue;
if (reason != null) apnContext.setReason(reason);
Pair<ApnContext, Integer> pair = new Pair<>(apnContext, cp.mConnectionGeneration);
- Message msg = mDct.obtainMessage(event, pair);
+ Message msg = mDct.obtainMessage(event, mCid, cp.mIsHandover ? 1 : 0, pair);
AsyncResult.forMessage(msg);
msg.sendToTarget();
}
@@ -624,6 +686,7 @@
long timeStamp = System.currentTimeMillis();
connectionCompletedMsg.arg1 = mCid;
+ connectionCompletedMsg.arg2 = cp.mIsHandover ? 1 : 0;
if (cause == DataFailCause.NONE) {
mCreateTime = timeStamp;
@@ -746,6 +809,7 @@
ConnectionParams cp) {
SetupResult result;
+ log("onSetupConnectionCompleted: resultCode=" + resultCode + ", response=" + response);
if (cp.mTag != mTag) {
if (DBG) {
log("onSetupConnectionCompleted stale cp.tag=" + cp.mTag + ", mtag=" + mTag);
@@ -1512,8 +1576,6 @@
@Override
public boolean processMessage(Message msg) {
- boolean retVal;
-
switch (msg.what) {
case EVENT_RESET:
case EVENT_REEVALUATE_RESTRICTED_STATE:
@@ -1521,45 +1583,43 @@
log("DcInactiveState: msg.what=" + getWhatToString(msg.what)
+ ", ignore we're already done");
}
- retVal = HANDLED;
- break;
-
+ return HANDLED;
case EVENT_CONNECT:
if (DBG) log("DcInactiveState: mag.what=EVENT_CONNECT");
ConnectionParams cp = (ConnectionParams) msg.obj;
- if (initConnection(cp)) {
- onConnect(mConnectionParams);
- transitionTo(mActivatingState);
- } else {
- if (DBG) {
- log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed");
- }
+
+ if (!initConnection(cp)) {
+ log("DcInactiveState: msg.what=EVENT_CONNECT initConnection failed");
notifyConnectCompleted(cp, DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
false);
+ transitionTo(mInactiveState);
+ return HANDLED;
}
- retVal = HANDLED;
- break;
+ int cause = connect(cp);
+ if (cause != DataFailCause.NONE) {
+ log("DcInactiveState: msg.what=EVENT_CONNECT connect failed");
+ notifyConnectCompleted(cp, cause, false);
+ transitionTo(mInactiveState);
+ return HANDLED;
+ }
+
+ transitionTo(mActivatingState);
+ return HANDLED;
case EVENT_DISCONNECT:
if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT");
notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
- retVal = HANDLED;
- break;
-
+ return HANDLED;
case EVENT_DISCONNECT_ALL:
if (DBG) log("DcInactiveState: msg.what=EVENT_DISCONNECT_ALL");
notifyDisconnectCompleted((DisconnectParams)msg.obj, false);
- retVal = HANDLED;
- break;
-
+ return HANDLED;
default:
if (VDBG) {
- log("DcInactiveState nothandled msg.what=" + getWhatToString(msg.what));
+ log("DcInactiveState not handled msg.what=" + getWhatToString(msg.what));
}
- retVal = NOT_HANDLED;
- break;
+ return NOT_HANDLED;
}
- return retVal;
}
}
private DcInactiveState mInactiveState = new DcInactiveState();
@@ -1728,9 +1788,30 @@
log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride
+ ", mUnmeteredUseOnly = " + mUnmeteredUseOnly);
}
- mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
- "DcNetworkAgent", mNetworkInfo, getNetworkCapabilities(), mLinkProperties,
- 50, misc);
+
+ if (mConnectionParams != null && mConnectionParams.mIsHandover) {
+ // If this is a data setup for handover, we need to reuse the existing network agent
+ // instead of creating a new one. This should be transparent to connectivity
+ // service.
+ DcTracker dcTracker = getHandoverDcTracker();
+ DataConnection dc = dcTracker.getDataConnectionByApnType(
+ mConnectionParams.mApnContext.getApnType());
+ if (dc != null) {
+ mNetworkAgent = dc.getNetworkAgent();
+ if (mNetworkAgent != null) {
+ mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities());
+ mNetworkAgent.sendLinkProperties(mLinkProperties);
+ } else {
+ loge("Failed to get network agent from original data connection " + dc);
+ }
+ } else {
+ loge("Cannot find the data connection for handover.");
+ }
+ } else {
+ mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
+ "DcNetworkAgent", mNetworkInfo, getNetworkCapabilities(), mLinkProperties,
+ 50, misc);
+ }
if (mDataServiceManager.getTransportType() == TransportType.WWAN) {
mPhone.mCi.registerForNattKeepaliveStatus(
getHandler(), DataConnection.EVENT_KEEPALIVE_STATUS, null);
@@ -1761,7 +1842,13 @@
mPhone.mCi.unregisterForLceInfo(getHandler());
}
if (mNetworkAgent != null) {
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ // We do not want to update the network info if this is a handover. For all other
+ // cases we need to update connectivity service with the latest network info.
+ //
+ // For handover, the network agent is transferred to the other data connection.
+ if (mDisconnectParams == null || !mDisconnectParams.mIsHandover) {
+ mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ }
mNetworkAgent = null;
}
}
@@ -2183,7 +2270,8 @@
new Pair<ApnContext, Integer>(apnContext, cp.mConnectionGeneration);
log("DcNetworkAgent: [unwanted]: disconnect apnContext=" + apnContext);
Message msg = mDct.obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair);
- DisconnectParams dp = new DisconnectParams(apnContext, apnContext.getReason(), msg);
+ DisconnectParams dp = new DisconnectParams(apnContext, apnContext.getReason(),
+ false, msg);
DataConnection.this.sendMessage(DataConnection.this.
obtainMessage(EVENT_DISCONNECT, dp));
}
@@ -2200,15 +2288,10 @@
@Override
protected void networkStatus(int status, String redirectUrl) {
- if(!TextUtils.isEmpty(redirectUrl)) {
- log("validation status: " + status + " with redirection URL: " + redirectUrl);
- /* its possible that we have multiple DataConnection with INTERNET_CAPABILITY
- all fail the validation with the same redirection url, send CMD back to DCTracker
- and let DcTracker to make the decision */
- Message msg = mDct.obtainMessage(DctConstants.EVENT_REDIRECTION_DETECTED,
- redirectUrl);
- msg.sendToTarget();
- }
+ log("validation status: " + status + " with redirection URL: " + redirectUrl);
+ Message msg = mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
+ status, 0, redirectUrl);
+ msg.sendToTarget();
}
@Override
@@ -2370,30 +2453,33 @@
* AsyncResult.result = FailCause and AsyncResult.exception = Exception().
* @param connectionGeneration used to track a single connection request so disconnects can get
* ignored if obsolete.
+ * @param isHandover {@code true} if this request is for handover.
*/
public void bringUp(ApnContext apnContext, int profileId, int rilRadioTechnology,
- Message onCompletedMsg, int connectionGeneration) {
+ Message onCompletedMsg, int connectionGeneration, boolean isHandover) {
if (DBG) {
log("bringUp: apnContext=" + apnContext + " onCompletedMsg=" + onCompletedMsg);
}
sendMessage(DataConnection.EVENT_CONNECT,
new ConnectionParams(apnContext, profileId, rilRadioTechnology, onCompletedMsg,
- connectionGeneration));
+ connectionGeneration, isHandover));
}
/**
* Tear down the connection through the apn on the network.
*
+ * @param apnContext APN context
+ * @param reason reason to tear down
* @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
* With AsyncResult.userObj set to the original msg.obj.
*/
public void tearDown(ApnContext apnContext, String reason, Message onCompletedMsg) {
if (DBG) {
- log("tearDown: apnContext=" + apnContext
- + " reason=" + reason + " onCompletedMsg=" + onCompletedMsg);
+ log("tearDown: apnContext=" + apnContext + " reason=" + reason + " onCompletedMsg="
+ + onCompletedMsg);
}
sendMessage(DataConnection.EVENT_DISCONNECT,
- new DisconnectParams(apnContext, reason, onCompletedMsg));
+ new DisconnectParams(apnContext, reason, false, onCompletedMsg));
}
// ******* "public" interface
@@ -2410,13 +2496,14 @@
* Tear down the connection through the apn on the network. Ignores reference count and
* and always tears down.
*
+ * @param isHandover {@code true} if this is for handover
* @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
* With AsyncResult.userObj set to the original msg.obj.
*/
- public void tearDownAll(String reason, Message onCompletedMsg) {
+ public void tearDownAll(String reason, boolean isHandover, Message onCompletedMsg) {
if (DBG) log("tearDownAll: reason=" + reason + " onCompletedMsg=" + onCompletedMsg);
sendMessage(DataConnection.EVENT_DISCONNECT_ALL,
- new DisconnectParams(null, reason, onCompletedMsg));
+ new DisconnectParams(null, reason, isHandover, onCompletedMsg));
}
/**
@@ -2484,6 +2571,10 @@
return new ArrayList<>(mApnContexts.keySet());
}
+ public DcNetworkAgent getNetworkAgent() {
+ return mNetworkAgent;
+ }
+
/**
* @return the string for msg.what as our info.
*/
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java
index d18d552..f1790a3 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcController.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcController.java
@@ -17,6 +17,7 @@
package com.android.internal.telephony.dataconnection;
import android.content.Context;
+import android.hardware.radio.V1_4.DataConnActiveStatus;
import android.net.INetworkPolicyListener;
import android.net.LinkAddress;
import android.net.LinkProperties.CompareResult;
@@ -65,17 +66,6 @@
// @GuardedBy("mDcListAll")
private final HashMap<Integer, DataConnection> mDcListActiveByCid = new HashMap<>();
- /**
- * Constants for the data connection activity:
- * physical link down/up
- *
- * TODO: Move to RILConstants.java
- */
- static final int DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE = 0;
- static final int DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT = 1;
- static final int DATA_CONNECTION_ACTIVE_PH_LINK_UP = 2;
- static final int DATA_CONNECTION_ACTIVE_UNKNOWN = Integer.MAX_VALUE;
-
private DccDefaultState mDccDefaultState = new DccDefaultState();
final TelephonyManager mTelephonyManager;
@@ -325,7 +315,7 @@
log("onDataStateChanged: Found ConnId=" + newState.getCallId()
+ " newState=" + newState.toString());
}
- if (newState.getActive() == DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE) {
+ if (newState.getActive() == DataConnActiveStatus.INACTIVE) {
if (mDct.isCleanupRequired.get()) {
apnsToCleanup.addAll(apnContexts);
mDct.isCleanupRequired.set(false);
@@ -413,10 +403,10 @@
}
}
- if (newState.getActive() == DATA_CONNECTION_ACTIVE_PH_LINK_UP) {
+ if (newState.getActive() == DataConnActiveStatus.ACTIVE) {
isAnyDataCallActive = true;
}
- if (newState.getActive() == DATA_CONNECTION_ACTIVE_PH_LINK_DORMANT) {
+ if (newState.getActive() == DataConnActiveStatus.DORMANT) {
isAnyDataCallDormant = true;
}
}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 6929ed4..daf2d7e 100755
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -16,12 +16,14 @@
package com.android.internal.telephony.dataconnection;
-import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
import static com.android.internal.telephony.RILConstants.DATA_PROFILE_DEFAULT;
import static com.android.internal.telephony.RILConstants.DATA_PROFILE_INVALID;
+import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.ProgressDialog;
@@ -38,6 +40,7 @@
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
+import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
import android.net.NetworkRequest;
@@ -102,6 +105,8 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
@@ -122,6 +127,59 @@
private static final boolean VDBG_STALL = false; // STOPSHIP if true
private static final boolean RADIO_TESTS = false;
+ @IntDef(value = {
+ REQUEST_TYPE_NORMAL,
+ REQUEST_TYPE_HANDOVER,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RequestNetworkType {}
+
+ /**
+ * Normal request for {@link #requestNetwork(NetworkRequest, int, LocalLog)}. For request
+ * network, this adds the request to the {@link ApnContext}. If there were no network request
+ * attached to the {@link ApnContext} earlier, this request setups a data connection.
+ */
+ public static final int REQUEST_TYPE_NORMAL = 1;
+
+ /**
+ * Handover request for {@link #requestNetwork(NetworkRequest, int, LocalLog)} or
+ * {@link #releaseNetwork(NetworkRequest, int, LocalLog)}. For request network, this
+ * initiates the handover data setup process. The existing data connection will be seamlessly
+ * handover to the new network. For release network, this performs a data connection softly
+ * clean up at the underlying layer (versus normal data release).
+ */
+ public static final int REQUEST_TYPE_HANDOVER = 2;
+
+ @IntDef(value = {
+ RELEASE_TYPE_NORMAL,
+ RELEASE_TYPE_DETACH,
+ RELEASE_TYPE_HANDOVER,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ReleaseNetworkType {}
+
+ /**
+ * For release network, this is just removing the network request from the {@link ApnContext}.
+ * Note this does not tear down the physical data connection. Normally the data connection is
+ * torn down by connectivity service directly calling {@link NetworkAgent#unwanted()}.
+ */
+ public static final int RELEASE_TYPE_NORMAL = 1;
+
+ /**
+ * Detach request for {@link #releaseNetwork(NetworkRequest, int, LocalLog)} only. This
+ * forces the APN context detach from the data connection. If this {@link ApnContext} is the
+ * last one attached to the data connection, the data connection will be torn down, otherwise
+ * the data connection remains active.
+ */
+ public static final int RELEASE_TYPE_DETACH = 2;
+
+ /**
+ * Handover request for {@link #releaseNetwork(NetworkRequest, int, LocalLog)}. For release
+ * network, this performs a data connection softly clean up at the underlying layer (versus
+ * normal data release).
+ */
+ public static final int RELEASE_TYPE_HANDOVER = 3;
+
private final String mLogTag;
public AtomicBoolean isCleanupRequired = new AtomicBoolean(false);
@@ -136,7 +194,6 @@
// All data enabling/disabling related settings
private final DataEnabledSettings mDataEnabledSettings;
-
/**
* After detecting a potential connection problem, this is the max number
* of subsequent polls before attempting recovery.
@@ -207,6 +264,9 @@
/* The Url passed as object parameter in CMD_ENABLE_MOBILE_PROVISIONING */
private String mProvisioningUrl = null;
+ /* Indicating data service is bound or not */
+ private boolean mDataServiceBound = false;
+
/* Intent for the provisioning apn alarm */
private static final String INTENT_PROVISIONING_APN_ALARM =
"com.android.internal.telephony.provisioning_apn_alarm";
@@ -421,15 +481,7 @@
if (DBG) {
log("onDataReconnect: state is FAILED|IDLE, disassociate");
}
- DataConnection dataConnection = apnContext.getDataConnection();
- if (dataConnection != null) {
- if (DBG) {
- log("onDataReconnect: tearDown apnContext=" + apnContext);
- }
- dataConnection.tearDown(apnContext, "", null);
- }
- apnContext.setDataConnection(null);
- apnContext.setState(DctConstants.State.IDLE);
+ apnContext.releaseDataConnection("");
} else {
if (DBG) log("onDataReconnect: keep associated");
}
@@ -487,7 +539,7 @@
// Reference counter for enabling fail fast
private static int sEnableFailFastRefCounter = 0;
// True if data stall detection is enabled
- private volatile boolean mDataStallDetectionEnabled = true;
+ private volatile boolean mDataStallNoRxEnabled = true;
private volatile boolean mFailFast = false;
@@ -573,6 +625,8 @@
private final int mTransportType;
+ private DataStallRecoveryHandler mDsRecoveryHandler;
+
//***** Constructor
public DcTracker(Phone phone, int transportType) {
super();
@@ -597,6 +651,8 @@
mAlarmManager =
(AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
+ mDsRecoveryHandler = new DataStallRecoveryHandler();
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
@@ -795,21 +851,25 @@
mPhone.notifyDataActivity();
}
- public void requestNetwork(NetworkRequest networkRequest, LocalLog log) {
+ public void requestNetwork(NetworkRequest networkRequest, @RequestNetworkType int type,
+ LocalLog log) {
final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest);
final ApnContext apnContext = mApnContextsByType.get(apnType);
- log.log("DcTracker.requestNetwork for " + networkRequest + " found " + apnContext);
- if (apnContext != null) apnContext.requestNetwork(networkRequest, log);
+ log.log("DcTracker.requestNetwork for " + networkRequest + " found " + apnContext
+ + ", type=" + requestTypeToString(type));
+ if (apnContext != null) {
+ apnContext.requestNetwork(networkRequest, type, log);
+ }
}
- public void releaseNetwork(NetworkRequest networkRequest, LocalLog log,
- boolean cleanUpConnection) {
+ public void releaseNetwork(NetworkRequest networkRequest, @ReleaseNetworkType int type,
+ LocalLog log) {
final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest);
final ApnContext apnContext = mApnContextsByType.get(apnType);
- log.log("DcTracker.releaseNetwork for " + networkRequest + " found " + apnContext);
+ log.log("DcTracker.releaseNetwork for " + networkRequest + " found " + apnContext
+ + ", type=" + releaseTypeToString(type));
if (apnContext != null) {
- apnContext.releaseNetwork(networkRequest, log);
- if (cleanUpConnection) cleanUpConnectionInternal(true, apnContext);
+ apnContext.releaseNetwork(networkRequest, type, log);
}
}
@@ -1319,7 +1379,7 @@
if (apnContext.isConnectable()) {
log("isConnectable() call trySetupData");
apnContext.setReason(reason);
- trySetupData(apnContext);
+ trySetupData(apnContext, false);
}
}
}
@@ -1330,7 +1390,7 @@
return result;
}
- private boolean trySetupData(ApnContext apnContext) {
+ private boolean trySetupData(ApnContext apnContext, boolean isHandover) {
if (mPhone.getSimulatedRadioControl() != null) {
// Assume data is connected on the simulator
@@ -1345,7 +1405,8 @@
DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
boolean isDataAllowed = isDataAllowed(apnContext, dataConnectionReasons);
String logStr = "trySetupData for APN type " + apnContext.getApnType() + ", reason: "
- + apnContext.getReason() + ". " + dataConnectionReasons.toString();
+ + apnContext.getReason() + ", isHandover=" + isHandover + ". "
+ + dataConnectionReasons.toString();
if (DBG) log(logStr);
apnContext.requestLog(logStr);
if (isDataAllowed) {
@@ -1377,7 +1438,7 @@
}
}
- boolean retValue = setupData(apnContext, radioTech);
+ boolean retValue = setupData(apnContext, radioTech, isHandover);
notifyOffApnsOfAvailability();
if (DBG) log("trySetupData: X retValue=" + retValue);
@@ -1394,7 +1455,7 @@
str.append("trySetupData failed. apnContext = [type=" + apnContext.getApnType()
+ ", mState=" + apnContext.getState() + ", apnEnabled="
+ apnContext.isEnabled() + ", mDependencyMet="
- + apnContext.getDependencyMet() + "] ");
+ + apnContext.isDependencyMet() + "] ");
if (!mDataEnabledSettings.isDataEnabled()) {
str.append("isDataEnabled() = false. " + mDataEnabledSettings);
@@ -1448,16 +1509,16 @@
* eventually tearing down all data connections after all APN contexts are detached from the
* data connections.
*
- * @param tearDown True if the underlying data connection should be disconnected when no
- * APN context attached to the data connection. False if we only want to reset the data
- * connection's state machine without requesting modem to tearing down the data connections.
+ * @param detach {@code true} if detaching APN context from the underlying data connection (when
+ * no other APN context is attached to the data connection, the data connection will be torn
+ * down.) {@code false} to only reset the data connection's state machine.
*
* @param reason reason for the clean up.
* @return boolean - true if we did cleanup any connections, false if they
* were already all disconnected.
*/
- private boolean cleanUpAllConnectionsInternal(boolean tearDown, String reason) {
- if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
+ private boolean cleanUpAllConnectionsInternal(boolean detach, String reason) {
+ if (DBG) log("cleanUpAllConnections: detach=" + detach + " reason=" + reason);
boolean didDisconnect = false;
boolean disableMeteredOnly = false;
@@ -1478,10 +1539,10 @@
if (apnContext.isDisconnected() == false) didDisconnect = true;
if (DBG) log("clean up metered ApnContext Type: " + apnContext.getApnType());
apnContext.setReason(reason);
- cleanUpConnectionInternal(tearDown, apnContext);
+ cleanUpConnectionInternal(detach, false, apnContext);
}
} else {
- // Exclude the IMS APN from single DataConenction case.
+ // Exclude the IMS APN from single data connection case.
if (reason.equals(Phone.REASON_SINGLE_PDN_ARBITRATION)
&& apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IMS)) {
continue;
@@ -1489,7 +1550,7 @@
// TODO - only do cleanup if not disconnected
if (apnContext.isDisconnected() == false) didDisconnect = true;
apnContext.setReason(reason);
- cleanUpConnectionInternal(tearDown, apnContext);
+ cleanUpConnectionInternal(detach, false, apnContext);
}
}
@@ -1500,7 +1561,7 @@
mRequestedApnType = ApnSetting.TYPE_DEFAULT;
log("cleanUpConnectionInternal: mDisconnectPendingCount = " + mDisconnectPendingCount);
- if (tearDown && mDisconnectPendingCount == 0) {
+ if (detach && mDisconnectPendingCount == 0) {
notifyAllDataDisconnected();
}
@@ -1522,38 +1583,33 @@
}
/**
- * Detach the APN context from the associated data connection. This data connection might be
+ * Detach the APN context from the associated data connection. This data connection will be
* torn down if no other APN context is attached to it.
*
- * @param tearDown True if tearing down data connection when no other APN context attached.
- * False to only reset the data connection's state machine.
- * @param apnContext The APN context to be detached
+ * @param detach {@code true} if detaching APN context from the underlying data connection (when
+ * no other APN context is attached to the data connection, the data connection will be torn
+ * down.) {@code false} to only reset the data connection's state machine.
+ * @param isHandover {@code true} if this is a handover request. When this is set to
+ * {@code true}, {@code detach} also needs to be set to {@code true}.
+ * @param apnContext The APN context to be detached.
*/
- private void cleanUpConnectionInternal(boolean tearDown, ApnContext apnContext) {
+ private void cleanUpConnectionInternal(boolean detach, boolean isHandover,
+ ApnContext apnContext) {
if (apnContext == null) {
if (DBG) log("cleanUpConnectionInternal: apn context is null");
return;
}
DataConnection dataConnection = apnContext.getDataConnection();
- String str = "cleanUpConnectionInternal: tearDown=" + tearDown + " reason="
+ String str = "cleanUpConnectionInternal: detach=" + detach + " reason="
+ apnContext.getReason();
if (VDBG) log(str + " apnContext=" + apnContext);
apnContext.requestLog(str);
- if (tearDown) {
+ if (detach) {
if (apnContext.isDisconnected()) {
- // The request is tearDown and but ApnContext is not connected.
+ // The request is detach and but ApnContext is not connected.
// If apnContext is not enabled anymore, break the linkage to the data connection.
- apnContext.setState(DctConstants.State.IDLE);
- if (!apnContext.isReady()) {
- if (dataConnection != null) {
- str = "cleanUpConnectionInternal: teardown, disconnected, !ready";
- if (DBG) log(str + " apnContext=" + apnContext);
- apnContext.requestLog(str);
- dataConnection.tearDown(apnContext, "", null);
- }
- apnContext.setDataConnection(null);
- }
+ apnContext.releaseDataConnection("");
} else {
// Connection is still there. Try to clean up.
if (dataConnection != null) {
@@ -1581,8 +1637,8 @@
Pair<ApnContext, Integer> pair = new Pair<>(apnContext, generation);
Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair);
- if (disconnectAll) {
- dataConnection.tearDownAll(apnContext.getReason(), msg);
+ if (disconnectAll || isHandover) {
+ dataConnection.tearDownAll(apnContext.getReason(), isHandover, msg);
} else {
dataConnection.tearDown(apnContext, apnContext.getReason(), msg);
}
@@ -1611,7 +1667,7 @@
if (dataConnection != null) {
cancelReconnectAlarm(apnContext);
}
- str = "cleanUpConnectionInternal: X tearDown=" + tearDown + " reason="
+ str = "cleanUpConnectionInternal: X detach=" + detach + " reason="
+ apnContext.getReason();
if (DBG) log(str + " apnContext=" + apnContext + " dc=" + apnContext.getDataConnection());
apnContext.requestLog(str);
@@ -1701,6 +1757,19 @@
}
/**
+ * @return the {@link DataConnection} with the given APN context. Null if no data connection
+ * is found.
+ */
+ public @Nullable DataConnection getDataConnectionByApnType(String apnType) {
+ // TODO: Clean up all APN type in string usage
+ ApnContext apnContext = mApnContexts.get(apnType);
+ if (apnContext != null) {
+ return apnContext.getDataConnection();
+ }
+ return null;
+ }
+
+ /**
* Determine if DUN connection is special and we need to teardown on start/stop
*/
private boolean teardownForDun() {
@@ -1761,11 +1830,12 @@
*
* @param apnContext APN context
* @param radioTech RAT of the data connection
+ * @param isHandover {@code true} if this is for data handover
* @return True if successful, otherwise false.
*/
- private boolean setupData(ApnContext apnContext, int radioTech) {
- if (DBG) log("setupData: apnContext=" + apnContext);
- apnContext.requestLog("setupData");
+ private boolean setupData(ApnContext apnContext, int radioTech, boolean isHandover) {
+ if (DBG) log("setupData: apnContext=" + apnContext + ", isHandover=" + isHandover);
+ apnContext.requestLog("setupData. handover=" + isHandover);
ApnSetting apnSetting;
DataConnection dataConnection = null;
@@ -1853,7 +1923,7 @@
Message msg = obtainMessage();
msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
msg.obj = new Pair<ApnContext, Integer>(apnContext, generation);
- dataConnection.bringUp(apnContext, profileId, radioTech, msg, generation);
+ dataConnection.bringUp(apnContext, profileId, radioTech, msg, generation, isHandover);
if (DBG) log("setupData: initing!");
return true;
@@ -2024,7 +2094,11 @@
*/
int reset = Integer.parseInt(SystemProperties.get("net.ppp.reset-by-timeout", "0"));
- SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset + 1));
+ try {
+ SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset + 1));
+ } catch (RuntimeException ex) {
+ log("Failed to set net.ppp.reset-by-timeout");
+ }
}
/**
@@ -2116,83 +2190,6 @@
setDataProfilesAsNeeded();
}
- private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) {
- boolean cleanup = false;
- boolean trySetup = false;
- String str ="applyNewState(" + apnContext.getApnType() + ", " + enabled +
- "(" + apnContext.isEnabled() + "), " + met + "(" +
- apnContext.getDependencyMet() +"))";
- if (DBG) log(str);
- apnContext.requestLog(str);
-
- if (apnContext.isReady()) {
- cleanup = true;
- if (enabled && met) {
- DctConstants.State state = apnContext.getState();
- switch(state) {
- case CONNECTING:
- case CONNECTED:
- case DISCONNECTING:
- // We're "READY" and active so just return
- if (DBG) log("applyNewState: 'ready' so return");
- apnContext.requestLog("applyNewState state=" + state + ", so return");
- return;
- case IDLE:
- // fall through: this is unexpected but if it happens cleanup and try setup
- case FAILED:
- case RETRYING:
- // We're "READY" but not active so disconnect (cleanup = true) and
- // connect (trySetup = true) to be sure we retry the connection.
- trySetup = true;
- apnContext.setReason(Phone.REASON_DATA_ENABLED);
- break;
- }
- } else if (met) {
- apnContext.setReason(Phone.REASON_DATA_DISABLED_INTERNAL);
- // If ConnectivityService has disabled this network, stop trying to bring
- // it up, but do not tear it down - ConnectivityService will do that
- // directly by talking with the DataConnection.
- //
- // This doesn't apply to DUN, however. Those connections have special
- // requirements from carriers and we need stop using them when the dun
- // request goes away. This applies to both CDMA and GSM because they both
- // can declare the DUN APN sharable by default traffic, thus still satisfying
- // those requests and not torn down organically.
- if ((apnContext.getApnType() == PhoneConstants.APN_TYPE_DUN && teardownForDun())
- || apnContext.getState() != DctConstants.State.CONNECTED) {
- str = "Clean up the connection. Apn type = " + apnContext.getApnType()
- + ", state = " + apnContext.getState();
- if (DBG) log(str);
- apnContext.requestLog(str);
- cleanup = true;
- } else {
- cleanup = false;
- }
- } else {
- apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET);
- }
- } else {
- if (enabled && met) {
- if (apnContext.isEnabled()) {
- apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET);
- } else {
- apnContext.setReason(Phone.REASON_DATA_ENABLED);
- }
- if (apnContext.getState() == DctConstants.State.FAILED) {
- apnContext.setState(DctConstants.State.IDLE);
- }
- trySetup = true;
- }
- }
- apnContext.setEnabled(enabled);
- apnContext.setDependencyMet(met);
- if (cleanup) cleanUpConnectionInternal(true, apnContext);
- if (trySetup) {
- apnContext.resetErrorCodeRetries();
- trySetupData(apnContext);
- }
- }
-
private DataConnection checkForCompatibleConnectedApnContext(ApnContext apnContext) {
int apnType = apnContext.getApnTypeBitmask();
ArrayList<ApnSetting> dunSettings = null;
@@ -2268,28 +2265,124 @@
return null;
}
- public void setEnabled(int apnType, boolean enable) {
- Message msg = obtainMessage(DctConstants.EVENT_ENABLE_NEW_APN);
- msg.arg1 = apnType;
- msg.arg2 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
- sendMessage(msg);
+ public void enableApn(@ApnSetting.ApnType int apnType, @RequestNetworkType int requestType) {
+ sendMessage(obtainMessage(DctConstants.EVENT_ENABLE_APN, apnType, requestType));
}
- private void onEnableApn(int apnType, int enabled) {
+ private void onEnableApn(@ApnSetting.ApnType int apnType, @RequestNetworkType int requestType) {
ApnContext apnContext = mApnContextsByType.get(apnType);
if (apnContext == null) {
- loge("onEnableApn(" + apnType + ", " + enabled + "): NO ApnContext");
+ loge("onEnableApn(" + apnType + "): NO ApnContext");
return;
}
- // TODO change our retry manager to use the appropriate numbers for the new APN
- if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState");
- applyNewState(apnContext, enabled == DctConstants.ENABLED, apnContext.getDependencyMet());
- if ((enabled == DctConstants.DISABLED) &&
- isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology()) &&
- !isHigherPriorityApnContextActive(apnContext)) {
+ boolean trySetup = false;
+ String str = "onEnableApn: apnType=" + ApnSetting.getApnTypeString(apnType)
+ + ", request type=" + requestType;
+ if (DBG) log(str);
+ apnContext.requestLog(str);
- if(DBG) log("onEnableApn: isOnlySingleDcAllowed true & higher priority APN disabled");
+ if (!apnContext.isDependencyMet()) {
+ apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET);
+ apnContext.setEnabled(true);
+ str = "onEnableApn: dependency is not met.";
+ if (DBG) log(str);
+ apnContext.requestLog(str);
+ return;
+ }
+
+ if (apnContext.isReady()) {
+ DctConstants.State state = apnContext.getState();
+ switch(state) {
+ case CONNECTING:
+ case CONNECTED:
+ case DISCONNECTING:
+ // We're "READY" and active so just return
+ if (DBG) log("onEnableApn: 'ready' so return");
+ apnContext.requestLog("onEnableApn state=" + state + ", so return");
+ return;
+ case IDLE:
+ // fall through: this is unexpected but if it happens cleanup and try setup
+ case FAILED:
+ case RETRYING:
+ // We're "READY" but not active so disconnect (cleanup = true) and
+ // connect (trySetup = true) to be sure we retry the connection.
+ trySetup = true;
+ apnContext.setReason(Phone.REASON_DATA_ENABLED);
+ break;
+ }
+ } else {
+ if (apnContext.isEnabled()) {
+ apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET);
+ } else {
+ apnContext.setReason(Phone.REASON_DATA_ENABLED);
+ }
+ if (apnContext.getState() == DctConstants.State.FAILED) {
+ apnContext.setState(DctConstants.State.IDLE);
+ }
+ trySetup = true;
+ }
+ apnContext.setEnabled(true);
+ if (trySetup) {
+ apnContext.resetErrorCodeRetries();
+ trySetupData(apnContext, requestType == REQUEST_TYPE_HANDOVER);
+ }
+ }
+
+ public void disableApn(@ApnSetting.ApnType int apnType, @ReleaseNetworkType int releaseType) {
+ sendMessage(obtainMessage(DctConstants.EVENT_DISABLE_APN, apnType, releaseType));
+ }
+
+ private void onDisableApn(@ApnSetting.ApnType int apnType,
+ @ReleaseNetworkType int releaseType) {
+ ApnContext apnContext = mApnContextsByType.get(apnType);
+ if (apnContext == null) {
+ loge("disableApn(" + apnType + "): NO ApnContext");
+ return;
+ }
+
+ boolean cleanup = false;
+ String str = "onDisableApn: apnType=" + ApnSetting.getApnTypeString(apnType)
+ + ", release type=" + releaseType;
+ if (DBG) log(str);
+ apnContext.requestLog(str);
+
+ if (apnContext.isReady()) {
+ cleanup = (releaseType == RELEASE_TYPE_DETACH
+ || releaseType == RELEASE_TYPE_HANDOVER);
+ if (apnContext.isDependencyMet()) {
+ apnContext.setReason(Phone.REASON_DATA_DISABLED_INTERNAL);
+ // If ConnectivityService has disabled this network, stop trying to bring
+ // it up, but do not tear it down - ConnectivityService will do that
+ // directly by talking with the DataConnection.
+ //
+ // This doesn't apply to DUN, however. Those connections have special
+ // requirements from carriers and we need stop using them when the dun
+ // request goes away. This applies to both CDMA and GSM because they both
+ // can declare the DUN APN sharable by default traffic, thus still satisfying
+ // those requests and not torn down organically.
+ if ((PhoneConstants.APN_TYPE_DUN.equals(apnContext.getApnType())
+ && teardownForDun())
+ || apnContext.getState() != DctConstants.State.CONNECTED) {
+ str = "Clean up the connection. Apn type = " + apnContext.getApnType()
+ + ", state = " + apnContext.getState();
+ if (DBG) log(str);
+ apnContext.requestLog(str);
+ cleanup = true;
+ }
+ } else {
+ apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET);
+ }
+ }
+
+ apnContext.setEnabled(false);
+ if (cleanup) {
+ cleanUpConnectionInternal(true, releaseType == RELEASE_TYPE_HANDOVER, apnContext);
+ }
+
+ if (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology())
+ && !isHigherPriorityApnContextActive(apnContext)) {
+ if (DBG) log("disableApn:isOnlySingleDcAllowed true & higher priority APN disabled");
// If the highest priority APN is disabled and only single
// data call is allowed, try to setup data call on other connectable APN.
setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION, RetryFailures.ALWAYS);
@@ -2511,7 +2604,7 @@
}
if (getOverallState() != DctConstants.State.IDLE) {
- cleanUpConnectionInternal(true, null);
+ cleanUpConnectionInternal(true, false, null);
}
}
@@ -2571,7 +2664,8 @@
* A SETUP (aka bringUp) has completed, possibly with an error. If
* there is an error this method will call {@link #onDataSetupCompleteError}.
*/
- private void onDataSetupComplete(ApnContext apnContext, boolean success, int cause) {
+ private void onDataSetupComplete(ApnContext apnContext, boolean success, int cause,
+ boolean isHandover) {
if (success) {
DataConnection dataConnection = apnContext.getDataConnection();
@@ -2595,7 +2689,7 @@
}
if (dataConnection == null) {
log("onDataSetupComplete: no connection to DC, handle as error");
- onDataSetupCompleteError(apnContext);
+ onDataSetupCompleteError(apnContext, isHandover);
} else {
ApnSetting apn = apnContext.getApnSetting();
if (DBG) {
@@ -2708,8 +2802,8 @@
} else {
if (DBG) {
ApnSetting apn = apnContext.getApnSetting();
- log(String.format("onDataSetupComplete: error apn=%s cause=%s",
- (apn == null ? "unknown" : apn.getApnName()), cause));
+ log("onDataSetupComplete: error apn=" + apn.getApnName() + ", cause=" + cause
+ + ", isHandover=" + isHandover);
}
if (DataFailCause.isEventLoggable(cause)) {
// Log this failure to the Event Logs.
@@ -2741,7 +2835,7 @@
log("cause = " + cause + ", mark apn as permanent failed. apn = " + apn);
apnContext.markApnPermanentFailed(apn);
}
- onDataSetupCompleteError(apnContext);
+ onDataSetupCompleteError(apnContext, isHandover);
}
}
@@ -2751,15 +2845,17 @@
* beginning if the list is empty. Between each SETUP request there will
* be a delay defined by {@link #getApnDelay()}.
*/
- private void onDataSetupCompleteError(ApnContext apnContext) {
+ private void onDataSetupCompleteError(ApnContext apnContext, boolean isHandover) {
long delay = apnContext.getDelayForNextApn(mFailFast);
// Check if we need to retry or not.
- if (delay >= 0) {
+ // TODO: We should support handover retry in the future.
+ if (delay >= 0 && !isHandover) {
if (DBG) log("onDataSetupCompleteError: Try next APN. delay = " + delay);
apnContext.setState(DctConstants.State.RETRYING);
// Wait a bit before trying the next APN, so that
// we're not tying up the RIL command channel
+
startAlarmForReconnect(delay, apnContext);
} else {
// If we are not going to retry any APN, set this APN context to failed state.
@@ -2767,19 +2863,36 @@
apnContext.setState(DctConstants.State.FAILED);
mPhone.notifyDataConnection(apnContext.getApnType());
apnContext.setDataConnection(null);
- log("onDataSetupCompleteError: Stop retrying APNs.");
+ log("onDataSetupCompleteError: Stop retrying APNs. delay=" + delay
+ + ", isHandover=" + isHandover);
}
}
/**
- * Called when EVENT_REDIRECTION_DETECTED is received.
+ * Called when EVENT_NETWORK_STATUS_CHANGED is received.
+ *
+ * @param status One of {@code NetworkAgent.VALID_NETWORK} or
+ * {@code NetworkAgent.INVALID_NETWORK}.
+ * @param redirectUrl If the Internet probe was redirected, this
+ * is the destination it was redirected to, otherwise {@code null}
*/
- private void onDataConnectionRedirected(String redirectUrl) {
+ private void onNetworkStatusChanged(int status, String redirectUrl) {
if (!TextUtils.isEmpty(redirectUrl)) {
Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED);
intent.putExtra(TelephonyIntents.EXTRA_REDIRECTION_URL_KEY, redirectUrl);
mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
log("Notify carrier signal receivers with redirectUrl: " + redirectUrl);
+ } else {
+ final boolean isValid = status == NetworkAgent.VALID_NETWORK;
+ if (!mDsRecoveryHandler.isRecoveryOnBadNetworkEnabled()) {
+ if (DBG) log("Skip data stall recovery on network status change with in threshold");
+ return;
+ }
+ if (mTransportType != TransportType.WWAN) {
+ if (DBG) log("Skip data stall recovery on non WWAN");
+ return;
+ }
+ mDsRecoveryHandler.processNetworkStatusChanged(isValid);
}
}
@@ -3282,6 +3395,7 @@
Pair<ApnContext, Integer> pair;
ApnContext apnContext;
int generation;
+ boolean isHandover;
switch (msg.what) {
case DctConstants.EVENT_RECORDS_LOADED:
// If onRecordsLoadedOrSubIdChanged() is not called here, it should be called on
@@ -3303,7 +3417,7 @@
break;
case DctConstants.EVENT_DO_RECOVERY:
- doRecovery();
+ mDsRecoveryHandler.doRecovery();
break;
case DctConstants.EVENT_APN_CHANGED:
@@ -3342,7 +3456,7 @@
apnContext = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT);
if (apnContext != null) {
apnContext.setReason(Phone.REASON_PS_RESTRICT_ENABLED);
- trySetupData(apnContext);
+ trySetupData(apnContext, false);
} else {
loge("**** Default ApnContext not found ****");
if (Build.IS_DEBUGGABLE) {
@@ -3353,16 +3467,12 @@
break;
case DctConstants.EVENT_TRY_SETUP_DATA:
- if (msg.obj instanceof ApnContext) {
- trySetupData((ApnContext) msg.obj);
- } else {
- loge("EVENT_TRY_SETUP request w/o apnContext or String");
- }
+ trySetupData((ApnContext) msg.obj, false);
break;
case DctConstants.EVENT_CLEAN_UP_CONNECTION:
if (DBG) log("EVENT_CLEAN_UP_CONNECTION");
- cleanUpConnectionInternal(true, (ApnContext) msg.obj);
+ cleanUpConnectionInternal(true, false, (ApnContext) msg.obj);
break;
case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS:
if ((msg.obj != null) && (msg.obj instanceof String == false)) {
@@ -3393,10 +3503,15 @@
mProvisioningSpinner = null;
}
break;
- case DctConstants.EVENT_ENABLE_NEW_APN:
+
+ case DctConstants.EVENT_ENABLE_APN:
onEnableApn(msg.arg1, msg.arg2);
break;
+ case DctConstants.EVENT_DISABLE_APN:
+ onDisableApn(msg.arg1, msg.arg2);
+ break;
+
case DctConstants.EVENT_DATA_STALL_ALARM:
onDataStallAlarm(msg.arg1);
break;
@@ -3409,10 +3524,22 @@
case DctConstants.EVENT_ROAMING_SETTING_CHANGE:
onDataRoamingOnOrSettingsChanged(msg.what);
break;
- case DctConstants.EVENT_REDIRECTION_DETECTED:
+
+ case DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE:
+ // Update sharedPreference to false when exits new device provisioning, indicating
+ // no users modifications on the settings for new devices. Thus carrier specific
+ // default roaming settings can be applied for new devices till user modification.
+ final SharedPreferences sp = PreferenceManager
+ .getDefaultSharedPreferences(mPhone.getContext());
+ if (!sp.contains(Phone.DATA_ROAMING_IS_USER_SETTING_KEY)) {
+ sp.edit().putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, false).commit();
+ }
+ break;
+
+ case DctConstants.EVENT_NETWORK_STATUS_CHANGED:
+ int status = msg.arg1;
String url = (String) msg.obj;
- log("dataConnectionTracker.handleMessage: EVENT_REDIRECTION_DETECTED=" + url);
- onDataConnectionRedirected(url);
+ onNetworkStatusChanged(status, url);
break;
case DctConstants.EVENT_RADIO_AVAILABLE:
@@ -3428,6 +3555,7 @@
pair = (Pair<ApnContext, Integer>) ar.userObj;
apnContext = pair.first;
generation = pair.second;
+ isHandover = msg.arg2 != 0;
if (apnContext.getConnectionGeneration() == generation) {
boolean success = true;
int cause = DataFailCause.UNKNOWN;
@@ -3435,7 +3563,7 @@
success = false;
cause = (int) ar.result;
}
- onDataSetupComplete(apnContext, success, cause);
+ onDataSetupComplete(apnContext, success, cause, isHandover);
} else {
loge("EVENT_DATA_SETUP_COMPLETE: Dropped the event because generation "
+ "did not match.");
@@ -3447,8 +3575,9 @@
pair = (Pair<ApnContext, Integer>) ar.userObj;
apnContext = pair.first;
generation = pair.second;
+ isHandover = msg.arg1 != 0;
if (apnContext.getConnectionGeneration() == generation) {
- onDataSetupCompleteError(apnContext);
+ onDataSetupCompleteError(apnContext, isHandover);
} else {
loge("EVENT_DATA_SETUP_COMPLETE_ERROR: Dropped the event because generation "
+ "did not match.");
@@ -3496,8 +3625,8 @@
if (mFailFast != enabled) {
mFailFast = enabled;
- mDataStallDetectionEnabled = !enabled;
- if (mDataStallDetectionEnabled
+ mDataStallNoRxEnabled = !enabled;
+ if (mDsRecoveryHandler.isNoRxDataStallDetectionEnabled()
&& (getOverallState() == DctConstants.State.CONNECTED)
&& (!mInVoiceCall ||
mPhone.getServiceStateTracker()
@@ -3543,7 +3672,7 @@
mIsProvisioning = false;
mProvisioningUrl = null;
stopProvisioningApnAlarm();
- cleanUpConnectionInternal(true, apnCtx);
+ cleanUpConnectionInternal(true, false, apnCtx);
} else {
if (DBG) {
log("EVENT_PROVISIONING_APN_ALARM: ignore stale tag,"
@@ -3774,7 +3903,7 @@
pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled);
pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum);
pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag);
- pw.println(" mDataStallDetectionEnabled=" + mDataStallDetectionEnabled);
+ pw.println(" mDataStallNoRxEnabled=" + mDataStallNoRxEnabled);
pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv);
pw.println(" mNoRecvPollCount=" + mNoRecvPollCount);
pw.println(" mResolver=" + mResolver);
@@ -3782,6 +3911,7 @@
pw.println(" mAutoAttachOnCreation=" + mAutoAttachOnCreation.get());
pw.println(" mIsScreenOn=" + mIsScreenOn);
pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator);
+ pw.println(" mDataServiceBound=" + mDataServiceBound);
pw.println(" mDataRoamingLeakageLog= ");
mDataRoamingLeakageLog.dump(fd, pw, args);
pw.println(" mApnSettingsInitializationLog= ");
@@ -3790,7 +3920,11 @@
pw.println(" ***************************************");
DcController dcc = mDcc;
if (dcc != null) {
- dcc.dump(fd, pw, args);
+ if (mDataServiceBound) {
+ dcc.dump(fd, pw, args);
+ } else {
+ pw.println(" Can't dump mDcc because data service is not bound.");
+ }
} else {
pw.println(" mDcc=null");
}
@@ -3954,10 +4088,10 @@
return true;
}
- private void cleanUpConnectionsOnUpdatedApns(boolean tearDown, String reason) {
- if (DBG) log("cleanUpConnectionsOnUpdatedApns: tearDown=" + tearDown);
+ private void cleanUpConnectionsOnUpdatedApns(boolean detach, String reason) {
+ if (DBG) log("cleanUpConnectionsOnUpdatedApns: detach=" + detach);
if (mAllApnSettings.isEmpty()) {
- cleanUpAllConnectionsInternal(tearDown, Phone.REASON_APN_CHANGED);
+ cleanUpAllConnectionsInternal(detach, Phone.REASON_APN_CHANGED);
} else {
int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
@@ -3983,7 +4117,7 @@
if (!apnContext.isDisconnected()) {
if (VDBG) log("cleanUpConnectionsOnUpdatedApns for " + apnContext);
apnContext.setReason(reason);
- cleanUpConnectionInternal(true, apnContext);
+ cleanUpConnectionInternal(true, false, apnContext);
}
}
}
@@ -3997,7 +4131,7 @@
mRequestedApnType = ApnSetting.TYPE_DEFAULT;
if (DBG) log("mDisconnectPendingCount = " + mDisconnectPendingCount);
- if (tearDown && mDisconnectPendingCount == 0) {
+ if (detach && mDisconnectPendingCount == 0) {
notifyAllDataDisconnected();
}
}
@@ -4165,80 +4299,172 @@
/**
* Data-Stall
*/
+
// Recovery action taken in case of data stall
- private static class RecoveryAction {
- public static final int GET_DATA_CALL_LIST = 0;
- public static final int CLEANUP = 1;
- public static final int REREGISTER = 2;
- public static final int RADIO_RESTART = 3;
+ @IntDef(
+ value = {
+ RECOVERY_ACTION_GET_DATA_CALL_LIST,
+ RECOVERY_ACTION_CLEANUP,
+ RECOVERY_ACTION_REREGISTER,
+ RECOVERY_ACTION_RADIO_RESTART
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ private @interface RecoveryAction {};
+ private static final int RECOVERY_ACTION_GET_DATA_CALL_LIST = 0;
+ private static final int RECOVERY_ACTION_CLEANUP = 1;
+ private static final int RECOVERY_ACTION_REREGISTER = 2;
+ private static final int RECOVERY_ACTION_RADIO_RESTART = 3;
- private static boolean isAggressiveRecovery(int value) {
- return ((value == RecoveryAction.CLEANUP) ||
- (value == RecoveryAction.REREGISTER) ||
- (value == RecoveryAction.RADIO_RESTART));
+ // Recovery handler class for cellular data stall
+ private class DataStallRecoveryHandler {
+ // Default minimum duration between each recovery steps
+ private static final int
+ DEFAULT_MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS = (3 * 60 * 1000); // 3 mins
+
+ // The elapsed real time of last recovery attempted
+ private long mTimeLastRecoveryStartMs;
+ // Whether current network good or not
+ private boolean mIsValidNetwork;
+
+ public DataStallRecoveryHandler() {
+ reset();
}
- }
- private int getRecoveryAction() {
- int action = Settings.System.getInt(mResolver,
- "radio.data.stall.recovery.action", RecoveryAction.GET_DATA_CALL_LIST);
- if (VDBG_STALL) log("getRecoveryAction: " + action);
- return action;
- }
+ public void reset() {
+ mTimeLastRecoveryStartMs = 0;
+ putRecoveryAction(RECOVERY_ACTION_GET_DATA_CALL_LIST);
+ }
- private void putRecoveryAction(int action) {
- Settings.System.putInt(mResolver, "radio.data.stall.recovery.action", action);
- if (VDBG_STALL) log("putRecoveryAction: " + action);
- }
+ public boolean isAggressiveRecovery() {
+ @RecoveryAction int action = getRecoveryAction();
- private void broadcastDataStallDetected(int recoveryAction) {
- Intent intent = new Intent(TelephonyManager.ACTION_DATA_STALL_DETECTED);
- SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
- intent.putExtra(TelephonyManager.EXTRA_RECOVERY_ACTION, recoveryAction);
- mPhone.getContext().sendBroadcast(intent, READ_PHONE_STATE);
- }
+ return ((action == RECOVERY_ACTION_CLEANUP)
+ || (action == RECOVERY_ACTION_REREGISTER)
+ || (action == RECOVERY_ACTION_RADIO_RESTART));
+ }
- private void doRecovery() {
- if (getOverallState() == DctConstants.State.CONNECTED) {
- // Go through a series of recovery steps, each action transitions to the next action
- final int recoveryAction = getRecoveryAction();
- TelephonyMetrics.getInstance().writeDataStallEvent(mPhone.getPhoneId(), recoveryAction);
- broadcastDataStallDetected(recoveryAction);
+ private long getMinDurationBetweenRecovery() {
+ return Settings.Global.getLong(mResolver,
+ Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS,
+ DEFAULT_MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS);
+ }
- switch (recoveryAction) {
- case RecoveryAction.GET_DATA_CALL_LIST:
- EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST,
- mSentSinceLastRecv);
- if (DBG) log("doRecovery() get data call list");
- mDataServiceManager.getDataCallList(obtainMessage());
- putRecoveryAction(RecoveryAction.CLEANUP);
- break;
- case RecoveryAction.CLEANUP:
- EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP,
- mSentSinceLastRecv);
- if (DBG) log("doRecovery() cleanup all connections");
- cleanUpAllConnectionsInternal(true, Phone.REASON_PDP_RESET);
- putRecoveryAction(RecoveryAction.REREGISTER);
- break;
- case RecoveryAction.REREGISTER:
- EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER,
- mSentSinceLastRecv);
- if (DBG) log("doRecovery() re-register");
- mPhone.getServiceStateTracker().reRegisterNetwork(null);
- putRecoveryAction(RecoveryAction.RADIO_RESTART);
- break;
- case RecoveryAction.RADIO_RESTART:
- EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART,
- mSentSinceLastRecv);
- if (DBG) log("restarting radio");
- restartRadio();
- putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
- break;
- default:
- throw new RuntimeException("doRecovery: Invalid recoveryAction="
- + recoveryAction);
+ private long getElapsedTimeSinceRecoveryMs() {
+ return (SystemClock.elapsedRealtime() - mTimeLastRecoveryStartMs);
+ }
+
+ @RecoveryAction
+ private int getRecoveryAction() {
+ @RecoveryAction int action = Settings.System.getInt(mResolver,
+ "radio.data.stall.recovery.action", RECOVERY_ACTION_GET_DATA_CALL_LIST);
+ if (VDBG_STALL) log("getRecoveryAction: " + action);
+ return action;
+ }
+
+ private void putRecoveryAction(@RecoveryAction int action) {
+ Settings.System.putInt(mResolver, "radio.data.stall.recovery.action", action);
+ if (VDBG_STALL) log("putRecoveryAction: " + action);
+ }
+
+ private void broadcastDataStallDetected(@RecoveryAction int recoveryAction) {
+ Intent intent = new Intent(TelephonyManager.ACTION_DATA_STALL_DETECTED);
+ SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
+ intent.putExtra(TelephonyManager.EXTRA_RECOVERY_ACTION, recoveryAction);
+ mPhone.getContext().sendBroadcast(intent, READ_PRIVILEGED_PHONE_STATE);
+ }
+
+ private boolean isRecoveryAlreadyStarted() {
+ return getRecoveryAction() != RECOVERY_ACTION_GET_DATA_CALL_LIST;
+ }
+
+ private boolean checkRecovery() {
+ // To avoid back to back recovery wait for a grace period
+ if (getElapsedTimeSinceRecoveryMs() < getMinDurationBetweenRecovery()) {
+ if (VDBG_STALL) log("skip back to back data stall recovery");
+ return false;
}
- mSentSinceLastRecv = 0;
+ // Data is not allowed in current environment
+ if (!isDataAllowed(null, null)) {
+ log("skipped data stall recovery due to data is not allowd");
+ return false;
+ }
+ return true;
+ }
+
+ private void triggerRecovery() {
+ sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY));
+ }
+
+ public void doRecovery() {
+ if (getOverallState() == DctConstants.State.CONNECTED) {
+ // Go through a series of recovery steps, each action transitions to the next action
+ @RecoveryAction final int recoveryAction = getRecoveryAction();
+ TelephonyMetrics.getInstance().writeDataStallEvent(
+ mPhone.getPhoneId(), recoveryAction);
+ broadcastDataStallDetected(recoveryAction);
+
+ switch (recoveryAction) {
+ case RECOVERY_ACTION_GET_DATA_CALL_LIST:
+ EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST,
+ mSentSinceLastRecv);
+ if (DBG) log("doRecovery() get data call list");
+ mDataServiceManager.getDataCallList(obtainMessage());
+ putRecoveryAction(RECOVERY_ACTION_CLEANUP);
+ break;
+ case RECOVERY_ACTION_CLEANUP:
+ EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP,
+ mSentSinceLastRecv);
+ if (DBG) log("doRecovery() cleanup all connections");
+ cleanUpAllConnections(Phone.REASON_PDP_RESET);
+ putRecoveryAction(RECOVERY_ACTION_REREGISTER);
+ break;
+ case RECOVERY_ACTION_REREGISTER:
+ EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER,
+ mSentSinceLastRecv);
+ if (DBG) log("doRecovery() re-register");
+ mPhone.getServiceStateTracker().reRegisterNetwork(null);
+ putRecoveryAction(RECOVERY_ACTION_RADIO_RESTART);
+ break;
+ case RECOVERY_ACTION_RADIO_RESTART:
+ EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART,
+ mSentSinceLastRecv);
+ if (DBG) log("restarting radio");
+ restartRadio();
+ reset();
+ break;
+ default:
+ throw new RuntimeException("doRecovery: Invalid recoveryAction="
+ + recoveryAction);
+ }
+ mSentSinceLastRecv = 0;
+ mTimeLastRecoveryStartMs = SystemClock.elapsedRealtime();
+ }
+ }
+
+ public void processNetworkStatusChanged(boolean isValid) {
+ if (isValid) {
+ mIsValidNetwork = true;
+ reset();
+ } else {
+ if (mIsValidNetwork || isRecoveryAlreadyStarted()) {
+ mIsValidNetwork = false;
+ // Check and trigger a recovery if network switched from good
+ // to bad or recovery is already started before.
+ if (checkRecovery()) {
+ if (DBG) log("trigger data stall recovery");
+ triggerRecovery();
+ }
+ }
+ }
+ }
+
+ public boolean isRecoveryOnBadNetworkEnabled() {
+ return Settings.Global.getInt(mResolver,
+ Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1) == 1;
+ }
+
+ public boolean isNoRxDataStallDetectionEnabled() {
+ return mDataStallNoRxEnabled && !isRecoveryOnBadNetworkEnabled();
}
}
@@ -4265,7 +4491,7 @@
if ( sent > 0 && received > 0 ) {
if (VDBG_STALL) log("updateDataStallInfo: IN/OUT");
mSentSinceLastRecv = 0;
- putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
+ mDsRecoveryHandler.reset();
} else if (sent > 0 && received == 0) {
if (isPhoneStateIdle()) {
mSentSinceLastRecv += sent;
@@ -4279,7 +4505,7 @@
} else if (sent == 0 && received > 0) {
if (VDBG_STALL) log("updateDataStallInfo: IN");
mSentSinceLastRecv = 0;
- putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
+ mDsRecoveryHandler.reset();
} else {
if (VDBG_STALL) log("updateDataStallInfo: NONE");
}
@@ -4314,7 +4540,8 @@
boolean suspectedStall = DATA_STALL_NOT_SUSPECTED;
if (mSentSinceLastRecv >= hangWatchdogTrigger) {
if (DBG) {
- log("onDataStallAlarm: tag=" + tag + " do recovery action=" + getRecoveryAction());
+ log("onDataStallAlarm: tag=" + tag + " do recovery action="
+ + mDsRecoveryHandler.getRecoveryAction());
}
suspectedStall = DATA_STALL_SUSPECTED;
sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY));
@@ -4328,13 +4555,13 @@
}
private void startDataStallAlarm(boolean suspectedStall) {
- int nextAction = getRecoveryAction();
int delayInMs;
- if (mDataStallDetectionEnabled && getOverallState() == DctConstants.State.CONNECTED) {
+ if (mDsRecoveryHandler.isNoRxDataStallDetectionEnabled()
+ && getOverallState() == DctConstants.State.CONNECTED) {
// If screen is on or data stall is currently suspected, set the alarm
// with an aggressive timeout.
- if (mIsScreenOn || suspectedStall || RecoveryAction.isAggressiveRecovery(nextAction)) {
+ if (mIsScreenOn || suspectedStall || mDsRecoveryHandler.isAggressiveRecovery()) {
delayInMs = Settings.Global.getInt(mResolver,
Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
@@ -4380,9 +4607,7 @@
if (isConnected() == false) return;
// To be called on screen status change.
// Do not cancel the alarm if it is set with aggressive timeout.
- int nextAction = getRecoveryAction();
-
- if (RecoveryAction.isAggressiveRecovery(nextAction)) {
+ if (mDsRecoveryHandler.isAggressiveRecovery()) {
if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm.");
return;
}
@@ -4475,5 +4700,23 @@
} else {
mDcc.dispose();
}
+ mDataServiceBound = bound;
+ }
+
+ public static String requestTypeToString(@RequestNetworkType int type) {
+ switch (type) {
+ case REQUEST_TYPE_NORMAL: return "NORMAL";
+ case REQUEST_TYPE_HANDOVER: return "HANDOVER";
+ }
+ return "UNKNOWN";
+ }
+
+ public static String releaseTypeToString(@ReleaseNetworkType int type) {
+ switch (type) {
+ case RELEASE_TYPE_NORMAL: return "NORMAL";
+ case RELEASE_TYPE_DETACH: return "DETACH";
+ case RELEASE_TYPE_HANDOVER: return "HANDOVER";
+ }
+ return "UNKNOWN";
}
}
diff --git a/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
index a606ad6..da584f5 100644
--- a/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
+++ b/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
@@ -25,7 +25,6 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.Rlog;
import android.util.LocalLog;
@@ -38,6 +37,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
+import java.util.Map;
public class TelephonyNetworkFactory extends NetworkFactory {
public final String LOG_TAG;
@@ -52,13 +52,15 @@
private final PhoneSwitcher mPhoneSwitcher;
private final SubscriptionController mSubscriptionController;
private final SubscriptionMonitor mSubscriptionMonitor;
- private final DcTracker mDcTracker;
private final LocalLog mLocalLog = new LocalLog(REQUEST_LOG_SIZE);
// Key: network request. Value: whether it's applied to DcTracker.
- private final HashMap<NetworkRequest, Boolean> mNetworkRequests = new HashMap();
+ private final Map<NetworkRequest, Boolean> mNetworkRequests = new HashMap<>();
private final Phone mPhone;
+
+ private final TransportManager mTransportManager;
+
private int mSubscriptionId;
private final static int TELEPHONY_NETWORK_SCORE = 50;
@@ -74,6 +76,7 @@
super(looper, phone.getContext(), "TelephonyNetworkFactory[" + phone.getPhoneId()
+ "]", null);
mPhone = phone;
+ mTransportManager = mPhone.getTransportManager();
mInternalHandler = new InternalHandler(looper);
mSubscriptionController = SubscriptionController.getInstance();
@@ -84,9 +87,6 @@
mPhoneSwitcher = PhoneSwitcher.getInstance();
mSubscriptionMonitor = subscriptionMonitor;
LOG_TAG = "TelephonyNetworkFactory[" + mPhone.getPhoneId() + "]";
- // TODO: Will need to dynamically route network requests to the corresponding DcTracker in
- // the future. For now we route everything to WWAN.
- mDcTracker = mPhone.getDcTracker(TransportType.WWAN);
mPhoneSwitcher.registerForActivePhoneSwitch(mInternalHandler, EVENT_ACTIVE_PHONE_SWITCH,
null);
@@ -151,6 +151,30 @@
}
}
+ private int getTransportTypeFromNetworkRequest(NetworkRequest networkRequest) {
+ int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest);
+ return mTransportManager.getCurrentTransport(apnType);
+ }
+
+ private void requestNetworkInternal(NetworkRequest networkRequest) {
+ int transportType = getTransportTypeFromNetworkRequest(networkRequest);
+ if (mPhone.getDcTracker(transportType) != null) {
+ // TODO: Handover logic will be added later. For now always normal request.
+ mPhone.getDcTracker(transportType).requestNetwork(networkRequest,
+ DcTracker.REQUEST_TYPE_NORMAL, mLocalLog);
+ }
+ }
+
+ private void releaseNetworkInternal(NetworkRequest networkRequest, boolean cleanUpOnRelease) {
+ int transportType = getTransportTypeFromNetworkRequest(networkRequest);
+ if (mPhone.getDcTracker(transportType) != null) {
+ // TODO: Handover logic will be added later. For now always normal or detach request.
+ mPhone.getDcTracker(transportType).releaseNetwork(networkRequest,
+ cleanUpOnRelease ? DcTracker.RELEASE_TYPE_DETACH
+ : DcTracker.RELEASE_TYPE_NORMAL, mLocalLog);
+ }
+ }
+
private void applyRequestsOnActivePhoneSwitch(NetworkRequest networkRequest,
boolean cleanUpOnRelease, int action) {
if (action == ACTION_NO_OP) return;
@@ -159,9 +183,9 @@
? "Requesting" : "Releasing") + " network request " + networkRequest;
mLocalLog.log(logStr);
if (action == ACTION_REQUEST) {
- mDcTracker.requestNetwork(networkRequest, mLocalLog);
+ requestNetworkInternal(networkRequest);
} else if (action == ACTION_RELEASE) {
- mDcTracker.releaseNetwork(networkRequest, mLocalLog, cleanUpOnRelease);
+ releaseNetworkInternal(networkRequest, cleanUpOnRelease);
}
}
@@ -221,7 +245,7 @@
mLocalLog.log(s);
if (shouldApply) {
- mDcTracker.requestNetwork(networkRequest, mLocalLog);
+ requestNetworkInternal(networkRequest);
}
}
@@ -242,9 +266,8 @@
log(s);
mLocalLog.log(s);
-
if (applied) {
- mDcTracker.releaseNetwork(networkRequest, mLocalLog, false);
+ releaseNetworkInternal(networkRequest, false);
}
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
index c54643b..9b7dd173 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
@@ -23,6 +23,7 @@
import android.os.Message;
import android.os.RegistrantList;
import android.os.SystemProperties;
+import android.telephony.CallQuality;
import android.telephony.NetworkScanRequest;
import android.telephony.Rlog;
import android.telephony.ServiceState;
@@ -133,6 +134,10 @@
mTtyModeReceivedRegistrants.notifyRegistrants(result);
}
+ public void onCallQualityChanged(CallQuality callQuality) {
+ mNotifier.notifyCallQualityChanged(this, callQuality);
+ }
+
@Override
public ServiceState getServiceState() {
// FIXME: we may need to provide this when data connectivity is lost
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 376c732..603f821 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -46,6 +46,7 @@
import android.telecom.ConferenceParticipant;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
+import android.telephony.CallQuality;
import android.telephony.CarrierConfigManager;
import android.telephony.DisconnectCause;
import android.telephony.PhoneNumberUtils;
@@ -2752,6 +2753,15 @@
conn.updateMultipartyState(isMultiParty);
}
}
+
+ /**
+ * Handles a change to the call quality for an {@code ImsCall}.
+ * Notifies apps through the System API {@link PhoneStateListener#onCallAttributesChanged}.
+ */
+ @Override
+ public void onCallQualityChanged(ImsCall imsCall, CallQuality callQuality) {
+ mPhone.onCallQualityChanged(callQuality);
+ }
};
/**
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
index ac219ea..5dd9975 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
@@ -32,10 +32,11 @@
import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IP;
import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV4V6;
import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV6;
+import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_NON_IP;
import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_PPP;
+import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_UNSTRUCTURED;
import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_UNKNOWN;
-import android.hardware.radio.V1_0.SetupDataCallResult;
import android.os.Build;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -1104,6 +1105,10 @@
return PDP_TYPE_IPV4V6;
case "PPP":
return PDP_TYPE_PPP;
+ case "NON-IP":
+ return PDP_TYPE_NON_IP;
+ case "UNSTRUCTURED":
+ return PDP_TYPE_UNSTRUCTURED;
}
Rlog.e(TAG, "Unknown type: " + type);
return PDP_UNKNOWN;
@@ -1419,23 +1424,23 @@
* @param result Data call result
*/
private void writeOnSetupDataCallResponse(int phoneId, int rilSerial, int rilError,
- int rilRequest, SetupDataCallResult result) {
+ int rilRequest, DataCallResponse response) {
RilSetupDataCallResponse setupDataCallResponse = new RilSetupDataCallResponse();
RilDataCall dataCall = new RilDataCall();
- if (result != null) {
- setupDataCallResponse.status =
- (result.status == 0 ? RilDataCallFailCause.PDP_FAIL_NONE : result.status);
- setupDataCallResponse.suggestedRetryTimeMillis = result.suggestedRetryTime;
+ if (response != null) {
+ setupDataCallResponse.status = (response.getStatus() == 0
+ ? RilDataCallFailCause.PDP_FAIL_NONE : response.getStatus());
+ setupDataCallResponse.suggestedRetryTimeMillis = response.getSuggestedRetryTime();
- dataCall.cid = result.cid;
- if (!TextUtils.isEmpty(result.type)) {
- dataCall.type = toPdpType(result.type);
+ dataCall.cid = response.getCallId();
+ if (!TextUtils.isEmpty(response.getType())) {
+ dataCall.type = toPdpType(response.getType());
}
- if (!TextUtils.isEmpty(result.ifname)) {
- dataCall.iframe = result.ifname;
+ if (!TextUtils.isEmpty(response.getIfname())) {
+ dataCall.iframe = response.getIfname();
}
}
setupDataCallResponse.call = dataCall;
@@ -1548,8 +1553,8 @@
int rilRequest, Object ret) {
switch (rilRequest) {
case RIL_REQUEST_SETUP_DATA_CALL:
- SetupDataCallResult result = (SetupDataCallResult) ret;
- writeOnSetupDataCallResponse(phoneId, rilSerial, rilError, rilRequest, result);
+ DataCallResponse response = (DataCallResponse) ret;
+ writeOnSetupDataCallResponse(phoneId, rilSerial, rilError, rilRequest, response);
break;
case RIL_REQUEST_DEACTIVATE_DATA_CALL:
writeOnDeactivateDataCallResponse(phoneId, rilError);
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommands.java b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
index cf2154c..0b1b349 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -29,7 +29,7 @@
import android.os.Parcel;
import android.os.SystemClock;
import android.os.WorkSource;
-import android.service.carrier.CarrierIdentifier;
+import android.telephony.CarrierRestrictionRules;
import android.telephony.CellInfo;
import android.telephony.CellInfoGsm;
import android.telephony.CellSignalStrengthCdma;
@@ -57,6 +57,7 @@
import com.android.internal.telephony.LastCallFailCause;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.RIL;
import com.android.internal.telephony.RadioCapability;
import com.android.internal.telephony.SmsResponse;
import com.android.internal.telephony.UUSInfo;
@@ -540,7 +541,12 @@
*/
@Override
public void getDataCallList(Message result) {
- resultSuccess(result, new ArrayList<DataCallResponse>(0));
+ ArrayList<SetupDataCallResult> dcCallList = new ArrayList<SetupDataCallResult>(0);
+ SimulatedCommandsVerifier.getInstance().getDataCallList(result);
+ if (mSetupDataCallResult != null) {
+ dcCallList.add(mSetupDataCallResult);
+ }
+ resultSuccess(result, dcCallList);
}
/**
@@ -1164,11 +1170,11 @@
}
}
+ DataCallResponse response = RIL.convertDataCallResult(mSetupDataCallResult);
if (mDcSuccess) {
- resultSuccess(result, mSetupDataCallResult);
+ resultSuccess(result, response);
} else {
- resultFail(result, mSetupDataCallResult,
- new RuntimeException("Setup data call failed!"));
+ resultFail(result, response, new RuntimeException("Setup data call failed!"));
}
}
@@ -2059,8 +2065,8 @@
}
@Override
- public void setAllowedCarriers(List<CarrierIdentifier> carriers, Message result,
- WorkSource workSource) {
+ public void setAllowedCarriers(CarrierRestrictionRules carrierRestrictionRules,
+ Message result, WorkSource workSource) {
unimplemented(result);
}
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java
index 97260af..a8db6c8 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCard.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java
@@ -25,6 +25,7 @@
import android.os.Message;
import android.telephony.Rlog;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.TelephonyComponentFactory;
@@ -489,7 +490,7 @@
* card or the EID of the card for an eUICC card.
*/
public String getCardId() {
- if (mCardId != null) {
+ if (!TextUtils.isEmpty(mCardId)) {
return mCardId;
} else if (mUiccProfile != null) {
return mUiccProfile.getIccId();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierRestrictionRulesTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierRestrictionRulesTest.java
new file mode 100644
index 0000000..e493577
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierRestrictionRulesTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.os.Parcel;
+import android.service.carrier.CarrierIdentifier;
+import android.telephony.CarrierRestrictionRules;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.ArrayList;
+
+/** Unit tests for {@link CarrierRestrictionRules}. */
+
+public class CarrierRestrictionRulesTest extends AndroidTestCase {
+
+ private static final String MCC1 = "110";
+ private static final String MNC1 = "210";
+ private static final String MCC2 = "120";
+ private static final String MNC2 = "220";
+ private static final String MCC1_WILDCHAR = "3??";
+ private static final String MNC1_WILDCHAR = "???";
+ private static final String MCC2_WILDCHAR = "31?";
+ private static final String MNC2_WILDCHAR = "?0";
+ private static final String GID1 = "80";
+
+ @SmallTest
+ public void testBuilderAllowedAndExcludedCarriers() {
+ ArrayList<CarrierIdentifier> allowedCarriers = new ArrayList<>();
+ allowedCarriers.add(new CarrierIdentifier(MCC1, MNC1, null, null, null, null));
+ allowedCarriers.add(new CarrierIdentifier(MCC2, MNC2, null, null, null, null));
+
+ ArrayList<CarrierIdentifier> excludedCarriers = new ArrayList<>();
+ excludedCarriers.add(new CarrierIdentifier(MCC2, MNC2, null, null, GID1, null));
+
+ CarrierRestrictionRules rules = CarrierRestrictionRules.newBuilder()
+ .setAllowedCarriers(allowedCarriers)
+ .setExcludedCarriers(excludedCarriers)
+ .build();
+
+ assertEquals(false, rules.isAllCarriersAllowed());
+ assertTrue(rules.getAllowedCarriers().equals(allowedCarriers));
+ assertTrue(rules.getExcludedCarriers().equals(excludedCarriers));
+ assertEquals(CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED,
+ rules.getDefaultCarrierRestriction());
+ }
+
+ @SmallTest
+ public void testBuilderEmptyLists() {
+ ArrayList<CarrierIdentifier> emptyCarriers = new ArrayList<>();
+
+ CarrierRestrictionRules rules = CarrierRestrictionRules.newBuilder().build();
+
+ assertEquals(false, rules.isAllCarriersAllowed());
+ assertTrue(rules.getAllowedCarriers().equals(emptyCarriers));
+ assertTrue(rules.getExcludedCarriers().equals(emptyCarriers));
+ assertEquals(CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED,
+ rules.getDefaultCarrierRestriction());
+ }
+
+ @SmallTest
+ public void testBuilderWildCharacter() {
+ ArrayList<CarrierIdentifier> allowedCarriers = new ArrayList<>();
+ allowedCarriers.add(new CarrierIdentifier(MCC1_WILDCHAR, MNC1_WILDCHAR, null, null,
+ null, null));
+
+ ArrayList<CarrierIdentifier> excludedCarriers = new ArrayList<>();
+ excludedCarriers.add(new CarrierIdentifier(MCC2_WILDCHAR, MNC2_WILDCHAR, null, null,
+ GID1, null));
+
+ CarrierRestrictionRules rules = CarrierRestrictionRules.newBuilder()
+ .setAllowedCarriers(allowedCarriers)
+ .setExcludedCarriers(excludedCarriers)
+ .build();
+
+ assertEquals(false, rules.isAllCarriersAllowed());
+ assertTrue(rules.getAllowedCarriers().equals(allowedCarriers));
+ assertTrue(rules.getExcludedCarriers().equals(excludedCarriers));
+ assertEquals(CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED,
+ rules.getDefaultCarrierRestriction());
+ }
+
+ @SmallTest
+ public void testBuilderDefaultAllowed() {
+ ArrayList<CarrierIdentifier> allowedCarriers = new ArrayList<>();
+ allowedCarriers.add(new CarrierIdentifier(MCC1, MNC1, null, null, null, null));
+ allowedCarriers.add(new CarrierIdentifier(MCC2, MNC2, null, null, null, null));
+
+ ArrayList<CarrierIdentifier> excludedCarriers = new ArrayList<>();
+ allowedCarriers.add(new CarrierIdentifier(MCC2, MNC2, null, null, GID1, null));
+
+ CarrierRestrictionRules rules = CarrierRestrictionRules.newBuilder()
+ .setAllowedCarriers(allowedCarriers)
+ .setExcludedCarriers(excludedCarriers)
+ .setDefaultCarrierRestriction(
+ CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_ALLOWED)
+ .build();
+
+ assertEquals(false, rules.isAllCarriersAllowed());
+ assertTrue(rules.getAllowedCarriers().equals(allowedCarriers));
+ assertTrue(rules.getExcludedCarriers().equals(excludedCarriers));
+ assertEquals(CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_ALLOWED,
+ rules.getDefaultCarrierRestriction());
+ }
+
+ @SmallTest
+ public void testBuilderAllCarriersAllowed() {
+ ArrayList<CarrierIdentifier> allowedCarriers = new ArrayList<>();
+ ArrayList<CarrierIdentifier> excludedCarriers = new ArrayList<>();
+
+ CarrierRestrictionRules rules = CarrierRestrictionRules.newBuilder()
+ .setAllCarriersAllowed()
+ .build();
+
+ assertEquals(true, rules.isAllCarriersAllowed());
+ assertTrue(rules.getAllowedCarriers().equals(allowedCarriers));
+ assertTrue(rules.getExcludedCarriers().equals(excludedCarriers));
+ assertEquals(CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_ALLOWED,
+ rules.getDefaultCarrierRestriction());
+ }
+
+ @SmallTest
+ public void testParcel() {
+ ArrayList<CarrierIdentifier> allowedCarriers = new ArrayList<>();
+ allowedCarriers.add(new CarrierIdentifier(MCC1, MNC1, null, null, null, null));
+ allowedCarriers.add(new CarrierIdentifier(MCC2, MNC2, null, null, null, null));
+
+ ArrayList<CarrierIdentifier> excludedCarriers = new ArrayList<>();
+ excludedCarriers.add(new CarrierIdentifier(MCC2, MNC2, null, null, GID1, null));
+
+ CarrierRestrictionRules rules = CarrierRestrictionRules.newBuilder()
+ .setAllowedCarriers(allowedCarriers)
+ .setExcludedCarriers(excludedCarriers)
+ .setDefaultCarrierRestriction(
+ CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED)
+ .setMultiSimPolicy(
+ CarrierRestrictionRules.MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT)
+ .build();
+
+ Parcel p = Parcel.obtain();
+ rules.writeToParcel(p, 0);
+ p.setDataPosition(0);
+
+ CarrierRestrictionRules newRules = CarrierRestrictionRules.CREATOR.createFromParcel(p);
+
+ assertEquals(false, rules.isAllCarriersAllowed());
+ assertTrue(allowedCarriers.equals(newRules.getAllowedCarriers()));
+ assertTrue(excludedCarriers.equals(newRules.getExcludedCarriers()));
+ assertEquals(rules.getDefaultCarrierRestriction(),
+ newRules.getDefaultCarrierRestriction());
+ assertEquals(rules.getMultiSimPolicy(),
+ CarrierRestrictionRules.MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT);
+ }
+
+ @SmallTest
+ public void testDefaultMultiSimPolicy() {
+ CarrierRestrictionRules rules = CarrierRestrictionRules.newBuilder().build();
+
+ assertEquals(CarrierRestrictionRules.MULTISIM_POLICY_NONE, rules.getMultiSimPolicy());
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
index 2758d7c..c9fa7b7 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
@@ -189,45 +189,49 @@
mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone);
verify(mTelephonyRegisteryMock, times(0)).notifyPreciseCallState(anyInt(), anyInt(),
- anyInt());
+ anyInt(), anyInt());
doReturn(mForeGroundCall).when(mPhone).getForegroundCall();
mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone);
verify(mTelephonyRegisteryMock, times(0)).notifyPreciseCallState(anyInt(), anyInt(),
- anyInt());
+ anyInt(), anyInt());
doReturn(mBackGroundCall).when(mPhone).getBackgroundCall();
mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone);
verify(mTelephonyRegisteryMock, times(0)).notifyPreciseCallState(anyInt(), anyInt(),
- anyInt());
+ anyInt(), anyInt());
doReturn(mRingingCall).when(mPhone).getRingingCall();
mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone);
verify(mTelephonyRegisteryMock, times(1)).notifyPreciseCallState(
PreciseCallState.PRECISE_CALL_STATE_IDLE,
PreciseCallState.PRECISE_CALL_STATE_IDLE,
- PreciseCallState.PRECISE_CALL_STATE_IDLE);
+ PreciseCallState.PRECISE_CALL_STATE_IDLE,
+ mPhone.getPhoneId());
doReturn(Call.State.ACTIVE).when(mForeGroundCall).getState();
mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone);
verify(mTelephonyRegisteryMock, times(1)).notifyPreciseCallState(
PreciseCallState.PRECISE_CALL_STATE_IDLE,
PreciseCallState.PRECISE_CALL_STATE_ACTIVE,
- PreciseCallState.PRECISE_CALL_STATE_IDLE);
+ PreciseCallState.PRECISE_CALL_STATE_IDLE,
+ mPhone.getPhoneId());
doReturn(Call.State.HOLDING).when(mBackGroundCall).getState();
mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone);
verify(mTelephonyRegisteryMock, times(1)).notifyPreciseCallState(
PreciseCallState.PRECISE_CALL_STATE_IDLE,
PreciseCallState.PRECISE_CALL_STATE_ACTIVE,
- PreciseCallState.PRECISE_CALL_STATE_HOLDING);
+ PreciseCallState.PRECISE_CALL_STATE_HOLDING,
+ mPhone.getPhoneId());
doReturn(Call.State.ALERTING).when(mRingingCall).getState();
mDefaultPhoneNotifierUT.notifyPreciseCallState(mPhone);
verify(mTelephonyRegisteryMock, times(1)).notifyPreciseCallState(
PreciseCallState.PRECISE_CALL_STATE_ALERTING,
PreciseCallState.PRECISE_CALL_STATE_ACTIVE,
- PreciseCallState.PRECISE_CALL_STATE_HOLDING);
+ PreciseCallState.PRECISE_CALL_STATE_HOLDING,
+ mPhone.getPhoneId());
}
@Test @SmallTest
diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
index e3e5d96..d074155 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
@@ -103,7 +103,8 @@
+ SubscriptionManager.ISO_COUNTRY_CODE + " TEXT,"
+ SubscriptionManager.CARRIER_ID + " INTEGER DEFAULT -1,"
+ SubscriptionManager.PROFILE_CLASS
- + " INTEGER DEFAULT " + SubscriptionManager.PROFILE_CLASS_DEFAULT
+ + " INTEGER DEFAULT " + SubscriptionManager.PROFILE_CLASS_DEFAULT + ","
+ + SubscriptionManager.SUBSCRIPTION_TYPE + " INTEGER DEFAULT 0"
+ ");";
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
index 04b36b8..8f97571 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
@@ -24,6 +24,7 @@
import android.text.SpannableStringBuilder;
import android.text.TextWatcher;
+import org.junit.Ignore;
import org.junit.Test;
public class PhoneNumberWatcherTest {
@@ -267,6 +268,7 @@
* case the replacement text should be formatted by the PhoneNumberFormattingTextWatcher.
*/
@Test @SmallTest
+ @Ignore("b/122886015")
public void testAutoCompleteUnformattedWithUnformattedNumber() {
String init = "650";
String replacement = "6501234567";
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
index b87b416..c23c274 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
@@ -92,6 +92,7 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.hardware.radio.V1_0.Carrier;
import android.hardware.radio.V1_0.CdmaSmsMessage;
import android.hardware.radio.V1_0.DataProfileInfo;
import android.hardware.radio.V1_0.GsmSmsMessage;
@@ -104,12 +105,15 @@
import android.hardware.radio.V1_0.SmsWriteArgs;
import android.hardware.radio.deprecated.V1_0.IOemHook;
import android.net.ConnectivityManager;
+import android.net.LinkAddress;
+import android.net.NetworkUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IPowerManager;
import android.os.Message;
import android.os.PowerManager;
import android.os.WorkSource;
+import android.service.carrier.CarrierIdentifier;
import android.telephony.AccessNetworkConstants;
import android.telephony.CellIdentityCdma;
import android.telephony.CellIdentityGsm;
@@ -130,6 +134,7 @@
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
+import android.telephony.data.DataCallResponse;
import android.telephony.data.DataProfile;
import androidx.test.filters.FlakyTest;
@@ -716,7 +721,7 @@
mSerialNumberCaptor.capture(),
eq((DataProfileInfo) invokeMethod(
mRILInstance,
- "convertToHalDataProfile",
+ "convertToHalDataProfile10",
new Class<?>[] {DataProfile.class},
new Object[] {dataProfile})),
eq(dataProfile.isPersistent()),
@@ -1027,7 +1032,7 @@
mRILInstance,
"obtainRequest",
new Class<?>[] {Integer.TYPE, Message.class, WorkSource.class},
- new Object[] {RIL_REQUEST_GET_SIM_STATUS, obtainMessage(), null});
+ new Object[] {RIL_REQUEST_GET_SIM_STATUS, obtainMessage(), new WorkSource()});
// The wake lock should be held when obtain a RIL request.
assertTrue(mRILInstance.getWakeLock(RIL.FOR_WAKELOCK).isHeld());
@@ -1526,6 +1531,57 @@
}
@Test
+ public void testConvertDataCallResult() throws Exception {
+ // Test V1.0 SetupDataCallResult
+ android.hardware.radio.V1_0.SetupDataCallResult result10 =
+ new android.hardware.radio.V1_0.SetupDataCallResult();
+ result10.status = android.hardware.radio.V1_0.DataCallFailCause.NONE;
+ result10.suggestedRetryTime = -1;
+ result10.cid = 0;
+ result10.active = 2;
+ result10.type = "IPV4V6";
+ result10.ifname = "ifname";
+ result10.addresses = "10.0.2.15 2607:fb90:a620:651d:eabe:f8da:c107:44be/64";
+ result10.dnses = "10.0.2.3 fd00:976a::9";
+ result10.gateways = "10.0.2.15 fe80::2";
+ result10.pcscf = "fd00:976a:c206:20::6 fd00:976a:c206:20::9 fd00:976a:c202:1d::9";
+ result10.mtu = 1500;
+
+ DataCallResponse response = new DataCallResponse(0, -1, 0, 2, "IPV4V6",
+ "ifname",
+ Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress("10.0.2.15"), 32),
+ new LinkAddress("2607:fb90:a620:651d:eabe:f8da:c107:44be/64")),
+ Arrays.asList(NetworkUtils.numericToInetAddress("10.0.2.3"),
+ NetworkUtils.numericToInetAddress("fd00:976a::9")),
+ Arrays.asList(NetworkUtils.numericToInetAddress("10.0.2.15"),
+ NetworkUtils.numericToInetAddress("fe80::2")),
+ Arrays.asList("fd00:976a:c206:20::6", "fd00:976a:c206:20::9",
+ "fd00:976a:c202:1d::9"),
+ 1500);
+
+ assertEquals(response, RIL.convertDataCallResult(result10));
+
+ // Test V1.4 SetupDataCallResult
+ android.hardware.radio.V1_4.SetupDataCallResult result14 =
+ new android.hardware.radio.V1_4.SetupDataCallResult();
+ result14.cause = android.hardware.radio.V1_4.DataCallFailCause.NONE;
+ result14.suggestedRetryTime = -1;
+ result14.cid = 0;
+ result14.active = android.hardware.radio.V1_4.DataConnActiveStatus.ACTIVE;
+ result14.type = android.hardware.radio.V1_4.PdpProtocolType.IPV4V6;
+ result14.ifname = "ifname";
+ result14.addresses = new ArrayList<>(
+ Arrays.asList("10.0.2.15", "2607:fb90:a620:651d:eabe:f8da:c107:44be/64"));
+ result14.dnses = new ArrayList<>(Arrays.asList("10.0.2.3", "fd00:976a::9"));
+ result14.gateways = new ArrayList<>(Arrays.asList("10.0.2.15", "fe80::2"));
+ result14.pcscf = new ArrayList<>(Arrays.asList(
+ "fd00:976a:c206:20::6", "fd00:976a:c206:20::9", "fd00:976a:c202:1d::9"));
+ result14.mtu = 1500;
+
+ assertEquals(response, RIL.convertDataCallResult(result14));
+ }
+
+ @Test
public void testGetWorksourceClientId() {
RILRequest request = RILRequest.obtain(0, null, null);
assertEquals(null, request.getWorkSourceClientId());
@@ -1700,4 +1756,50 @@
assertEquals(BEARER_BITMAP, dpi.bearerBitmap);
assertEquals(MTU, dpi.mtu);
}
+
+ @Test
+ public void testCreateCarrierRestrictionList() {
+ ArrayList<CarrierIdentifier> carriers = new ArrayList<>();
+ carriers.add(new CarrierIdentifier("110", "120", null, null, null, null));
+ carriers.add(new CarrierIdentifier("210", "220", "SPN", null, null, null));
+ carriers.add(new CarrierIdentifier("310", "320", null, "012345", null, null));
+ carriers.add(new CarrierIdentifier("410", "420", null, null, "GID1", null));
+ carriers.add(new CarrierIdentifier("510", "520", null, null, null, "GID2"));
+
+ Carrier c1 = new Carrier();
+ c1.mcc = "110";
+ c1.mnc = "120";
+ c1.matchType = CarrierIdentifier.MatchType.ALL;
+ Carrier c2 = new Carrier();
+ c2.mcc = "210";
+ c2.mnc = "220";
+ c2.matchType = CarrierIdentifier.MatchType.SPN;
+ c2.matchData = "SPN";
+ Carrier c3 = new Carrier();
+ c3.mcc = "310";
+ c3.mnc = "320";
+ c3.matchType = CarrierIdentifier.MatchType.IMSI_PREFIX;
+ c3.matchData = "012345";
+ Carrier c4 = new Carrier();
+ c4.mcc = "410";
+ c4.mnc = "420";
+ c4.matchType = CarrierIdentifier.MatchType.GID1;
+ c4.matchData = "GID1";
+ Carrier c5 = new Carrier();
+ c5.mcc = "510";
+ c5.mnc = "520";
+ c5.matchType = CarrierIdentifier.MatchType.GID2;
+ c5.matchData = "GID2";
+
+ ArrayList<Carrier> expected = new ArrayList<>();
+ expected.add(c1);
+ expected.add(c2);
+ expected.add(c3);
+ expected.add(c4);
+ expected.add(c5);
+
+ ArrayList<Carrier> result = RIL.createCarrierRestrictionList(carriers);
+
+ assertTrue(result.equals(expected));
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
index 1b7fdd8..29cfd27 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
@@ -46,8 +46,11 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Comparator;
import java.util.List;
+import java.util.Map;
public class SubscriptionControllerTest extends TelephonyTest {
private static final int SINGLE_SIM = 1;
@@ -58,13 +61,19 @@
@Mock
private ITelephonyRegistry.Stub mTelephonyRegisteryMock;
+ private static final String MAC_ADDRESS_PREFIX = "mac_";
+ private static final String DISPLAY_NAME_PREFIX = "my_phone_";
+
@Before
public void setUp() throws Exception {
super.setUp("SubscriptionControllerTest");
doReturn(SINGLE_SIM).when(mTelephonyManager).getSimCount();
doReturn(SINGLE_SIM).when(mTelephonyManager).getPhoneCount();
-
+ mMockContentResolver = (MockContentResolver) mContext.getContentResolver();
+ mFakeTelephonyProvider = new FakeTelephonyProvider();
+ mMockContentResolver.addProvider(SubscriptionManager.CONTENT_URI.getAuthority(),
+ mFakeTelephonyProvider);
replaceInstance(SubscriptionController.class, "sInstance", null, null);
SubscriptionController.init(mContext, null);
@@ -75,11 +84,6 @@
mContextFixture.putIntArrayResource(com.android.internal.R.array.sim_colors, new int[]{5});
mSubscriptionControllerUT.getInstance().updatePhonesAvailability(new Phone[]{mPhone});
- mMockContentResolver = (MockContentResolver) mContext.getContentResolver();
- mFakeTelephonyProvider = new FakeTelephonyProvider();
- mMockContentResolver.addProvider(SubscriptionManager.CONTENT_URI.getAuthority(),
- mFakeTelephonyProvider);
-
}
@After
@@ -91,6 +95,7 @@
/*clear sub info in mSubscriptionControllerUT since they will otherwise be persistent
* between each test case. */
mSubscriptionControllerUT.clearSubInfo();
+ mSubscriptionControllerUT.resetStaticMembers();
/* clear settings for default voice/data/sms sub ID */
Settings.Global.putInt(mContext.getContentResolver(),
@@ -215,7 +220,7 @@
}
@Test @SmallTest
- public void testDefaultSubID() {
+ public void testDefaultSubIdOnSingleSimDevice() {
assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
mSubscriptionControllerUT.getDefaultDataSubId());
assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
@@ -225,12 +230,10 @@
/* insert one sim */
testInsertSim();
// if support single sim, sms/data/voice default sub should be the same
- assertNotSame(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
- mSubscriptionControllerUT.getDefaultSubId());
- assertEquals(mSubscriptionControllerUT.getDefaultDataSubId(),
- mSubscriptionControllerUT.getDefaultSmsSubId());
- assertEquals(mSubscriptionControllerUT.getDefaultDataSubId(),
- mSubscriptionControllerUT.getDefaultVoiceSubId());
+ assertEquals(1, mSubscriptionControllerUT.getDefaultSubId());
+ assertEquals(1, mSubscriptionControllerUT.getDefaultDataSubId());
+ assertEquals(1, mSubscriptionControllerUT.getDefaultSmsSubId());
+ assertEquals(1, mSubscriptionControllerUT.getDefaultVoiceSubId());
}
@Test @SmallTest
@@ -409,6 +412,168 @@
.notifyOpportunisticSubscriptionInfoChanged();
}
+ @Test @SmallTest
+ public void testInsertRemoteSim() {
+ makeThisDeviceMultiSimCapable();
+
+ // verify there are no sim's in the system.
+ assertEquals(0, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage));
+
+ addAndVerifyRemoteSimAddition(1, 0);
+ }
+
+ private void addAndVerifyRemoteSimAddition(int num, int numOfCurrentSubs) {
+ // Verify the number of current subs in the system
+ assertEquals(numOfCurrentSubs,
+ mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage));
+
+ // if there are current subs in the system, get that info
+ List<SubscriptionInfo> mSubList;
+ ArrayList<String> macAddresses = new ArrayList<>();
+ ArrayList<String> displayNames = new ArrayList<>();
+ if (numOfCurrentSubs > 0) {
+ mSubList = mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage);
+ assertNotNull(mSubList);
+ assertEquals(numOfCurrentSubs, mSubList.size());
+ for (SubscriptionInfo info : mSubList) {
+ assertNotNull(info.getIccId());
+ assertNotNull(info.getDisplayName());
+ macAddresses.add(info.getIccId());
+ displayNames.add(info.getDisplayName().toString());
+ }
+ }
+
+ // To add more subs, we need to create macAddresses + displaynames.
+ for (int i = 0; i < num; i++) {
+ macAddresses.add(MAC_ADDRESS_PREFIX + (numOfCurrentSubs + i));
+ displayNames.add(DISPLAY_NAME_PREFIX + (numOfCurrentSubs + i));
+ }
+
+ // Add subs - one at a time and verify the contents in subscription info data structs
+ for (int i = 0; i < num; i++) {
+ int index = numOfCurrentSubs + i;
+ mSubscriptionControllerUT.addSubInfo(macAddresses.get(index), displayNames.get(index),
+ SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB,
+ SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM);
+
+ // make sure the subscription is added in SubscriptionController data structs
+ Map<Integer, ArrayList<Integer>> slotIndexToSubsMap =
+ mSubscriptionControllerUT.getSlotIndexToSubIdsMap();
+ assertNotNull(slotIndexToSubsMap);
+ // Since All remote sim's go to the same slot index, there should only be one entry
+ assertEquals(1, slotIndexToSubsMap.size());
+
+ // get all the subscriptions available. should be what is just added in this method
+ // PLUS the number of subs that already existed before
+ int expectedNumOfSubs = numOfCurrentSubs + i + 1;
+ ArrayList<Integer> subIdsList =
+ slotIndexToSubsMap.get(SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB);
+ assertNotNull(subIdsList);
+ assertEquals(expectedNumOfSubs, subIdsList.size());
+
+ // validate slot index, sub id etc
+ mSubList = mSubscriptionControllerUT.getActiveSubscriptionInfoList(mCallingPackage);
+ assertNotNull(mSubList);
+ assertEquals(expectedNumOfSubs, mSubList.size());
+
+ // sort on subscription-id which will make sure the previously existing subscriptions
+ // are in earlier slots in the array
+ mSubList.sort(SUBSCRIPTION_INFO_COMPARATOR);
+
+ // Verify the subscription data. Skip the verification for the existing subs.
+ for (int j = numOfCurrentSubs; j < mSubList.size(); j++) {
+ SubscriptionInfo info = mSubList.get(j);
+ assertTrue(SubscriptionManager.isValidSubscriptionId(info.getSubscriptionId()));
+ assertEquals(SubscriptionManager.SLOT_INDEX_FOR_REMOTE_SIM_SUB,
+ info.getSimSlotIndex());
+ assertEquals(SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM,
+ info.getSubscriptionType());
+ assertEquals(macAddresses.get(j), info.getIccId());
+ assertEquals(displayNames.get(j), info.getDisplayName());
+ }
+ }
+ }
+
+ private static final Comparator<SubscriptionInfo> SUBSCRIPTION_INFO_COMPARATOR =
+ Comparator.comparingInt(o -> o.getSubscriptionId());
+
+ @Test @SmallTest
+ public void testInsertMultipleRemoteSims() {
+ makeThisDeviceMultiSimCapable();
+
+ // verify that there are no subscription info records
+ assertEquals(0, mSubscriptionControllerUT.getAllSubInfoCount(mCallingPackage));
+ Map<Integer, ArrayList<Integer>> slotIndexToSubsMap =
+ mSubscriptionControllerUT.getSlotIndexToSubIdsMap();
+ assertNotNull(slotIndexToSubsMap);
+ assertTrue(slotIndexToSubsMap.isEmpty());
+
+ // Add a few subscriptions
+ addAndVerifyRemoteSimAddition(4, 0);
+ }
+
+
+ @Test @SmallTest
+ public void testDefaultSubIdOnMultiSimDevice() {
+ makeThisDeviceMultiSimCapable();
+
+ // Initially, defaults should be -1
+ assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+ mSubscriptionControllerUT.getDefaultDataSubId());
+ assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+ mSubscriptionControllerUT.getDefaultSmsSubId());
+ assertEquals(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+ mSubscriptionControllerUT.getDefaultSmsSubId());
+
+ // Insert one Remote-Sim.
+ testInsertRemoteSim();
+
+ // defaults should be set to this newly-inserted subscription
+ assertEquals(1, mSubscriptionControllerUT.getDefaultSubId());
+ assertEquals(1, mSubscriptionControllerUT.getDefaultDataSubId());
+ assertEquals(1, mSubscriptionControllerUT.getDefaultSmsSubId());
+ assertEquals(1, mSubscriptionControllerUT.getDefaultVoiceSubId());
+
+ // Add a few subscriptions
+ addAndVerifyRemoteSimAddition(4, 1);
+
+ // defaults should be still be set to the first sub - and unchanged by the addition of
+ // the above multiple sims.
+ assertEquals(1, mSubscriptionControllerUT.getDefaultSubId());
+ assertEquals(1, mSubscriptionControllerUT.getDefaultDataSubId());
+ assertEquals(1, mSubscriptionControllerUT.getDefaultSmsSubId());
+ assertEquals(1, mSubscriptionControllerUT.getDefaultVoiceSubId());
+ }
+
+ @Test @SmallTest
+ public void testRemoveSubscription() {
+ makeThisDeviceMultiSimCapable();
+
+ /* insert some sims */
+ testInsertMultipleRemoteSims();
+ assertEquals(1, mSubscriptionControllerUT.getDefaultSubId());
+ int[] subIdsArray = mSubscriptionControllerUT.getActiveSubIdList();
+ assertTrue(subIdsArray.length > 0);
+ int len = subIdsArray.length;
+
+ // remove the first sim - which also is the default sim.
+ int result = mSubscriptionControllerUT.removeSubInfo(MAC_ADDRESS_PREFIX + 0,
+ SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM);
+
+ assertTrue(result > 0);
+ // now check the number of subs left. should be one less than earlier
+ int[] newSubIdsArray = mSubscriptionControllerUT.getActiveSubIdList();
+ assertTrue(newSubIdsArray.length > 0);
+ assertEquals(len - 1, newSubIdsArray.length);
+
+ // now check that there is a new default
+ assertNotSame(1, mSubscriptionControllerUT.getDefaultSubId());
+ }
+
+ private void makeThisDeviceMultiSimCapable() {
+ doReturn(10).when(mTelephonyManager).getSimCount();
+ }
+
@Test
@SmallTest
public void testSetSubscriptionGroupWithModifyPermission() throws Exception {
@@ -444,6 +609,7 @@
public void testSetSubscriptionGroupWithCarrierPrivilegePermission() throws Exception {
testInsertSim();
// Adding a second profile and mark as embedded.
+ // TODO b/123300875 slot index 1 is not expected to be valid
mSubscriptionControllerUT.addSubInfoRecord("test2", 1);
ContentValues values = new ContentValues();
values.put(SubscriptionManager.IS_EMBEDDED, 1);
@@ -484,6 +650,7 @@
// Put sub3 into slot 1 to make sub2 inactive.
mContextFixture.addCallingOrSelfPermission(
android.Manifest.permission.MODIFY_PHONE_STATE);
+ // TODO b/123300875 slot index 1 is not expected to be valid
mSubscriptionControllerUT.addSubInfoRecord("test3", 1);
mContextFixture.removeCallingOrSelfPermission(
android.Manifest.permission.MODIFY_PHONE_STATE);
@@ -590,6 +757,7 @@
@Test
@SmallTest
public void testGetActiveSubIdList() throws Exception {
+ // TODO b/123300875 slot index 1 is not expected to be valid
mSubscriptionControllerUT.addSubInfoRecord("123", 1); // sub 1
mSubscriptionControllerUT.addSubInfoRecord("456", 0); // sub 2
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
index a935b38..c804cd0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
@@ -511,25 +511,15 @@
when(mSubscriptionController.getSubscriptionInfoListForEmbeddedSubscriptionUpdate(
new String[0], false /* removable */)).thenReturn(subInfoList);
- assertTrue(mUpdater.updateEmbeddedSubscriptions(FAKE_CARD_ID));
+ assertFalse(mUpdater.updateEmbeddedSubscriptions(FAKE_CARD_ID));
// No new entries should be created.
verify(mSubscriptionController, times(0)).clearSubInfo();
verify(mSubscriptionController, never()).insertEmptySubInfoRecord(anyString(), anyInt());
- // 1 should not have been touched.
+ // No existing entries should have been updated.
verify(mContentProvider, never()).update(eq(SubscriptionManager.CONTENT_URI), any(),
- eq(SubscriptionManager.ICC_ID + "=\"1\""), isNull());
- verify(mContentProvider, never()).update(eq(SubscriptionManager.CONTENT_URI), any(),
- eq(SubscriptionManager.ICC_ID + "IN (\"1\")"), isNull());
-
- // 2 should have been removed since it was returned from the cache but the LPA had an
- // error when listing.
- ArgumentCaptor<ContentValues> iccid2Values = ArgumentCaptor.forClass(ContentValues.class);
- verify(mContentProvider).update(eq(SubscriptionManager.CONTENT_URI), iccid2Values.capture(),
- eq(SubscriptionManager.ICC_ID + " IN (\"2\")"), isNull());
- assertEquals(0,
- iccid2Values.getValue().getAsInteger(SubscriptionManager.IS_EMBEDDED).intValue());
+ any(), isNull());
}
@Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java
index 2d2d7ba..736ea5a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnContextTest.java
@@ -21,9 +21,11 @@
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
import android.net.NetworkRequest;
import android.telephony.data.ApnSetting;
@@ -87,14 +89,6 @@
@Test
@SmallTest
- public void testDependencyMet() throws Exception {
- assertTrue(mApnContext.getDependencyMet());
- mApnContext.setDependencyMet(false);
- assertFalse(mApnContext.getDependencyMet());
- }
-
- @Test
- @SmallTest
public void testReason() throws Exception {
mApnContext.setReason("dataEnabled");
assertEquals("dataEnabled", mApnContext.getReason());
@@ -108,7 +102,6 @@
mApnContext.setState(DctConstants.State.DISCONNECTING);
assertEquals(DctConstants.State.DISCONNECTING, mApnContext.getState());
mApnContext.setEnabled(true);
- mApnContext.setDependencyMet(true);
assertFalse(mApnContext.isConnectable());
mApnContext.setState(DctConstants.State.RETRYING);
@@ -123,19 +116,92 @@
@Test
@SmallTest
- public void testNetworkRequest() throws Exception {
+ public void testNetworkRequestNormal() throws Exception {
LocalLog log = new LocalLog(3);
- NetworkRequest nr = new NetworkRequest.Builder().build();
- mApnContext.requestNetwork(nr, log);
+ NetworkRequest nr1 = new NetworkRequest.Builder().build();
+ mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log);
- verify(mDcTracker, times(1)).setEnabled(eq(ApnSetting.TYPE_DEFAULT), eq(true));
- mApnContext.requestNetwork(nr, log);
- verify(mDcTracker, times(1)).setEnabled(eq(ApnSetting.TYPE_DEFAULT), eq(true));
+ verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.REQUEST_TYPE_NORMAL));
+ mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log);
+ verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.REQUEST_TYPE_NORMAL));
- mApnContext.releaseNetwork(nr, log);
- verify(mDcTracker, times(1)).setEnabled(eq(ApnSetting.TYPE_DEFAULT), eq(false));
- mApnContext.releaseNetwork(nr, log);
- verify(mDcTracker, times(1)).setEnabled(eq(ApnSetting.TYPE_DEFAULT), eq(false));
+ mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log);
+ // The same request should be ignore.
+ verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.REQUEST_TYPE_NORMAL));
+
+ NetworkRequest nr2 = new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .build();
+ LocalLog log2 = new LocalLog(3);
+
+ mApnContext.requestNetwork(nr2, DcTracker.REQUEST_TYPE_NORMAL, log2);
+ verify(mDcTracker, times(2)).enableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.REQUEST_TYPE_NORMAL));
+
+ mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_NORMAL, log);
+ verify(mDcTracker, never()).disableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.RELEASE_TYPE_NORMAL));
+
+ mApnContext.releaseNetwork(nr2, DcTracker.RELEASE_TYPE_NORMAL, log2);
+ verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.RELEASE_TYPE_NORMAL));
+ }
+
+ @Test
+ @SmallTest
+ public void testNetworkRequestDetach() throws Exception {
+ LocalLog log = new LocalLog(3);
+ NetworkRequest nr1 = new NetworkRequest.Builder().build();
+ mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log);
+
+ verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.REQUEST_TYPE_NORMAL));
+ mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log);
+ verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.REQUEST_TYPE_NORMAL));
+
+ mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_NORMAL, log);
+ // The same request should be ignore.
+ verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.REQUEST_TYPE_NORMAL));
+
+ NetworkRequest nr2 = new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .build();
+ LocalLog log2 = new LocalLog(3);
+
+ mApnContext.requestNetwork(nr2, DcTracker.REQUEST_TYPE_NORMAL, log2);
+ verify(mDcTracker, times(2)).enableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.REQUEST_TYPE_NORMAL));
+
+ mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_DETACH, log);
+ verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.RELEASE_TYPE_DETACH));
+
+ mApnContext.releaseNetwork(nr2, DcTracker.RELEASE_TYPE_NORMAL, log2);
+ verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.RELEASE_TYPE_NORMAL));
+ }
+
+ @Test
+ @SmallTest
+ public void testNetworkRequestHandover() throws Exception {
+ LocalLog log = new LocalLog(3);
+ NetworkRequest nr1 = new NetworkRequest.Builder().build();
+ mApnContext.requestNetwork(nr1, DcTracker.REQUEST_TYPE_HANDOVER, log);
+ verify(mDcTracker, times(1)).enableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.REQUEST_TYPE_HANDOVER));
+
+ mApnContext.releaseNetwork(nr1, DcTracker.RELEASE_TYPE_HANDOVER, log);
+ verify(mDcTracker, times(1)).disableApn(eq(ApnSetting.TYPE_DEFAULT),
+ eq(DcTracker.RELEASE_TYPE_HANDOVER));
}
@Test
@@ -198,17 +264,10 @@
@SmallTest
public void testIsReady() throws Exception {
mApnContext.setEnabled(true);
- mApnContext.setDependencyMet(true);
assertTrue(mApnContext.isReady());
mApnContext.setEnabled(false);
assertFalse(mApnContext.isReady());
-
- mApnContext.setDependencyMet(false);
- assertFalse(mApnContext.isReady());
-
- mApnContext.setEnabled(true);
- assertFalse(mApnContext.isReady());
}
@Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/CellularDataServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/CellularDataServiceTest.java
deleted file mode 100644
index a34febc..0000000
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/CellularDataServiceTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-
-import static junit.framework.Assert.assertEquals;
-
-import android.hardware.radio.V1_0.SetupDataCallResult;
-import android.net.LinkAddress;
-import android.net.NetworkUtils;
-import android.telephony.data.DataCallResponse;
-
-import com.android.internal.telephony.dataconnection.CellularDataService;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Arrays;
-
-public class CellularDataServiceTest extends TelephonyTest {
-
- private CellularDataService mCellularDataService;
-
- @Before
- public void setUp() throws Exception {
- super.setUp(getClass().getSimpleName());
- mCellularDataService = new CellularDataService();
- }
-
- @After
- public void tearDown() throws Exception {
- super.tearDown();
- }
-
- @Test
- public void testConvertDataCallResult() throws Exception {
-
- SetupDataCallResult result = new SetupDataCallResult();
- result.status = 0;
- result.suggestedRetryTime = -1;
- result.cid = 1;
- result.active = 1;
- result.type = "IP";
- result.ifname = "eth0";
- result.addresses = "10.0.2.15";
- result.dnses = "10.0.2.3";
- result.gateways = "10.0.2.15 fe80::2";
- result.pcscf = "";
- result.mtu = 1500;
-
- DataCallResponse response = new DataCallResponse(0, -1, 1, 1, "IP",
- "eth0",
- Arrays.asList(new LinkAddress(NetworkUtils.numericToInetAddress("10.0.2.15"), 32)),
- Arrays.asList(NetworkUtils.numericToInetAddress("10.0.2.3")),
- Arrays.asList(NetworkUtils.numericToInetAddress("10.0.2.15"),
- NetworkUtils.numericToInetAddress("fe80::2")),
- Arrays.asList(""),
- 1500);
-
- assertEquals(response, mCellularDataService.convertDataCallResult(result));
-
- result.status = 0;
- result.suggestedRetryTime = -1;
- result.cid = 0;
- result.active = 2;
- result.type = "IPV4V6";
- result.ifname = "ifname";
- result.addresses = "2607:fb90:a620:651d:eabe:f8da:c107:44be/64";
- result.dnses = "fd00:976a::9 fd00:976a::10";
- result.gateways = "fe80::4c61:1832:7b28:d36c 1.2.3.4";
- result.pcscf = "fd00:976a:c206:20::6 fd00:976a:c206:20::9 fd00:976a:c202:1d::9";
- result.mtu = 1500;
-
- response = new DataCallResponse(0, -1, 0, 2, "IPV4V6",
- "ifname",
- Arrays.asList(new LinkAddress("2607:fb90:a620:651d:eabe:f8da:c107:44be/64")),
- Arrays.asList(NetworkUtils.numericToInetAddress("fd00:976a::9"),
- NetworkUtils.numericToInetAddress("fd00:976a::10")),
- Arrays.asList(NetworkUtils.numericToInetAddress("fe80::4c61:1832:7b28:d36c"),
- NetworkUtils.numericToInetAddress("1.2.3.4")),
- Arrays.asList("fd00:976a:c206:20::6", "fd00:976a:c206:20::9",
- "fd00:976a:c202:1d::9"),
- 1500);
-
- assertEquals(response, mCellularDataService.convertDataCallResult(result));
- }
-}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
index 6e9fa7b..08b1ab1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -48,6 +48,7 @@
import android.database.MatrixCursor;
import android.hardware.radio.V1_0.SetupDataCallResult;
import android.net.LinkProperties;
+import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.Uri;
@@ -580,9 +581,9 @@
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
waitForMs(200);
- logd("Sending EVENT_ENABLE_NEW_APN");
+ logd("Sending EVENT_ENABLE_APN");
// APN id 0 is APN_TYPE_DEFAULT
- mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
+ mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL);
waitForMs(200);
dataConnectionReasons = new DataConnectionReasons();
@@ -629,9 +630,9 @@
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
waitForMs(200);
- logd("Sending EVENT_ENABLE_NEW_APN");
+ logd("Sending EVENT_ENABLE_APN");
// APN id 0 is APN_TYPE_DEFAULT
- mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
+ mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL);
waitForMs(200);
dataConnectionReasons = new DataConnectionReasons();
@@ -685,8 +686,8 @@
//set Default and MMS to be metered in the CarrierConfigManager
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
- mDct.setEnabled(ApnSetting.TYPE_IMS, true);
- mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
+ mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL);
+ mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL);
logd("Sending EVENT_RECORDS_LOADED");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
@@ -734,8 +735,8 @@
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
- mDct.setEnabled(ApnSetting.TYPE_IMS, true);
- mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
+ mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL);
+ mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL);
logd("Sending EVENT_RECORDS_LOADED");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
@@ -786,8 +787,8 @@
//set Default and MMS to be metered in the CarrierConfigManager
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
- mDct.setEnabled(ApnSetting.TYPE_IMS, true);
- mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
+ mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL);
+ mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL);
logd("Sending DISABLE_ROAMING_CMD");
mDct.setDataRoamingEnabledByUser(false);
@@ -863,7 +864,7 @@
NetworkRequest nr = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).build();
LocalLog l = new LocalLog(100);
- mDct.requestNetwork(nr, l);
+ mDct.requestNetwork(nr, DcTracker.REQUEST_TYPE_NORMAL, l);
waitForMs(200);
verifyDataConnected(FAKE_APN1);
@@ -898,8 +899,8 @@
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
- mDct.setEnabled(ApnSetting.TYPE_IMS, true);
- mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
+ mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL);
+ mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL);
logd("Sending EVENT_RECORDS_LOADED");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
@@ -940,7 +941,7 @@
doReturn(apnSetting).when(mApnContext).getApnSetting();
doReturn(mDataConnection).when(mApnContext).getDataConnection();
doReturn(true).when(mApnContext).isEnabled();
- doReturn(true).when(mApnContext).getDependencyMet();
+ doReturn(true).when(mApnContext).isDependencyMet();
doReturn(true).when(mApnContext).isReady();
doReturn(false).when(mApnContext).hasRestrictedRequests(eq(true));
}
@@ -1187,7 +1188,7 @@
.getRilDataRadioTechnology();
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_DEFAULT});
- mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
+ mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL);
initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
logd("Sending EVENT_RECORDS_LOADED");
@@ -1307,7 +1308,7 @@
.getRilDataRadioTechnology();
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_DEFAULT});
- mDct.setEnabled(ApnSetting.TYPE_DEFAULT, true);
+ mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL);
initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
logd("Sending EVENT_RECORDS_LOADED");
@@ -1426,6 +1427,220 @@
true, DataEnabledSettings.REASON_PROVISIONING_DATA_ENABLED_CHANGED);
}*/
+ @Test
+ @SmallTest
+ public void testNetworkStatusChangedRecoveryOFF() throws Exception {
+ ContentResolver resolver = mContext.getContentResolver();
+ Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);
+
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
+ mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL);
+ mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL);
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
+ verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
+ eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
+ mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+ eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
+ any(Message.class));
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, LTE_BEARER_BITMASK);
+
+ logd("Sending EVENT_NETWORK_STATUS_CHANGED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
+ NetworkAgent.VALID_NETWORK, 0, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_NETWORK_STATUS_CHANGED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
+ NetworkAgent.INVALID_NETWORK, 0, null));
+ waitForMs(200);
+
+ // Verify that its no-op when the new data stall detection feature is disabled
+ verify(mSimulatedCommandsVerifier, times(0)).getDataCallList(any(Message.class));
+ }
+
+ @Test
+ @SmallTest
+ public void testNetworkStatusChangedRecoveryON() throws Exception {
+ ContentResolver resolver = mContext.getContentResolver();
+ Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1);
+ Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 0);
+
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
+ mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL);
+ mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL);
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
+ verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
+ eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
+ mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+ eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
+ any(Message.class));
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, LTE_BEARER_BITMASK);
+
+ logd("Sending EVENT_NETWORK_STATUS_CHANGED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
+ NetworkAgent.VALID_NETWORK, 0, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_NETWORK_STATUS_CHANGED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
+ NetworkAgent.INVALID_NETWORK, 0, null));
+ waitForMs(200);
+
+ verify(mSimulatedCommandsVerifier, times(1)).getDataCallList(any(Message.class));
+
+ // reset the setting at the end of this test
+ Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);
+ waitForMs(200);
+ }
+
+ @Test
+ @SmallTest
+ public void testRecoveryStepPDPReset() throws Exception {
+ ContentResolver resolver = mContext.getContentResolver();
+ Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1);
+ Settings.Global.putLong(resolver,
+ Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100);
+ Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 1);
+
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
+ mDct.enableApn(ApnSetting.TYPE_IMS, DcTracker.REQUEST_TYPE_NORMAL);
+ mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL);
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
+ verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
+ eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
+ mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+ eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
+ any(Message.class));
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, LTE_BEARER_BITMASK);
+
+ logd("Sending EVENT_NETWORK_STATUS_CHANGED false");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
+ NetworkAgent.INVALID_NETWORK, 0, null));
+ waitForMs(200);
+
+ // expected tear down all DataConnections
+ verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall(
+ eq(DataService.REQUEST_REASON_NORMAL), anyInt(),
+ any(Message.class));
+
+ // reset the setting at the end of this test
+ Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);
+ waitForMs(200);
+ }
+
+
+ @Test
+ @SmallTest
+ public void testRecoveryStepReRegister() throws Exception {
+ ContentResolver resolver = mContext.getContentResolver();
+ Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1);
+ Settings.Global.putLong(resolver,
+ Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100);
+ Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 2);
+
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
+ mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL);
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
+ verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
+ eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
+ mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+ eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
+ any(Message.class));
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, LTE_BEARER_BITMASK);
+
+ logd("Sending EVENT_NETWORK_STATUS_CHANGED false");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
+ NetworkAgent.INVALID_NETWORK, 0, null));
+ waitForMs(200);
+
+ // expected to get preferred network type
+ verify(mSST, times(1)).reRegisterNetwork(eq(null));
+
+ // reset the setting at the end of this test
+ Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);
+ }
+
+ @Test
+ @SmallTest
+ public void testRecoveryStepRestartRadio() throws Exception {
+ ContentResolver resolver = mContext.getContentResolver();
+ Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1);
+ Settings.Global.putLong(resolver,
+ Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS, 100);
+ Settings.System.putInt(resolver, "radio.data.stall.recovery.action", 3);
+
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
+ mDct.enableApn(ApnSetting.TYPE_DEFAULT, DcTracker.REQUEST_TYPE_NORMAL);
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
+ verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
+ eq(ServiceState.rilRadioTechnologyToAccessNetworkType(
+ mServiceState.getRilDataRadioTechnology())), dpCaptor.capture(),
+ eq(false), eq(false), eq(DataService.REQUEST_REASON_NORMAL), any(),
+ any(Message.class));
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 21, 1, LTE_BEARER_BITMASK);
+
+ logd("Sending EVENT_NETWORK_STATUS_CHANGED false");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
+ NetworkAgent.INVALID_NETWORK, 0, null));
+ waitForMs(200);
+
+ // expected to get preferred network type
+ verify(mSST, times(1)).powerOffRadioSafely();
+
+ // reset the setting at the end of this test
+ Settings.Global.putInt(resolver, Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 0);
+ }
+
private void verifyDataEnabledChangedMessage(boolean enabled, int reason) {
verify(mHandler, times(1)).sendMessageDelayed(any(), anyLong());
Pair<Boolean, Integer> result = (Pair) ((AsyncResult) mMessage.obj).result;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
index 8521369..49fe5bc 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
@@ -20,7 +20,7 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import android.content.Context;
@@ -113,12 +113,12 @@
doAnswer(invocation -> {
mNetworkRequestList.add((NetworkRequest) invocation.getArguments()[0]);
return null;
- }).when(mDcTracker).requestNetwork(any(), any());
+ }).when(mDcTracker).requestNetwork(any(), anyInt(), any());
doAnswer(invocation -> {
mNetworkRequestList.remove((NetworkRequest) invocation.getArguments()[0]);
return null;
- }).when(mDcTracker).releaseNetwork(any(), any(), anyBoolean());
+ }).when(mDcTracker).releaseNetwork(any(), anyInt(), any());
}
@After
@@ -149,9 +149,6 @@
mTelephonyNetworkFactoryUT = new TelephonyNetworkFactory(mSubscriptionMonitorMock, mLooper,
mPhone);
-
- replaceInstance(TelephonyNetworkFactory.class, "mDcTracker",
- mTelephonyNetworkFactoryUT, mDcTracker);
}
/**
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
index 95f1b3a..6b987b7 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
@@ -35,9 +35,11 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
-import android.hardware.radio.V1_0.SetupDataCallResult;
+import android.net.LinkAddress;
+import android.net.NetworkUtils;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
+import android.telephony.data.DataCallResponse;
import android.telephony.ims.ImsCallSession;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.feature.MmTelFeature;
@@ -70,6 +72,7 @@
import org.mockito.Mock;
import java.lang.reflect.Method;
+import java.util.Arrays;
public class TelephonyMetricsTest extends TelephonyTest {
@@ -390,21 +393,22 @@
@Test
@SmallTest
public void testWriteOnSetupDataCallResponse() throws Exception {
- SetupDataCallResult result = new SetupDataCallResult();
- result.status = 5;
- result.suggestedRetryTime = 6;
- result.cid = 7;
- result.active = 8;
- result.type = "IPV4V6";
- result.ifname = FAKE_IFNAME;
- result.addresses = FAKE_ADDRESS;
- result.dnses = FAKE_DNS;
- result.gateways = FAKE_GATEWAY;
- result.pcscf = FAKE_PCSCF_ADDRESS;
- result.mtu = 1440;
+ DataCallResponse response = new DataCallResponse(
+ 5, /* status */
+ 6, /* suggestedRetryTime */
+ 7, /* cid */
+ 8, /* active */
+ "IPV4V6", /* type */
+ FAKE_IFNAME, /* ifname */
+ Arrays.asList(new LinkAddress(
+ NetworkUtils.numericToInetAddress(FAKE_ADDRESS), 0)), /* addresses */
+ Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_DNS)), /* dnses */
+ Arrays.asList(NetworkUtils.numericToInetAddress(FAKE_GATEWAY)), /* gateways */
+ Arrays.asList(FAKE_PCSCF_ADDRESS), /* pcscfs */
+ 1440 /* mtu */);
mMetrics.writeOnRilSolicitedResponse(mPhone.getPhoneId(), 1, 2,
- RIL_REQUEST_SETUP_DATA_CALL, result);
+ RIL_REQUEST_SETUP_DATA_CALL, response);
TelephonyLog log = buildProto();
assertEquals(1, log.events.length);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
index a77588b..9ef18ee 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
@@ -59,6 +59,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.HashMap;
+import java.util.List;
/**
* @hide
@@ -656,7 +657,8 @@
}
@Override
- public boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdownEnabled) {
+ public boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdownEnabled,
+ List<String> lockdownWhitelist) {
throw new RuntimeException("not implemented");
}
@@ -666,6 +668,16 @@
}
@Override
+ public boolean isVpnLockdownEnabled(int userId) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public List<String> getVpnLockdownWhitelist(int userId) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
public int checkMobileProvisioning(int suggestedTimeOutMs) {
throw new RuntimeException("not implemented");
}
@@ -946,6 +958,13 @@
}
@Override
+ public void startNattKeepaliveWithFd(Network network, FileDescriptor fd, int resourceId,
+ int intervalSeconds, Messenger messenger,
+ IBinder binder, String srcAddr, String dstAddr) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
public void stopKeepalive(Network network, int slot) {
throw new RuntimeException("not implemented");
}
@@ -988,4 +1007,19 @@
public NetworkRequest getDefaultRequest() {
throw new RuntimeException("not implemented");
}
+
+ @Override
+ public boolean isCallerCurrentAlwaysOnVpnApp() {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public boolean isCallerCurrentAlwaysOnVpnLockdownApp() {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public boolean getAvoidBadWifi() {
+ return true;
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java
index beeba62..411ed1d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java
@@ -144,6 +144,15 @@
throw new RuntimeException("not implemented");
}
@Override
+ public int addSubInfo(String uniqueId, String displayName, int slotIndex,
+ int subscriptionType) {
+ throw new RuntimeException("not implemented");
+ }
+ @Override
+ public int removeSubInfo(String uniqueId, int subscriptionType) {
+ throw new RuntimeException("not implemented");
+ }
+ @Override
public boolean setPlmnSpn(int slotIndex, boolean showPlmn, String plmn, boolean showSpn,
String spn) {
throw new RuntimeException("not implemented");
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
index 418b46c..d5c6362 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
@@ -22,6 +22,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.telephony.CallQuality;
import android.telephony.CellInfo;
import android.telephony.DataFailCause;
import android.telephony.PhoneCapability;
@@ -367,8 +368,13 @@
}
@Override
+ public void notifyCallQualityChanged(CallQuality callQuality, int phoneId) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ @Override
public void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
- int backgroundCallState) {
+ int backgroundCallState, int phoneId) {
throw new RuntimeException("Not implemented");
}