Merge "Support CDMA call duration reset in telephony connection"
am: cb78596686
Change-Id: I47c7e07142f23784a4a76e6a97919e9bc1930fc4
diff --git a/proto/src/telephony.proto b/proto/src/telephony.proto
index 215d14e..e441f71 100644
--- a/proto/src/telephony.proto
+++ b/proto/src/telephony.proto
@@ -476,6 +476,96 @@
// LCE service not supported
RIL_E_LCE_NOT_SUPPORTED_NEW = 37;
+
+ // Not sufficient memory to process the request
+ RIL_E_NO_MEMORY = 38;
+
+ // Modem hit unexpected error scenario while handling this request
+ RIL_E_INTERNAL_ERR = 39;
+
+ // Hit platform or system error
+ RIL_E_SYSTEM_ERR = 40;
+
+ // Vendor RIL got unexpected or incorrect response from modem for this request
+ RIL_E_MODEM_ERR = 41;
+
+ // Unexpected request for the current state
+ RIL_E_INVALID_STATE = 42;
+
+ // Not sufficient resource to process the request
+ RIL_E_NO_RESOURCES = 43;
+
+ // Received error from SIM card
+ RIL_E_SIM_ERR = 44;
+
+ // Received invalid arguments in request
+ RIL_E_INVALID_ARGUMENTS = 45;
+
+ // Cannot process the request in current SIM state
+ RIL_E_INVALID_SIM_STATE = 46;
+
+ // Cannot process the request in current Modem state
+ RIL_E_INVALID_MODEM_STATE = 47;
+
+ // Received invalid call id in request
+ RIL_E_INVALID_CALL_ID = 48;
+
+ // ACK received when there is no SMS to ack
+ RIL_E_NO_SMS_TO_ACK = 49;
+
+ // Received error from network
+ RIL_E_NETWORK_ERR = 50;
+
+ // Operation denied due to overly-frequent requests
+ RIL_E_REQUEST_RATE_LIMITED = 51;
+
+ // SIM is busy
+ RIL_E_SIM_BUSY = 52;
+
+ // The target EF is full
+ RIL_E_SIM_FULL = 53;
+
+ // Request is rejected by network
+ RIL_E_NETWORK_REJECT = 54;
+
+ // Not allowed the request now
+ RIL_E_OPERATION_NOT_ALLOWED = 55;
+
+ // The request record is empty
+ RIL_E_EMPTY_RECORD = 56;
+
+ // Invalid sms format
+ RIL_E_INVALID_SMS_FORMAT = 57;
+
+ // Message not encoded properly
+ RIL_E_ENCODING_ERR = 58;
+
+ // SMSC address specified is invalid
+ RIL_E_INVALID_SMSC_ADDRESS = 59;
+
+ // No such entry present to perform the request
+ RIL_E_NO_SUCH_ENTRY = 60;
+
+ // Network is not ready to perform the request
+ RIL_E_NETWORK_NOT_READY = 61;
+
+ // Device does not have this value provisioned
+ RIL_E_NOT_PROVISIONED = 62;
+
+ // Device does not have subscription
+ RIL_E_NO_SUBSCRIPTION = 63;
+
+ // Network cannot be found
+ RIL_E_NO_NETWORK_FOUND = 64;
+
+ // Operation cannot be performed because the device is currently in use
+ RIL_E_DEVICE_IN_USE = 65;
+
+ // Operation aborted
+ RIL_E_ABORTED = 66;
+
+ // Invalid response sent by vendor code
+ RIL_E_INVALID_RESPONSE = 67;
}
// PDP_type values in TS 27.007 section 10.1.1.
@@ -553,6 +643,9 @@
// Carrier Identification Matching Event
CARRIER_ID_MATCHING = 13;
+
+ // Carrier Key Change event.
+ CARRIER_KEY_CHANGED = 14;
}
// Setup a packet data connection
@@ -743,6 +836,26 @@
optional RilDataCall call = 3;
}
+ // Carrier Key Change Event.
+ message CarrierKeyChange {
+
+ enum KeyType {
+
+ // Key Type Unknown.
+ UNKNOWN = 0;
+ // Key Type for WLAN.
+ WLAN = 1;
+ // Key Type for EPDG.
+ EPDG = 2;
+ }
+
+ // Key type of the Encryption key.
+ optional KeyType key_type = 1;
+
+ // Whether the download was successful or not.
+ optional bool isDownloadSuccessful = 2;
+ }
+
// Deactivate packet data connection
message RilDeactivateDataCall {
@@ -850,6 +963,9 @@
// Carrier id matching event
optional CarrierIdMatching carrier_id_matching = 16;
+
+ // Carrier key change
+ optional CarrierKeyChange carrier_key_change = 17;
}
enum TimeInterval {
@@ -1229,16 +1345,16 @@
message CBMessage {
// CB message format
- optional Format msgFormat = 1;
+ optional Format msg_format = 1;
// CB message priority
- optional CBPriority msgPriority = 2;
+ optional CBPriority msg_priority = 2;
// Type of CB msg
- optional CBMessageType msgType = 3;
+ optional CBMessageType msg_type = 3;
// Service category of CB message
- optional int32 serviceCategory = 4;
+ optional int32 service_category = 4;
}
enum CBMessageType {
diff --git a/src/java/com/android/internal/telephony/CarrierIdentifier.java b/src/java/com/android/internal/telephony/CarrierIdentifier.java
index 69131ca..1ff8971 100644
--- a/src/java/com/android/internal/telephony/CarrierIdentifier.java
+++ b/src/java/com/android/internal/telephony/CarrierIdentifier.java
@@ -211,11 +211,13 @@
if (mIccRecords != null) {
logd("Removing stale icc objects.");
mIccRecords.unregisterForRecordsLoaded(this);
+ mIccRecords.unregisterForRecordsOverride(this);
mIccRecords = null;
}
if (newIccRecords != null) {
logd("new Icc object");
newIccRecords.registerForRecordsLoaded(this, SIM_LOAD_EVENT, null);
+ newIccRecords.registerForRecordsOverride(this, SIM_LOAD_EVENT, null);
mIccRecords = newIccRecords;
}
}
diff --git a/src/java/com/android/internal/telephony/CarrierInfoManager.java b/src/java/com/android/internal/telephony/CarrierInfoManager.java
index 6a6a065..f645746 100644
--- a/src/java/com/android/internal/telephony/CarrierInfoManager.java
+++ b/src/java/com/android/internal/telephony/CarrierInfoManager.java
@@ -29,6 +29,8 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.telephony.metrics.TelephonyMetrics;
+
import java.util.Date;
/**
@@ -50,30 +52,30 @@
/**
* Returns Carrier specific information that will be used to encrypt the IMSI and IMPI.
* @param keyType whether the key is being used for WLAN or ePDG.
- * @param mContext
+ * @param context
* @return ImsiEncryptionInfo which contains the information, including the public key, to be
* used for encryption.
*/
public static ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType,
- Context mContext) {
+ Context context) {
String mcc = "";
String mnc = "";
final TelephonyManager telephonyManager =
- (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- String networkOperator = telephonyManager.getNetworkOperator();
- if (!TextUtils.isEmpty(networkOperator)) {
- mcc = networkOperator.substring(0, 3);
- mnc = networkOperator.substring(3);
+ (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+ String simOperator = telephonyManager.getSimOperator();
+ if (!TextUtils.isEmpty(simOperator)) {
+ mcc = simOperator.substring(0, 3);
+ mnc = simOperator.substring(3);
Log.i(LOG_TAG, "using values for mnc, mcc: " + mnc + "," + mcc);
} else {
- Log.e(LOG_TAG, "Invalid networkOperator: " + networkOperator);
+ Log.e(LOG_TAG, "Invalid networkOperator: " + simOperator);
return null;
}
Cursor findCursor = null;
try {
// In the current design, MVNOs are not supported. If we decide to support them,
// we'll need to add to this CL.
- ContentResolver mContentResolver = mContext.getContentResolver();
+ ContentResolver mContentResolver = context.getContentResolver();
String[] columns = {Telephony.CarrierColumns.PUBLIC_KEY,
Telephony.CarrierColumns.EXPIRATION_TIME,
Telephony.CarrierColumns.KEY_IDENTIFIER};
@@ -107,12 +109,13 @@
/**
* Inserts or update the Carrier Key in the database
* @param imsiEncryptionInfo ImsiEncryptionInfo object.
- * @param mContext Context.
+ * @param context Context.
*/
public static void updateOrInsertCarrierKey(ImsiEncryptionInfo imsiEncryptionInfo,
- Context mContext) {
+ Context context, int phoneId) {
byte[] keyBytes = imsiEncryptionInfo.getPublicKey().getEncoded();
- ContentResolver mContentResolver = mContext.getContentResolver();
+ ContentResolver mContentResolver = context.getContentResolver();
+ TelephonyMetrics tm = TelephonyMetrics.getInstance();
// In the current design, MVNOs are not supported. If we decide to support them,
// we'll need to add to this CL.
ContentValues contentValues = new ContentValues();
@@ -125,6 +128,7 @@
contentValues.put(Telephony.CarrierColumns.PUBLIC_KEY, keyBytes);
contentValues.put(Telephony.CarrierColumns.EXPIRATION_TIME,
imsiEncryptionInfo.getExpirationTime().getTime());
+ boolean downloadSuccessfull = true;
try {
Log.i(LOG_TAG, "Inserting imsiEncryptionInfo into db");
mContentResolver.insert(Telephony.CarrierColumns.CONTENT_URI, contentValues);
@@ -145,12 +149,17 @@
String.valueOf(imsiEncryptionInfo.getKeyType())});
if (nRows == 0) {
Log.d(LOG_TAG, "Error updating values:" + imsiEncryptionInfo);
+ downloadSuccessfull = false;
}
} catch (Exception ex) {
Log.d(LOG_TAG, "Error updating values:" + imsiEncryptionInfo + ex);
+ downloadSuccessfull = false;
}
} catch (Exception e) {
Log.d(LOG_TAG, "Error inserting/updating values:" + imsiEncryptionInfo + e);
+ downloadSuccessfull = false;
+ } finally {
+ tm.writeCarrierKeyEvent(phoneId, imsiEncryptionInfo.getKeyType(), downloadSuccessfull);
}
}
@@ -162,12 +171,12 @@
* {@link java.security.PublicKey} and the Key Identifier.
* The keyIdentifier Attribute value pair that helps a server locate
* the private key to decrypt the permanent identity.
- * @param mContext Context.
+ * @param context Context.
*/
public static void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo,
- Context mContext) {
+ Context context, int phoneId) {
Log.i(LOG_TAG, "inserting carrier key: " + imsiEncryptionInfo);
- updateOrInsertCarrierKey(imsiEncryptionInfo, mContext);
+ updateOrInsertCarrierKey(imsiEncryptionInfo, context, phoneId);
//todo send key to modem. Will be done in a subsequent CL.
}
diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
index 2f57838..c4c5a30 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
@@ -281,6 +281,7 @@
CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
PersistableBundle b = carrierConfigManager.getConfigForSubId(mPhone.getSubId());
+
for (Map.Entry<Integer, NotificationType> entry : mNotificationTypeMap.entrySet()) {
NotificationType notificationType = entry.getValue();
notificationType.setDelay(b);
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 5dd36ad..2871e3a 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -29,6 +29,7 @@
import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
@@ -1387,7 +1388,11 @@
if (b != null) {
String defaultVmNumber =
b.getString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_STRING);
- if (!TextUtils.isEmpty(defaultVmNumber)) {
+ String defaultVmNumberRoaming =
+ b.getString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_ROAMING_STRING);
+ if (!TextUtils.isEmpty(defaultVmNumberRoaming) && mSST.mSS.getRoaming()) {
+ number = defaultVmNumberRoaming;
+ } else {
number = defaultVmNumber;
}
}
@@ -1504,15 +1509,20 @@
}
@Override
+ @Nullable
public String getSubscriberId() {
- if (isPhoneTypeGsm()) {
- IccRecords r = mIccRecords.get();
- return (r != null) ? r.getIMSI() : null;
- } else if (isPhoneTypeCdma()) {
- return mSST.getImsi();
- } else { //isPhoneTypeCdmaLte()
- return (mSimRecords != null) ? mSimRecords.getIMSI() : "";
+ String subscriberId = null;
+ if (isPhoneTypeCdma()) {
+ subscriberId = mSST.getImsi();
+ } else {
+ // Both Gsm and CdmaLte get the IMSI from Usim.
+ IccRecords iccRecords = mUiccController.getIccRecords(
+ mPhoneId, UiccController.APP_FAM_3GPP);
+ if (iccRecords != null) {
+ subscriberId = iccRecords.getIMSI();
+ }
}
+ return subscriberId;
}
@Override
@@ -1522,7 +1532,7 @@
@Override
public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo) {
- CarrierInfoManager.setCarrierInfoForImsiEncryption(imsiEncryptionInfo, mContext);
+ CarrierInfoManager.setCarrierInfoForImsiEncryption(imsiEncryptionInfo, mContext, mPhoneId);
}
@Override
@@ -1536,13 +1546,13 @@
}
@Override
- public void resetCarrierKeysForImsiEncryption() {
- mCIM.resetCarrierKeysForImsiEncryption(mContext, mPhoneId);
+ public int getCarrierIdListVersion() {
+ return mCarrerIdentifier.getCarrierListVersion();
}
@Override
- public int getCarrierIdListVersion() {
- return mCarrerIdentifier.getCarrierListVersion();
+ public void resetCarrierKeysForImsiEncryption() {
+ mCIM.resetCarrierKeysForImsiEncryption(mContext, mPhoneId);
}
@Override
@@ -2339,14 +2349,14 @@
int current_cdma_roaming_mode =
Settings.Global.getInt(getContext().getContentResolver(),
Settings.Global.CDMA_ROAMING_MODE,
- CarrierConfigManager.CDMA_ROAMING_MODE_RADIO_DEFAULT);
+ TelephonyManager.CDMA_ROAMING_MODE_RADIO_DEFAULT);
switch (config_cdma_roaming_mode) {
// Carrier's cdma_roaming_mode will overwrite the user's previous settings
// Keep the user's previous setting in global variable which will be used
// when carrier's setting is turn off.
- case CarrierConfigManager.CDMA_ROAMING_MODE_HOME:
- case CarrierConfigManager.CDMA_ROAMING_MODE_AFFILIATED:
- case CarrierConfigManager.CDMA_ROAMING_MODE_ANY:
+ case TelephonyManager.CDMA_ROAMING_MODE_HOME:
+ case TelephonyManager.CDMA_ROAMING_MODE_AFFILIATED:
+ case TelephonyManager.CDMA_ROAMING_MODE_ANY:
logd("cdma_roaming_mode is going to changed to "
+ config_cdma_roaming_mode);
setCdmaRoamingPreference(config_cdma_roaming_mode,
@@ -2355,7 +2365,7 @@
// When carrier's setting is turn off, change the cdma_roaming_mode to the
// previous user's setting
- case CarrierConfigManager.CDMA_ROAMING_MODE_RADIO_DEFAULT:
+ case TelephonyManager.CDMA_ROAMING_MODE_RADIO_DEFAULT:
if (current_cdma_roaming_mode != config_cdma_roaming_mode) {
logd("cdma_roaming_mode is going to changed to "
+ current_cdma_roaming_mode);
diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java
index b51498e..2c42033 100644
--- a/src/java/com/android/internal/telephony/InboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java
@@ -794,6 +794,13 @@
int destPort = tracker.getDestPort();
boolean block = false;
+ // Do not process when the message count is invalid.
+ if (messageCount <= 0) {
+ loge("processMessagePart: returning false due to invalid message count "
+ + messageCount);
+ return false;
+ }
+
if (messageCount == 1) {
// single-part message
pdus = new byte[][]{tracker.getPdu()};
@@ -829,6 +836,17 @@
int index = cursor.getInt(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING
.get(SEQUENCE_COLUMN)) - tracker.getIndexOffset();
+ // The invalid PDUs can be received and stored in the raw table. The range
+ // check ensures the process not crash even if the seqNumber in the
+ // UserDataHeader is invalid.
+ if (index >= pdus.length || index < 0) {
+ loge(String.format(
+ "processMessagePart: invalid seqNumber = %d, messageCount = %d",
+ index + tracker.getIndexOffset(),
+ messageCount));
+ continue;
+ }
+
pdus[index] = HexDump.hexStringToByteArray(cursor.getString(
PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING.get(PDU_COLUMN)));
diff --git a/src/java/com/android/internal/telephony/InboundSmsTracker.java b/src/java/com/android/internal/telephony/InboundSmsTracker.java
index c63ccc8..36c6996 100644
--- a/src/java/com/android/internal/telephony/InboundSmsTracker.java
+++ b/src/java/com/android/internal/telephony/InboundSmsTracker.java
@@ -195,7 +195,7 @@
mAddress = cursor.getString(InboundSmsHandler.ADDRESS_COLUMN);
mDisplayAddress = cursor.getString(InboundSmsHandler.DISPLAY_ADDRESS_COLUMN);
- if (cursor.isNull(InboundSmsHandler.COUNT_COLUMN)) {
+ if (cursor.getInt(InboundSmsHandler.COUNT_COLUMN) == 1) {
// single-part message
long rowId = cursor.getLong(InboundSmsHandler.ID_COLUMN);
mReferenceNumber = -1;
@@ -250,8 +250,8 @@
values.put("display_originating_addr", mDisplayAddress);
values.put("reference_number", mReferenceNumber);
values.put("sequence", mSequenceNumber);
- values.put("count", mMessageCount);
}
+ values.put("count", mMessageCount);
values.put("message_body", mMessageBody);
return values;
}
diff --git a/src/java/com/android/internal/telephony/LocaleTracker.java b/src/java/com/android/internal/telephony/LocaleTracker.java
index 8977b03..a18e90f 100644
--- a/src/java/com/android/internal/telephony/LocaleTracker.java
+++ b/src/java/com/android/internal/telephony/LocaleTracker.java
@@ -344,6 +344,7 @@
msg = "getCellInfo: cell info=" + mCellInfo;
if (DBG) log(msg);
mLocalLog.log(msg);
+
if (mCellInfo == null || mCellInfo.size() == 0) {
// If we can't get a valid cell info. Try it again later.
long delay = getCellInfoDelayTime(++mFailCellInfoCount);
@@ -401,7 +402,7 @@
// country of the carrier we see. If we can't see any, reset to 0 so we don't
// broadcast on forbidden channels.
((WifiManager) mPhone.getContext().getSystemService(Context.WIFI_SERVICE))
- .setCountryCode(countryIso, false);
+ .setCountryCode(countryIso);
}
}
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 899f1fc..2682cee 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -536,7 +536,7 @@
// note this is not persisting
WifiManager wM = (WifiManager)
mContext.getSystemService(Context.WIFI_SERVICE);
- wM.setCountryCode(country, false);
+ wM.setCountryCode(country);
}
}
diff --git a/src/java/com/android/internal/telephony/PhoneInternalInterface.java b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
index 91b7b28..123914e 100644
--- a/src/java/com/android/internal/telephony/PhoneInternalInterface.java
+++ b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
@@ -22,14 +22,14 @@
import android.os.Message;
import android.os.ResultReceiver;
import android.os.WorkSource;
-import android.telephony.CarrierConfigManager;
import android.telecom.VideoProfile;
import android.telephony.CellLocation;
import android.telephony.ImsiEncryptionInfo;
import android.telephony.NetworkScanRequest;
import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
-import com.android.internal.telephony.PhoneConstants.*; // ????
+import com.android.internal.telephony.PhoneConstants.DataState;
import java.util.List;
@@ -212,11 +212,11 @@
// Used for CDMA roaming mode
// Home Networks only, as defined in PRL
- static final int CDMA_RM_HOME = CarrierConfigManager.CDMA_ROAMING_MODE_HOME;
+ int CDMA_RM_HOME = TelephonyManager.CDMA_ROAMING_MODE_HOME;
// Roaming an Affiliated networks, as defined in PRL
- static final int CDMA_RM_AFFILIATED = CarrierConfigManager.CDMA_ROAMING_MODE_AFFILIATED;
+ int CDMA_RM_AFFILIATED = TelephonyManager.CDMA_ROAMING_MODE_AFFILIATED;
// Roaming on Any Network, as defined in PRL
- static final int CDMA_RM_ANY = CarrierConfigManager.CDMA_ROAMING_MODE_ANY;
+ int CDMA_RM_ANY = TelephonyManager.CDMA_ROAMING_MODE_ANY;
// Used for CDMA subscription mode
static final int CDMA_SUBSCRIPTION_UNKNOWN =-1; // Unknown
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 9f7ea05..143b1c9 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 The Android Open Source Project
+ * Copyright (C) 2006 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.
@@ -127,6 +127,7 @@
*/
public class RIL extends BaseCommands implements CommandsInterface {
static final String RILJ_LOG_TAG = "RILJ";
+ static final String RILJ_WAKELOCK_TAG = "*telephony-radio*";
// Have a separate wakelock instance for Ack
static final String RILJ_ACK_WAKELOCK_NAME = "RILJ_ACK_WL";
static final boolean RILJ_LOGD = true;
@@ -468,7 +469,7 @@
mRadioProxyDeathRecipient = new RadioProxyDeathRecipient();
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, RILJ_LOG_TAG);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, RILJ_WAKELOCK_TAG);
mWakeLock.setReferenceCounted(false);
mAckWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, RILJ_ACK_WAKELOCK_NAME);
mAckWakeLock.setReferenceCounted(false);
@@ -4259,13 +4260,6 @@
return workSource;
}
- private String getWorkSourceClientId(WorkSource workSource) {
- if (workSource != null) {
- return String.valueOf(workSource.get(0)) + ":" + workSource.getName(0);
- }
-
- return null;
- }
/**
* Holds a PARTIAL_WAKE_LOCK whenever
@@ -4289,7 +4283,7 @@
mWakeLockCount++;
mWlSequenceNum++;
- String clientId = getWorkSourceClientId(rr.mWorkSource);
+ String clientId = rr.getWorkSourceClientId();
if (!mClientWakelockTracker.isClientActive(clientId)) {
if (mActiveWakelockWorkSource != null) {
mActiveWakelockWorkSource.add(rr.mWorkSource);
@@ -4351,7 +4345,7 @@
mClientWakelockTracker.stopTracking(rr.mClientId,
rr.mRequest, rr.mSerial,
(mWakeLockCount > 1) ? mWakeLockCount - 1 : 0);
- String clientId = getWorkSourceClientId(rr.mWorkSource);;
+ String clientId = rr.getWorkSourceClientId();
if (!mClientWakelockTracker.isClientActive(clientId)
&& (mActiveWakelockWorkSource != null)) {
mActiveWakelockWorkSource.remove(rr.mWorkSource);
diff --git a/src/java/com/android/internal/telephony/RILRequest.java b/src/java/com/android/internal/telephony/RILRequest.java
index d20ce22..2464cc3 100644
--- a/src/java/com/android/internal/telephony/RILRequest.java
+++ b/src/java/com/android/internal/telephony/RILRequest.java
@@ -20,8 +20,10 @@
import android.os.Message;
import android.os.SystemClock;
import android.os.WorkSource;
+import android.os.WorkSource.WorkChain;
import android.telephony.Rlog;
+import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
@@ -111,13 +113,14 @@
* @param workSource WorkSource to track the client
* @return a RILRequest instance from the pool.
*/
- static RILRequest obtain(int request, Message result, WorkSource workSource) {
+ // @VisibleForTesting
+ public static RILRequest obtain(int request, Message result, WorkSource workSource) {
RILRequest rr = null;
rr = obtain(request, result);
if (workSource != null) {
rr.mWorkSource = workSource;
- rr.mClientId = String.valueOf(workSource.get(0)) + ":" + workSource.getName(0);
+ rr.mClientId = rr.getWorkSourceClientId();
} else {
Rlog.e(LOG_TAG, "null workSource " + request);
}
@@ -126,6 +129,28 @@
}
/**
+ * Generate a String client ID from the WorkSource.
+ */
+ // @VisibleForTesting
+ public String getWorkSourceClientId() {
+ if (mWorkSource == null || mWorkSource.isEmpty()) {
+ return null;
+ }
+
+ if (mWorkSource.size() > 0) {
+ return mWorkSource.get(0) + ":" + mWorkSource.getName(0);
+ }
+
+ final ArrayList<WorkChain> workChains = mWorkSource.getWorkChains();
+ if (workChains != null && !workChains.isEmpty()) {
+ final WorkChain workChain = workChains.get(0);
+ return workChain.getAttributionUid() + ":" + workChain.getTags()[0];
+ }
+
+ return null;
+ }
+
+ /**
* Returns a RILRequest instance to the pool.
*
* Note: This should only be called once per use.
diff --git a/src/java/com/android/internal/telephony/RadioConfig.java b/src/java/com/android/internal/telephony/RadioConfig.java
index 764fc10..c258f6c 100644
--- a/src/java/com/android/internal/telephony/RadioConfig.java
+++ b/src/java/com/android/internal/telephony/RadioConfig.java
@@ -50,7 +50,6 @@
private static final boolean DBG = true;
private static final boolean VDBG = false; //STOPSHIP if true
- private static final String RADIO_CONFIG_SERVICE_NAME = "radioconfig";
private static final int EVENT_SERVICE_DEAD = 1;
private final boolean mIsMobileNetworkSupported;
@@ -167,7 +166,7 @@
}
try {
- mRadioConfigProxy = IRadioConfig.getService(RADIO_CONFIG_SERVICE_NAME, true);
+ mRadioConfigProxy = IRadioConfig.getService(true);
if (mRadioConfigProxy != null) {
mRadioConfigProxy.linkToDeath(mServiceDeathRecipient,
mRadioConfigProxyCookie.incrementAndGet());
diff --git a/src/java/com/android/internal/telephony/RatRatcheter.java b/src/java/com/android/internal/telephony/RatRatcheter.java
index 3745182..6b76414 100644
--- a/src/java/com/android/internal/telephony/RatRatcheter.java
+++ b/src/java/com/android/internal/telephony/RatRatcheter.java
@@ -124,9 +124,9 @@
int newDataRat = ratchetRat(oldSS.getRilDataRadioTechnology(),
newSS.getRilDataRadioTechnology());
newSS.setRilDataRadioTechnology(newDataRat);
- } else if (oldSS.getRilVoiceRadioTechnology() != newSS.getRilVoiceRadioTechnology()) {
+ } else if (oldSS.getRilDataRadioTechnology() != newSS.getRilDataRadioTechnology()) {
// resume rat ratchet on following rat change within the same location
- mVoiceRatchetEnabled = true;
+ mDataRatchetEnabled = true;
}
boolean newUsingCA = oldSS.isUsingCarrierAggregation()
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index b572934..f05471f 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -79,6 +79,7 @@
import android.util.LocalLog;
import android.util.Pair;
import android.util.SparseArray;
+import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.TimestampedValue;
@@ -2917,6 +2918,9 @@
if (hasRilDataRadioTechnologyChanged) {
tm.setDataNetworkTypeForPhone(mPhone.getPhoneId(), mSS.getRilDataRadioTechnology());
+ StatsLog.write(StatsLog.MOBILE_RADIO_TECHNOLOGY_CHANGED,
+ ServiceState.rilRadioTechnologyToNetworkType(mSS.getRilDataRadioTechnology()),
+ mPhone.getPhoneId());
if (ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
== mSS.getRilDataRadioTechnology()) {
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index c16ba7d..4a08445 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -393,20 +393,12 @@
ContentResolver contentResolver = mContext.getContentResolver();
if (msisdn != null) {
- ContentValues number = new ContentValues(1);
- number.put(SubscriptionManager.NUMBER, msisdn);
- contentResolver.update(SubscriptionManager.CONTENT_URI, number,
- SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "="
- + Long.toString(subId), null);
-
- // refresh Cached Active Subscription Info List
- SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList();
+ SubscriptionController.getInstance().setDisplayNumber(msisdn, subId);
}
SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
String nameToSet;
String simCarrierName = tm.getSimOperatorName(subId);
- ContentValues name = new ContentValues(1);
if (subInfo != null && subInfo.getNameSource() !=
SubscriptionManager.NAME_SOURCE_USER_INPUT) {
@@ -415,14 +407,8 @@
} else {
nameToSet = "CARD " + Integer.toString(slotId + 1);
}
- name.put(SubscriptionManager.DISPLAY_NAME, nameToSet);
logd("sim name = " + nameToSet);
- contentResolver.update(SubscriptionManager.CONTENT_URI, name,
- SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID
- + "=" + Long.toString(subId), null);
-
- // refresh Cached Active Subscription Info List
- SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList();
+ SubscriptionController.getInstance().setDisplayName(nameToSet, subId);
}
/* Update preferred network type and network selection mode on SIM change.
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index dc8d9fa..856f39f 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -181,6 +181,7 @@
return IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
}
+
public LocaleTracker makeLocaleTracker(Phone phone, Looper looper) {
return new LocaleTracker(phone, looper);
}
diff --git a/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java b/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java
index 1294762..a87cbf1 100644
--- a/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java
+++ b/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java
@@ -95,6 +95,7 @@
* Wrapper to combine multiple PDU into an SMS message
*/
private static class FullMessage {
+
public SmsMessage firstMessage;
public String fullMessageBody;
}
@@ -143,7 +144,7 @@
WrappedMessageData messageData = VisualVoicemailSmsParser
.parseAlternativeFormat(asciiMessage);
if (messageData != null) {
- sendVvmSmsBroadcast(context, phoneAccountHandle, messageData, null);
+ sendVvmSmsBroadcast(context, settings, phoneAccountHandle, messageData, null);
}
// Confidence for what the message actually is is low. Don't remove the message and let
// system decide. Usually because it is not parsable it will be dropped.
@@ -177,7 +178,7 @@
return false;
}
- sendVvmSmsBroadcast(context, phoneAccountHandle, messageData, null);
+ sendVvmSmsBroadcast(context, settings, phoneAccountHandle, messageData, null);
return true;
}
@@ -193,7 +194,7 @@
if (pattern.matcher(messageBody).matches()) {
Log.w(TAG, "Incoming SMS matches pattern " + pattern + " but has illegal format, "
+ "still dropping as VVM SMS");
- sendVvmSmsBroadcast(context, phoneAccountHandle, null, messageBody);
+ sendVvmSmsBroadcast(context, settings, phoneAccountHandle, null, messageBody);
return true;
}
}
@@ -233,7 +234,8 @@
}
}
- private static void sendVvmSmsBroadcast(Context context, PhoneAccountHandle phoneAccountHandle,
+ private static void sendVvmSmsBroadcast(Context context,
+ VisualVoicemailSmsFilterSettings filterSettings, PhoneAccountHandle phoneAccountHandle,
@Nullable WrappedMessageData messageData, @Nullable String messageBody) {
Log.i(TAG, "VVM SMS received");
Intent intent = new Intent(VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED);
@@ -247,6 +249,7 @@
}
builder.setPhoneAccountHandle(phoneAccountHandle);
intent.putExtra(VoicemailContract.EXTRA_VOICEMAIL_SMS, builder.build());
+ intent.putExtra(VoicemailContract.EXTRA_TARGET_PACKAGE, filterSettings.packageName);
intent.setPackage(TELEPHONY_SERVICE_PACKAGE);
context.sendBroadcast(intent);
}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index 00af9fe..c392e27 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -52,6 +52,7 @@
import android.util.LocalLog;
import android.util.Pair;
import android.util.SparseArray;
+import android.util.StatsLog;
import android.util.TimeUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -1475,6 +1476,12 @@
public void enter() {
mTag += 1;
if (DBG) log("DcInactiveState: enter() mTag=" + mTag);
+ StatsLog.write(StatsLog.MOBILE_CONNECTION_STATE_CHANGED,
+ StatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__INACTIVE,
+ mPhone.getPhoneId(), mId,
+ mApnSetting != null ? (long) mApnSetting.getApnTypeBitmask() : 0L,
+ mApnSetting != null
+ ? mApnSetting.canHandleType(ApnSetting.TYPE_DEFAULT) : false);
if (mConnectionParams != null) {
if (DBG) {
@@ -1565,6 +1572,15 @@
*/
private class DcActivatingState extends State {
@Override
+ public void enter() {
+ StatsLog.write(StatsLog.MOBILE_CONNECTION_STATE_CHANGED,
+ StatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__ACTIVATING,
+ mPhone.getPhoneId(), mId,
+ mApnSetting != null ? (long) mApnSetting.getApnTypeBitmask() : 0L,
+ mApnSetting != null
+ ? mApnSetting.canHandleType(ApnSetting.TYPE_DEFAULT) : false);
+ }
+ @Override
public boolean processMessage(Message msg) {
boolean retVal;
AsyncResult ar;
@@ -1672,6 +1688,12 @@
@Override public void enter() {
if (DBG) log("DcActiveState: enter dc=" + DataConnection.this);
+ StatsLog.write(StatsLog.MOBILE_CONNECTION_STATE_CHANGED,
+ StatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__ACTIVE,
+ mPhone.getPhoneId(), mId,
+ mApnSetting != null ? (long) mApnSetting.getApnTypeBitmask() : 0L,
+ mApnSetting != null
+ ? mApnSetting.canHandleType(ApnSetting.TYPE_DEFAULT) : false);
updateNetworkInfo();
@@ -1979,6 +2001,15 @@
*/
private class DcDisconnectingState extends State {
@Override
+ public void enter() {
+ StatsLog.write(StatsLog.MOBILE_CONNECTION_STATE_CHANGED,
+ StatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__DISCONNECTING,
+ mPhone.getPhoneId(), mId,
+ mApnSetting != null ? (long) mApnSetting.getApnTypeBitmask() : 0L,
+ mApnSetting != null
+ ? mApnSetting.canHandleType(ApnSetting.TYPE_DEFAULT) : false);
+ }
+ @Override
public boolean processMessage(Message msg) {
boolean retVal;
@@ -2028,6 +2059,15 @@
*/
private class DcDisconnectionErrorCreatingConnection extends State {
@Override
+ public void enter() {
+ StatsLog.write(StatsLog.MOBILE_CONNECTION_STATE_CHANGED,
+ StatsLog.MOBILE_CONNECTION_STATE_CHANGED__STATE__DISCONNECTION_ERROR_CREATING_CONNECTION,
+ mPhone.getPhoneId(), mId,
+ mApnSetting != null ? (long) mApnSetting.getApnTypeBitmask() : 0L,
+ mApnSetting != null
+ ? mApnSetting.canHandleType(ApnSetting.TYPE_DEFAULT) : false);
+ }
+ @Override
public boolean processMessage(Message msg) {
boolean retVal;
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java b/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java
index 8c3f751..5e01686 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java
@@ -16,10 +16,18 @@
package com.android.internal.telephony.dataconnection;
+import static android.telephony.AccessNetworkConstants.TransportType.WLAN;
+import static android.telephony.AccessNetworkConstants.TransportType.WWAN;
+
+import android.annotation.NonNull;
+import android.app.AppOpsManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.net.LinkProperties;
import android.os.AsyncResult;
import android.os.Handler;
@@ -28,7 +36,7 @@
import android.os.PersistableBundle;
import android.os.RegistrantList;
import android.os.RemoteException;
-import android.telephony.AccessNetworkConstants;
+import android.os.ServiceManager;
import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
import android.telephony.data.DataCallResponse;
@@ -41,8 +49,10 @@
import com.android.internal.telephony.Phone;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -58,6 +68,8 @@
private final Phone mPhone;
private final CarrierConfigManager mCarrierConfigManager;
+ private final AppOpsManager mAppOps;
+ private final IPackageManager mPackageManager;
private final int mTransportType;
@@ -73,14 +85,10 @@
private final RegistrantList mDataCallListChangedRegistrants = new RegistrantList();
+ // not final because it is set by the onServiceConnected method
+ private ComponentName mComponentName;
+
private class DataServiceManagerDeathRecipient implements IBinder.DeathRecipient {
-
- private final ComponentName mComponentName;
-
- DataServiceManagerDeathRecipient(ComponentName name) {
- mComponentName = name;
- }
-
@Override
public void binderDied() {
// TODO: try to rebind the service.
@@ -89,12 +97,53 @@
}
}
+ private void grantPermissionsToService(String packageName) {
+ final String[] pkgToGrant = {packageName};
+ try {
+ mPackageManager.grantDefaultPermissionsToEnabledTelephonyDataServices(
+ pkgToGrant, mPhone.getContext().getUserId());
+ mAppOps.setMode(AppOpsManager.OP_MANAGE_IPSEC_TUNNELS, mPhone.getContext().getUserId(),
+ pkgToGrant[0], AppOpsManager.MODE_ALLOWED);
+ } catch (RemoteException e) {
+ loge("Binder to package manager died, permission grant for DataService failed.");
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Loop through all DataServices installed on the system and revoke permissions from any that
+ * are not currently the WWAN or WLAN data service.
+ */
+ private void revokePermissionsFromUnusedDataServices() {
+ // Except the current data services from having their permissions removed.
+ Set<String> dataServices = getAllDataServicePackageNames();
+ for (int transportType : new int[] {WWAN, WLAN}) {
+ dataServices.remove(getDataServicePackageName(transportType));
+ }
+
+ try {
+ String[] dataServicesArray = new String[dataServices.size()];
+ dataServices.toArray(dataServicesArray);
+ mPackageManager.revokeDefaultPermissionsFromDisabledTelephonyDataServices(
+ dataServicesArray, mPhone.getContext().getUserId());
+ for (String pkg : dataServices) {
+ mAppOps.setMode(AppOpsManager.OP_MANAGE_IPSEC_TUNNELS,
+ mPhone.getContext().getUserId(),
+ pkg, AppOpsManager.MODE_ERRORED);
+ }
+ } catch (RemoteException e) {
+ loge("Binder to package manager died; failed to revoke DataService permissions.");
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
private final class CellularDataServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DBG) log("onServiceConnected");
+ mComponentName = name;
mIDataService = IDataService.Stub.asInterface(service);
- mDeathRecipient = new DataServiceManagerDeathRecipient(name);
+ mDeathRecipient = new DataServiceManagerDeathRecipient();
mBound = true;
try {
@@ -186,16 +235,22 @@
mBound = false;
mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService(
Context.CARRIER_CONFIG_SERVICE);
-
+ mPackageManager = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+ mAppOps = (AppOpsManager) phone.getContext().getSystemService(Context.APP_OPS_SERVICE);
bindDataService();
}
private void bindDataService() {
+ // Start by cleaning up all packages that *shouldn't* have permissions.
+ revokePermissionsFromUnusedDataServices();
+
String packageName = getDataServicePackageName();
if (TextUtils.isEmpty(packageName)) {
loge("Can't find the binding package");
return;
}
+ // Then pre-emptively grant the permissions to the package we will bind.
+ grantPermissionsToService(packageName);
try {
if (!mPhone.getContext().bindService(
@@ -209,18 +264,55 @@
}
}
+ @NonNull
+ private Set<String> getAllDataServicePackageNames() {
+ // Cowardly using the public PackageManager interface here.
+ // Note: This matches only packages that were installed on the system image. If we ever
+ // expand the permissions model to allow CarrierPrivileged packages, then this will need
+ // to be updated.
+ List<ResolveInfo> dataPackages =
+ mPhone.getContext().getPackageManager().queryIntentServices(
+ new Intent(DataService.DATA_SERVICE_INTERFACE),
+ PackageManager.MATCH_SYSTEM_ONLY);
+ HashSet<String> packageNames = new HashSet<>();
+ for (ResolveInfo info : dataPackages) {
+ if (info.serviceInfo == null) continue;
+ packageNames.add(info.serviceInfo.packageName);
+ }
+ return packageNames;
+ }
+
+ /**
+ * Get the data service package name for our current transport type.
+ *
+ * @return package name of the data service package for the the current transportType.
+ */
private String getDataServicePackageName() {
+ return getDataServicePackageName(mTransportType);
+ }
+
+ /**
+ * Get the data service package by transport type.
+ *
+ * When we bind to a DataService package, we need to revoke permissions from stale
+ * packages; we need to exclude data packages for all transport types, so we need to
+ * to be able to query by transport type.
+ *
+ * @param transportType either WWAN or WLAN
+ * @return package name of the data service package for the specified transportType.
+ */
+ private String getDataServicePackageName(int transportType) {
String packageName;
int resourceId;
String carrierConfig;
- switch (mTransportType) {
- case AccessNetworkConstants.TransportType.WWAN:
+ switch (transportType) {
+ case WWAN:
resourceId = com.android.internal.R.string.config_wwan_data_service_package;
carrierConfig = CarrierConfigManager
.KEY_CARRIER_DATA_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING;
break;
- case AccessNetworkConstants.TransportType.WLAN:
+ case WLAN:
resourceId = com.android.internal.R.string.config_wlan_data_service_package;
carrierConfig = CarrierConfigManager
.KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING;
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index 50130c8..8d9cb59 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony.dataconnection;
+import static android.Manifest.permission.READ_PHONE_STATE;
+
import android.annotation.NonNull;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -4538,11 +4540,20 @@
if (VDBG_STALL) log("putRecoveryAction: " + action);
}
+ 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);
+ }
+
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);
+
switch (recoveryAction) {
case RecoveryAction.GET_DATA_CALL_LIST:
EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST,
diff --git a/src/java/com/android/internal/telephony/euicc/EuiccCardController.java b/src/java/com/android/internal/telephony/euicc/EuiccCardController.java
index d3c59a3..5c5d244 100644
--- a/src/java/com/android/internal/telephony/euicc/EuiccCardController.java
+++ b/src/java/com/android/internal/telephony/euicc/EuiccCardController.java
@@ -220,6 +220,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getAllProfiles callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getAllProfiles callback failure.", exception);
@@ -258,6 +259,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getProfile callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getProfile callback failure.", exception);
@@ -296,6 +298,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("disableProfile callback onException: ", e);
callback.onComplete(getResultCode(e));
} catch (RemoteException exception) {
loge("disableProfile callback failure.", exception);
@@ -338,6 +341,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("switchToProfile callback onException: ", e);
callback.onComplete(getResultCode(e), profile);
} catch (RemoteException exception) {
loge("switchToProfile callback failure.", exception);
@@ -351,6 +355,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getProfile in switchToProfile callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("switchToProfile callback failure.", exception);
@@ -389,6 +394,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("setNickname callback onException: ", e);
callback.onComplete(getResultCode(e));
} catch (RemoteException exception) {
loge("setNickname callback failure.", exception);
@@ -417,19 +423,19 @@
AsyncResultCallback<Void> cardCb = new AsyncResultCallback<Void>() {
@Override
public void onResult(Void result) {
- SubscriptionController.getInstance().requestEmbeddedSubscriptionInfoListRefresh(
- () -> {
- try {
- callback.onComplete(EuiccCardManager.RESULT_OK);
- } catch (RemoteException exception) {
- loge("deleteProfile callback failure.", exception);
- }
- });
+ Log.i(TAG, "Request subscription info list refresh after delete.");
+ SubscriptionController.getInstance().requestEmbeddedSubscriptionInfoListRefresh();
+ try {
+ callback.onComplete(EuiccCardManager.RESULT_OK);
+ } catch (RemoteException exception) {
+ loge("deleteProfile callback failure.", exception);
+ }
};
@Override
public void onException(Throwable e) {
try {
+ loge("deleteProfile callback onException: ", e);
callback.onComplete(getResultCode(e));
} catch (RemoteException exception) {
loge("deleteProfile callback failure.", exception);
@@ -458,19 +464,19 @@
AsyncResultCallback<Void> cardCb = new AsyncResultCallback<Void>() {
@Override
public void onResult(Void result) {
- SubscriptionController.getInstance().requestEmbeddedSubscriptionInfoListRefresh(
- () -> {
- try {
- callback.onComplete(EuiccCardManager.RESULT_OK);
- } catch (RemoteException exception) {
- loge("resetMemory callback failure.", exception);
- }
- });
+ Log.i(TAG, "Request subscription info list refresh after reset memory.");
+ SubscriptionController.getInstance().requestEmbeddedSubscriptionInfoListRefresh();
+ try {
+ callback.onComplete(EuiccCardManager.RESULT_OK);
+ } catch (RemoteException exception) {
+ loge("resetMemory callback failure.", exception);
+ }
}
@Override
public void onException(Throwable e) {
try {
+ loge("resetMemory callback onException: ", e);
callback.onComplete(getResultCode(e));
} catch (RemoteException exception) {
loge("resetMemory callback failure.", exception);
@@ -509,6 +515,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getDefaultSmdpAddress callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getDefaultSmdpAddress callback failure.", exception);
@@ -547,6 +554,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getSmdsAddress callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getSmdsAddress callback failure.", exception);
@@ -585,6 +593,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("setDefaultSmdpAddress callback onException: ", e);
callback.onComplete(getResultCode(e));
} catch (RemoteException exception) {
loge("setDefaultSmdpAddress callback failure.", exception);
@@ -624,6 +633,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getRulesAuthTable callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getRulesAuthTable callback failure.", exception);
@@ -662,6 +672,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getEuiccChallenge callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getEuiccChallenge callback failure.", exception);
@@ -700,6 +711,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getEuiccInfo1 callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getEuiccInfo1 callback failure.", exception);
@@ -738,6 +750,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getEuiccInfo2 callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getEuiccInfo2 callback failure.", exception);
@@ -777,6 +790,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("authenticateServer callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("authenticateServer callback failure.", exception);
@@ -817,6 +831,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("prepareDownload callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("prepareDownload callback failure.", exception);
@@ -846,19 +861,19 @@
AsyncResultCallback<byte[]> cardCb = new AsyncResultCallback<byte[]>() {
@Override
public void onResult(byte[] result) {
- SubscriptionController.getInstance().requestEmbeddedSubscriptionInfoListRefresh(
- () -> {
- try {
- callback.onComplete(EuiccCardManager.RESULT_OK, result);
- } catch (RemoteException exception) {
- loge("loadBoundProfilePackage callback failure.", exception);
- }
- });
+ Log.i(TAG, "Request subscription info list refresh after install.");
+ SubscriptionController.getInstance().requestEmbeddedSubscriptionInfoListRefresh();
+ try {
+ callback.onComplete(EuiccCardManager.RESULT_OK, result);
+ } catch (RemoteException exception) {
+ loge("loadBoundProfilePackage callback failure.", exception);
+ }
}
@Override
public void onException(Throwable e) {
try {
+ loge("loadBoundProfilePackage callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("loadBoundProfilePackage callback failure.", exception);
@@ -897,6 +912,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("cancelSession callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("cancelSession callback failure.", exception);
@@ -936,6 +952,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("listNotifications callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("listNotifications callback failure.", exception);
@@ -975,6 +992,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("retrieveNotificationList callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("retrieveNotificationList callback failure.", exception);
@@ -1014,6 +1032,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("retrieveNotification callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("retrieveNotification callback failure.", exception);
@@ -1053,6 +1072,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("removeNotificationFromList callback onException: ", e);
callback.onComplete(getResultCode(e));
} catch (RemoteException exception) {
loge("removeNotificationFromList callback failure.", exception);
diff --git a/src/java/com/android/internal/telephony/euicc/EuiccController.java b/src/java/com/android/internal/telephony/euicc/EuiccController.java
index 8c1b81e..ca36cf0 100644
--- a/src/java/com/android/internal/telephony/euicc/EuiccController.java
+++ b/src/java/com/android/internal/telephony/euicc/EuiccController.java
@@ -24,6 +24,7 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ComponentInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Binder;
@@ -984,6 +985,10 @@
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public void sendOtaStatusChangedBroadcast() {
Intent intent = new Intent(EuiccManager.ACTION_OTA_STATUS_CHANGED);
+ ComponentInfo bestComponent = mConnector.findBestComponent(mContext.getPackageManager());
+ if (bestComponent != null) {
+ intent.setPackage(bestComponent.packageName);
+ }
mContext.sendBroadcast(intent, permission.WRITE_EMBEDDED_SUBSCRIPTIONS);
}
diff --git a/src/java/com/android/internal/telephony/gsm/GsmCellBroadcastHandler.java b/src/java/com/android/internal/telephony/gsm/GsmCellBroadcastHandler.java
index dec9805..f30b386 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmCellBroadcastHandler.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmCellBroadcastHandler.java
@@ -78,6 +78,7 @@
handleBroadcastSms(cbMessage);
return true;
}
+ if (VDBG) log("Not handled GSM broadcasts.");
}
return super.handleSmsMessage(message);
}
@@ -106,6 +107,7 @@
}
SmsCbHeader header = new SmsCbHeader(receivedPdu);
+ if (VDBG) log("header=" + header);
String plmn = TelephonyManager.from(mContext).getNetworkOperatorForPhone(
mPhone.getPhoneId());
int lac = -1;
@@ -154,12 +156,14 @@
mSmsCbPageMap.put(concatInfo, pdus);
}
+ if (VDBG) log("pdus size=" + pdus.length);
// Page parameter is one-based
pdus[header.getPageIndex() - 1] = receivedPdu;
for (byte[] pdu : pdus) {
if (pdu == null) {
// Still missing pages, exit
+ log("still missing pdu");
return null;
}
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index eb77a93..94b771f 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -312,6 +312,7 @@
@VisibleForTesting
public void setServiceState(int state) {
boolean isVoiceRegStateChanged = false;
+
synchronized (this) {
isVoiceRegStateChanged = mSS.getVoiceRegState() != state;
mSS.setVoiceRegState(state);
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
index e573fbd..7361e70 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
@@ -499,9 +499,6 @@
return false;
}
- public void saveClirSetting(int commandInterfaceCLIRMode) {
- }
-
@Override
public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
return null;
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index f32b74c..77ee27a 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -25,7 +25,10 @@
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
+import android.net.NetworkRequest;
import android.net.NetworkStats;
import android.net.Uri;
import android.os.AsyncResult;
@@ -243,6 +246,24 @@
}
};
+ /**
+ * Tracks whether we are currently monitoring network connectivity for the purpose of warning
+ * the user of an inability to handover from LTE to WIFI for video calls.
+ */
+ private boolean mIsMonitoringConnectivity = false;
+
+ /**
+ * Network callback used to schedule the handover check when a wireless network connects.
+ */
+ private ConnectivityManager.NetworkCallback mNetworkCallback =
+ new ConnectivityManager.NetworkCallback() {
+ @Override
+ public void onAvailable(Network network) {
+ Rlog.i(LOG_TAG, "Network available: " + network);
+ scheduleHandoverCheck();
+ }
+ };
+
//***** Constants
static final int MAX_CONNECTIONS = 7;
@@ -598,6 +619,22 @@
private boolean mNotifyHandoverVideoFromWifiToLTE = false;
/**
+ * Carrier configuration option which determines whether the carrier wants to inform the user
+ * when a video call is handed over from LTE to WIFI.
+ * See {@link CarrierConfigManager#KEY_NOTIFY_HANDOVER_VIDEO_FROM_LTE_TO_WIFI_BOOL} for more
+ * information.
+ */
+ private boolean mNotifyHandoverVideoFromLTEToWifi = false;
+
+ /**
+ * When {@code} false, indicates that no handover from LTE to WIFI has occurred during the start
+ * of the call.
+ * When {@code true}, indicates that the start of call handover from LTE to WIFI has been
+ * attempted (it may have suceeded or failed).
+ */
+ private boolean mHasPerformedStartOfCallHandover = false;
+
+ /**
* Carrier configuration option which determines whether the carrier supports the
* {@link VideoProfile#STATE_PAUSED} signalling.
* See {@link CarrierConfigManager#KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL} for more information.
@@ -1032,6 +1069,16 @@
}
mCarrierConfigLoaded = true;
+ updateCarrierConfigCache(carrierConfig);
+ }
+
+ /**
+ * Updates the local carrier config cache from a bundle obtained from the carrier config
+ * manager. Also supports unit testing by injecting configuration at test time.
+ * @param carrierConfig The config bundle.
+ */
+ @VisibleForTesting
+ public void updateCarrierConfigCache(PersistableBundle carrierConfig) {
mAllowEmergencyVideoCalls =
carrierConfig.getBoolean(CarrierConfigManager.KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL);
mTreatDowngradedVideoCallsAsVideoCalls =
@@ -1049,6 +1096,8 @@
CarrierConfigManager.KEY_SUPPORT_DOWNGRADE_VT_TO_AUDIO_BOOL);
mNotifyHandoverVideoFromWifiToLTE = carrierConfig.getBoolean(
CarrierConfigManager.KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL);
+ mNotifyHandoverVideoFromLTEToWifi = carrierConfig.getBoolean(
+ CarrierConfigManager.KEY_NOTIFY_HANDOVER_VIDEO_FROM_LTE_TO_WIFI_BOOL);
mIgnoreDataEnabledChangedForVideoCalls = carrierConfig.getBoolean(
CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS);
mIsViLteDataMetered = carrierConfig.getBoolean(
@@ -2116,13 +2165,18 @@
processCallStateChange(imsCall, ImsPhoneCall.State.ACTIVE,
DisconnectCause.NOT_DISCONNECTED);
- if (mNotifyVtHandoverToWifiFail &&
- !imsCall.isWifiCall() && imsCall.isVideoCall() && isWifiConnected()) {
- // Schedule check to see if handover succeeded.
- sendMessageDelayed(obtainMessage(EVENT_CHECK_FOR_WIFI_HANDOVER, imsCall),
- HANDOVER_TO_WIFI_TIMEOUT_MS);
+ if (mNotifyVtHandoverToWifiFail && imsCall.isVideoCall() && !imsCall.isWifiCall()) {
+ if (isWifiConnected()) {
+ // Schedule check to see if handover succeeded.
+ sendMessageDelayed(obtainMessage(EVENT_CHECK_FOR_WIFI_HANDOVER, imsCall),
+ HANDOVER_TO_WIFI_TIMEOUT_MS);
+ } else {
+ // No wifi connectivity, so keep track of network availability for potential
+ // handover.
+ registerForConnectivityChanges();
+ }
}
-
+ mHasPerformedStartOfCallHandover = false;
mMetrics.writeOnImsCallStarted(mPhone.getPhoneId(), imsCall.getCallSession());
}
@@ -2607,18 +2661,35 @@
boolean isHandoverToWifi = srcAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN
&& srcAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
&& targetAccessTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
- if (isHandoverToWifi) {
- // If we handed over to wifi successfully, don't check for failure in the future.
- removeMessages(EVENT_CHECK_FOR_WIFI_HANDOVER);
- }
+ // Only consider it a handover from WIFI if the source and target radio tech is known.
+ boolean isHandoverFromWifi =
+ srcAccessTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
+ && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN
+ && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
ImsPhoneConnection conn = findConnection(imsCall);
if (conn != null) {
- // Only consider it a handover from WIFI if the source and target radio tech is known.
- boolean isHandoverFromWifi =
- srcAccessTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
- && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN
- && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
+ if (conn.getDisconnectCause() == DisconnectCause.NOT_DISCONNECTED) {
+ if (isHandoverToWifi) {
+ removeMessages(EVENT_CHECK_FOR_WIFI_HANDOVER);
+
+ if (mNotifyHandoverVideoFromLTEToWifi && mHasPerformedStartOfCallHandover) {
+ // This is a handover which happened mid-call (ie not the start of call
+ // handover from LTE to WIFI), so we'll notify the InCall UI.
+ conn.onConnectionEvent(
+ TelephonyManager.EVENT_HANDOVER_VIDEO_FROM_LTE_TO_WIFI, null);
+ }
+
+ // We are on WIFI now so no need to get notified of network availability.
+ unregisterForConnectivityChanges();
+ } else if (isHandoverFromWifi && imsCall.isVideoCall()) {
+ // A video call just dropped from WIFI to LTE; we want to be informed if a
+ // new WIFI
+ // network comes into range.
+ registerForConnectivityChanges();
+ }
+ }
+
if (isHandoverFromWifi && imsCall.isVideoCall()) {
if (mNotifyHandoverVideoFromWifiToLTE && mIsDataEnabled) {
if (conn.getDisconnectCause() == DisconnectCause.NOT_DISCONNECTED) {
@@ -2644,6 +2715,9 @@
loge("onCallHandover :: connection null.");
}
+ if (!mHasPerformedStartOfCallHandover) {
+ mHasPerformedStartOfCallHandover = true;
+ }
mMetrics.writeOnImsCallHandoverEvent(mPhone.getPhoneId(),
TelephonyCallSession.Event.Type.IMS_CALL_HANDOVER, imsCall.getCallSession(),
srcAccessTech, targetAccessTech, reasonInfo);
@@ -2669,11 +2743,20 @@
// If we know we failed to handover, don't check for failure in the future.
removeMessages(EVENT_CHECK_FOR_WIFI_HANDOVER);
+ if (imsCall.isVideoCall()
+ && conn.getDisconnectCause() == DisconnectCause.NOT_DISCONNECTED) {
+ // Start listening for a WIFI network to come into range for potential handover.
+ registerForConnectivityChanges();
+ }
+
if (mNotifyVtHandoverToWifiFail) {
// Only notify others if carrier config indicates to do so.
conn.onHandoverToWifiFailed();
}
}
+ if (!mHasPerformedStartOfCallHandover) {
+ mHasPerformedStartOfCallHandover = true;
+ }
}
@Override
@@ -2747,6 +2830,8 @@
public void onCallTerminated(ImsCall imsCall, ImsReasonInfo reasonInfo) {
if (DBG) log("mImsUssdListener onCallTerminated reasonCode=" + reasonInfo.getCode());
removeMessages(EVENT_CHECK_FOR_WIFI_HANDOVER);
+ mHasPerformedStartOfCallHandover = false;
+ unregisterForConnectivityChanges();
if (imsCall == mUssdSession) {
mUssdSession = null;
@@ -3029,12 +3114,24 @@
case EVENT_CHECK_FOR_WIFI_HANDOVER:
if (msg.obj instanceof ImsCall) {
ImsCall imsCall = (ImsCall) msg.obj;
+ if (imsCall != mForegroundCall.getImsCall()) {
+ Rlog.i(LOG_TAG, "handoverCheck: no longer FG; check skipped.");
+ unregisterForConnectivityChanges();
+ // Handover check and its not the foreground call any more.
+ return;
+ }
if (!imsCall.isWifiCall()) {
// Call did not handover to wifi, notify of handover failure.
ImsPhoneConnection conn = findConnection(imsCall);
if (conn != null) {
+ Rlog.i(LOG_TAG, "handoverCheck: handover failed.");
conn.onHandoverToWifiFailed();
}
+
+ if (imsCall.isVideoCall()
+ && conn.getDisconnectCause() == DisconnectCause.NOT_DISCONNECTED) {
+ registerForConnectivityChanges();
+ }
}
}
break;
@@ -3698,8 +3795,66 @@
}
/**
- * @return {@code true} if downgrading of a video call to audio is supported.
+ * Registers for changes to network connectivity. Specifically requests the availability of new
+ * WIFI networks which an IMS video call could potentially hand over to.
*/
+ private void registerForConnectivityChanges() {
+ if (mIsMonitoringConnectivity || !mNotifyVtHandoverToWifiFail) {
+ return;
+ }
+ ConnectivityManager cm = (ConnectivityManager) mPhone.getContext()
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (cm != null) {
+ Rlog.i(LOG_TAG, "registerForConnectivityChanges");
+ NetworkCapabilities capabilities = new NetworkCapabilities();
+ capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+ NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ builder.setCapabilities(capabilities);
+ cm.registerNetworkCallback(builder.build(), mNetworkCallback);
+ mIsMonitoringConnectivity = true;
+ }
+ }
+
+ /**
+ * Unregister for connectivity changes. Will be called when a call disconnects or if the call
+ * ends up handing over to WIFI.
+ */
+ private void unregisterForConnectivityChanges() {
+ if (!mIsMonitoringConnectivity || !mNotifyVtHandoverToWifiFail) {
+ return;
+ }
+ ConnectivityManager cm = (ConnectivityManager) mPhone.getContext()
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (cm != null) {
+ Rlog.i(LOG_TAG, "unregisterForConnectivityChanges");
+ cm.unregisterNetworkCallback(mNetworkCallback);
+ mIsMonitoringConnectivity = false;
+ }
+ }
+
+ /**
+ * If the foreground call is a video call, schedule a handover check if one is not already
+ * scheduled. This method is intended ONLY for use when scheduling to watch for mid-call
+ * handovers.
+ */
+ private void scheduleHandoverCheck() {
+ ImsCall fgCall = mForegroundCall.getImsCall();
+ ImsPhoneConnection conn = mForegroundCall.getFirstConnection();
+ if (!mNotifyVtHandoverToWifiFail || fgCall == null || !fgCall.isVideoCall() || conn == null
+ || conn.getDisconnectCause() != DisconnectCause.NOT_DISCONNECTED) {
+ return;
+ }
+
+ if (!hasMessages(EVENT_CHECK_FOR_WIFI_HANDOVER)) {
+ Rlog.i(LOG_TAG, "scheduleHandoverCheck: schedule");
+ sendMessageDelayed(obtainMessage(EVENT_CHECK_FOR_WIFI_HANDOVER, fgCall),
+ HANDOVER_TO_WIFI_TIMEOUT_MS);
+ }
+ }
+
+ /**
+ * @return {@code true} if downgrading of a video call to audio is supported.
+ */
public boolean isCarrierDowngradeOfVtCallSupported() {
return mSupportDowngradeVtToAudio;
}
@@ -3719,6 +3874,7 @@
}
sb.append(capabilities);
mMmTelCapabilities = new MmTelFeature.MmTelCapabilities(capabilities);
+
boolean isVideoEnabled = isVideoCallEnabled();
boolean isVideoEnabledStatechanged = tmpIsVideoCallEnabled != isVideoEnabled;
if (DBG) {
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java b/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
index d28c035..e06ead2 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
@@ -21,6 +21,7 @@
import static com.android.internal.telephony.nano.TelephonyProto.RilDataCall;
import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierIdMatching;
+import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierKeyChange;
import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.ModemRestart;
import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCall;
@@ -126,4 +127,10 @@
mEvent.carrierIdMatching = carrierIdMatching;
return this;
}
+
+ public TelephonyEventBuilder setCarrierKeyChange(CarrierKeyChange carrierKeyChange) {
+ mEvent.type = TelephonyEvent.Type.CARRIER_KEY_CHANGED;
+ mEvent.carrierKeyChange = carrierKeyChange;
+ return this;
+ }
}
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
index 8b9d580..a436d25 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
@@ -44,14 +44,14 @@
import android.telephony.TelephonyManager;
import android.telephony.data.DataCallResponse;
import android.telephony.data.DataService;
+import android.telephony.ims.ImsCallSession;
+import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.text.TextUtils;
import android.util.Base64;
import android.util.SparseArray;
-import android.telephony.ims.ImsReasonInfo;
-import android.telephony.ims.ImsCallSession;
import com.android.internal.telephony.GsmCdmaConnection;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RIL;
@@ -62,6 +62,7 @@
import com.android.internal.telephony.nano.TelephonyProto;
import com.android.internal.telephony.nano.TelephonyProto.ImsCapabilities;
import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
+import com.android.internal.telephony.nano.TelephonyProto.ModemPowerStats;
import com.android.internal.telephony.nano.TelephonyProto.RilDataCall;
import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
@@ -71,6 +72,7 @@
import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierIdMatching;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierIdMatchingResult;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.CarrierKeyChange;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.ModemRestart;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall.DeactivateReason;
@@ -78,7 +80,6 @@
import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse.RilDataCallFailCause;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyLog;
-import com.android.internal.telephony.nano.TelephonyProto.ModemPowerStats;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState;
import com.android.internal.telephony.nano.TelephonyProto.TelephonySettings;
import com.android.internal.telephony.nano.TelephonyProto.TimeInterval;
@@ -534,7 +535,6 @@
log.endTime = new TelephonyProto.Time();
log.endTime.systemTimestampMillis = System.currentTimeMillis();
log.endTime.elapsedTimestampMillis = SystemClock.elapsedRealtime();
-
return log;
}
@@ -550,6 +550,23 @@
}
/**
+ * Write the Carrier Key change event
+ *
+ * @param phoneId Phone id
+ * @param keyType type of key
+ * @param isDownloadSuccessful true if the key was successfully downloaded
+ */
+ public void writeCarrierKeyEvent(int phoneId, int keyType, boolean isDownloadSuccessful) {
+ final CarrierKeyChange carrierKeyChange = new CarrierKeyChange();
+ carrierKeyChange.keyType = keyType;
+ carrierKeyChange.isDownloadSuccessful = isDownloadSuccessful;
+ TelephonyEvent event = new TelephonyEventBuilder(phoneId).setCarrierKeyChange(
+ carrierKeyChange).build();
+ addTelephonyEvent(event);
+ }
+
+
+ /**
* Get the time interval with reduced prevision
*
* @param previousTimestamp Previous timestamp in milliseconds
@@ -1854,4 +1871,4 @@
public void writeOnImsCallResumeFailed(int phoneId, ImsCallSession session,
ImsReasonInfo reasonInfo) {}
public void writeOnRilTimeoutResponse(int phoneId, int rilSerial, int rilRequest) {}
-}
\ No newline at end of file
+}
diff --git a/src/java/com/android/internal/telephony/uicc/CarrierAppInstallReceiver.java b/src/java/com/android/internal/telephony/uicc/CarrierAppInstallReceiver.java
new file mode 100644
index 0000000..22e4e2c
--- /dev/null
+++ b/src/java/com/android/internal/telephony/uicc/CarrierAppInstallReceiver.java
@@ -0,0 +1,47 @@
+/*
+ * 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.uicc;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * Hides the carrier app install notification if the correct packages are installed
+ */
+public class CarrierAppInstallReceiver extends BroadcastReceiver {
+ private static final String LOG_TAG = "CarrierAppInstall";
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
+ Log.d(LOG_TAG, "Received package install intent");
+ String intentPackageName = intent.getData().getSchemeSpecificPart();
+ if (TextUtils.isEmpty(intentPackageName)) {
+ Log.w(LOG_TAG, "Package is empty, ignoring");
+ return;
+ }
+
+ InstallCarrierAppUtils.hideNotification(context, intentPackageName);
+
+ if (!InstallCarrierAppUtils.isPackageInstallNotificationActive(context)) {
+ InstallCarrierAppUtils.unregisterPackageInstallReceiver(context);
+ }
+ }
+ }
+}
diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java
index 6a630d6..97d497c 100644
--- a/src/java/com/android/internal/telephony/uicc/IccRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java
@@ -62,6 +62,7 @@
protected RegistrantList mNewSmsRegistrants = new RegistrantList();
protected RegistrantList mNetworkSelectionModeAutomaticRegistrants = new RegistrantList();
protected RegistrantList mSpnUpdatedRegistrants = new RegistrantList();
+ protected RegistrantList mRecordsOverrideRegistrants = new RegistrantList();
protected int mRecordsToLoad; // number of pending load requests
@@ -218,7 +219,7 @@
mCarrierTestOverride.override(mccmnc, imsi, iccid, gid1, gid2, pnn, spn);
mTelephonyManager.setSimOperatorNameForPhone(mParentApp.getPhoneId(), spn);
mTelephonyManager.setSimOperatorNumericForPhone(mParentApp.getPhoneId(), mccmnc);
- mRecordsLoadedRegistrants.notifyRegistrants();
+ mRecordsOverrideRegistrants.notifyRegistrants();
}
/**
@@ -308,10 +309,28 @@
r.notifyRegistrant(new AsyncResult(null, null, null));
}
}
+
public void unregisterForRecordsLoaded(Handler h) {
mRecordsLoadedRegistrants.remove(h);
}
+ public void unregisterForRecordsOverride(Handler h) {
+ mRecordsOverrideRegistrants.remove(h);
+ }
+
+ public void registerForRecordsOverride(Handler h, int what, Object obj) {
+ if (mDestroyed.get()) {
+ return;
+ }
+
+ Registrant r = new Registrant(h, what, obj);
+ mRecordsOverrideRegistrants.add(r);
+
+ if (getRecordsLoaded()) {
+ r.notifyRegistrant(new AsyncResult(null, null, null));
+ }
+ }
+
/**
* Register to be notified when records are loaded for a PIN or PUK locked SIM
*/
diff --git a/src/java/com/android/internal/telephony/uicc/InstallCarrierAppTrampolineActivity.java b/src/java/com/android/internal/telephony/uicc/InstallCarrierAppTrampolineActivity.java
new file mode 100644
index 0000000..2c29266
--- /dev/null
+++ b/src/java/com/android/internal/telephony/uicc/InstallCarrierAppTrampolineActivity.java
@@ -0,0 +1,120 @@
+/*
+ * 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.uicc;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Trampoline activity used to start the full screen dialog that is shown when a SIM is inserted
+ * and requires a carrier app download
+ */
+public class InstallCarrierAppTrampolineActivity extends Activity {
+ private static final String LOG_TAG = "CarrierAppInstall";
+ private static final int INSTALL_CARRIER_APP_DIALOG_REQUEST = 1;
+
+ // TODO(b/73648962): Move DOWNLOAD_RESULT and CARRIER_NAME to a shared location
+ /**
+ * This must remain in sync with
+ * {@link com.android.simappdialog.InstallCarrierAppActivity#DOWNLOAD_RESULT}
+ */
+ private static final int DOWNLOAD_RESULT = 2;
+
+ /**
+ * This must remain in sync with
+ * {@link com.android.simappdialog.InstallCarrierAppActivity#BUNDLE_KEY_CARRIER_NAME}
+ */
+ private static final String CARRIER_NAME = "carrier_name";
+
+ /** Bundle key for the name of the package to be downloaded */
+ private static final String BUNDLE_KEY_PACKAGE_NAME = "package_name";
+
+ /** Returns intent used to start this activity */
+ public static Intent get(Context context, String packageName) {
+ Intent intent = new Intent(context, InstallCarrierAppTrampolineActivity.class);
+ intent.putExtra(BUNDLE_KEY_PACKAGE_NAME, packageName);
+ return intent;
+ }
+
+ private String mPackageName;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Intent intent = getIntent();
+ if (intent != null) {
+ mPackageName = intent.getStringExtra(BUNDLE_KEY_PACKAGE_NAME);
+ }
+
+ // If this is the first activity creation, show notification after delay regardless of
+ // result code, but only if the app is not installed.
+ if (savedInstanceState == null) {
+ long sleepTimeMillis = Settings.Global.getLong(getContentResolver(),
+ Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS,
+ TimeUnit.HOURS.toMillis(24));
+ Log.d(LOG_TAG, "Sleeping carrier app install notification for : " + sleepTimeMillis
+ + " millis");
+ InstallCarrierAppUtils.showNotificationIfNotInstalledDelayed(
+ this,
+ mPackageName,
+ sleepTimeMillis);
+ }
+
+ // Display dialog activity if available
+ Intent showDialogIntent = new Intent();
+ ComponentName dialogComponentName = ComponentName.unflattenFromString(
+ Resources.getSystem().getString(
+ com.android.internal.R.string.config_carrierAppInstallDialogComponent));
+ showDialogIntent.setComponent(dialogComponentName);
+ String appName = InstallCarrierAppUtils.getAppNameFromPackageName(this, mPackageName);
+ if (!TextUtils.isEmpty(appName)) {
+ showDialogIntent.putExtra(CARRIER_NAME, appName);
+ }
+
+ if (showDialogIntent.resolveActivity(getPackageManager()) == null) {
+ Log.d(LOG_TAG, "Could not resolve activity for installing the carrier app");
+ finishNoAnimation();
+ } else {
+ startActivityForResult(showDialogIntent, INSTALL_CARRIER_APP_DIALOG_REQUEST);
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == INSTALL_CARRIER_APP_DIALOG_REQUEST) {
+ if (resultCode == DOWNLOAD_RESULT) {
+ startActivity(InstallCarrierAppUtils.getPlayStoreIntent(mPackageName));
+ }
+ finishNoAnimation();
+ }
+ }
+
+ private void finishNoAnimation() {
+ finish();
+ overridePendingTransition(0, 0);
+ }
+}
diff --git a/src/java/com/android/internal/telephony/uicc/InstallCarrierAppUtils.java b/src/java/com/android/internal/telephony/uicc/InstallCarrierAppUtils.java
new file mode 100644
index 0000000..325b3c6
--- /dev/null
+++ b/src/java/com/android/internal/telephony/uicc/InstallCarrierAppUtils.java
@@ -0,0 +1,208 @@
+/*
+ * 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.uicc;
+
+import static android.content.Context.ALARM_SERVICE;
+
+import android.app.AlarmManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
+import android.text.TextUtils;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.util.NotificationChannelController;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Utility methods for installing the carrier app when a SIM is insterted without the carrier app
+ * for that SIM installed.
+ */
+@VisibleForTesting
+public class InstallCarrierAppUtils {
+ // TODO(b/72714040) centralize notification IDs
+ private static final int ACTIVATE_CELL_SERVICE_NOTIFICATION_ID = 12;
+ private static CarrierAppInstallReceiver sCarrierAppInstallReceiver = null;
+
+ static void showNotification(Context context, String pkgName) {
+ Resources res = Resources.getSystem();
+ String title = res.getString(
+ com.android.internal.R.string.install_carrier_app_notification_title);
+ String appName = getAppNameFromPackageName(context, pkgName);
+ String message;
+ if (TextUtils.isEmpty(appName)) {
+ message = res.getString(R.string.install_carrier_app_notification_text);
+ } else {
+ message = res.getString(R.string.install_carrier_app_notification_text_app_name,
+ appName);
+ }
+ String downloadButtonText = res.getString(R.string.install_carrier_app_notification_button);
+
+ boolean persistent = Settings.Global.getInt(
+ context.getContentResolver(),
+ Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT, 1) == 1;
+
+ PendingIntent goToStore = PendingIntent.getActivity(context, 0,
+ getPlayStoreIntent(pkgName), PendingIntent.FLAG_UPDATE_CURRENT);
+
+ Notification.Action goToStoreAction =
+ new Notification.Action.Builder(null, downloadButtonText, goToStore).build();
+
+ Notification notification = new Notification.Builder(context,
+ NotificationChannelController.CHANNEL_ID_SIM)
+ .setContentTitle(title)
+ .setContentText(message)
+ .setSmallIcon(R.drawable.ic_signal_cellular_alt_24px)
+ .addAction(goToStoreAction)
+ .setOngoing(persistent)
+ .setVisibility(Notification.VISIBILITY_SECRET) // Should not appear on lock screen
+ .build();
+
+ getNotificationManager(context).notify(
+ pkgName,
+ ACTIVATE_CELL_SERVICE_NOTIFICATION_ID,
+ notification);
+ }
+
+ static void hideAllNotifications(Context context) {
+ NotificationManager notificationManager = getNotificationManager(context);
+ StatusBarNotification[] activeNotifications = notificationManager.getActiveNotifications();
+
+ if (activeNotifications == null) {
+ return;
+ }
+
+ for (StatusBarNotification notification : activeNotifications) {
+ if (notification.getId() == ACTIVATE_CELL_SERVICE_NOTIFICATION_ID) {
+ notificationManager.cancel(notification.getTag(), notification.getId());
+ }
+ }
+ }
+
+ static void hideNotification(Context context, String pkgName) {
+ getNotificationManager(context).cancel(pkgName, ACTIVATE_CELL_SERVICE_NOTIFICATION_ID);
+ }
+
+ static Intent getPlayStoreIntent(String pkgName) {
+ // Open play store to download package
+ Intent storeIntent = new Intent(Intent.ACTION_VIEW);
+ storeIntent.setData(Uri.parse("market://details?id=" + pkgName));
+ storeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ return storeIntent;
+ }
+
+ static void showNotificationIfNotInstalledDelayed(Context context,
+ String pkgName, long delayMillis) {
+ AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ context,
+ 0,
+ ShowInstallAppNotificationReceiver.get(context, pkgName),
+ 0);
+ alarmManager.set(AlarmManager.ELAPSED_REALTIME,
+ SystemClock.elapsedRealtime() + delayMillis,
+ pendingIntent);
+
+ }
+
+ static void registerPackageInstallReceiver(Context context) {
+ if (sCarrierAppInstallReceiver == null) {
+ sCarrierAppInstallReceiver = new CarrierAppInstallReceiver();
+ context = context.getApplicationContext();
+ IntentFilter intentFilter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addDataScheme("package");
+ context.registerReceiver(sCarrierAppInstallReceiver, intentFilter);
+ }
+ }
+
+ static void unregisterPackageInstallReceiver(Context context) {
+ if (sCarrierAppInstallReceiver == null) {
+ return;
+ }
+ context = context.getApplicationContext();
+ context.unregisterReceiver(sCarrierAppInstallReceiver);
+ sCarrierAppInstallReceiver = null;
+ }
+
+ static boolean isPackageInstallNotificationActive(Context context) {
+ StatusBarNotification[] activeNotifications =
+ getNotificationManager(context).getActiveNotifications();
+
+ for (StatusBarNotification notification : activeNotifications) {
+ if (notification.getId() == ACTIVATE_CELL_SERVICE_NOTIFICATION_ID) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static String getAppNameFromPackageName(Context context, String packageName) {
+ String whitelistSetting = Settings.Global.getString(
+ context.getContentResolver(),
+ Settings.Global.CARRIER_APP_NAMES);
+ return getAppNameFromPackageName(packageName, whitelistSetting);
+ }
+
+ /**
+ * @param packageName the name of the package. Will be used as a key into the map
+ * @param mapString map of package name to application name in the format:
+ * packageName1:appName1;packageName2:appName2;
+ * @return the name of the application for the package name provided.
+ */
+ @VisibleForTesting
+ public static String getAppNameFromPackageName(String packageName, String mapString) {
+ packageName = packageName.toLowerCase();
+ final String pairDelim = "\\s*;\\s*";
+ final String keyValueDelim = "\\s*:\\s*";
+
+ if (TextUtils.isEmpty(mapString)) {
+ return null;
+ }
+
+ List<String> keyValuePairList = Arrays.asList(mapString.split(pairDelim));
+
+ if (keyValuePairList.isEmpty()) {
+ return null;
+ }
+
+ for (String keyValueString: keyValuePairList) {
+ String[] keyValue = keyValueString.split(keyValueDelim);
+
+ if (keyValue.length == 2) {
+ if (keyValue[0].equals(packageName)) {
+ return keyValue[1];
+ }
+ }
+ }
+ return null;
+ }
+ private static NotificationManager getNotificationManager(Context context) {
+ return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+}
diff --git a/src/java/com/android/internal/telephony/uicc/ShowInstallAppNotificationReceiver.java b/src/java/com/android/internal/telephony/uicc/ShowInstallAppNotificationReceiver.java
new file mode 100644
index 0000000..6c89448
--- /dev/null
+++ b/src/java/com/android/internal/telephony/uicc/ShowInstallAppNotificationReceiver.java
@@ -0,0 +1,46 @@
+/*
+ * 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.uicc;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Receiver used to show a notification that prompts the user to install the package (contained in
+ * string extras) from the play store
+ */
+public class ShowInstallAppNotificationReceiver extends BroadcastReceiver {
+ private static final String EXTRA_PACKAGE_NAME = "package_name";
+
+ /** Returns intent used to send a broadcast to this receiver */
+ public static Intent get(Context context, String pkgName) {
+ Intent intent = new Intent(context, ShowInstallAppNotificationReceiver.class);
+ intent.putExtra(EXTRA_PACKAGE_NAME, pkgName);
+ return intent;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String pkgName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
+
+ if (!UiccProfile.isPackageInstalled(context, pkgName)) {
+ InstallCarrierAppUtils.showNotification(context, pkgName);
+ InstallCarrierAppUtils.registerPackageInstallReceiver(context);
+ }
+ }
+}
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
index 6620d83..a45c247 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
@@ -36,6 +36,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
@@ -250,6 +251,16 @@
}
/**
+ * Returns list of access rules.
+ */
+ public List<UiccAccessRule> getAccessRules() {
+ if (mAccessRules == null) {
+ return Collections.emptyList();
+ }
+ return Collections.unmodifiableList(mAccessRules);
+ }
+
+ /**
* Returns the status of the carrier privileges for the input certificate and package name.
*
* @param signature The signature of the certificate.
diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
index f7aeaa1..a0eb8d9 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 The Android Open Source Project
+ * 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.
@@ -16,18 +16,16 @@
package com.android.internal.telephony.uicc;
-import android.app.AlertDialog;
import android.app.usage.UsageStatsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
-import android.content.res.Resources;
+import android.database.ContentObserver;
import android.net.Uri;
import android.os.AsyncResult;
import android.os.Binder;
@@ -44,10 +42,11 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.UiccAccessRule;
import android.text.TextUtils;
-import android.view.WindowManager;
+import android.util.ArrayMap;
+import android.util.ArraySet;
-import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.IccCard;
@@ -66,8 +65,10 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
-import java.util.HashSet;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* This class represents the carrier profiles in the {@link UiccCard}. Each profile contains
@@ -134,6 +135,17 @@
private IccRecords mIccRecords = null;
private IccCardConstants.State mExternalState = IccCardConstants.State.UNKNOWN;
+ private final ContentObserver mProvisionCompleteContentObserver =
+ new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mContext.getContentResolver().unregisterContentObserver(this);
+ for (String pkgName : getUninstalledCarrierPackages()) {
+ InstallCarrierAppUtils.showNotification(mContext, pkgName);
+ InstallCarrierAppUtils.registerPackageInstallReceiver(mContext);
+ }
+ }
+ };
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -186,7 +198,7 @@
case EVENT_CARRIER_PRIVILEGES_LOADED:
if (VDBG) log("handleMessage: EVENT_CARRIER_PRIVILEGES_LOADED");
- onCarrierPriviligesLoadedMessage();
+ onCarrierPrivilegesLoadedMessage();
updateExternalState();
break;
@@ -256,6 +268,9 @@
unregisterAllAppEvents();
unregisterCurrAppEvents();
+ InstallCarrierAppUtils.hideAllNotifications(mContext);
+ InstallCarrierAppUtils.unregisterPackageInstallReceiver(mContext);
+
mCi.unregisterForOffOrNotAvailable(mHandler);
mContext.unregisterReceiver(mReceiver);
@@ -1085,8 +1100,8 @@
mCarrierPrivilegeRegistrants.remove(h);
}
}
-
- /**
+
+ /**
* Unregister for notifications when operator brand name is overriden.
*
* @param h Handler to be removed from the registrant list.
@@ -1097,8 +1112,8 @@
}
}
- private boolean isPackageInstalled(String pkgName) {
- PackageManager pm = mContext.getPackageManager();
+ static boolean isPackageInstalled(Context context, String pkgName) {
+ PackageManager pm = context.getPackageManager();
try {
pm.getPackageInfo(pkgName, PackageManager.GET_ACTIVITIES);
if (DBG) log(pkgName + " is installed.");
@@ -1109,72 +1124,97 @@
}
}
- private class ClickListener implements DialogInterface.OnClickListener {
- String mPkgName;
- ClickListener(String pkgName) {
- this.mPkgName = pkgName;
- }
- @Override
- public void onClick(DialogInterface dialog, int which) {
- synchronized (mLock) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- Intent market = new Intent(Intent.ACTION_VIEW);
- market.setData(Uri.parse("market://details?id=" + mPkgName));
- market.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(market);
- } else if (which == DialogInterface.BUTTON_NEGATIVE) {
- if (DBG) log("Not now clicked for carrier app dialog.");
- }
- }
- }
- }
-
private void promptInstallCarrierApp(String pkgName) {
- DialogInterface.OnClickListener listener = new ClickListener(pkgName);
-
- Resources r = Resources.getSystem();
- String message = r.getString(R.string.carrier_app_dialog_message);
- String buttonTxt = r.getString(R.string.carrier_app_dialog_button);
- String notNowTxt = r.getString(R.string.carrier_app_dialog_not_now);
-
- AlertDialog dialog = new AlertDialog.Builder(mContext)
- .setMessage(message)
- .setNegativeButton(notNowTxt, listener)
- .setPositiveButton(buttonTxt, listener)
- .create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
- dialog.show();
+ Intent showDialogIntent = InstallCarrierAppTrampolineActivity.get(mContext, pkgName);
+ mContext.startActivity(showDialogIntent);
}
- private void onCarrierPriviligesLoadedMessage() {
+ private void onCarrierPrivilegesLoadedMessage() {
UsageStatsManager usm = (UsageStatsManager) mContext.getSystemService(
Context.USAGE_STATS_SERVICE);
if (usm != null) {
usm.onCarrierPrivilegedAppsChanged();
}
+
+ InstallCarrierAppUtils.hideAllNotifications(mContext);
+ InstallCarrierAppUtils.unregisterPackageInstallReceiver(mContext);
+
synchronized (mLock) {
mCarrierPrivilegeRegistrants.notifyRegistrants();
- String whitelistSetting = Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.CARRIER_APP_WHITELIST);
- if (TextUtils.isEmpty(whitelistSetting)) {
- return;
- }
- HashSet<String> carrierAppSet = new HashSet<String>(
- Arrays.asList(whitelistSetting.split("\\s*;\\s*")));
- if (carrierAppSet.isEmpty()) {
- return;
- }
-
- List<String> pkgNames = mCarrierPrivilegeRules.getPackageNames();
- for (String pkgName : pkgNames) {
- if (!TextUtils.isEmpty(pkgName) && carrierAppSet.contains(pkgName)
- && !isPackageInstalled(pkgName)) {
+ boolean isProvisioned = Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 1) == 1;
+ // Only show dialog if the phone is through with Setup Wizard. Otherwise, wait for
+ // completion and show a notification instead
+ if (isProvisioned) {
+ for (String pkgName : getUninstalledCarrierPackages()) {
promptInstallCarrierApp(pkgName);
}
+ } else {
+ final Uri uri = Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED);
+ mContext.getContentResolver().registerContentObserver(
+ uri,
+ false,
+ mProvisionCompleteContentObserver);
}
}
}
+ private Set<String> getUninstalledCarrierPackages() {
+ String whitelistSetting = Settings.Global.getString(
+ mContext.getContentResolver(),
+ Settings.Global.CARRIER_APP_WHITELIST);
+ if (TextUtils.isEmpty(whitelistSetting)) {
+ return Collections.emptySet();
+ }
+ Map<String, String> certPackageMap = parseToCertificateToPackageMap(whitelistSetting);
+ if (certPackageMap.isEmpty()) {
+ return Collections.emptySet();
+ }
+
+ Set<String> uninstalledCarrierPackages = new ArraySet<>();
+ List<UiccAccessRule> accessRules = mCarrierPrivilegeRules.getAccessRules();
+ for (UiccAccessRule accessRule : accessRules) {
+ String certHexString = accessRule.getCertificateHexString().toUpperCase();
+ String pkgName = certPackageMap.get(certHexString);
+ if (!TextUtils.isEmpty(pkgName) && !isPackageInstalled(mContext, pkgName)) {
+ uninstalledCarrierPackages.add(pkgName);
+ }
+ }
+ return uninstalledCarrierPackages;
+ }
+
+ /**
+ * Converts a string in the format: key1:value1;key2:value2... into a map where the keys are
+ * hex representations of app certificates - all upper case - and the values are package names
+ * @hide
+ */
+ @VisibleForTesting
+ public static Map<String, String> parseToCertificateToPackageMap(String whitelistSetting) {
+ final String pairDelim = "\\s*;\\s*";
+ final String keyValueDelim = "\\s*:\\s*";
+
+ List<String> keyValuePairList = Arrays.asList(whitelistSetting.split(pairDelim));
+
+ if (keyValuePairList.isEmpty()) {
+ return Collections.emptyMap();
+ }
+
+ Map<String, String> map = new ArrayMap<>(keyValuePairList.size());
+ for (String keyValueString: keyValuePairList) {
+ String[] keyValue = keyValueString.split(keyValueDelim);
+
+ if (keyValue.length == 2) {
+ map.put(keyValue[0].toUpperCase(), keyValue[1]);
+ } else {
+ loge("Incorrect length of key-value pair in carrier app whitelist map. "
+ + "Length should be exactly 2");
+ }
+ }
+
+ return map;
+ }
+
/**
* Check whether the specified type of application exists in the profile.
*
@@ -1513,7 +1553,7 @@
Rlog.d(LOG_TAG, msg);
}
- private void loge(String msg) {
+ private static void loge(String msg) {
Rlog.e(LOG_TAG, msg);
}
@@ -1522,6 +1562,15 @@
}
/**
+ * Reloads carrier privileges as if a change were just detected. Useful to force a profile
+ * refresh without having to physically insert or remove a SIM card.
+ */
+ @VisibleForTesting
+ public void refresh() {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARRIER_PRIVILEGES_LOADED));
+ }
+
+ /**
* Dump
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java b/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java
index 103c75b..b8b2818 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java
@@ -88,7 +88,7 @@
// Device capabilities.
private static final String DEV_CAP_GSM = "gsm";
private static final String DEV_CAP_UTRAN = "utran";
- private static final String DEV_CAP_CDMA_1X = "cdma_1x";
+ private static final String DEV_CAP_CDMA_1X = "cdma1x";
private static final String DEV_CAP_HRPD = "hrpd";
private static final String DEV_CAP_EHRPD = "ehrpd";
private static final String DEV_CAP_EUTRAN = "eutran";
@@ -162,7 +162,12 @@
@Override
public void onException(Throwable e) {
- // Not notifying registrants if getting eid fails.
+ // Still notifying registrants even getting eid fails.
+ if (mEidReadyRegistrants != null) {
+ mEidReadyRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
+ }
+ mEid = "";
+ mCardId = "";
Rlog.e(LOG_TAG, "Failed loading eid", e);
}
};
@@ -183,6 +188,15 @@
(byte[] response) -> mSpecVersion, callback, handler);
}
+ @Override
+ protected void updateCardId() {
+ if (TextUtils.isEmpty(mEid)) {
+ super.updateCardId();
+ } else {
+ mCardId = mEid;
+ }
+ }
+
/**
* Gets a list of user-visible profiles.
*
@@ -234,7 +248,10 @@
sendApdu(
newRequestProvider((RequestBuilder requestBuilder) ->
requestBuilder.addStoreData(Asn1Node.newBuilder(Tags.TAG_GET_PROFILES)
- .addChildAsBytes(Tags.TAG_ICCID, IccUtils.bcdToBytes(iccid))
+ .addChild(Asn1Node.newBuilder(Tags.TAG_CTX_COMP_0)
+ .addChildAsBytes(
+ Tags.TAG_ICCID, IccUtils.bcdToBytes(padTrailingFs(iccid)))
+ .build())
.addChildAsBytes(Tags.TAG_TAG_LIST, Tags.EUICC_PROFILE_TAGS)
.build().toHex())),
(byte[] response) -> {
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java b/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java
index 05cc78c..7001f6d 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java
@@ -198,10 +198,12 @@
Handler handler) {
ByteArrayOutputStream resultBuilder =
responseBuilder == null ? new ByteArrayOutputStream() : responseBuilder;
- try {
- resultBuilder.write(lastResponse.payload);
- } catch (IOException e) {
- // Should never reach here.
+ if (lastResponse.payload != null) {
+ try {
+ resultBuilder.write(lastResponse.payload);
+ } catch (IOException e) {
+ // Should never reach here.
+ }
}
if (lastResponse.sw1 != SW1_MORE_RESPONSE) {
lastResponse.payload = resultBuilder.toByteArray();
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/apdu/RequestBuilder.java b/src/java/com/android/internal/telephony/uicc/euicc/apdu/RequestBuilder.java
index c2a63ee..7a7fa5e 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/apdu/RequestBuilder.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/apdu/RequestBuilder.java
@@ -81,13 +81,11 @@
int totalSubCmds = totalLen == 0 ? 1 : (totalLen + mMaxApduDataLen - 1) / mMaxApduDataLen;
for (int i = 1; i < totalSubCmds; ++i) {
String data = cmdHex.substring(startPos, startPos + cmdLen);
- addApdu(CLA_STORE_DATA, INS_STORE_DATA, P1_STORE_DATA_INTERM, i - 1, mMaxApduDataLen,
- data);
+ addApdu(CLA_STORE_DATA, INS_STORE_DATA, P1_STORE_DATA_INTERM, i - 1, data);
startPos += cmdLen;
}
String data = cmdHex.substring(startPos);
- addApdu(CLA_STORE_DATA, INS_STORE_DATA, P1_STORE_DATA_END, totalSubCmds - 1,
- totalLen % mMaxApduDataLen, data);
+ addApdu(CLA_STORE_DATA, INS_STORE_DATA, P1_STORE_DATA_END, totalSubCmds - 1, data);
}
List<ApduCommand> getCommands() {
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/async/AsyncResultCallback.java b/src/java/com/android/internal/telephony/uicc/euicc/async/AsyncResultCallback.java
index 6e93687..b28e7e7 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/async/AsyncResultCallback.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/async/AsyncResultCallback.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony.uicc.euicc.async;
+import android.telephony.Rlog;
+
/**
* Class to deliver the returned value from an asynchronous call. Either {@link #onResult(Result)}
* or {@link #onException(Throwable)} will be called. You can create an anonymous subclass and
@@ -38,9 +40,13 @@
*/
public abstract class AsyncResultCallback<Result> {
+ private static final String LOG_TAG = "AsyncResultCallback";
+
/** This will be called when the result is returned. */
public abstract void onResult(Result result);
/** This will be called when any exception is thrown. */
- public void onException(Throwable e) {}
+ public void onException(Throwable e) {
+ Rlog.e(LOG_TAG, "Error in onException", e);
+ }
}
diff --git a/src/java/com/android/internal/telephony/util/NotificationChannelController.java b/src/java/com/android/internal/telephony/util/NotificationChannelController.java
index 3f6da54..bf84c18 100644
--- a/src/java/com/android/internal/telephony/util/NotificationChannelController.java
+++ b/src/java/com/android/internal/telephony/util/NotificationChannelController.java
@@ -39,6 +39,7 @@
public static final String CHANNEL_ID_ALERT = "alert";
public static final String CHANNEL_ID_CALL_FORWARD = "callForward";
public static final String CHANNEL_ID_MOBILE_DATA_STATUS = "mobileDataAlertNew";
+ public static final String CHANNEL_ID_SIM = "sim";
public static final String CHANNEL_ID_SMS = "sms";
public static final String CHANNEL_ID_VOICE_MAIL = "voiceMail";
public static final String CHANNEL_ID_WFC = "wfc";
@@ -67,6 +68,14 @@
// allow users to block notifications from system
mobileDataStatusChannel.setBlockableSystem(true);
+ final NotificationChannel simChannel = new NotificationChannel(
+ CHANNEL_ID_SIM,
+ context.getText(R.string.notification_channel_sim),
+ NotificationManager.IMPORTANCE_LOW
+ );
+
+ simChannel.setSound(null, null);
+
context.getSystemService(NotificationManager.class)
.createNotificationChannels(Arrays.asList(
new NotificationChannel(CHANNEL_ID_CALL_FORWARD,
@@ -79,7 +88,8 @@
context.getText(R.string.notification_channel_wfc),
NotificationManager.IMPORTANCE_LOW),
alertChannel,
- mobileDataStatusChannel));
+ mobileDataStatusChannel,
+ simChannel));
// only for update
if (getChannel(CHANNEL_ID_VOICE_MAIL, context) != null) {
migrateVoicemailNotificationSettings(context);
diff --git a/tests/telephonytests/Android.mk b/tests/telephonytests/Android.mk
index 6709d46..b9bf282 100644
--- a/tests/telephonytests/Android.mk
+++ b/tests/telephonytests/Android.mk
@@ -5,19 +5,23 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
-#LOCAL_STATIC_JAVA_LIBRARIES := librilproto-java
+LOCAL_JAVA_LIBRARIES := \
+ android.test.runner \
+ ims-common \
+ bouncycastle \
+ android.test.base \
+ android.test.mock
-LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common ims-common services.core bouncycastle
LOCAL_STATIC_JAVA_LIBRARIES := guava \
frameworks-base-testutils \
+ services.core \
+ telephony-common \
mockito-target-minus-junit4 \
android-support-test \
- platform-test-annotations \
- legacy-android-test
+ platform-test-annotations
LOCAL_PACKAGE_NAME := FrameworksTelephonyTests
LOCAL_PRIVATE_PLATFORM_APIS := true
-
LOCAL_COMPATIBILITY_SUITE := device-tests
include $(BUILD_PACKAGE)
diff --git a/tests/telephonytests/AndroidTest.xml b/tests/telephonytests/AndroidTest.xml
index dadff8b..74b2799 100644
--- a/tests/telephonytests/AndroidTest.xml
+++ b/tests/telephonytests/AndroidTest.xml
@@ -23,5 +23,6 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.frameworks.telephonytests" />
<option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
</test>
</configuration>
diff --git a/tests/telephonytests/src/com/android/internal/telephony/AppSmsManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/AppSmsManagerTest.java
new file mode 100644
index 0000000..bae1632
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/AppSmsManagerTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 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.fail;
+
+import android.content.Intent;
+import android.provider.Telephony.Sms.Intents;
+import android.telephony.SmsMessage;
+
+import com.android.internal.telephony.uicc.IccUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class AppSmsManagerTest extends TelephonyTest {
+
+ /**
+ * The sms message information represent by the {@link #PDU}.
+ *
+ * SMSC#+31624000000
+ * Sender:+31641600986
+ * TimeStamp:26/08/02 19:37:41
+ * TP_PID:00
+ * TP_DCS:00
+ * TP_DCS-popis:Uncompressed Text
+ * class:0
+ * Alphabet:Default
+ * How are you?
+ * Length:12
+ */
+ private static final String PDU =
+ "07911326040000F0040B911346610089F60000208062917314080CC8F71D14969741F977FD07";
+
+ private AppSmsManager mAppSmsManagerUT;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp("AppSmsManagerTest");
+ mAppSmsManagerUT = new AppSmsManager(mContextFixture.getTestDouble());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testHandleSmsReceivedIntent() {
+ Intent intent = new Intent();
+ intent.setAction(Intents.SMS_DELIVER_ACTION);
+ intent.putExtra("pdus", new byte[][]{IccUtils.hexStringToBytes(PDU), null, null});
+ intent.putExtra("format", SmsMessage.FORMAT_3GPP);
+
+ try {
+ // Assumes the AppSmsManager can handle the null pdu.
+ mAppSmsManagerUT.handleSmsReceivedIntent(intent);
+ } catch (NullPointerException ex) {
+ fail("Test failed because of null pointer exception " + ex);
+ }
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java
index 9974a6d..54a56df 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierAppUtilsTest.java
@@ -27,6 +27,7 @@
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArrayMap;
+import android.util.ArraySet;
import org.junit.Test;
import org.mockito.Mock;
@@ -38,7 +39,11 @@
public class CarrierAppUtilsTest extends InstrumentationTestCase {
private static final String CARRIER_APP = "com.example.carrier";
- private static final String[] CARRIER_APPS = new String[] { CARRIER_APP };
+ private static final ArraySet<String> CARRIER_APPS = new ArraySet<>();
+ static {
+ CARRIER_APPS.add(CARRIER_APP);
+ }
+
private static final String ASSOCIATED_APP = "com.example.associated";
private static final ArrayMap<String, List<String>> ASSOCIATED_APPS = new ArrayMap<>();
static {
@@ -73,7 +78,7 @@
@Test @SmallTest
public void testDisableCarrierAppsUntilPrivileged_EmptyList() {
CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
- mTelephonyManager, mContentResolver, USER_ID, new String[0],
+ mTelephonyManager, mContentResolver, USER_ID, new ArraySet<>(),
ASSOCIATED_APPS);
Mockito.verifyNoMoreInteractions(mPackageManager, mTelephonyManager);
}
@@ -83,9 +88,11 @@
public void testDisableCarrierAppsUntilPrivileged_MissingApp() throws Exception {
Mockito.when(mPackageManager.getApplicationInfo("com.example.missing.app",
PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, USER_ID)).thenReturn(null);
+ ArraySet<String> systemCarrierAppsDisabledUntilUsed = new ArraySet<>();
+ systemCarrierAppsDisabledUntilUsed.add("com.example.missing.app");
CarrierAppUtils.disableCarrierAppsUntilPrivileged(CALLING_PACKAGE, mPackageManager,
mTelephonyManager, mContentResolver, USER_ID,
- new String[] { "com.example.missing.app" }, ASSOCIATED_APPS);
+ systemCarrierAppsDisabledUntilUsed, ASSOCIATED_APPS);
Mockito.verify(mPackageManager, Mockito.never()).setApplicationEnabledSetting(
Mockito.anyString(), Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt(),
Mockito.anyString());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java
index 59d8872..5de4871 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java
@@ -52,7 +52,6 @@
/**
* Unit tests for {@link com.android.internal.telephony.CarrierServiceStateTracker}.
*/
-@SmallTest
public class CarrierServiceStateTrackerTest extends TelephonyTest {
public static final String LOG_TAG = "CSST";
public static final int TEST_TIMEOUT = 5000;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index 77eb7dc..60bc61f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -32,6 +32,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -61,6 +62,7 @@
import com.android.internal.telephony.uicc.IccCardApplicationStatus;
import com.android.internal.telephony.uicc.IccException;
import com.android.internal.telephony.uicc.IccRecords;
+import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.telephony.uicc.UiccProfile;
import com.android.internal.telephony.uicc.UiccSlot;
@@ -70,6 +72,7 @@
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import java.util.List;
@@ -179,6 +182,57 @@
@Test
@SmallTest
+ public void testGetSubscriberIdForGsmPhone() {
+ final String subscriberId = "123456789";
+ IccRecords iccRecords = Mockito.mock(IccRecords.class);
+ doReturn(subscriberId).when(iccRecords).getIMSI();
+ doReturn(iccRecords).when(mUiccController)
+ .getIccRecords(anyInt() /* phoneId */, eq(UiccController.APP_FAM_3GPP));
+
+ // Ensure the phone type is GSM
+ GsmCdmaPhone spyPhone = spy(mPhoneUT);
+ doReturn(false).when(spyPhone).isPhoneTypeCdma();
+ doReturn(false).when(spyPhone).isPhoneTypeCdmaLte();
+ doReturn(true).when(spyPhone).isPhoneTypeGsm();
+
+ assertEquals(subscriberId, spyPhone.getSubscriberId());
+ }
+
+ @Test
+ @SmallTest
+ public void testGetSubscriberIdForCdmaLtePhone() {
+ final String subscriberId = "abcdefghijk";
+ IccRecords iccRecords = Mockito.mock(IccRecords.class);
+ doReturn(subscriberId).when(iccRecords).getIMSI();
+ doReturn(iccRecords).when(mUiccController)
+ .getIccRecords(anyInt() /* phoneId */, eq(UiccController.APP_FAM_3GPP));
+
+ // Ensure the phone type is CdmaLte
+ GsmCdmaPhone spyPhone = spy(mPhoneUT);
+ doReturn(false).when(spyPhone).isPhoneTypeCdma();
+ doReturn(true).when(spyPhone).isPhoneTypeCdmaLte();
+ doReturn(false).when(spyPhone).isPhoneTypeGsm();
+
+ assertEquals(subscriberId, spyPhone.getSubscriberId());
+ }
+
+ @Test
+ @SmallTest
+ public void testGetSubscriberIdForCdmaPhone() {
+ final String subscriberId = "987654321";
+ doReturn(subscriberId).when(mSST).getImsi();
+
+ // Ensure the phone type is GSM
+ GsmCdmaPhone spyPhone = spy(mPhoneUT);
+ doReturn(true).when(spyPhone).isPhoneTypeCdma();
+ doReturn(false).when(spyPhone).isPhoneTypeCdmaLte();
+ doReturn(false).when(spyPhone).isPhoneTypeGsm();
+
+ assertEquals(subscriberId, spyPhone.getSubscriberId());
+ }
+
+ @Test
+ @SmallTest
public void testGetCellLocation() {
// GSM
CellLocation cellLocation = new GsmCellLocation();
@@ -368,6 +422,21 @@
putString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_STRING, voiceMailNumber);
assertEquals(voiceMailNumber, mPhoneUT.getVoiceMailNumber());
+ // voicemail number from config for roaming network
+ String voiceMailNumberForRoaming = "1234567892";
+ mContextFixture.getCarrierConfigBundle()
+ .putString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_ROAMING_STRING,
+ voiceMailNumberForRoaming);
+ //Verify voicemail number for home
+ doReturn(false).when(mSST.mSS).getRoaming();
+ assertEquals(voiceMailNumber, mPhoneUT.getVoiceMailNumber());
+ //Move to roaming condition, verify voicemail number for roaming
+ doReturn(true).when(mSST.mSS).getRoaming();
+ assertEquals(voiceMailNumberForRoaming, mPhoneUT.getVoiceMailNumber());
+ //Move to home condition, verify voicemail number for home
+ doReturn(false).when(mSST.mSS).getRoaming();
+ assertEquals(voiceMailNumber, mPhoneUT.getVoiceMailNumber());
+
// voicemail number that is explicitly set
voiceMailNumber = "1234567891";
mPhoneUT.setVoiceMailNumber("alphaTag", voiceMailNumber, null);
@@ -400,6 +469,21 @@
putString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_STRING, voiceMailNumber);
assertEquals(voiceMailNumber, mPhoneUT.getVoiceMailNumber());
+ // voicemail number from config for roaming network
+ String voiceMailNumberForRoaming = "1234567892";
+ mContextFixture.getCarrierConfigBundle()
+ .putString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_ROAMING_STRING,
+ voiceMailNumberForRoaming);
+ //Verify voicemail number for home
+ doReturn(false).when(mSST.mSS).getRoaming();
+ assertEquals(voiceMailNumber, mPhoneUT.getVoiceMailNumber());
+ //Move to roaming condition, verify voicemail number for roaming
+ doReturn(true).when(mSST.mSS).getRoaming();
+ assertEquals(voiceMailNumberForRoaming, mPhoneUT.getVoiceMailNumber());
+ //Move to home condition, verify voicemail number for home
+ doReturn(false).when(mSST.mSS).getRoaming();
+ assertEquals(voiceMailNumber, mPhoneUT.getVoiceMailNumber());
+
// voicemail number from sharedPreference
mPhoneUT.setVoiceMailNumber("alphaTag", voiceMailNumber, null);
ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java
index bcc1730..02f78ab 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java
@@ -98,7 +98,7 @@
public void testUpdateOperatorNumericSync() throws Exception {
mLocaleTracker.updateOperatorNumericSync(US_MCC + FAKE_MNC);
assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
- verify(mWifiManager).setCountryCode(US_COUNTRY_CODE, false);
+ verify(mWifiManager).setCountryCode(US_COUNTRY_CODE);
}
@Test
@@ -107,7 +107,7 @@
mLocaleTracker.updateOperatorNumericAsync(US_MCC + FAKE_MNC);
waitForMs(100);
assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
- verify(mWifiManager).setCountryCode(US_COUNTRY_CODE, false);
+ verify(mWifiManager).setCountryCode(US_COUNTRY_CODE);
}
@Test
@@ -116,7 +116,7 @@
mLocaleTracker.updateOperatorNumericAsync("");
waitForHandlerAction(mLocaleTracker, 100);
assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
- verify(mWifiManager).setCountryCode(US_COUNTRY_CODE, false);
+ verify(mWifiManager).setCountryCode(US_COUNTRY_CODE);
}
@Test
@@ -126,7 +126,7 @@
mLocaleTracker.updateOperatorNumericAsync("");
waitForHandlerAction(mLocaleTracker, 100);
assertEquals(COUNTRY_CODE_UNAVAILABLE, mLocaleTracker.getCurrentCountry());
- verify(mWifiManager).setCountryCode(COUNTRY_CODE_UNAVAILABLE, false);
+ verify(mWifiManager).setCountryCode(COUNTRY_CODE_UNAVAILABLE);
}
@Test
@@ -134,18 +134,18 @@
public void testTogglingAirplaneMode() throws Exception {
mLocaleTracker.updateOperatorNumericSync(US_MCC + FAKE_MNC);
assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
- verify(mWifiManager).setCountryCode(US_COUNTRY_CODE, false);
+ verify(mWifiManager).setCountryCode(US_COUNTRY_CODE);
doReturn(false).when(mSST).getDesiredPowerState();
mLocaleTracker.updateOperatorNumericAsync("");
waitForHandlerAction(mLocaleTracker, 100);
assertEquals(COUNTRY_CODE_UNAVAILABLE, mLocaleTracker.getCurrentCountry());
- verify(mWifiManager).setCountryCode(COUNTRY_CODE_UNAVAILABLE, false);
+ verify(mWifiManager).setCountryCode(COUNTRY_CODE_UNAVAILABLE);
doReturn(true).when(mSST).getDesiredPowerState();
mLocaleTracker.updateOperatorNumericSync(US_MCC + FAKE_MNC);
assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
- verify(mWifiManager, times(2)).setCountryCode(US_COUNTRY_CODE, false);
+ verify(mWifiManager, times(2)).setCountryCode(US_COUNTRY_CODE);
}
@Test
@@ -155,12 +155,12 @@
mLocaleTracker.updateOperatorNumericAsync("");
waitForHandlerAction(mLocaleTracker, 100);
assertEquals(COUNTRY_CODE_UNAVAILABLE, mLocaleTracker.getCurrentCountry());
- verify(mWifiManager).setCountryCode(COUNTRY_CODE_UNAVAILABLE, false);
+ verify(mWifiManager).setCountryCode(COUNTRY_CODE_UNAVAILABLE);
doReturn(Arrays.asList(mCellInfo)).when(mPhone).getAllCellInfo(isNull());
waitForHandlerActionDelayed(mLocaleTracker, 100, 2500);
assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
- verify(mWifiManager).setCountryCode(US_COUNTRY_CODE, false);
+ verify(mWifiManager).setCountryCode(US_COUNTRY_CODE);
}
@Test
@@ -170,7 +170,7 @@
mLocaleTracker.updateOperatorNumericAsync("");
waitForHandlerAction(mLocaleTracker, 100);
assertEquals(COUNTRY_CODE_UNAVAILABLE, mLocaleTracker.getCurrentCountry());
- verify(mWifiManager).setCountryCode(COUNTRY_CODE_UNAVAILABLE, false);
+ verify(mWifiManager).setCountryCode(COUNTRY_CODE_UNAVAILABLE);
doReturn(Arrays.asList(mCellInfo)).when(mPhone).getAllCellInfo(isNull());
ServiceState ss = new ServiceState();
@@ -179,6 +179,6 @@
mLocaleTracker.sendMessage(mLocaleTracker.obtainMessage(3, ar));
waitForHandlerAction(mLocaleTracker, 100);
assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
- verify(mWifiManager).setCountryCode(US_COUNTRY_CODE, false);
+ verify(mWifiManager).setCountryCode(US_COUNTRY_CODE);
}
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
index 10dd6f2..cfc0ca8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
@@ -804,6 +804,7 @@
}
}
+ @FlakyTest
@Test
public void testIccOpenLogicalChannel() throws Exception {
String aid = "aid";
@@ -1517,6 +1518,30 @@
assertEquals(expected, cellInfoCdma);
}
+ @Test
+ public void testGetWorksourceClientId() {
+ RILRequest request = RILRequest.obtain(0, null, null);
+ assertEquals(null, request.getWorkSourceClientId());
+
+ request = RILRequest.obtain(0, null, new WorkSource());
+ assertEquals(null, request.getWorkSourceClientId());
+
+ WorkSource ws = new WorkSource();
+ ws.add(100);
+ request = RILRequest.obtain(0, null, ws);
+ assertEquals("100:null", request.getWorkSourceClientId());
+
+ ws = new WorkSource();
+ ws.add(100, "foo");
+ request = RILRequest.obtain(0, null, ws);
+ assertEquals("100:foo", request.getWorkSourceClientId());
+
+ ws = new WorkSource();
+ ws.createWorkChain().addNode(100, "foo").addNode(200, "bar");
+ request = RILRequest.obtain(0, null, ws);
+ assertEquals("100:foo", request.getWorkSourceClientId());
+ }
+
private ArrayList<CellInfo> getCellInfoListForLTE(
String mcc, String mnc, String alphaLong, String alphaShort) {
android.hardware.radio.V1_2.CellInfoLte lte = new android.hardware.radio.V1_2.CellInfoLte();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
index 33782b2..f3b3197 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
@@ -331,7 +331,6 @@
doReturn(Arrays.asList(mSubInfo)).when(mSubscriptionController)
.getSubInfoUsingSlotIndexPrivileged(eq(FAKE_SUB_ID_1), anyBoolean());
-
mUpdater.updateInternalIccState(
IccCardConstants.INTENT_VALUE_ICC_LOCKED, "TESTING", FAKE_SUB_ID_1);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
index ce5eaeb..dab06d8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
@@ -71,6 +71,7 @@
import com.android.internal.telephony.dataconnection.DataConnection.SetupResult;
import com.android.internal.util.IState;
import com.android.internal.util.StateMachine;
+import com.android.server.pm.PackageManagerService;
import org.junit.After;
import org.junit.Before;
@@ -94,6 +95,8 @@
ApnContext mApnContext;
@Mock
DcFailBringUp mDcFailBringUp;
+ @Mock
+ PackageManagerService mMockPackageManagerInternal;
private DataConnection mDc;
private DataConnectionTestHandler mDataConnectionTestHandler;
@@ -191,7 +194,7 @@
public void setUp() throws Exception {
logd("+Setup!");
super.setUp(getClass().getSimpleName());
-
+ mServiceManagerMockedServices.put("package", mMockPackageManagerInternal);
doReturn("fake.action_detached").when(mPhone).getActionDetached();
replaceInstance(ConnectionParams.class, "mApnContext", mCp, mApnContext);
replaceInstance(ConnectionParams.class, "mRilRat", mCp,
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 451571e..a13c951 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -80,6 +80,7 @@
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyTest;
+import com.android.server.pm.PackageManagerService;
import org.junit.After;
import org.junit.Before;
@@ -142,6 +143,8 @@
ApnSetting mApnSetting;
@Mock
DcAsyncChannel mDcac;
+ @Mock
+ PackageManagerService mMockPackageManagerInternal;
private DcTracker mDct;
private DcTrackerTestHandler mDcTrackerTestHandler;
@@ -461,6 +464,7 @@
doReturn(1).when(mIsub).getDefaultDataSubId();
doReturn(mIsub).when(mBinder).queryLocalInterface(anyString());
mServiceManagerMockedServices.put("isub", mBinder);
+ mServiceManagerMockedServices.put("package", mMockPackageManagerInternal);
mContextFixture.putStringArrayResource(
com.android.internal.R.array.config_cell_retries_per_error_code,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
index 4e0035c..12453ed 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
@@ -606,6 +606,50 @@
@Test
@MediumTest
+ public void testMultiPartSmsWithInvalidSeqNumber() {
+ transitionFromStartupToIdle();
+
+ // prepare SMS part 1 and part 2
+ prepareMultiPartSms(false);
+
+ mSmsHeader.concatRef = new SmsHeader.ConcatRef();
+ doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader();
+
+ doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory)
+ .makeInboundSmsTracker(nullable(byte[].class), anyLong(), anyInt(), anyBoolean(),
+ nullable(String.class), nullable(String.class), anyInt(), anyInt(),
+ anyInt(), anyBoolean(), nullable(String.class));
+ mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
+ mSmsMessage, null));
+ waitForMs(100);
+
+ // verify the message is stored in the raw table
+ assertEquals(1, mContentProvider.getNumRows());
+
+ // State machine should go back to idle and wait for second part
+ assertEquals("IdleState", getCurrentState().getName());
+
+ // change seqNumber in part 2 to an invalid value
+ int invalidSeqNumber = -1;
+ mInboundSmsTrackerCVPart2.put("sequence", invalidSeqNumber);
+ doReturn(invalidSeqNumber).when(mInboundSmsTrackerPart2).getSequenceNumber();
+
+ doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory)
+ .makeInboundSmsTracker(nullable(byte[].class), anyLong(), anyInt(), anyBoolean(),
+ nullable(String.class), nullable(String.class), anyInt(), anyInt(),
+ anyInt(), anyBoolean(), nullable(String.class));
+ mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
+ mSmsMessage, null));
+ waitForMs(100);
+
+ // verify no broadcasts sent
+ verify(mContext, never()).sendBroadcast(any(Intent.class));
+ // State machine should go back to idle
+ assertEquals("IdleState", getCurrentState().getName());
+ }
+
+ @Test
+ @MediumTest
public void testMultipartSmsFromBlockedNumber_noBroadcastsSent() {
mFakeBlockedNumberContentProvider.mBlockedNumbers.add("1234567890");
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java
index fd19f80..2bf0094 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java
@@ -61,11 +61,8 @@
ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED;
PersistableBundle mBundle;
-
- @Mock
- IBinder mBinder;
- @Mock
- ImsConfigImplBase mImsConfigImplBaseMock;
+ @Mock IBinder mBinder;
+ @Mock ImsConfigImplBase mImsConfigImplBaseMock;
Hashtable<Integer, Integer> mProvisionedIntVals = new Hashtable<>();
Hashtable<Integer, String> mProvisionedStringVals = new Hashtable<>();
ImsConfigImplBase.ImsConfigStub mImsConfigStub;
@@ -191,7 +188,6 @@
eq(SubscriptionManager.WFC_IMS_ENABLED),
eq("1"));
}
-
@Test
public void testGetProvisionedValues() throws Exception {
ImsManager imsManager = initializeProvisionedValues();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
index 8914aee..eac6159 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
@@ -42,11 +42,14 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
+import android.os.PersistableBundle;
import android.support.test.filters.FlakyTest;
import android.telecom.VideoProfile;
+import android.telephony.CarrierConfigManager;
import android.telephony.DisconnectCause;
import android.telephony.PhoneNumberUtils;
import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.ImsCallSession;
import android.telephony.ims.ImsReasonInfo;
@@ -111,6 +114,7 @@
ImsReasonInfo.CODE_ANSWERED_ELSEWHERE);
mCTUT.addReasonCodeRemapping(510, "Call answered elsewhere.",
ImsReasonInfo.CODE_ANSWERED_ELSEWHERE);
+ mCTUT.setDataEnabled(true);
mCTHander = new Handler(mCTUT.getLooper());
setReady(true);
}
@@ -164,7 +168,7 @@
}
}).when(mImsCall).hold();
- doReturn(mImsCallSession).when(mImsCall).getCallSession();
+ mImsCall.attachSession(mImsCallSession);
}
@Before
@@ -175,6 +179,7 @@
mImsManagerInstances.put(mImsPhone.getPhoneId(), mImsManager);
mImsCall = spy(new ImsCall(mContext, mImsCallProfile));
mSecondImsCall = spy(new ImsCall(mContext, mImsCallProfile));
+ mImsPhoneConnectionListener = mock(ImsPhoneConnection.Listener.class);
imsCallMocking(mImsCall);
imsCallMocking(mSecondImsCall);
doReturn(ImsFeature.STATE_READY).when(mImsManager).getImsServiceState();
@@ -191,6 +196,7 @@
public ImsCall answer(InvocationOnMock invocation) throws Throwable {
mImsCallListener =
(ImsCall.Listener) invocation.getArguments()[2];
+ mImsCall.setListener(mImsCallListener);
return mImsCall;
}
}).when(mImsManager).takeCall(any(), any(), any());
@@ -198,9 +204,9 @@
doAnswer(new Answer<ImsCall>() {
@Override
public ImsCall answer(InvocationOnMock invocation) throws Throwable {
- mImsCallListener = (ImsCall.Listener) invocation.getArguments()[2];
+ mImsCallListener =
+ (ImsCall.Listener) invocation.getArguments()[2];
mSecondImsCall.setListener(mImsCallListener);
-
return mSecondImsCall;
}
}).when(mImsManager).makeCall(eq(mImsCallProfile), (String []) any(),
@@ -345,6 +351,9 @@
assertEquals(PhoneConstants.State.RINGING, mCTUT.getState());
assertTrue(mCTUT.mRingingCall.isRinging());
assertEquals(1, mCTUT.mRingingCall.getConnections().size());
+ ImsPhoneConnection connection =
+ (ImsPhoneConnection) mCTUT.mRingingCall.getConnections().get(0);
+ connection.addListener(mImsPhoneConnectionListener);
}
@Test
@@ -651,6 +660,55 @@
nullable(MmTelFeature.Listener.class));
}
+ /**
+ * Test notification of handover from LTE to WIFI and WIFI to LTE and ensure that the expected
+ * connection events are sent.
+ */
+ @Test
+ @SmallTest
+ public void testNotifyHandovers() {
+ setupCarrierConfig();
+
+ //establish a MT call
+ testImsMTCallAccept();
+ ImsPhoneConnection connection =
+ (ImsPhoneConnection) mCTUT.mForegroundCall.getConnections().get(0);
+ ImsCall call = connection.getImsCall();
+ // Needs to be a video call to see this signalling.
+ mImsCallProfile.mCallType = ImsCallProfile.CALL_TYPE_VT;
+
+ // First handover from LTE to WIFI; this takes us into a mid-call state.
+ call.getImsCallSessionListenerProxy().callSessionHandover(call.getCallSession(),
+ ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN,
+ new ImsReasonInfo());
+ // Handover back to LTE.
+ call.getImsCallSessionListenerProxy().callSessionHandover(call.getCallSession(),
+ ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN, ServiceState.RIL_RADIO_TECHNOLOGY_LTE,
+ new ImsReasonInfo());
+ verify(mImsPhoneConnectionListener).onConnectionEvent(eq(
+ TelephonyManager.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE), isNull());
+
+ // Finally hand back to WIFI
+ call.getImsCallSessionListenerProxy().callSessionHandover(call.getCallSession(),
+ ServiceState.RIL_RADIO_TECHNOLOGY_LTE, ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN,
+ new ImsReasonInfo());
+ verify(mImsPhoneConnectionListener).onConnectionEvent(eq(
+ TelephonyManager.EVENT_HANDOVER_VIDEO_FROM_LTE_TO_WIFI), isNull());
+ }
+
+ /**
+ * Configure carrier config options relevant to the unit test.
+ */
+ public void setupCarrierConfig() {
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putBoolean(CarrierConfigManager.KEY_NOTIFY_HANDOVER_VIDEO_FROM_LTE_TO_WIFI_BOOL,
+ true);
+ bundle.putBoolean(CarrierConfigManager.KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL,
+ true);
+ bundle.putBoolean(CarrierConfigManager.KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, true);
+ mCTUT.updateCarrierConfigCache(bundle);
+ }
+
@Test
@SmallTest
public void testLowBatteryDisconnectMidCall() {
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 71d0794..95f1b3a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
@@ -45,8 +45,6 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Base64;
-import android.telephony.ims.ImsReasonInfo;
-import android.telephony.ims.ImsCallSession;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.GsmCdmaConnection;
import com.android.internal.telephony.PhoneConstants;
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 9210a08..8b89269 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
@@ -757,6 +757,11 @@
mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger));
}
+ @Override
+ public byte[] getNetworkWatchlistConfigHash() {
+ throw new RuntimeException("not implemented");
+ }
+
private void handleUnregisterNetworkFactory(Messenger messenger) {
NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(messenger);
if (nfi == null) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/InstallCarrierAppUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/InstallCarrierAppUtilsTest.java
new file mode 100644
index 0000000..bc297a3
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/InstallCarrierAppUtilsTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.uicc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Tests for {@link InstallCarrierAppUtils}
+ */
+public class InstallCarrierAppUtilsTest {
+ @Test
+ @SmallTest
+ public void testParseAppNameMapFromString_emptyMap() {
+ String appNameKey = "com.app.package1";
+ String mapString = "";
+ String appName =
+ InstallCarrierAppUtils.getAppNameFromPackageName(appNameKey, mapString);
+ assertNull(appName);
+ }
+
+ @Test
+ @SmallTest
+ public void testParseAppNameMapFromString_completeMap() {
+ String appName1Key = "com.app.package1";
+ String appName2Key = "com.app.package2";
+ String expectedAppName1 = "AppName1";
+ String expectedAppName2 = "AppName2";
+ String mapString = appName1Key + ":" + expectedAppName1 + ";"
+ + appName2Key + ":" + expectedAppName2 + ";";
+
+ String appName1 =
+ InstallCarrierAppUtils.getAppNameFromPackageName(appName1Key, mapString);
+ String appName2 =
+ InstallCarrierAppUtils.getAppNameFromPackageName(appName2Key, mapString);
+ assertEquals(expectedAppName1, appName1);
+ assertEquals(expectedAppName2, appName2);
+ }
+
+ @Test
+ @SmallTest
+ public void testParseAppNameMapFromString_packageCaseMismatch() {
+ String appNameKey = "com.app.package1";
+ String expectedAppName = "AppName1";
+ String mapString = appNameKey + ":" + expectedAppName + ";";
+
+ String appNameCaseTestKey = "cOm.ApP.pAcKaGe1";
+ String appName1 =
+ InstallCarrierAppUtils.getAppNameFromPackageName(appNameCaseTestKey, mapString);
+ assertEquals(expectedAppName, appName1);
+ }
+
+ @Test
+ @SmallTest
+ public void testParseAppNameMapFromString_packageNotFound() {
+ String appNameKey = "com.app.package1";
+ String expectedAppName = "AppName1";
+ String mapString = appNameKey + ":" + expectedAppName + ";";
+
+ String missingAppNameKey = "AppName3";
+ String missingAppName =
+ InstallCarrierAppUtils.getAppNameFromPackageName(missingAppNameKey, mapString);
+ assertNull(missingAppName);
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java
index 404754c..b76f2cf 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java
@@ -48,6 +48,8 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import java.util.Map;
+
public class UiccProfileTest extends TelephonyTest {
private UiccProfile mUiccProfile;
@@ -177,6 +179,28 @@
@Test
@SmallTest
+ public void testParseWhitelistMapFromString() {
+ String whitelist = "";
+ Map<String, String> parsedMap = UiccProfile.parseToCertificateToPackageMap(whitelist);
+ assertTrue(parsedMap.isEmpty());
+
+ whitelist = "nokey;value;separation";
+ parsedMap = UiccProfile.parseToCertificateToPackageMap(whitelist);
+ assertTrue(parsedMap.isEmpty());
+
+ whitelist = "KEY1:value1";
+ parsedMap = UiccProfile.parseToCertificateToPackageMap(whitelist);
+ assertEquals("value1", parsedMap.get("KEY1"));
+
+ whitelist = "KEY1:value1; KEY2:value2 ;KEY3:value3";
+ parsedMap = UiccProfile.parseToCertificateToPackageMap(whitelist);
+ assertEquals("value1", parsedMap.get("KEY1"));
+ assertEquals("value2", parsedMap.get("KEY2"));
+ assertEquals("value3", parsedMap.get("KEY3"));
+ }
+
+ @Test
+ @SmallTest
public void testUpdateUiccProfileApplication() {
/* update app status and index */
IccCardApplicationStatus cdmaApp = composeUiccApplicationStatus(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java
index dc621a5..a3d7245 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java
@@ -274,7 +274,7 @@
"com.google.android.apps.myapp", 1)
},
profile.getUiccAccessRules().toArray());
- verifyStoreData(channel, "BF2D195A0A896700000000004523015C0B5A909192B79F709599BF76");
+ verifyStoreData(channel, "BF2D1BA00C5A0A896700000000004523015C0B5A909192B79F709599BF76");
}
@Test
@@ -608,11 +608,11 @@
assertUnexpectedException(resultCaptor.exception);
assertEquals("BF3802A000", IccUtils.bytesToHexString(resultCaptor.result));
verifyStoreData(channel,
- "BF3846" + "A000" + "A100" + "A200" + "A300" + "A03C"
+ "BF384B" + "A000" + "A100" + "A200" + "A300" + "A041"
+ "800D4131423243332D583459355A36" // Matching id
- + "A12B800489674523" // TAC
+ + "A130800489674523" // TAC
// Device capabilities
- + "A11980030B000081030B0000830303000084030C000085030B0000"
+ + "A11E80030B000081030B00008203010000830303000084030C000085030B0000"
+ "82088967452301214305"); // IMEI
}
@@ -927,7 +927,7 @@
child = node.getChild(Tags.TAG_CTX_1);
assertTrue(Arrays.equals(new byte[] {11, 0 , 0}, child.asBytes()));
- devCapItem = "cdma_1x,1";
+ devCapItem = "cdma1x,1";
mEuiccCard.addDeviceCapability(devCapsBuilder, devCapItem);
node = devCapsBuilder.build();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java
index 55626a2..2bd995d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java
@@ -244,6 +244,50 @@
}
@Test
+ public void testSendStoreDataLongDataMod0() throws InterruptedException {
+ String aid = "B2C3D4";
+ ApduSender sender = new ApduSender(mMockCi, aid, false /* supportExtendedApdu */);
+
+ int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "9000");
+ LogicalChannelMocker.mockSendToLogicalChannel(mMockCi, channel, "9000", "B2222B9000");
+ LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel);
+
+ // Each segment has 0xFF (the limit of a single command) bytes.
+ String s1 = new String(new char[0xFF]).replace("\0", "AA");
+ String s2 = new String(new char[0xFF]).replace("\0", "BB");
+ String longData = s1 + s2;
+ sender.send((selectResponse, requestBuilder) -> {
+ requestBuilder.addStoreData(longData);
+ }, mResponseCaptor, mHandler);
+ mResponseCaptor.await();
+
+ assertEquals("B2222B", IccUtils.bytesToHexString(mResponseCaptor.response));
+ verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x11),
+ eq(0), eq(0xFF), eq(s1), any());
+ verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x91),
+ eq(1), eq(0xFF), eq(s2), any());
+ }
+
+ @Test
+ public void testSendStoreDataLen0() throws InterruptedException {
+ String aid = "B2C3D4";
+ ApduSender sender = new ApduSender(mMockCi, aid, false /* supportExtendedApdu */);
+
+ int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "9000");
+ LogicalChannelMocker.mockSendToLogicalChannel(mMockCi, channel, "B2222B9000");
+ LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel);
+
+ sender.send((selectResponse, requestBuilder) -> {
+ requestBuilder.addStoreData("");
+ }, mResponseCaptor, mHandler);
+ mResponseCaptor.await();
+
+ assertEquals("B2222B", IccUtils.bytesToHexString(mResponseCaptor.response));
+ verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x91),
+ eq(0), eq(0), eq(""), any());
+ }
+
+ @Test
public void testSendErrorResponseInMiddle() throws InterruptedException {
String aid = "B2C3D4";
ApduSender sender = new ApduSender(mMockCi, aid, false /* supportExtendedApdu */);