diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2017-11-28 23:51:17 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2017-11-28 23:51:17 +0000 |
commit | 63eb6ad287546db3afab23c2360da649424e2d35 (patch) | |
tree | 1343a07368deb3a742de8a228e3ab97f070b5ed1 | |
parent | c6f499e4a2242fcbb185cd615debc32320ec0579 (diff) | |
parent | 551e63a25455174ee5da8bf7d9439c4046ca8f38 (diff) | |
download | telephony-oreo-m3-release.tar.gz |
Snap for 4448085 from 551e63a25455174ee5da8bf7d9439c4046ca8f38 to oc-m3-releaseandroid-8.1.0_r9android-8.1.0_r7android-8.1.0_r22android-8.1.0_r21android-8.1.0_r18android-8.1.0_r17android-8.1.0_r14android-8.1.0_r13oreo-m5-releaseoreo-m3-release
Change-Id: Ided9fdd740a1b2f5afb2863b9214779c3e37220f
20 files changed, 641 insertions, 99 deletions
diff --git a/Android.mk b/Android.mk index 70a88db7c5..b440b28dcf 100644 --- a/Android.mk +++ b/Android.mk @@ -25,7 +25,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src/java) \ $(call all-logtags-files-under, src/java) \ $(call all-proto-files-under, proto) -LOCAL_JAVA_LIBRARIES := voip-common ims-common services +LOCAL_JAVA_LIBRARIES := voip-common ims-common services bouncycastle LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.radio-V1.1-java-static \ android.hardware.radio.deprecated-V1.0-java-static diff --git a/src/java/com/android/internal/telephony/CallForwardInfo.java b/src/java/com/android/internal/telephony/CallForwardInfo.java index dccf3066a9..e40028fc28 100644 --- a/src/java/com/android/internal/telephony/CallForwardInfo.java +++ b/src/java/com/android/internal/telephony/CallForwardInfo.java @@ -16,12 +16,16 @@ package com.android.internal.telephony; +import android.telecom.Log; + /** * See also RIL_CallForwardInfo in include/telephony/ril.h * * {@hide} */ public class CallForwardInfo { + private static final String TAG = "CallForwardInfo"; + public int status; /*1 = active, 0 = not active */ public int reason; /* from TS 27.007 7.11 "reason" */ public int serviceClass; /* Saum of CommandsInterface.SERVICE_CLASS */ @@ -31,9 +35,9 @@ public class CallForwardInfo { @Override public String toString() { - return super.toString() + (status == 0 ? " not active " : " active ") - + " reason: " + reason - + " serviceClass: " + serviceClass + " " + timeSeconds + " seconds"; - + return "[CallForwardInfo: status=" + (status == 0 ? " not active " : " active ") + + ", reason= " + reason + + ", serviceClass= " + serviceClass + ", timeSec= " + timeSeconds + " seconds" + + ", number=" + Log.pii(number) + "]"; } } diff --git a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java index bca337d81c..66bc529114 100644 --- a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java +++ b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java @@ -18,6 +18,8 @@ package com.android.internal.telephony; import static android.preference.PreferenceManager.getDefaultSharedPreferences; +import static java.nio.charset.StandardCharsets.UTF_8; + import android.app.AlarmManager; import android.app.DownloadManager; import android.app.PendingIntent; @@ -34,21 +36,28 @@ import android.telephony.ImsiEncryptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; -import android.util.Base64; import android.util.Log; +import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; +import com.android.org.bouncycastle.util.io.pem.PemReader; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; +import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.Reader; +import java.security.PublicKey; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.util.Date; +import java.util.zip.GZIPInputStream; /** * This class contains logic to get Certificates and keep them current. @@ -68,16 +77,19 @@ public class CarrierKeyDownloadManager { private static final String INTENT_KEY_RENEWAL_ALARM_PREFIX = "com.android.internal.telephony.carrier_key_download_alarm"; - private int mKeyAvailability = 0; + @VisibleForTesting + public int mKeyAvailability = 0; public static final String MNC = "MNC"; public static final String MCC = "MCC"; private static final String SEPARATOR = ":"; - private static final String JSON_KEY = "key"; - private static final String JSON_TYPE = "type"; - private static final String JSON_IDENTIFIER = "identifier"; - private static final String JSON_EXPIRATION_DATE = "expiration-date"; + private static final String JSON_CERTIFICATE = "certificate"; + // This is a hack to accommodate certain Carriers who insists on using the public-key + // field to store the certificate. We'll just use which-ever is not null. + private static final String JSON_CERTIFICATE_ALTERNATE = "public-key"; + private static final String JSON_TYPE = "key-type"; + private static final String JSON_IDENTIFIER = "key-identifier"; private static final String JSON_CARRIER_KEYS = "carrier-keys"; private static final String JSON_TYPE_VALUE_WLAN = "WLAN"; private static final String JSON_TYPE_VALUE_EPDG = "EPDG"; @@ -89,7 +101,7 @@ public class CarrierKeyDownloadManager { private final Phone mPhone; private final Context mContext; - private final DownloadManager mDownloadManager; + public final DownloadManager mDownloadManager; private String mURL; public CarrierKeyDownloadManager(Phone phone) { @@ -173,14 +185,11 @@ public class CarrierKeyDownloadManager { } /** - * this method resets the alarm. Starts by cleaning up the existing alarms. - * We look at the earliest expiration date, and setup an alarms X days prior. - * If the expiration date is in the past, we'll setup an alarm to run the next day. This - * could happen if the download has failed. + * this method returns the date to be used to decide on when to start downloading the key. + * from the carrier. **/ - private void resetRenewalAlarm() { - cleanupRenewalAlarms(); - int slotId = mPhone.getPhoneId(); + @VisibleForTesting + public long getExpirationDate() { long minExpirationDate = Long.MAX_VALUE; for (int key_type : CARRIER_KEY_TYPES) { if (!isKeyEnabled(key_type)) { @@ -204,6 +213,20 @@ public class CarrierKeyDownloadManager { } else { minExpirationDate = minExpirationDate - DEFAULT_RENEWAL_WINDOW_DAYS * DAY_IN_MILLIS; } + return minExpirationDate; + } + + /** + * this method resets the alarm. Starts by cleaning up the existing alarms. + * We look at the earliest expiration date, and setup an alarms X days prior. + * If the expiration date is in the past, we'll setup an alarm to run the next day. This + * could happen if the download has failed. + **/ + @VisibleForTesting + public void resetRenewalAlarm() { + cleanupRenewalAlarms(); + int slotId = mPhone.getPhoneId(); + long minExpirationDate = getExpirationDate(); Log.d(LOG_TAG, "minExpirationDate: " + new Date(minExpirationDate)); final AlarmManager alarmManager = (AlarmManager) mContext.getSystemService( Context.ALARM_SERVICE); @@ -225,21 +248,30 @@ public class CarrierKeyDownloadManager { } /** + * Returns the sim operator. + **/ + @VisibleForTesting + public String getSimOperator() { + final TelephonyManager telephonyManager = + (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); + return telephonyManager.getSimOperator(mPhone.getSubId()); + } + + /** * checks if the download was sent by this particular instance. We do this by including the * slot id in the key. If no value is found, we know that the download was not for this * instance of the phone. **/ - private boolean isValidDownload(String mccMnc) { + @VisibleForTesting + public boolean isValidDownload(String mccMnc) { String mccCurrent = ""; String mncCurrent = ""; String mccSource = ""; String mncSource = ""; - final TelephonyManager telephonyManager = - (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); - String networkOperator = telephonyManager.getNetworkOperator(mPhone.getSubId()); - if (TextUtils.isEmpty(networkOperator) || TextUtils.isEmpty(mccMnc)) { - Log.e(LOG_TAG, "networkOperator or mcc/mnc is empty"); + String simOperator = getSimOperator(); + if (TextUtils.isEmpty(simOperator) || TextUtils.isEmpty(mccMnc)) { + Log.e(LOG_TAG, "simOperator or mcc/mnc is empty"); return false; } @@ -248,8 +280,8 @@ public class CarrierKeyDownloadManager { mncSource = splitValue[1]; Log.d(LOG_TAG, "values from sharedPrefs mcc, mnc: " + mccSource + "," + mncSource); - mccCurrent = networkOperator.substring(0, 3); - mncCurrent = networkOperator.substring(3); + mccCurrent = simOperator.substring(0, 3); + mncCurrent = simOperator.substring(3); Log.d(LOG_TAG, "using values for mcc, mnc: " + mccCurrent + "," + mncCurrent); if (TextUtils.equals(mncSource, mncCurrent) && TextUtils.equals(mccSource, mccCurrent)) { @@ -267,6 +299,7 @@ public class CarrierKeyDownloadManager { DownloadManager.Query query = new DownloadManager.Query(); query.setFilterById(carrierKeyDownloadIdentifier); Cursor cursor = mDownloadManager.query(query); + InputStream source = null; if (cursor == null) { return; @@ -275,7 +308,7 @@ public class CarrierKeyDownloadManager { int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS); if (DownloadManager.STATUS_SUCCESSFUL == cursor.getInt(columnIndex)) { try { - final InputStream source = new FileInputStream( + source = new FileInputStream( mDownloadManager.openDownloadedFile(carrierKeyDownloadIdentifier) .getFileDescriptor()); jsonStr = convertToString(source); @@ -285,6 +318,11 @@ public class CarrierKeyDownloadManager { + ". " + e); } finally { mDownloadManager.remove(carrierKeyDownloadIdentifier); + try { + source.close(); + } catch (IOException e) { + e.printStackTrace(); + } } } Log.d(LOG_TAG, "Completed downloading keys"); @@ -324,43 +362,43 @@ public class CarrierKeyDownloadManager { } private static String convertToString(InputStream is) { - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - StringBuilder sb = new StringBuilder(); - - String line; try { + // The current implementation at certain Carriers has the data gzipped, which requires + // us to unzip the contents. Longer term, we want to add a flag in carrier config which + // determines if the data needs to be zipped or not. + GZIPInputStream gunzip = new GZIPInputStream(is); + BufferedReader reader = new BufferedReader(new InputStreamReader(gunzip, UTF_8)); + StringBuilder sb = new StringBuilder(); + + String line; while ((line = reader.readLine()) != null) { sb.append(line).append('\n'); } + return sb.toString(); } catch (IOException e) { e.printStackTrace(); - } finally { - try { - is.close(); - } catch (IOException e) { - e.printStackTrace(); - } } - return sb.toString(); + return null; } /** * Converts the string into a json object to retreive the nodes. The Json should have 3 nodes, * including the Carrier public key, the key type and the key identifier. Once the nodes have * been extracted, they get persisted to the database. Sample: - * "carrier-keys": [ { "key": "", - * "type": WLAN, - * "identifier": "", - * "expiration-date": 1502577746000 + * "carrier-keys": [ { "certificate": "", + * "key-type": "WLAN", + * "key-identifier": "" * } ] * @param jsonStr the json string. - * @param mccMnc contains the mcc, mnc + * @param mccMnc contains the mcc, mnc. */ - private void parseJsonAndPersistKey(String jsonStr, String mccMnc) { + @VisibleForTesting + public void parseJsonAndPersistKey(String jsonStr, String mccMnc) { if (TextUtils.isEmpty(jsonStr) || TextUtils.isEmpty(mccMnc)) { Log.e(LOG_TAG, "jsonStr or mcc, mnc: is empty"); return; } + PemReader reader = null; try { String mcc = ""; String mnc = ""; @@ -369,10 +407,16 @@ public class CarrierKeyDownloadManager { mnc = splitValue[1]; JSONObject jsonObj = new JSONObject(jsonStr); JSONArray keys = jsonObj.getJSONArray(JSON_CARRIER_KEYS); - for (int i = 0; i < keys.length(); i++) { JSONObject key = keys.getJSONObject(i); - String carrierKey = key.getString(JSON_KEY); + // This is a hack to accommodate certain carriers who insist on using the public-key + // field to store the certificate. We'll just use which-ever is not null. + String cert = null; + if (key.has(JSON_CERTIFICATE)) { + cert = key.getString(JSON_CERTIFICATE); + } else { + cert = key.getString(JSON_CERTIFICATE_ALTERNATE); + } String typeString = key.getString(JSON_TYPE); int type = UNINITIALIZED_KEY_TYPE; if (typeString.equals(JSON_TYPE_VALUE_WLAN)) { @@ -380,13 +424,27 @@ public class CarrierKeyDownloadManager { } else if (typeString.equals(JSON_TYPE_VALUE_EPDG)) { type = TelephonyManager.KEY_TYPE_EPDG; } - long expiration_date = key.getLong(JSON_EXPIRATION_DATE); String identifier = key.getString(JSON_IDENTIFIER); - savePublicKey(carrierKey, type, identifier, expiration_date, - mcc, mnc); + ByteArrayInputStream inStream = new ByteArrayInputStream(cert.getBytes()); + Reader fReader = new BufferedReader(new InputStreamReader(inStream)); + reader = new PemReader(fReader); + Pair<PublicKey, Long> keyInfo = + getKeyInformation(reader.readPemObject().getContent()); + reader.close(); + savePublicKey(keyInfo.first, type, identifier, keyInfo.second, mcc, mnc); } } catch (final JSONException e) { Log.e(LOG_TAG, "Json parsing error: " + e.getMessage()); + } catch (final Exception e) { + Log.e(LOG_TAG, "Exception getting certificate: " + e); + } finally { + try { + if (reader != null) { + reader.close(); + } + } catch (final Exception e) { + Log.e(LOG_TAG, "Exception getting certificate: " + e); + } } } @@ -394,8 +452,8 @@ public class CarrierKeyDownloadManager { * introspects the mKeyAvailability bitmask * @return true if the digit at position k is 1, else false. */ - - private boolean isKeyEnabled(int keyType) { + @VisibleForTesting + public boolean isKeyEnabled(int keyType) { //since keytype has values of 1, 2.... we need to subtract 1 from the keytype. int returnValue = (mKeyAvailability >> (keyType - 1)) & 1; return (returnValue == 1) ? true : false; @@ -427,15 +485,13 @@ public class CarrierKeyDownloadManager { private boolean downloadKey() { Log.d(LOG_TAG, "starting download from: " + mURL); - final TelephonyManager telephonyManager = - (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); String mcc = ""; String mnc = ""; - String networkOperator = telephonyManager.getNetworkOperator(mPhone.getSubId()); + String simOperator = getSimOperator(); - if (!TextUtils.isEmpty(networkOperator)) { - mcc = networkOperator.substring(0, 3); - mnc = networkOperator.substring(3); + if (!TextUtils.isEmpty(simOperator)) { + mcc = simOperator.substring(0, 3); + mnc = simOperator.substring(3); Log.d(LOG_TAG, "using values for mcc, mnc: " + mcc + "," + mnc); } else { Log.e(LOG_TAG, "mcc, mnc: is empty"); @@ -461,11 +517,35 @@ public class CarrierKeyDownloadManager { return true; } - private void savePublicKey(String key, int type, String identifier, long expirationDate, + /** + * Save the public key + * @param certificate certificate that contains the public key. + * @return Pair containing the Public Key and the expiration date. + **/ + @VisibleForTesting + public static Pair<PublicKey, Long> getKeyInformation(byte[] certificate) throws Exception { + InputStream inStream = new ByteArrayInputStream(certificate); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream); + Pair<PublicKey, Long> keyInformation = + new Pair(cert.getPublicKey(), cert.getNotAfter().getTime()); + return keyInformation; + } + + /** + * Save the public key + * @param publicKey public key. + * @param type key-type. + * @param identifier which is an opaque string. + * @param expirationDate expiration date of the key. + * @param mcc + * @param mnc + **/ + @VisibleForTesting + public void savePublicKey(PublicKey publicKey, int type, String identifier, long expirationDate, String mcc, String mnc) { - byte[] keyBytes = Base64.decode(key.getBytes(), Base64.DEFAULT); ImsiEncryptionInfo imsiEncryptionInfo = new ImsiEncryptionInfo(mcc, mnc, type, identifier, - keyBytes, new Date(expirationDate)); + publicKey, new Date(expirationDate)); mPhone.setCarrierInfoForImsiEncryption(imsiEncryptionInfo); } } diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java index 8df201e583..77a39eb902 100644 --- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java @@ -79,13 +79,8 @@ public class CarrierServiceStateTracker extends Handler { switch (msg.what) { case CARRIER_EVENT_VOICE_REGISTRATION: case CARRIER_EVENT_DATA_REGISTRATION: - handleConfigChanges(); - break; case CARRIER_EVENT_VOICE_DEREGISTRATION: case CARRIER_EVENT_DATA_DEREGISTRATION: - if (isRadioOffOrAirplaneMode()) { - break; - } handleConfigChanges(); break; case NOTIFICATION_EMERGENCY_NETWORK: @@ -317,8 +312,8 @@ public class CarrierServiceStateTracker extends Handler { Rlog.i(LOG_TAG, "PrefNetworkNotification: sendMessage() w/values: " + "," + isPhoneStillRegistered() + "," + mDelay + "," + isGlobalMode() + "," + mSST.isRadioOn()); - if (mDelay == UNINITIALIZED_DELAY_VALUE || isPhoneStillRegistered() - || isGlobalMode()) { + if (mDelay == UNINITIALIZED_DELAY_VALUE || isPhoneStillRegistered() || isGlobalMode() + || isRadioOffOrAirplaneMode()) { return false; } return true; diff --git a/src/java/com/android/internal/telephony/ClientWakelockTracker.java b/src/java/com/android/internal/telephony/ClientWakelockTracker.java index 5bec60ba2f..fa71e76951 100644 --- a/src/java/com/android/internal/telephony/ClientWakelockTracker.java +++ b/src/java/com/android/internal/telephony/ClientWakelockTracker.java @@ -18,10 +18,10 @@ package com.android.internal.telephony; import android.os.SystemClock; import android.telephony.ClientRequestStats; -import android.telephony.Rlog; import com.android.internal.annotations.VisibleForTesting; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -119,13 +119,13 @@ public class ClientWakelockTracker { return false; } - void dumpClientRequestTracker() { - Rlog.d(RIL.RILJ_LOG_TAG, "-------mClients---------------"); + void dumpClientRequestTracker(PrintWriter pw) { + pw.println("-------mClients---------------"); synchronized (mClients) { for (String key : mClients.keySet()) { - Rlog.d(RIL.RILJ_LOG_TAG, "Client : " + key); - Rlog.d(RIL.RILJ_LOG_TAG, mClients.get(key).toString()); + pw.println("Client : " + key); + pw.println(mClients.get(key).toString()); } } } -}
\ No newline at end of file +} diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java index c13e54086e..98c0a32ecc 100644 --- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -125,6 +125,9 @@ public class DefaultPhoneNotifier implements PhoneNotifier { int subId = sender.getSubId(); try { if (mRegistry != null) { + Rlog.d(LOG_TAG, "notifyCallForwardingChanged: subId=" + subId + ", isCFActive=" + + sender.getCallForwardingIndicator()); + mRegistry.notifyCallForwardingChangedForSubscriber(subId, sender.getCallForwardingIndicator()); } diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 35a2d41ebb..5053341670 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -1855,6 +1855,8 @@ public class GsmCdmaPhone extends Phone { @Override public void setTTYMode(int ttyMode, Message onComplete) { + // Send out the TTY Mode change over RIL as well + super.setTTYMode(ttyMode, onComplete); if (mImsPhone != null) { mImsPhone.setTTYMode(ttyMode, onComplete); } @@ -2547,6 +2549,7 @@ public class GsmCdmaPhone extends Phone { private void processIccRecordEvents(int eventCode) { switch (eventCode) { case IccRecords.EVENT_CFI: + logi("processIccRecordEvents: EVENT_CFI"); notifyCallForwardingIndicator(); break; } diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java index 59195f83ba..391de50019 100644 --- a/src/java/com/android/internal/telephony/InboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java @@ -158,6 +158,17 @@ public abstract class InboundSmsHandler extends StateMachine { /** New SMS received as an AsyncResult. */ public static final int EVENT_INJECT_SMS = 8; + /** Update tracker object; used only in waiting state */ + private static final int EVENT_UPDATE_TRACKER = 9; + + /** Timeout in case state machine is stuck in a state for too long; used only in waiting + * state */ + private static final int EVENT_STATE_TIMEOUT = 10; + + /** Timeout duration for EVENT_STATE_TIMEOUT */ + @VisibleForTesting + public static final int STATE_TIMEOUT = 30000; + /** Wakelock release delay when returning to idle state. */ private static final int WAKELOCK_TIMEOUT = 3000; @@ -450,6 +461,7 @@ public abstract class InboundSmsHandler extends StateMachine { // if any broadcasts were sent, transition to waiting state InboundSmsTracker inboundSmsTracker = (InboundSmsTracker) msg.obj; if (processMessagePart(inboundSmsTracker)) { + sendMessage(EVENT_UPDATE_TRACKER, inboundSmsTracker); transitionTo(mWaitingState); } else { // if event is sent from SmsBroadcastUndelivered.broadcastSms(), and @@ -493,18 +505,41 @@ public abstract class InboundSmsHandler extends StateMachine { * {@link IdleState} after any deferred {@link #EVENT_BROADCAST_SMS} messages are handled. */ private class WaitingState extends State { + private InboundSmsTracker mTracker; + + @Override + public void enter() { + if (DBG) log("entering Waiting state"); + mTracker = null; + sendMessageDelayed(EVENT_STATE_TIMEOUT, STATE_TIMEOUT); + } + @Override public void exit() { if (DBG) log("exiting Waiting state"); // Before moving to idle state, set wakelock timeout to WAKE_LOCK_TIMEOUT milliseconds // to give any receivers time to take their own wake locks setWakeLockTimeout(WAKELOCK_TIMEOUT); + if (VDBG) { + if (hasMessages(EVENT_STATE_TIMEOUT)) { + log("exiting Waiting state: removing EVENT_STATE_TIMEOUT from message queue"); + } + if (hasMessages(EVENT_UPDATE_TRACKER)) { + log("exiting Waiting state: removing EVENT_UPDATE_TRACKER from message queue"); + } + } + removeMessages(EVENT_STATE_TIMEOUT); + removeMessages(EVENT_UPDATE_TRACKER); } @Override public boolean processMessage(Message msg) { log("WaitingState.processMessage:" + msg.what); switch (msg.what) { + case EVENT_UPDATE_TRACKER: + mTracker = (InboundSmsTracker) msg.obj; + return HANDLED; + case EVENT_BROADCAST_SMS: // defer until the current broadcast completes deferMessage(msg); @@ -520,6 +555,18 @@ public abstract class InboundSmsHandler extends StateMachine { // not ready to return to idle; ignore return HANDLED; + case EVENT_STATE_TIMEOUT: + // stuck in WaitingState for too long; drop the message and exit this state + if (mTracker != null) { + log("WaitingState.processMessage: EVENT_STATE_TIMEOUT; dropping message"); + dropSms(new SmsBroadcastReceiver(mTracker)); + } else { + log("WaitingState.processMessage: EVENT_STATE_TIMEOUT; mTracker is null " + + "- sending EVENT_BROADCAST_COMPLETE"); + sendMessage(EVENT_BROADCAST_COMPLETE); + } + return HANDLED; + default: // parent state handles the other message types return NOT_HANDLED; diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index 28e45565fa..8b0c6775db 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -56,6 +56,7 @@ import android.telephony.SignalStrength; import android.telephony.SubscriptionManager; import android.telephony.VoLteServiceState; import android.text.TextUtils; +import android.util.Log; import com.android.ims.ImsCall; import com.android.ims.ImsConfig; @@ -1789,7 +1790,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { int status = enable ? IccRecords.CALL_FORWARDING_STATUS_ENABLED : IccRecords.CALL_FORWARDING_STATUS_DISABLED; int subId = getSubId(); - Rlog.d(LOG_TAG, "setCallForwardingIndicatorInSharedPref: Storing status = " + status + + Rlog.i(LOG_TAG, "setCallForwardingIndicatorInSharedPref: Storing status = " + status + " in pref " + CF_STATUS + subId); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); @@ -1831,6 +1832,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { if (callForwardingIndicator == IccRecords.CALL_FORWARDING_STATUS_UNKNOWN) { callForwardingIndicator = getCallForwardingIndicatorFromSharedPref(); } + Rlog.v(LOG_TAG, "getCallForwardingIndicator: iccForwardingFlag=" + (r != null + ? r.getVoiceCallForwardingFlag() : "null") + ", sharedPrefFlag=" + + getCallForwardingIndicatorFromSharedPref()); return (callForwardingIndicator == IccRecords.CALL_FORWARDING_STATUS_ENABLED); } diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 3ed591f9b4..226ee8e3dc 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -4910,7 +4910,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { } pw.println(" mLastNITZTimeInfo=" + Arrays.toString(mLastNITZTimeInfo)); pw.println(" mTestingEmergencyCall=" + mTestingEmergencyCall.get()); - mClientWakelockTracker.dumpClientRequestTracker(); + mClientWakelockTracker.dumpClientRequestTracker(pw); } public List<ClientRequestStats> getClientRequestStats() { diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index e9d6759944..d3c17dd89f 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -210,6 +210,7 @@ public class ServiceStateTracker extends Handler { protected static final int EVENT_ALL_DATA_DISCONNECTED = 49; protected static final int EVENT_PHONE_TYPE_SWITCHED = 50; protected static final int EVENT_RADIO_POWER_FROM_CARRIER = 51; + protected static final int EVENT_SIM_NOT_INSERTED = 52; protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; @@ -354,6 +355,14 @@ public class ServiceStateTracker extends Handler { } // update voicemail count and notify message waiting changed mPhone.updateVoiceMail(); + + // cancel notifications if we see SIM_NOT_INSERTED (This happens on bootup before + // the SIM is first detected and then subsequently on SIM removals) + if (mSubscriptionController.getSlotIndex(subId) + == SubscriptionManager.SIM_NOT_INSERTED) { + // this is handled on the main thread to mitigate racing with setNotification(). + sendMessage(obtainMessage(EVENT_SIM_NOT_INSERTED)); + } } } }; @@ -446,7 +455,6 @@ public class ServiceStateTracker extends Handler { public static final int CS_NORMAL_ENABLED = 1005; // Access Control blocks normal voice/sms service public static final int CS_EMERGENCY_ENABLED = 1006; // Access Control blocks emergency call service public static final int CS_REJECT_CAUSE_ENABLED = 2001; // Notify MM rejection cause - public static final int CS_REJECT_CAUSE_DISABLED = 2002; // Cancel MM rejection cause /** Notification id. */ public static final int PS_NOTIFICATION = 888; // Id to update and cancel PS restricted public static final int CS_NOTIFICATION = 999; // Id to update and cancel CS restricted @@ -1297,6 +1305,14 @@ public class ServiceStateTracker extends Handler { } break; + case EVENT_SIM_NOT_INSERTED: + if (DBG) log("EVENT_SIM_NOT_INSERTED"); + cancelAllNotifications(); + mMdn = null; + mMin = null; + mIsMinInfoReady = false; + break; + case EVENT_ALL_DATA_DISCONNECTED: int dds = SubscriptionManager.getDefaultDataSubscriptionId(); ProxyController.getInstance().unregisterForAllDataDisconnected(dds, this); @@ -2820,7 +2836,7 @@ public class ServiceStateTracker extends Handler { } if (hasRejectCauseChanged) { - setNotification(mRejectCode == 0 ? CS_REJECT_CAUSE_DISABLED : CS_REJECT_CAUSE_ENABLED); + setNotification(CS_REJECT_CAUSE_ENABLED); } if (hasChanged) { @@ -3846,6 +3862,18 @@ public class ServiceStateTracker extends Handler { } /** + * Cancels all notifications posted to NotificationManager. These notifications for restricted + * state and rejection cause for cs registration are no longer valid after the SIM has been + * removed. + */ + private void cancelAllNotifications() { + if (DBG) log("setNotification: cancelAllNotifications"); + NotificationManager notificationManager = (NotificationManager) + mPhone.getContext().getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.cancelAll(); + } + + /** * Post a notification to NotificationManager for restricted state and * rejection cause for cs registration * @@ -3920,17 +3948,14 @@ public class ServiceStateTracker extends Handler { notificationId = CS_REJECT_CAUSE_NOTIFICATION; int resId = selectResourceForRejectCode(mRejectCode); if (0 == resId) { - // cancel notification because current reject code is not handled. - notifyType = CS_REJECT_CAUSE_DISABLED; + loge("setNotification: mRejectCode=" + mRejectCode + " is not handled."); + return; } else { icon = com.android.internal.R.drawable.stat_notify_mmcc_indication_icn; title = Resources.getSystem().getString(resId); details = null; } break; - case CS_REJECT_CAUSE_DISABLED: - notificationId = CS_REJECT_CAUSE_NOTIFICATION; - break; } if (DBG) { @@ -3954,8 +3979,7 @@ public class ServiceStateTracker extends Handler { NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - if (notifyType == PS_DISABLED || notifyType == CS_DISABLED - || notifyType == CS_REJECT_CAUSE_DISABLED) { + if (notifyType == PS_DISABLED || notifyType == CS_DISABLED) { // cancel previous post notification notificationManager.cancel(notificationId); } else { diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 3c13a408ae..45dc0b2798 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -713,7 +713,6 @@ public class ImsPhone extends ImsPhoneBase { @Override public void setTTYMode(int ttyMode, Message onComplete) { - super.setTTYMode(ttyMode, onComplete); mCT.setTtyMode(ttyMode); } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java index 87b96d8b8b..c165b03e3b 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java @@ -496,9 +496,6 @@ abstract class ImsPhoneBase extends Phone { 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 c19c28bc1f..072da68ed9 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -726,6 +726,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { return NetworkStats.UID_ALL; } + // Initialize to UID_ALL so at least it can be counted to overall data usage if + // the dialer's package uid is not available. int uid = NetworkStats.UID_ALL; try { uid = context.getPackageManager().getPackageUid(pkg, 0); @@ -2549,7 +2551,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN; if (isHandoverFromWifi && imsCall.isVideoCall()) { - if (mNotifyHandoverVideoFromWifiToLTE) { + if (mNotifyHandoverVideoFromWifiToLTE && mIsDataEnabled) { log("onCallHandover :: notifying of WIFI to LTE handover."); conn.onConnectionEvent( TelephonyManager.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE, null); @@ -2558,7 +2560,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { if (!mIsDataEnabled && mIsViLteDataMetered) { // Call was downgraded from WIFI to LTE and data is metered; downgrade the // call now. - downgradeVideoCall(ImsReasonInfo.CODE_DATA_DISABLED, conn); + downgradeVideoCall(ImsReasonInfo.CODE_WIFI_LOST, conn); } } } else { @@ -2999,6 +3001,17 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // a separate entry if uid is different from the previous snapshot. NetworkStats vtDataUsageUidSnapshot = new NetworkStats(currentTime, 1); vtDataUsageUidSnapshot.combineAllValues(mVtDataUsageUidSnapshot); + + // The dialer uid might not be initialized correctly during boot up due to telecom service + // not ready or its default dialer cache not ready. So we double check again here to see if + // default dialer uid is really not available. + if (mDefaultDialerUid.get() == NetworkStats.UID_ALL) { + final TelecomManager telecomManager = + (TelecomManager) mPhone.getContext().getSystemService(Context.TELECOM_SERVICE); + mDefaultDialerUid.set( + getPackageUid(mPhone.getContext(), telecomManager.getDefaultDialerPackage())); + } + // Since the modem only reports the total vt data usage rather than rx/tx separately, // the only thing we can do here is splitting the usage into half rx and half tx. vtDataUsageUidSnapshot.combineValues(new NetworkStats.Entry( @@ -3507,8 +3520,9 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { // If the carrier supports downgrading to voice, then we can simply issue a // downgrade to voice instead of terminating the call. modifyVideoCall(imsCall, VideoProfile.STATE_AUDIO_ONLY); - } else if (mSupportPauseVideo) { - // The carrier supports video pause signalling, so pause the video. + } else if (mSupportPauseVideo && reasonCode != ImsReasonInfo.CODE_WIFI_LOST) { + // The carrier supports video pause signalling, so pause the video if we didn't just + // lose wifi; in that case just disconnect. mShouldUpdateImsConfigOnDisconnect = true; conn.pauseVideo(VideoPauseTracker.SOURCE_DATA_ENABLED); } else { diff --git a/src/java/com/android/internal/telephony/util/NotificationChannelController.java b/src/java/com/android/internal/telephony/util/NotificationChannelController.java index 9967b05dc0..54d7d1abd8 100644 --- a/src/java/com/android/internal/telephony/util/NotificationChannelController.java +++ b/src/java/com/android/internal/telephony/util/NotificationChannelController.java @@ -58,21 +58,26 @@ public class NotificationChannelController { alertChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build()); + final NotificationChannel mobileDataStatusChannel = new NotificationChannel( + CHANNEL_ID_MOBILE_DATA_STATUS, + context.getText(R.string.notification_channel_mobile_data_status), + NotificationManager.IMPORTANCE_LOW); + // allow users to block notifications from system + mobileDataStatusChannel.setBlockableSystem(true); + context.getSystemService(NotificationManager.class) .createNotificationChannels(Arrays.asList( new NotificationChannel(CHANNEL_ID_CALL_FORWARD, context.getText(R.string.notification_channel_call_forward), NotificationManager.IMPORTANCE_LOW), - new NotificationChannel(CHANNEL_ID_MOBILE_DATA_STATUS, - context.getText(R.string.notification_channel_mobile_data_status), - NotificationManager.IMPORTANCE_LOW), new NotificationChannel(CHANNEL_ID_SMS, context.getText(R.string.notification_channel_sms), NotificationManager.IMPORTANCE_HIGH), new NotificationChannel(CHANNEL_ID_WFC, context.getText(R.string.notification_channel_wfc), NotificationManager.IMPORTANCE_LOW), - alertChannel)); + alertChannel, + mobileDataStatusChannel)); // 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 fd2cbb2a57..b777fac90f 100644 --- a/tests/telephonytests/Android.mk +++ b/tests/telephonytests/Android.mk @@ -7,7 +7,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) #LOCAL_STATIC_JAVA_LIBRARIES := librilproto-java -LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common ims-common services.core +LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common ims-common services.core bouncycastle LOCAL_STATIC_JAVA_LIBRARIES := guava \ frameworks-base-testutils \ mockito-target-minus-junit4 \ diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java new file mode 100644 index 0000000000..4b99cbe58f --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierKeyDownloadMgrTest.java @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony; + +import android.app.DownloadManager; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.HandlerThread; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.telephony.ImsiEncryptionInfo; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Pair; + +import com.android.org.bouncycastle.util.io.pem.PemReader; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Matchers; +import org.mockito.MockitoAnnotations; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.security.PublicKey; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +import static android.preference.PreferenceManager.getDefaultSharedPreferences; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class CarrierKeyDownloadMgrTest extends TelephonyTest { + + private static final String LOG_TAG = "CarrierKeyDownloadManager"; + + private CarrierKeyDownloadManager mCarrierKeyDM; + private CarrierActionAgentHandler mCarrierActionAgentHandler; + + private String mURL = "http://www.google.com"; + + private static final String CERT = "-----BEGIN CERTIFICATE-----\r\nMIIFjzCCBHegAwIBAgIUPxj3SLif82Ky1RlUy8p2EWJCh8MwDQYJKoZIhvcNAQELBQAwgY0xCzAJBgNVBAYTAk5MMRIwEAYDVQQHEwlBbXN0ZXJkYW0xJTAjBgNVBAoTHFZlcml6b24gRW50ZXJwcmlzZSBTb2x1dGlvbnMxEzARBgNVBAsTCkN5YmVydHJ1c3QxLjAsBgNVBAMTJVZlcml6b24gUHVibGljIFN1cmVTZXJ2ZXIgQ0EgRzE0LVNIQTIwHhcNMTcwODE0MTc0MzM4WhcNMTkwODE0MTc0MzM4WjCBmTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFjAUBgNVBAcTDUJhc2tpbmcgUmlkZ2UxIjAgBgNVBAoTGVZlcml6b24gRGF0YSBTZXJ2aWNlcyBMTEMxHzAdBgNVBAsTFk5ldHdvcmsgU3lzdGVtIFN1cHBvcnQxGDAWBgNVBAMTD3ZpMWx2Lmltc3ZtLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALUQKWTHi4Hjpd1LQwJ87RXa0Rs3rVonvVevliqdUH5BikjhAzvIqwPSXeRQqkaRTFIyp0NKcNqGdjAaHRo43gdHeWSH331sS6CMZDg988gZznskzCqJJo6ii5FuLC8qe2YDsHxT+CefXev2rn6Bj1ei2X74uZsy5KlkBRZfFHtPdK6/EK5TpzrvcXfDyOK1rn8FTno1bQOTAhL39GPcLhdrXV7AN+lu+EBpdCqlTdcoDxsqavi/91MwUIVEzxJmycKloT6OWfU44r7+L5SYYgc88NTaGL/BvCFwHRIa1ZgYSGeAPes45792MGG7tfr/ttAGp9UEwTv2zWTxzWnRP/UCAwEAAaOCAdcwggHTMAwGA1UdEwEB/wQCMAAwTAYDVR0gBEUwQzBBBgkrBgEEAbE+ATIwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly9zZWN1cmUub21uaXJvb3QuY29tL3JlcG9zaXRvcnkwgakGCCsGAQUFBwEBBIGcMIGZMC0GCCsGAQUFBzABhiFodHRwOi8vdnBzc2cxNDIub2NzcC5vbW5pcm9vdC5jb20wMwYIKwYBBQUHMAKGJ2h0dHA6Ly9jYWNlcnQub21uaXJvb3QuY29tL3Zwc3NnMTQyLmNydDAzBggrBgEFBQcwAoYnaHR0cDovL2NhY2VydC5vbW5pcm9vdC5jb20vdnBzc2cxNDIuZGVyMBoGA1UdEQQTMBGCD3ZpMWx2Lmltc3ZtLmNvbTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB8GA1UdIwQYMBaAFOQtu5EBZSYftHo/oxUlpM6MRDM7MD4GA1UdHwQ3MDUwM6AxoC+GLWh0dHA6Ly92cHNzZzE0Mi5jcmwub21uaXJvb3QuY29tL3Zwc3NnMTQyLmNybDAdBgNVHQ4EFgQUv5SaSyNM/yXw1v0N9TNpjsFCaPcwDQYJKoZIhvcNAQELBQADggEBACNJusTULj1KyV4RwiskKfp4wI9Hsz3ESbZS/ijF9D57BQ0UwkELU9r6rEAhsYLUvMq4sDhDbYIdupgP4MBzFnjkKult7VQm5W3nCcuHgXYFAJ9Y1a4OZAo/4hrHj70W9TsQ1ioSMjUT4F8bDUYZI0kcyH8e/+2DaTsLUpHw3L+Keu8PsJVBLnvcKJjWrZD/Bgd6JuaTX2G84i0rY0GJuO9CxLNJa6n61Mz5cqLYIuwKgiVgTA2n71YITyFICOFPFX1vSx35AWvD6aVYblxtC8mpCdF2h4s1iyrpXeji2GCJLwsNVtTtNQ4zWX3Gnq683wzkYZeyOHUyftIgAQZ+HsY=\r\n-----END CERTIFICATE-----"; + + + private String mJsonStr = "{ \"carrier-keys\": [ { \"certificate\": \"" + CERT + "\", \"key-type\": \"WLAN\", \"key-identifier\": \"key1=value\", \"expiration-date\": 1502577746000 }, { \"certificate\": \"" + CERT + "\", \"key-type\": \"WLAN\", \"key-identifier\": \"key1=value\", \"expiration-date\": 1502577746000 }]}"; + + private String mJsonStr1 = "{ \"carrier-keys\": [ { \"public-key\": \"" + CERT + "\", \"key-type\": \"WLAN\", \"key-identifier\": \"key1=value\", \"expiration-date\": 1502577746000 }, { \"public-key\": \"" + CERT + "\", \"key-type\": \"WLAN\", \"key-identifier\": \"key1=value\", \"expiration-date\": 1502577746000 }]}"; + + private class CarrierActionAgentHandler extends HandlerThread { + + private CarrierActionAgentHandler(String name) { + super(name); + } + + @Override + public void onLooperPrepared() { + mCarrierKeyDM = new CarrierKeyDownloadManager(mPhone); + setReady(true); + } + } + + @Before + public void setUp() throws Exception { + logd("CarrierActionAgentTest +Setup!"); + MockitoAnnotations.initMocks(this); + super.setUp(getClass().getSimpleName()); + mCarrierActionAgentHandler = new CarrierActionAgentHandler(getClass().getSimpleName()); + mCarrierActionAgentHandler.start(); + waitUntilReady(); + logd("CarrierActionAgentTest -Setup!"); + } + + @After + public void tearDown() throws Exception { + mCarrierActionAgentHandler.quit(); + super.tearDown(); + } + + /* Checks if the expiration date is calculated correctly + * In this case the expiration date should be the next day. + */ + @Test + @SmallTest + public void testExpirationDate1Day() { + java.security.PublicKey publicKey = null; + mCarrierKeyDM.mKeyAvailability = 3; + SimpleDateFormat dt = new SimpleDateFormat("yyyy-mm-dd"); + Calendar cal = new GregorianCalendar(); + cal.add(Calendar.DATE, 6); + Date date = cal.getTime(); + Calendar expectedCal = new GregorianCalendar(); + expectedCal.add(Calendar.DATE, 1); + String dateExpected = dt.format(expectedCal.getTime()); + ImsiEncryptionInfo imsiEncryptionInfo = new ImsiEncryptionInfo("mcc", "mnc", 1, + "keyIdentifier", publicKey, date); + when(mPhone.getCarrierInfoForImsiEncryption(anyInt())).thenReturn(imsiEncryptionInfo); + Date expirationDate = new Date(mCarrierKeyDM.getExpirationDate()); + assertTrue(dt.format(expirationDate).equals(dateExpected)); + } + + /** + * Checks if the expiration date is calculated correctly + * In this case the expiration date should be the expiration date of the key. + **/ + @Test + @SmallTest + public void testExpirationDate7Day() { + java.security.PublicKey publicKey = null; + mCarrierKeyDM.mKeyAvailability = 3; + SimpleDateFormat dt = new SimpleDateFormat("yyyy-mm-dd"); + Calendar cal = new GregorianCalendar(); + cal.add(Calendar.DATE, 10); + Date date = cal.getTime(); + Calendar expectedCal = new GregorianCalendar(); + expectedCal.add(Calendar.DATE, 3); + String dateExpected = dt.format(expectedCal.getTime()); + ImsiEncryptionInfo imsiEncryptionInfo = new ImsiEncryptionInfo("mcc", "mnc", 1, + "keyIdentifier", publicKey, date); + when(mPhone.getCarrierInfoForImsiEncryption(anyInt())).thenReturn(imsiEncryptionInfo); + Date expirationDate = new Date(mCarrierKeyDM.getExpirationDate()); + assertTrue(dt.format(expirationDate).equals(dateExpected)); + } + + /** + * Checks if the json is parse correctly. + * Verify that setCarrierInfoForImsiEncryption is called with the right params + **/ + @Test + @SmallTest + public void testParseJson() { + ByteArrayInputStream certBytes = new ByteArrayInputStream(CERT.getBytes()); + Reader fRd = new BufferedReader(new InputStreamReader(certBytes)); + PemReader reader = new PemReader(fRd); + Pair<PublicKey, Long> keyInfo = null; + try { + keyInfo = mCarrierKeyDM.getKeyInformation(reader.readPemObject().getContent()); + } catch (Exception e) { + fail(LOG_TAG + "exception creating public key"); + } + ImsiEncryptionInfo imsiEncryptionInfo = new ImsiEncryptionInfo("310", "270", 2, + "key1=value", keyInfo.first, new Date(keyInfo.second)); + String mccMnc = "310:270"; + mCarrierKeyDM.parseJsonAndPersistKey(mJsonStr, mccMnc); + verify(mPhone, times(2)).setCarrierInfoForImsiEncryption( + (Matchers.refEq(imsiEncryptionInfo))); + } + + /** + * Checks if the json is parse correctly. + * Same as testParseJason, except that the test looks for the "public-key" field. + **/ + @Test + @SmallTest + public void testParseJsonPublicKey() { + ByteArrayInputStream certBytes = new ByteArrayInputStream(CERT.getBytes()); + Reader fRd = new BufferedReader(new InputStreamReader(certBytes)); + PemReader reader = new PemReader(fRd); + Pair<PublicKey, Long> keyInfo = null; + try { + keyInfo = mCarrierKeyDM.getKeyInformation(reader.readPemObject().getContent()); + } catch (Exception e) { + fail(LOG_TAG + "exception creating public key"); + } + ImsiEncryptionInfo imsiEncryptionInfo = new ImsiEncryptionInfo("310", "270", 2, + "key1=value", keyInfo.first, new Date(keyInfo.second)); + String mccMnc = "310:270"; + mCarrierKeyDM.parseJsonAndPersistKey(mJsonStr1, mccMnc); + verify(mPhone, times(2)).setCarrierInfoForImsiEncryption( + (Matchers.refEq(imsiEncryptionInfo))); + } + + /** + * Checks if the json is parse correctly. + * Since the json is bad, we want to verify that savePublicKey is not called. + **/ + @Test + @SmallTest + public void testParseBadJsonFail() { + String mccMnc = "310:290"; + String badJsonStr = "{badJsonString}"; + mCarrierKeyDM.parseJsonAndPersistKey(badJsonStr, mccMnc); + verify(mPhone, times(0)).setCarrierInfoForImsiEncryption(any()); + } + + /** + * Checks if the download is valid. + * returns true since the mnc/mcc is valid. + **/ + @Test + @SmallTest + public void testIsValidDownload() { + String mccMnc = "310:260"; + when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260"); + assertTrue(mCarrierKeyDM.isValidDownload(mccMnc)); + } + + /** + * Checks if the download is valid. + * returns false since the mnc/mcc is in-valid. + **/ + @Test + @SmallTest + public void testIsValidDownloadFail() { + String mccMnc = "310:290"; + when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260"); + assertFalse(mCarrierKeyDM.isValidDownload(mccMnc)); + } + + /** + * Tests if the key is enabled. + * tests for all bit-mask value. + **/ + @Test + @SmallTest + public void testIsKeyEnabled() { + mCarrierKeyDM.mKeyAvailability = 3; + assertTrue(mCarrierKeyDM.isKeyEnabled(1)); + assertTrue(mCarrierKeyDM.isKeyEnabled(2)); + mCarrierKeyDM.mKeyAvailability = 2; + assertFalse(mCarrierKeyDM.isKeyEnabled(1)); + assertTrue(mCarrierKeyDM.isKeyEnabled(2)); + mCarrierKeyDM.mKeyAvailability = 1; + assertTrue(mCarrierKeyDM.isKeyEnabled(1)); + assertFalse(mCarrierKeyDM.isKeyEnabled(2)); + } + + /** + * Tests sending the ACTION_DOWNLOAD_COMPLETE intent. + * Verify that the alarm will kick-off the next day. + **/ + @Test + @SmallTest + public void testDownloadComplete() { + SharedPreferences.Editor editor = getDefaultSharedPreferences(mContext).edit(); + String mccMnc = "310:260"; + int slotId = mPhone.getPhoneId(); + editor.putString("CARRIER_KEY_DM_MCC_MNC" + slotId, mccMnc); + editor.commit(); + + SimpleDateFormat dt = new SimpleDateFormat("yyyy-mm-dd"); + Calendar expectedCal = new GregorianCalendar(); + expectedCal.add(Calendar.DATE, 1); + String dateExpected = dt.format(expectedCal.getTime()); + + when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260"); + Intent mIntent = new Intent(DownloadManager.ACTION_DOWNLOAD_COMPLETE); + mContext.sendBroadcast(mIntent); + Date expirationDate = new Date(mCarrierKeyDM.getExpirationDate()); + assertTrue(dt.format(expirationDate).equals(dateExpected)); + } + + /** + * Test sending the ACTION_CARRIER_CONFIG_CHANGED intent. + * Verify that the right mnc/mcc gets stored in the preferences. + **/ + @Test + @SmallTest + public void testCarrierConfigChanged() { + CarrierConfigManager carrierConfigManager = (CarrierConfigManager) + mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); + int slotId = mPhone.getPhoneId(); + PersistableBundle bundle = carrierConfigManager.getConfigForSubId(slotId); + bundle.putInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, 3); + bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL); + + when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260"); + Intent mIntent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + mIntent.putExtra(PhoneConstants.PHONE_KEY, 0); + mContext.sendBroadcast(mIntent); + SharedPreferences preferences = getDefaultSharedPreferences(mContext); + String mccMnc = preferences.getString("CARRIER_KEY_DM_MCC_MNC" + slotId, null); + assertTrue(mccMnc.equals("310:260")); + } + + /** + * Tests sending the INTENT_KEY_RENEWAL_ALARM_PREFIX intent. + * Verify that the right mnc/mcc gets stored in the preferences. + **/ + @Test + @SmallTest + public void testAlarmRenewal() { + CarrierConfigManager carrierConfigManager = (CarrierConfigManager) + mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); + int slotId = mPhone.getPhoneId(); + PersistableBundle bundle = carrierConfigManager.getConfigForSubId(slotId); + bundle.putInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT, 3); + bundle.putString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING, mURL); + + when(mTelephonyManager.getSimOperator(anyInt())).thenReturn("310260"); + Intent mIntent = new Intent("com.android.internal.telephony.carrier_key_download_alarm" + + slotId); + mContext.sendBroadcast(mIntent); + SharedPreferences preferences = getDefaultSharedPreferences(mContext); + String mccMnc = preferences.getString("CARRIER_KEY_DM_MCC_MNC" + slotId, null); + assertTrue(mccMnc.equals("310:260")); + } +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java index 7e8a4393fa..2afdcf97d7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java +++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.when; import android.app.AlarmManager; import android.app.AppOpsManager; +import android.app.DownloadManager; import android.app.NotificationManager; import android.app.usage.UsageStatsManager; import android.content.BroadcastReceiver; @@ -240,6 +241,8 @@ public class ContextFixture implements TestFixture<Context> { return mEuiccManager; case Context.TELECOM_SERVICE: return mTelecomManager; + case Context.DOWNLOAD_SERVICE: + return mDownloadManager; case Context.DISPLAY_SERVICE: case Context.POWER_SERVICE: // PowerManager and DisplayManager are final classes so cannot be mocked, @@ -496,6 +499,7 @@ public class ContextFixture implements TestFixture<Context> { private final Resources mResources = mock(Resources.class); private final PackageManager mPackageManager = mock(PackageManager.class); private final TelephonyManager mTelephonyManager = mock(TelephonyManager.class); + private final DownloadManager mDownloadManager = mock(DownloadManager.class); private final AppOpsManager mAppOpsManager = mock(AppOpsManager.class); private final NotificationManager mNotificationManager = mock(NotificationManager.class); private final UserManager mUserManager = mock(UserManager.class); diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java index 260b23500b..5e3f9487c3 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java @@ -26,6 +26,7 @@ import android.support.test.filters.FlakyTest; import android.telephony.PhoneNumberUtils; import android.test.suitebuilder.annotation.SmallTest; import android.text.SpannableStringBuilder; +import android.text.style.TtsSpan; import org.junit.Ignore; import org.junit.Test; @@ -751,4 +752,21 @@ public class PhoneNumberUtilsTest { assertEquals("tim_123", PhoneNumberUtils.getUsernameFromUriNumber("tim_123@zzz.org")); assertEquals("5103331245", PhoneNumberUtils.getUsernameFromUriNumber("5103331245")); } + + @SmallTest + @Test + public void testCreateTtsSpan() { + checkTtsNumber("650 555 1212", "650-555-1212"); + checkTtsNumber("6505551212", "+1-650-555-1212"); + checkTtsNumber("232", "232"); + checkTtsNumber("*232", "*232"); + checkTtsNumber("*232#", "*232#"); + checkTtsNumber("*650 555 1212#", "*650-555-1212#"); + } + + private void checkTtsNumber(String expected, String sourceNumber) { + TtsSpan ttsSpan = PhoneNumberUtils.createTtsSpan(sourceNumber); + assertEquals(TtsSpan.TYPE_TELEPHONE, ttsSpan.getType()); + assertEquals(expected, ttsSpan.getArgs().getString(TtsSpan.ARG_NUMBER_PARTS)); + } } 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 bb090147c5..02758ac397 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java @@ -47,8 +47,8 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Telephony; import android.support.test.filters.FlakyTest; +import android.support.test.filters.MediumTest; import android.test.mock.MockContentResolver; -import android.test.suitebuilder.annotation.MediumTest; import com.android.internal.telephony.FakeSmsContentProvider; import com.android.internal.telephony.InboundSmsHandler; @@ -781,4 +781,28 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { verifySmsIntentBroadcasts(0); } + + @FlakyTest + @Ignore + @Test + @MediumTest + public void testWaitingStateTimeout() throws Exception { + transitionFromStartupToIdle(); + + // send new SMS to state machine and verify that triggers SMS_DELIVER_ACTION + mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, + new AsyncResult(null, mSmsMessage, null)); + waitForMs(100); + + ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); + verify(mContext, times(1)).sendBroadcast( + intentArgumentCaptor.capture()); + assertEquals(Telephony.Sms.Intents.SMS_DELIVER_ACTION, + intentArgumentCaptor.getAllValues().get(0).getAction()); + assertEquals("WaitingState", getCurrentState().getName()); + + waitForMs(InboundSmsHandler.STATE_TIMEOUT + 300); + + assertEquals("IdleState", getCurrentState().getName()); + } } |