diff options
Diffstat (limited to 'telephony/java')
60 files changed, 4674 insertions, 3247 deletions
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index dbe8431..4368464 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -22,11 +22,17 @@ import android.database.Cursor; import android.net.Uri; import android.os.SystemProperties; import android.provider.Contacts; +import android.provider.ContactsContract; import android.text.Editable; import android.text.SpannableStringBuilder; import android.text.TextUtils; +import android.util.Log; import android.util.SparseIntArray; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_IDP_STRING; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY; + import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -56,6 +62,9 @@ public class PhoneNumberUtils public static final int TOA_International = 0x91; public static final int TOA_Unknown = 0x81; + static final String LOG_TAG = "PhoneNumberUtils"; + private static final boolean DBG = false; + /* * global-phone-number = ["+"] 1*( DIGIT / written-sep ) * written-sep = ("-"/".") @@ -129,15 +138,23 @@ public class PhoneNumberUtils } String type = intent.resolveType(context); + String phoneColumn = null; + + // Correctly read out the phone entry based on requested provider + final String authority = uri.getAuthority(); + if (Contacts.AUTHORITY.equals(authority)) { + phoneColumn = Contacts.People.Phones.NUMBER; + } else if (ContactsContract.AUTHORITY.equals(authority)) { + phoneColumn = ContactsContract.CommonDataKinds.Phone.NUMBER; + } - Cursor c = context.getContentResolver().query( - uri, new String[]{ Contacts.People.Phones.NUMBER }, - null, null, null); + final Cursor c = context.getContentResolver().query(uri, new String[] { + phoneColumn + }, null, null, null); if (c != null) { try { if (c.moveToFirst()) { - number = c.getString( - c.getColumnIndex(Contacts.People.Phones.NUMBER)); + number = c.getString(c.getColumnIndex(phoneColumn)); } } finally { c.close(); @@ -218,6 +235,9 @@ public class PhoneNumberUtils } } + private static void log(String msg) { + Log.d(LOG_TAG, msg); + } /** index of the last character of the network portion * (eg anything after is a post-dial string) */ @@ -732,6 +752,14 @@ public class PhoneNumberUtils return true; } + private static boolean isNonSeparator(String address) { + for (int i = 0, count = address.length(); i < count; i++) { + if (!isNonSeparator(address.charAt(i))) { + return false; + } + } + return true; + } /** * Note: calls extractNetworkPortion(), so do not use for * SIM EF[ADN] style records @@ -903,7 +931,7 @@ public class PhoneNumberUtils "JM", // Jamaica "PR", // Puerto Rico "MS", // Montserrat - "NP", // Northern Mariana Islands + "MP", // Northern Mariana Islands "KN", // Saint Kitts and Nevis "LC", // Saint Lucia "VC", // Saint Vincent and the Grenadines @@ -936,17 +964,7 @@ public class PhoneNumberUtils public static int getFormatTypeForLocale(Locale locale) { String country = locale.getCountry(); - // Check for the NANP countries - int length = NANP_COUNTRIES.length; - for (int i = 0; i < length; i++) { - if (NANP_COUNTRIES[i].equals(country)) { - return FORMAT_NANP; - } - } - if (locale.equals(Locale.JAPAN)) { - return FORMAT_JAPAN; - } - return FORMAT_UNKNOWN; + return getFormatTypeFromCountryCode(country); } /** @@ -990,6 +1008,7 @@ public class PhoneNumberUtils * as: * * <p><code> + * xxxxx * xxx-xxxx * xxx-xxx-xxxx * 1-xxx-xxx-xxxx @@ -1003,7 +1022,11 @@ public class PhoneNumberUtils if (length > "+1-nnn-nnn-nnnn".length()) { // The string is too long to be formatted return; + } else if (length <= 5) { + // The string is either a shortcode or too short to be formatted + return; } + CharSequence saved = text.subSequence(0, length); // Strip the dashes first, as we're going to add them back @@ -1215,4 +1238,288 @@ public class PhoneNumberUtils KEYPAD_MAP.put('w', '9'); KEYPAD_MAP.put('x', '9'); KEYPAD_MAP.put('y', '9'); KEYPAD_MAP.put('z', '9'); KEYPAD_MAP.put('W', '9'); KEYPAD_MAP.put('X', '9'); KEYPAD_MAP.put('Y', '9'); KEYPAD_MAP.put('Z', '9'); } + + //================ Plus Code formatting ========================= + private static final char PLUS_SIGN_CHAR = '+'; + private static final String PLUS_SIGN_STRING = "+"; + private static final String NANP_IDP_STRING = "011"; + private static final int NANP_LENGTH = 10; + + /** + * This function checks if there is a plus sign (+) in the passed-in dialing number. + * If there is, it processes the plus sign based on the default telephone + * numbering plan of the system when the phone is activated and the current + * telephone numbering plan of the system that the phone is camped on. + * Currently, we only support the case that the default and current telephone + * numbering plans are North American Numbering Plan(NANP). + * + * The passed-in dialStr should only contain the valid format as described below, + * 1) the 1st character in the dialStr should be one of the really dialable + * characters listed below + * ISO-LATIN characters 0-9, *, # , + + * 2) the dialStr should already strip out the separator characters, + * every character in the dialStr should be one of the non separator characters + * listed below + * ISO-LATIN characters 0-9, *, # , +, WILD, WAIT, PAUSE + * + * Otherwise, this function returns the dial string passed in + * + * @param dialStr the original dial string + * @return the converted dial string if the current/default countries belong to NANP, + * and if there is the "+" in the original dial string. Otherwise, the original dial + * string returns. + * + * This API is for CDMA only + * + * @hide TODO: pending API Council approval + */ + public static String cdmaCheckAndProcessPlusCode(String dialStr) { + if (!TextUtils.isEmpty(dialStr)) { + if (isReallyDialable(dialStr.charAt(0)) && + isNonSeparator(dialStr)) { + String currIso = SystemProperties.get(PROPERTY_OPERATOR_ISO_COUNTRY, ""); + String defaultIso = SystemProperties.get(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, ""); + if (!TextUtils.isEmpty(currIso) && !TextUtils.isEmpty(defaultIso)) { + return cdmaCheckAndProcessPlusCodeByNumberFormat(dialStr, + getFormatTypeFromCountryCode(currIso), + getFormatTypeFromCountryCode(defaultIso)); + } + } + } + return dialStr; + } + + /** + * This function should be called from checkAndProcessPlusCode only + * And it is used for test purpose also. + * + * It checks the dial string by looping through the network portion, + * post dial portion 1, post dial porting 2, etc. If there is any + * plus sign, then process the plus sign. + * Currently, this function supports the plus sign conversion within NANP only. + * Specifically, it handles the plus sign in the following ways: + * 1)+1NANP,remove +, e.g. + * +18475797000 is converted to 18475797000, + * 2)+NANP or +non-NANP Numbers,replace + with the current NANP IDP, e.g, + * +8475797000 is converted to 0118475797000, + * +11875767800 is converted to 01111875767800 + * 3)+1NANP in post dial string(s), e.g. + * 8475797000;+18475231753 is converted to 8475797000;18475231753 + * + * + * @param dialStr the original dial string + * @param currFormat the numbering system of the current country that the phone is camped on + * @param defaultFormat the numbering system of the country that the phone is activated on + * @return the converted dial string if the current/default countries belong to NANP, + * and if there is the "+" in the original dial string. Otherwise, the original dial + * string returns. + * + * @hide + */ + public static String + cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int currFormat,int defaultFormt) { + String retStr = dialStr; + + // Checks if the plus sign character is in the passed-in dial string + if (dialStr != null && + dialStr.lastIndexOf(PLUS_SIGN_STRING) != -1) { + // Format the string based on the rules for the country the number is from, + // and the current country the phone is camped on. + if ((currFormat == defaultFormt) && (currFormat == FORMAT_NANP)) { + // Handle case where default and current telephone numbering plans are NANP. + String postDialStr = null; + String tempDialStr = dialStr; + + // Sets the retStr to null since the conversion will be performed below. + retStr = null; + if (DBG) log("checkAndProcessPlusCode,dialStr=" + dialStr); + // This routine is to process the plus sign in the dial string by loop through + // the network portion, post dial portion 1, post dial portion 2... etc. if + // applied + do { + String networkDialStr; + networkDialStr = extractNetworkPortion(tempDialStr); + // Handles the conversion within NANP + networkDialStr = processPlusCodeWithinNanp(networkDialStr); + + // Concatenates the string that is converted from network portion + if (!TextUtils.isEmpty(networkDialStr)) { + if (retStr == null) { + retStr = networkDialStr; + } else { + retStr = retStr.concat(networkDialStr); + } + } else { + // This should never happen since we checked the if dialStr is null + // and if it contains the plus sign in the beginning of this function. + // The plus sign is part of the network portion. + Log.e("checkAndProcessPlusCode: null newDialStr", networkDialStr); + return dialStr; + } + postDialStr = extractPostDialPortion(tempDialStr); + if (!TextUtils.isEmpty(postDialStr)) { + int dialableIndex = findDialableIndexFromPostDialStr(postDialStr); + + // dialableIndex should always be greater than 0 + if (dialableIndex >= 1) { + retStr = appendPwCharBackToOrigDialStr(dialableIndex, + retStr,postDialStr); + // Skips the P/W character, extracts the dialable portion + tempDialStr = postDialStr.substring(dialableIndex); + } else { + // Non-dialable character such as P/W should not be at the end of + // the dial string after P/W processing in CdmaConnection.java + // Set the postDialStr to "" to break out of the loop + if (dialableIndex < 0) { + postDialStr = ""; + } + Log.e("wrong postDialStr=", postDialStr); + } + } + if (DBG) log("checkAndProcessPlusCode,postDialStr=" + postDialStr); + } while (!TextUtils.isEmpty(postDialStr) && !TextUtils.isEmpty(tempDialStr)); + } else { + // TODO: Support NANP international conversion and other telephone numbering plans. + // Currently the phone is never used in non-NANP system, so return the original + // dial string. + Log.e("checkAndProcessPlusCode:non-NANP not supported", dialStr); + } + } + return retStr; + } + + // This function gets the default international dialing prefix + private static String getDefaultIdp( ) { + String ps = null; + SystemProperties.get(PROPERTY_IDP_STRING, ps); + if (TextUtils.isEmpty(ps)) { + ps = NANP_IDP_STRING; + } + return ps; + } + + private static boolean isTwoToNine (char c) { + if (c >= '2' && c <= '9') { + return true; + } else { + return false; + } + } + + private static int getFormatTypeFromCountryCode (String country) { + // Check for the NANP countries + int length = NANP_COUNTRIES.length; + for (int i = 0; i < length; i++) { + if (NANP_COUNTRIES[i].compareToIgnoreCase(country) == 0) { + return FORMAT_NANP; + } + } + if ("jp".compareToIgnoreCase(country) == 0) { + return FORMAT_JAPAN; + } + return FORMAT_UNKNOWN; + } + + /** + * This function checks if the passed in string conforms to the NANP format + * i.e. NXX-NXX-XXXX, N is any digit 2-9 and X is any digit 0-9 + */ + private static boolean isNanp (String dialStr) { + boolean retVal = false; + if (dialStr != null) { + if (dialStr.length() == NANP_LENGTH) { + if (isTwoToNine(dialStr.charAt(0)) && + isTwoToNine(dialStr.charAt(3))) { + retVal = true; + for (int i=1; i<NANP_LENGTH; i++ ) { + char c=dialStr.charAt(i); + if (!PhoneNumberUtils.isISODigit(c)) { + retVal = false; + break; + } + } + } + } + } else { + Log.e("isNanp: null dialStr passed in", dialStr); + } + return retVal; + } + + /** + * This function checks if the passed in string conforms to 1-NANP format + */ + private static boolean isOneNanp(String dialStr) { + boolean retVal = false; + if (dialStr != null) { + String newDialStr = dialStr.substring(1); + if ((dialStr.charAt(0) == '1') && isNanp(newDialStr)) { + retVal = true; + } + } else { + Log.e("isOneNanp: null dialStr passed in", dialStr); + } + return retVal; + } + + /** + * This function handles the plus code conversion within NANP CDMA network + * If the number format is + * 1)+1NANP,remove +, + * 2)other than +1NANP, any + numbers,replace + with the current IDP + */ + private static String processPlusCodeWithinNanp(String networkDialStr) { + String retStr = networkDialStr; + + if (DBG) log("processPlusCodeWithinNanp,networkDialStr=" + networkDialStr); + // If there is a plus sign at the beginning of the dial string, + // Convert the plus sign to the default IDP since it's an international number + if (networkDialStr != null & + networkDialStr.charAt(0) == PLUS_SIGN_CHAR && + networkDialStr.length() > 1) { + String newStr = networkDialStr.substring(1); + if (isOneNanp(newStr)) { + // Remove the leading plus sign + retStr = newStr; + } else { + String idpStr = getDefaultIdp(); + // Replaces the plus sign with the default IDP + retStr = networkDialStr.replaceFirst("[+]", idpStr); + } + } + if (DBG) log("processPlusCodeWithinNanp,retStr=" + retStr); + return retStr; + } + + // This function finds the index of the dialable character(s) + // in the post dial string + private static int findDialableIndexFromPostDialStr(String postDialStr) { + for (int index = 0;index < postDialStr.length();index++) { + char c = postDialStr.charAt(index); + if (isReallyDialable(c)) { + return index; + } + } + return -1; + } + + // This function appends the non-diablable P/W character to the original + // dial string based on the dialable index passed in + private static String + appendPwCharBackToOrigDialStr(int dialableIndex,String origStr, String dialStr) { + String retStr; + + // There is only 1 P/W character before the dialable characters + if (dialableIndex == 1) { + StringBuilder ret = new StringBuilder(origStr); + ret = ret.append(dialStr.charAt(0)); + retStr = ret.toString(); + } else { + // It means more than 1 P/W characters in the post dial string, + // appends to retStr + String nonDigitStr = dialStr.substring(0,dialableIndex); + retStr = origStr.concat(nonDigitStr); + } + return retStr; + } } diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index e113680..73e7baa5 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -154,8 +154,9 @@ public class PhoneStateListener { * @see ServiceState#STATE_IN_SERVICE * @see ServiceState#STATE_OUT_OF_SERVICE * @see ServiceState#STATE_POWER_OFF - * @deprecated, @see #onSignalStrengthsChanged + * @deprecated see #onSignalStrengthsChanged */ + @Deprecated public void onSignalStrengthChanged(int asu) { // default implementation empty } diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 50c4d41..06b5c26 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -83,6 +83,12 @@ public class ServiceState implements Parcelable { public static final int RADIO_TECHNOLOGY_EVDO_0 = 7; /** @hide */ public static final int RADIO_TECHNOLOGY_EVDO_A = 8; + /** @hide */ + public static final int RADIO_TECHNOLOGY_HSDPA = 9; + /** @hide */ + public static final int RADIO_TECHNOLOGY_HSUPA = 10; + /** @hide */ + public static final int RADIO_TECHNOLOGY_HSPA = 11; /** * Available registration states for GSM, UMTS and CDMA. @@ -366,6 +372,15 @@ public class ServiceState implements Parcelable { case 8: radioTechnology = "EvDo rev. A"; break; + case 9: + radioTechnology = "HSDPA"; + break; + case 10: + radioTechnology = "HSUPA"; + break; + case 11: + radioTechnology = "HSPA"; + break; default: Log.w(LOG_TAG, "mRadioTechnology variable out of range."); break; diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 82539fb..14b1563 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -54,10 +54,13 @@ public final class SmsManager { * @param sentIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is sucessfully sent, or failed. * The result code will be <code>Activity.RESULT_OK<code> for success, - * or one of these errors: - * <code>RESULT_ERROR_GENERIC_FAILURE</code> - * <code>RESULT_ERROR_RADIO_OFF</code> - * <code>RESULT_ERROR_NULL_PDU</code>. + * or one of these errors:<br> + * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> + * <code>RESULT_ERROR_RADIO_OFF</code><br> + * <code>RESULT_ERROR_NULL_PDU</code><br> + * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include + * the extra "errorCode" containing a radio technology specific value, + * generally only useful for troubleshooting.<br> * The per-application based SMS control checks sentIntent. If sentIntent * is NULL the caller will be checked against all unknown applications, * which cause smaller number of SMS to be sent in checking period. @@ -109,10 +112,13 @@ public final class SmsManager { * <code>PendingIntent</code>s (one for each message part) that is * broadcast when the corresponding message part has been sent. * The result code will be <code>Activity.RESULT_OK<code> for success, - * or one of these errors: - * <code>RESULT_ERROR_GENERIC_FAILURE</code> - * <code>RESULT_ERROR_RADIO_OFF</code> - * <code>RESULT_ERROR_NULL_PDU</code>. + * or one of these errors:<br> + * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> + * <code>RESULT_ERROR_RADIO_OFF</code><br> + * <code>RESULT_ERROR_NULL_PDU</code><br> + * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include + * the extra "errorCode" containing a radio technology specific value, + * generally only useful for troubleshooting.<br> * The per-application based SMS control checks sentIntent. If sentIntent * is NULL the caller will be checked against all unknown applicaitons, * which cause smaller number of SMS to be sent in checking period. @@ -169,10 +175,13 @@ public final class SmsManager { * @param sentIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is sucessfully sent, or failed. * The result code will be <code>Activity.RESULT_OK<code> for success, - * or one of these errors: - * <code>RESULT_ERROR_GENERIC_FAILURE</code> - * <code>RESULT_ERROR_RADIO_OFF</code> - * <code>RESULT_ERROR_NULL_PDU</code>. + * or one of these errors:<br> + * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> + * <code>RESULT_ERROR_RADIO_OFF</code><br> + * <code>RESULT_ERROR_NULL_PDU</code><br> + * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include + * the extra "errorCode" containing a radio technology specific value, + * generally only useful for troubleshooting.<br> * The per-application based SMS control checks sentIntent. If sentIntent * is NULL the caller will be checked against all unknown applicaitons, * which cause smaller number of SMS to be sent in checking period. @@ -210,10 +219,13 @@ public final class SmsManager { * @param sentIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is successfully sent, or failed. * The result code will be <code>Activity.RESULT_OK<code> for success, - * or one of these errors: - * <code>RESULT_ERROR_GENERIC_FAILURE</code> - * <code>RESULT_ERROR_RADIO_OFF</code> - * <code>RESULT_ERROR_NULL_PDU</code>. + * or one of these errors:<br> + * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> + * <code>RESULT_ERROR_RADIO_OFF</code><br> + * <code>RESULT_ERROR_NULL_PDU</code><br> + * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include + * the extra "errorCode" containing a radio technology specific value, + * generally only useful for troubleshooting.<br> * The per-application based SMS control checks sentIntent. If sentIntent * is NULL the caller will be checked against all unknown applications, * which cause smaller number of SMS to be sent in checking period. @@ -409,4 +421,6 @@ public final class SmsManager { static public final int RESULT_ERROR_NULL_PDU = 3; /** Failed because service is currently unavailable */ static public final int RESULT_ERROR_NO_SERVICE = 4; + /** Failed because we reached the sending queue limit. {@hide} */ + static public final int RESULT_ERROR_LIMIT_EXCEEDED = 5; } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index ed9af66..f3304a3 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -382,6 +382,15 @@ public class TelephonyManager { /** Current network is 1xRTT*/ /** @hide */ public static final int NETWORK_TYPE_1xRTT = 7; + /** Current network is HSDPA */ + /** @hide */ + public static final int NETWORK_TYPE_HSDPA = 8; + /** Current network is HSUPA */ + /** @hide */ + public static final int NETWORK_TYPE_HSUPA = 9; + /** Current network is HSPA */ + /** @hide */ + public static final int NETWORK_TYPE_HSPA = 10; /** * Returns a constant indicating the radio technology (network type) @@ -392,35 +401,25 @@ public class TelephonyManager { * @see #NETWORK_TYPE_GPRS * @see #NETWORK_TYPE_EDGE * @see #NETWORK_TYPE_UMTS + * @see #NETWORK_TYPE_HSDPA + * @see #NETWORK_TYPE_HSUPA + * @see #NETWORK_TYPE_HSPA * @see #NETWORK_TYPE_CDMA * @see #NETWORK_TYPE_EVDO_0 * @see #NETWORK_TYPE_EVDO_A * @see #NETWORK_TYPE_1xRTT */ public int getNetworkType() { - String prop = SystemProperties.get(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE); - if ("GPRS".equals(prop)) { - return NETWORK_TYPE_GPRS; - } - else if ("EDGE".equals(prop)) { - return NETWORK_TYPE_EDGE; - } - else if ("UMTS".equals(prop)) { - return NETWORK_TYPE_UMTS; - } - else if ("CDMA".equals(prop)) { - return NETWORK_TYPE_CDMA; - } - else if ("CDMA - EvDo rev. 0".equals(prop)) { - return NETWORK_TYPE_EVDO_0; - } - else if ("CDMA - EvDo rev. A".equals(prop)) { - return NETWORK_TYPE_EVDO_A; - } - else if ("CDMA - 1xRTT".equals(prop)) { - return NETWORK_TYPE_1xRTT; + try{ + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getNetworkType(); + } else { + // This can happen when the ITelephony interface is not up yet. + return NETWORK_TYPE_UNKNOWN; } - else { + } catch(RemoteException ex){ + // This shouldn't happen in the normal case return NETWORK_TYPE_UNKNOWN; } } @@ -440,6 +439,12 @@ public class TelephonyManager { return "EDGE"; case NETWORK_TYPE_UMTS: return "UMTS"; + case NETWORK_TYPE_HSDPA: + return "HSDPA"; + case NETWORK_TYPE_HSUPA: + return "HSUPA"; + case NETWORK_TYPE_HSPA: + return "HSPA"; case NETWORK_TYPE_CDMA: return "CDMA"; case NETWORK_TYPE_EVDO_0: diff --git a/telephony/java/android/telephony/gsm/SmsMessage.java b/telephony/java/android/telephony/gsm/SmsMessage.java index 84dfca0..37ef912 100644 --- a/telephony/java/android/telephony/gsm/SmsMessage.java +++ b/telephony/java/android/telephony/gsm/SmsMessage.java @@ -345,6 +345,7 @@ public class SmsMessage { * the number of code units used, and int[2] is the number of code * units remaining until the next message. int[3] is the encoding * type that should be used for the message. + * @deprecated Use android.telephony.SmsMessage. */ @Deprecated public static int[] calculateLength(String messageBody, boolean use7bitOnly) { diff --git a/telephony/java/com/android/internal/telephony/Call.java b/telephony/java/com/android/internal/telephony/Call.java index 7eb9d85..b95dd11 100644 --- a/telephony/java/com/android/internal/telephony/Call.java +++ b/telephony/java/com/android/internal/telephony/Call.java @@ -25,10 +25,10 @@ public abstract class Call { /* Enums */ public enum State { - IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED; + IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING; public boolean isAlive() { - return !(this == IDLE || this == DISCONNECTED); + return !(this == IDLE || this == DISCONNECTED || this == DISCONNECTING); } public boolean isRinging() { diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java index afc8b62..bda2d22 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfo.java +++ b/telephony/java/com/android/internal/telephony/CallerInfo.java @@ -20,9 +20,8 @@ import android.content.Context; import android.database.Cursor; import android.graphics.drawable.Drawable; import android.net.Uri; -import android.provider.Contacts; -import android.provider.Contacts.People; -import android.provider.Contacts.Phones; +import android.provider.ContactsContract.PhoneLookup; +import android.provider.ContactsContract.CommonDataKinds.Phone; import android.text.TextUtils; import android.telephony.TelephonyManager; import android.telephony.PhoneNumberUtils; @@ -134,44 +133,39 @@ public class CallerInfo { int columnIndex; // Look for the name - columnIndex = cursor.getColumnIndex(People.NAME); + columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME); if (columnIndex != -1) { info.name = cursor.getString(columnIndex); } // Look for the number - columnIndex = cursor.getColumnIndex(Phones.NUMBER); + columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER); if (columnIndex != -1) { info.phoneNumber = cursor.getString(columnIndex); } // Look for the label/type combo - columnIndex = cursor.getColumnIndex(Phones.LABEL); + columnIndex = cursor.getColumnIndex(PhoneLookup.LABEL); if (columnIndex != -1) { - int typeColumnIndex = cursor.getColumnIndex(Phones.TYPE); + int typeColumnIndex = cursor.getColumnIndex(PhoneLookup.TYPE); if (typeColumnIndex != -1) { info.numberType = cursor.getInt(typeColumnIndex); info.numberLabel = cursor.getString(columnIndex); - info.phoneLabel = Contacts.Phones.getDisplayLabel(context, + info.phoneLabel = Phone.getDisplayLabel(context, info.numberType, info.numberLabel) .toString(); } } // Look for the person ID - columnIndex = cursor.getColumnIndex(Phones.PERSON_ID); + columnIndex = cursor.getColumnIndex(PhoneLookup._ID); if (columnIndex != -1) { info.person_id = cursor.getLong(columnIndex); - } else { - columnIndex = cursor.getColumnIndex(People._ID); - if (columnIndex != -1) { - info.person_id = cursor.getLong(columnIndex); - } } // look for the custom ringtone, create from the string stored // in the database. - columnIndex = cursor.getColumnIndex(People.CUSTOM_RINGTONE); + columnIndex = cursor.getColumnIndex(PhoneLookup.CUSTOM_RINGTONE); if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) { info.contactRingtoneUri = Uri.parse(cursor.getString(columnIndex)); } else { @@ -180,7 +174,7 @@ public class CallerInfo { // look for the send to voicemail flag, set it to true only // under certain circumstances. - columnIndex = cursor.getColumnIndex(People.SEND_TO_VOICEMAIL); + columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL); info.shouldSendToVoicemail = (columnIndex != -1) && ((cursor.getInt(columnIndex)) == 1); info.contactExists = true; @@ -256,8 +250,7 @@ public class CallerInfo { } } - Uri contactUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, - Uri.encode(number)); + Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number); CallerInfo info = getCallerInfo(context, contactUri); diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java index f81f42a..ef456f0 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java +++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java @@ -24,7 +24,7 @@ import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.provider.Contacts; +import android.provider.ContactsContract.PhoneLookup; import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -303,7 +303,7 @@ public class CallerInfoAsyncQuery { public static CallerInfoAsyncQuery startQuery(int token, Context context, String number, OnQueryCompleteListener listener, Object cookie) { //contruct the URI object and start Query. - Uri contactRef = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, number); + Uri contactRef = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number); CallerInfoAsyncQuery c = new CallerInfoAsyncQuery(); c.allocate(context, contactRef); diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java index e583110..ed8bc1e 100644 --- a/telephony/java/com/android/internal/telephony/CommandsInterface.java +++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java @@ -82,15 +82,6 @@ public interface CommandsInterface { } } - enum IccStatus { - ICC_ABSENT, - ICC_NOT_READY, - ICC_READY, - ICC_PIN, - ICC_PUK, - ICC_NETWORK_PERSONALIZATION - } - //***** Constants // Used as parameter to dial() and setCLIR() below @@ -534,15 +525,6 @@ public interface CommandsInterface { void unregisterForCdmaOtaProvision(Handler h); /** - * Returns current ICC status. - * - * AsyncResult.result is IccStatus - * - */ - - void getIccStatus(Message result); - - /** * Supply the ICC PIN to the ICC card * * returned message @@ -625,8 +607,9 @@ public interface CommandsInterface { * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result contains a List of DataCallState - * @deprecated + * @deprecated Do not use. */ + @Deprecated void getPDPContextList(Message result); /** @@ -797,8 +780,9 @@ public interface CommandsInterface { * cause code returned as int[0] in Message.obj.response * returns an integer cause code defined in TS 24.008 * section 6.1.3.1.3 or close approximation - * @deprecated + * @deprecated Do not use. */ + @Deprecated void getLastPdpFailCause (Message result); /** @@ -1243,8 +1227,10 @@ public interface CommandsInterface { * Request the device MDN / H_SID / H_NID / MIN. * "response" is const char ** * [0] is MDN if CDMA subscription is available - * [1] is H_SID (Home SID) if CDMA subscription is available - * [2] is H_NID (Home NID) if CDMA subscription is available + * [1] is a comma separated list of H_SID (Home SID) in decimal format + * if CDMA subscription is available + * [2] is a comma separated list of H_NID (Home NID) in decimal format + * if CDMA subscription is available * [3] is MIN (10 digits, MIN2+MIN1) if CDMA subscription is available */ public void getCDMASubscription(Message response); @@ -1316,11 +1302,13 @@ public interface CommandsInterface { * the username for APN, or NULL * @param password * the password for APN, or NULL + * @param authType + * the PAP / CHAP auth type. Values is one of SETUP_DATA_AUTH_* * @param result * Callback message */ public void setupDataCall(String radioTechnology, String profile, String apn, - String user, String password, Message result); + String user, String password, String authType, Message result); /** * Deactivate packet data connection @@ -1366,4 +1354,12 @@ public interface CommandsInterface { * @param response callback message */ public void exitEmergencyCallbackMode(Message response); + + /** + * Request the status of the ICC and UICC cards. + * + * @param response + * Callback message containing {@link IccCardStatus} structure for the card. + */ + public void getIccCardStatus(Message result); } diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java index 92f6cb8..e6fd0a0 100644 --- a/telephony/java/com/android/internal/telephony/Connection.java +++ b/telephony/java/com/android/internal/telephony/Connection.java @@ -56,7 +56,8 @@ public abstract class Connection { CDMA_RETRY_ORDER, /* requeseted service is rejected, retry delay is set */ CDMA_ACCESS_FAILURE, CDMA_PREEMPTED, - CDMA_NOT_EMERGENCY /* not an emergency call */ + CDMA_NOT_EMERGENCY, /* not an emergency call */ + ERROR_UNSPECIFIED } Object userData; diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index c074cb8..ece708a 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -24,14 +24,18 @@ import android.os.Message; import android.os.RemoteException; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; +import android.text.TextUtils; import android.util.Log; +import java.util.ArrayList; + /** * {@hide} * */ public abstract class DataConnectionTracker extends Handler { - private static final boolean DBG = true; + protected static final boolean DBG = true; + protected final String LOG_TAG = "DataConnectionTracker"; /** * IDLE: ready to start data connection setup, default state @@ -67,7 +71,7 @@ public abstract class DataConnectionTracker extends Handler { DORMANT } - //***** Event Codes + /***** Event Codes *****/ protected static final int EVENT_DATA_SETUP_COMPLETE = 1; protected static final int EVENT_RADIO_AVAILABLE = 3; protected static final int EVENT_RECORDS_LOADED = 4; @@ -94,12 +98,33 @@ public abstract class DataConnectionTracker extends Handler { protected static final int EVENT_PS_RESTRICT_ENABLED = 32; protected static final int EVENT_PS_RESTRICT_DISABLED = 33; public static final int EVENT_CLEAN_UP_CONNECTION = 34; + protected static final int EVENT_CDMA_OTA_PROVISION = 35; + protected static final int EVENT_RESTART_RADIO = 36; + private static final int EVENT_ENABLE_APN_REQUEST = 37; + + /***** Constants *****/ + + protected static final int APN_INVALID_ID = -1; + protected static final int APN_DEFAULT_ID = 0; + protected static final int APN_MMS_ID = 1; + protected static final int APN_SUPL_ID = 2; + protected static final int APN_DUN_ID = 3; + protected static final int APN_HIPRI_ID = 4; + protected static final int APN_NUM_TYPES = 5; + + protected static final int APN_DISABLED = 0; + protected static final int APN_ENABLED = 1; + + protected boolean[] dataEnabled = new boolean[APN_NUM_TYPES]; + protected int enabledCount = 0; - //***** Constants - protected static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000; + /* Currently requested APN type */ + protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT; - /** Cap out with 30 min retry interval. */ - protected static final int RECONNECT_DELAY_MAX_MILLIS = 30 * 60 * 1000; + /** Retry configuration: A doubling of retry times from 5secs to 30minutes */ + protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000," + + "5000,10000,20000,40000,80000:5000,160000:5000," + + "320000:5000,640000:5000,1280000:5000,1800000:5000"; /** Slow poll when attempting connection recovery. */ protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000; @@ -145,6 +170,9 @@ public abstract class DataConnectionTracker extends Handler { protected int mNoRecvPollCount = 0; protected boolean netStatPollEnabled = false; + /** Manage the behavior of data retry after failure */ + protected final RetryManager mRetryMgr = new RetryManager(); + // wifi connection status will be updated by sticky intent protected boolean mIsWifiConnected = false; @@ -162,6 +190,8 @@ public abstract class DataConnectionTracker extends Handler { this.phone = phone; } + public abstract void dispose(); + public Activity getActivity() { return activity; } @@ -201,10 +231,13 @@ public abstract class DataConnectionTracker extends Handler { if (getDataOnRoamingEnabled() != enabled) { Settings.Secure.putInt(phone.getContext().getContentResolver(), Settings.Secure.DATA_ROAMING, enabled ? 1 : 0); + if (phone.getServiceState().getRoaming()) { + if (enabled) { + mRetryMgr.resetRetryCount(); + } + sendMessage(obtainMessage(EVENT_ROAMING_ON)); + } } - Message roamingMsg = phone.getServiceState().getRoaming() ? - obtainMessage(EVENT_ROAMING_ON) : obtainMessage(EVENT_ROAMING_OFF); - sendMessage(roamingMsg); } //Retrieve the data roaming setting from the shared preferences. @@ -218,7 +251,7 @@ public abstract class DataConnectionTracker extends Handler { } // abstract handler methods - protected abstract void onTrySetupData(String reason); + protected abstract boolean onTrySetupData(String reason); protected abstract void onRoamingOff(); protected abstract void onRoamingOn(); protected abstract void onRadioAvailable(); @@ -229,10 +262,39 @@ public abstract class DataConnectionTracker extends Handler { protected abstract void onVoiceCallEnded(); protected abstract void onCleanUpConnection(boolean tearDown, String reason); - //***** Overridden from Handler + @Override public void handleMessage (Message msg) { switch (msg.what) { + case EVENT_ENABLE_APN_REQUEST: + int apnId = msg.arg1; + synchronized (this) { + if (DBG) { + Log.d(LOG_TAG, "got EVENT_ENABLE_APN_REQUEST with apnType = " + apnId + + " and enable = " + msg.arg2); + Log.d(LOG_TAG, "dataEnabled[apnId] = " + dataEnabled[apnId] + + ", enabledCount = " + enabledCount); + } + if (msg.arg2 == APN_ENABLED) { + // enable + if (!dataEnabled[apnId]) { + dataEnabled[apnId] = true; + enabledCount++; + } + onTrySetupData(null); + } else { + // disable + if (dataEnabled[apnId]) { + dataEnabled[apnId] = false; + enabledCount--; + if (enabledCount == 0) { + onCleanUpConnection(true, Phone.REASON_DATA_DISABLED); + } + } + } + } + break; + case EVENT_TRY_SETUP_DATA: String reason = null; if (msg.obj instanceof String) { @@ -242,6 +304,9 @@ public abstract class DataConnectionTracker extends Handler { break; case EVENT_ROAMING_OFF: + if (getDataOnRoamingEnabled() == false) { + mRetryMgr.resetRetryCount(); + } onRoamingOff(); break; @@ -290,30 +355,161 @@ public abstract class DataConnectionTracker extends Handler { * @return {@code false} if data connectivity has been explicitly disabled, * {@code true} otherwise. */ - public abstract boolean getDataEnabled(); + public synchronized boolean getDataEnabled() { + return dataEnabled[APN_DEFAULT_ID]; + } /** * Report on whether data connectivity is enabled * @return {@code false} if data connectivity has been explicitly disabled, * {@code true} otherwise. */ - public abstract boolean getAnyDataEnabled(); + public boolean getAnyDataEnabled() { + return (enabledCount != 0); + } + + protected abstract void startNetStatPoll(); + + protected abstract void stopNetStatPoll(); + + protected abstract void restartRadio(); + + protected abstract void log(String s); + + protected int apnTypeToId(String type) { + if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) { + return APN_DEFAULT_ID; + } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return APN_MMS_ID; + } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) { + return APN_SUPL_ID; + } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) { + return APN_DUN_ID; + } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) { + return APN_HIPRI_ID; + } else { + return APN_INVALID_ID; + } + } + + protected abstract boolean isApnTypeActive(String type); + + protected abstract boolean isApnTypeAvailable(String type); + + protected abstract String[] getActiveApnTypes(); + + protected abstract String getActiveApnString(); + + public abstract ArrayList<DataConnection> getAllDataConnections(); + + protected abstract String getInterfaceName(String apnType); + + protected abstract String getIpAddress(String apnType); + + protected abstract String getGateway(String apnType); + + protected abstract String[] getDnsServers(String apnType); + + protected abstract void setState(State s); + + protected synchronized boolean isEnabled(int id) { + if (id != APN_INVALID_ID) { + return dataEnabled[id]; + } + return false; + } + + /** + * Ensure that we are connected to an APN of the specified type. + * @param type the APN type (currently the only valid values + * are {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}) + * @return the result of the operation. Success is indicated by + * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or + * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast + * will be sent by the ConnectivityManager when a connection to + * the APN has been established. + */ + public int enableApnType(String type) { + int id = apnTypeToId(type); + if (id == APN_INVALID_ID) { + return Phone.APN_REQUEST_FAILED; + } + + // If already active, return + if(DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = " + + isApnTypeActive(type) + " and state = " + state); + + if (isApnTypeActive(type)) { + if (state == State.INITING) return Phone.APN_REQUEST_STARTED; + else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE; + } + + if (!isApnTypeAvailable(type)) { + return Phone.APN_TYPE_NOT_AVAILABLE; + } + + setEnabled(id, true); + mRequestedApnType = type; + sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN)); + return Phone.APN_REQUEST_STARTED; + } + + /** + * The APN of the specified type is no longer needed. Ensure that if + * use of the default APN has not been explicitly disabled, we are connected + * to the default APN. + * @param type the APN type. The only valid values are currently + * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}. + * @return + */ + public synchronized int disableApnType(String type) { + if (DBG) Log.d(LOG_TAG, "disableApnType("+type+")"); + int id = apnTypeToId(type); + if (id == APN_INVALID_ID) { + return Phone.APN_REQUEST_FAILED; + } + if (isEnabled(id)) { + setEnabled(id, false); + if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { + mRequestedApnType = Phone.APN_TYPE_DEFAULT; + if (dataEnabled[APN_DEFAULT_ID]) { + return Phone.APN_ALREADY_ACTIVE; + } else { + return Phone.APN_REQUEST_STARTED; + } + } else { + return Phone.APN_REQUEST_STARTED; + } + } else { + return Phone.APN_REQUEST_FAILED; + } + } + + protected void setEnabled(int id, boolean enable) { + if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ") with old state = " + + dataEnabled[id] + " and enabledCount = " + enabledCount); + + Message msg = obtainMessage(EVENT_ENABLE_APN_REQUEST); + msg.arg1 = id; + msg.arg2 = (enable ? APN_ENABLED : APN_DISABLED); + sendMessage(msg); + } /** * Prevent mobile data connections from being established, * or once again allow mobile data connections. If the state * toggles, then either tear down or set up data, as * appropriate to match the new state. + * <p>This operation only affects the default APN, and if the same APN is + * currently being used for MMS traffic, the teardown will not happen + * even when {@code enable} is {@code false}.</p> * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data * @return {@code true} if the operation succeeded */ - public abstract boolean setDataEnabled(boolean enable); - - protected abstract void startNetStatPoll(); - - protected abstract void stopNetStatPoll(); - - protected abstract void restartRadio(); + public boolean setDataEnabled(boolean enable) { + if (DBG) Log.d(LOG_TAG, "setDataEnabled(" + enable + ")"); + setEnabled(APN_DEFAULT_ID, enable); + return true; + } - protected abstract void log(String s); } diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java index d6151c6..00d7c72 100644 --- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -94,8 +94,11 @@ public class DefaultPhoneNotifier implements PhoneNotifier { public void notifyDataConnection(Phone sender, String reason) { try { - mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()), - sender.isDataConnectivityPossible(), reason, sender.getActiveApn(), + mRegistry.notifyDataConnection( + convertDataState(sender.getDataConnectionState()), + sender.isDataConnectivityPossible(), reason, + sender.getActiveApn(), + sender.getActiveApnTypes(), sender.getInterfaceName(null)); } catch (RemoteException ex) { // system process is dead diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java index e8095e1..461b694 100644 --- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java +++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java @@ -183,15 +183,9 @@ public class GsmAlphabet { } int headerBits = (header.length + 1) * 8; - int headerSeptets = headerBits / 7; - headerSeptets += (headerBits % 7) > 0 ? 1 : 0; + int headerSeptets = (headerBits + 6) / 7; - int sz = data.length(); - int septetCount; - septetCount = countGsmSeptets(data, true) + headerSeptets; - - byte[] ret = stringToGsm7BitPacked(data, 0, septetCount, - (headerSeptets*7), true); + byte[] ret = stringToGsm7BitPacked(data, headerSeptets, true); // Paste in the header ret[1] = (byte)header.length; @@ -215,7 +209,7 @@ public class GsmAlphabet { */ public static byte[] stringToGsm7BitPacked(String data) throws EncodeException { - return stringToGsm7BitPacked(data, 0, -1, 0, true); + return stringToGsm7BitPacked(data, 0, true); } /** @@ -228,58 +222,37 @@ public class GsmAlphabet { * septets. * * @param data the text to convert to septets - * @param dataOffset the character offset in data to start the encoding from - * @param maxSeptets the maximum number of septets to convert, or -1 for no - * enforced maximum. - * @param startingBitOffset the number of padding bits to put before - * the start of the first septet at the begining of the array + * @param startingSeptetOffset the number of padding septets to put before + * the character data at the begining of the array * @param throwException If true, throws EncodeException on invalid char. * If false, replaces unencodable char with GSM alphabet space char. * * @throws EncodeException if String is too large to encode */ - public static byte[] stringToGsm7BitPacked(String data, int dataOffset, - int maxSeptets, int startingBitOffset, boolean throwException) - throws EncodeException { - - int sz = data.length(); - int septetCount; - if (maxSeptets == -1) { - septetCount = countGsmSeptets(data, true); - } else { - septetCount = maxSeptets; + public static byte[] stringToGsm7BitPacked(String data, int startingSeptetOffset, + boolean throwException) throws EncodeException { + int dataLen = data.length(); + int septetCount = countGsmSeptets(data, throwException) + startingSeptetOffset; + if (septetCount > 255) { + throw new EncodeException("Payload cannot exceed 255 septets"); } - - if(septetCount > 0xff) { - throw new EncodeException("Payload cannot exceed " + Short.MAX_VALUE - + " septets"); - } - - // Enough for all the septets and the length 2 byte prefix - byte[] ret = new byte[1 + (((septetCount * 7) + 7) / 8)]; - - int bitOffset = startingBitOffset; - int septets = startingBitOffset/7; - for (int i = dataOffset; i < sz && septets < septetCount; i++, bitOffset += 7) { + int byteCount = ((septetCount * 7) + 7) / 8; + byte[] ret = new byte[byteCount + 1]; // Include space for one byte length prefix. + for (int i = 0, septets = startingSeptetOffset, bitOffset = startingSeptetOffset * 7; + i < dataLen && septets < septetCount; + i++, bitOffset += 7) { char c = data.charAt(i); - int v = GsmAlphabet.charToGsm(c, throwException); if (v == GSM_EXTENDED_ESCAPE) { - // Lookup the extended char - v = GsmAlphabet.charToGsmExtended(c); - + v = GsmAlphabet.charToGsmExtended(c); // Lookup the extended char. packSmsChar(ret, bitOffset, GSM_EXTENDED_ESCAPE); bitOffset += 7; septets++; } - packSmsChar(ret, bitOffset, v); septets++; } - - // See check for > 0xff above - ret[0] = (byte)septets; - + ret[0] = (byte) (septetCount); // Validated by check above. return ret; } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index d83b135..63c23ae 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -239,9 +239,18 @@ interface ITelephony { String getCdmaEriText(); /** + * Returns true if CDMA provisioning needs to run. + */ + boolean getCdmaNeedsProvisioning(); + + /** * Returns the unread count of voicemails */ int getVoiceMessageCount(); + /** + * Returns the network type + */ + int getNetworkType(); } diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 865c6ca..6b42e6b 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -32,7 +32,7 @@ interface ITelephonyRegistry { void notifyCallForwardingChanged(boolean cfi); void notifyDataActivity(int state); void notifyDataConnection(int state, boolean isDataConnectivityPossible, - String reason, String apn, String interfaceName); + String reason, String apn, in String[] apnTypes, String interfaceName); void notifyDataConnectionFailed(String reason); void notifyCellLocation(in Bundle cellLocation); } diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java index d7ad492..6657060 100644 --- a/telephony/java/com/android/internal/telephony/IccCard.java +++ b/telephony/java/com/android/internal/telephony/IccCard.java @@ -16,13 +16,40 @@ package com.android.internal.telephony; -import android.os.Message; +import static android.Manifest.permission.READ_PHONE_STATE; +import android.app.ActivityManagerNative; +import android.content.Intent; +import android.os.AsyncResult; import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.util.Log; + +import com.android.internal.telephony.PhoneBase; +import com.android.internal.telephony.CommandsInterface.RadioState; /** * {@hide} */ -public interface IccCard { +public abstract class IccCard { + protected String mLogTag; + protected boolean mDbg; + + private IccCardStatus mIccCardStatus = null; + protected State mState = null; + protected PhoneBase mPhone; + private RegistrantList mAbsentRegistrants = new RegistrantList(); + private RegistrantList mPinLockedRegistrants = new RegistrantList(); + private RegistrantList mNetworkLockedRegistrants = new RegistrantList(); + + private boolean mDesiredPinLocked; + private boolean mDesiredFdnEnabled; + private boolean mIccPinLocked = true; // Default to locked + private boolean mIccFdnEnabled = false; // Default to disabled. + // Will be updated when SIM_READY. + + /* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */ static public final String INTENT_KEY_ICC_STATE = "ss"; /* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */ @@ -46,6 +73,17 @@ public interface IccCard { /* NETWORK means ICC is locked on NETWORK PERSONALIZATION */ static public final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK"; + protected static final int EVENT_ICC_LOCKED_OR_ABSENT = 1; + private static final int EVENT_GET_ICC_STATUS_DONE = 2; + protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3; + private static final int EVENT_PINPUK_DONE = 4; + private static final int EVENT_REPOLL_STATUS_DONE = 5; + protected static final int EVENT_ICC_READY = 6; + private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7; + private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8; + private static final int EVENT_CHANGE_ICC_PASSWORD_DONE = 9; + private static final int EVENT_QUERY_FACILITY_FDN_DONE = 10; + private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11; /* UNKNOWN is a transient state, for example, after uesr inputs ICC pin under @@ -58,33 +96,108 @@ public interface IccCard { PIN_REQUIRED, PUK_REQUIRED, NETWORK_LOCKED, - READY; + READY, + NOT_READY; public boolean isPinLocked() { return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED)); } } - State getState(); + public State getState() { + if (mState == null) { + switch(mPhone.mCM.getRadioState()) { + /* This switch block must not return anything in + * State.isLocked() or State.ABSENT. + * If it does, handleSimStatus() may break + */ + case RADIO_OFF: + case RADIO_UNAVAILABLE: + case SIM_NOT_READY: + case RUIM_NOT_READY: + return State.UNKNOWN; + case SIM_LOCKED_OR_ABSENT: + case RUIM_LOCKED_OR_ABSENT: + //this should be transient-only + return State.UNKNOWN; + case SIM_READY: + case RUIM_READY: + case NV_READY: + return State.READY; + case NV_NOT_READY: + return State.ABSENT; + } + } else { + return mState; + } + + Log.e(mLogTag, "IccCard.getState(): case should never be reached"); + return State.UNKNOWN; + } + + public IccCard(PhoneBase phone, String logTag, Boolean dbg) { + mPhone = phone; + mLogTag = logTag; + mDbg = dbg; + } + + abstract public void dispose(); + protected void finalize() { + if(mDbg) Log.d(mLogTag, "IccCard finalized"); + } /** * Notifies handler of any transition into State.ABSENT */ - void registerForAbsent(Handler h, int what, Object obj); - void unregisterForAbsent(Handler h); + public void registerForAbsent(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + mAbsentRegistrants.add(r); + + if (getState() == State.ABSENT) { + r.notifyRegistrant(); + } + } + + public void unregisterForAbsent(Handler h) { + mAbsentRegistrants.remove(h); + } /** - * Notifies handler of any transition into State.isPinLocked() + * Notifies handler of any transition into State.NETWORK_LOCKED */ - void registerForLocked(Handler h, int what, Object obj); - void unregisterForLocked(Handler h); + public void registerForNetworkLocked(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + mNetworkLockedRegistrants.add(r); + + if (getState() == State.NETWORK_LOCKED) { + r.notifyRegistrant(); + } + } + + public void unregisterForNetworkLocked(Handler h) { + mNetworkLockedRegistrants.remove(h); + } /** - * Notifies handler of any transition into State.NETWORK_LOCKED + * Notifies handler of any transition into State.isPinLocked() */ - void registerForNetworkLocked(Handler h, int what, Object obj); - void unregisterForNetworkLocked(Handler h); + public void registerForLocked(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + + mPinLockedRegistrants.add(r); + + if (getState().isPinLocked()) { + r.notifyRegistrant(); + } + } + + public void unregisterForLocked(Handler h) { + mPinLockedRegistrants.remove(h); + } + /** * Supply the ICC PIN to the ICC @@ -107,10 +220,30 @@ public interface IccCard { * */ - void supplyPin (String pin, Message onComplete); - void supplyPuk (String puk, String newPin, Message onComplete); - void supplyPin2 (String pin2, Message onComplete); - void supplyPuk2 (String puk2, String newPin2, Message onComplete); + public void supplyPin (String pin, Message onComplete) { + mPhone.mCM.supplyIccPin(pin, mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyPuk (String puk, String newPin, Message onComplete) { + mPhone.mCM.supplyIccPuk(puk, newPin, + mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyPin2 (String pin2, Message onComplete) { + mPhone.mCM.supplyIccPin2(pin2, + mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyPuk2 (String puk2, String newPin2, Message onComplete) { + mPhone.mCM.supplyIccPuk2(puk2, newPin2, + mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } + + public void supplyNetworkDepersonalization (String pin, Message onComplete) { + if(mDbg) log("Network Despersonalization: " + pin); + mPhone.mCM.supplyNetworkDepersonalization(pin, + mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete)); + } /** * Check whether ICC pin lock is enabled @@ -119,35 +252,9 @@ public interface IccCard { * @return true for ICC locked enabled * false for ICC locked disabled */ - boolean getIccLockEnabled (); - - /** - * Set the ICC pin lock enabled or disabled - * When the operation is complete, onComplete will be sent to its handler - * - * @param enabled "true" for locked "false" for unlocked. - * @param password needed to change the ICC pin state, aka. Pin1 - * @param onComplete - * onComplete.obj will be an AsyncResult - * ((AsyncResult)onComplete.obj).exception == null on success - * ((AsyncResult)onComplete.obj).exception != null on fail - */ - void setIccLockEnabled(boolean enabled, String password, Message onComplete); - - - /** - * Change the ICC password used in ICC pin lock - * When the operation is complete, onComplete will be sent to its handler - * - * @param oldPassword is the old password - * @param newPassword is the new password - * @param onComplete - * onComplete.obj will be an AsyncResult - * ((AsyncResult)onComplete.obj).exception == null on success - * ((AsyncResult)onComplete.obj).exception != null on fail - */ - void changeIccLockPassword(String oldPassword, String newPassword, - Message onComplete); + public boolean getIccLockEnabled() { + return mIccPinLocked; + } /** * Check whether ICC fdn (fixed dialing number) is enabled @@ -156,36 +263,99 @@ public interface IccCard { * @return true for ICC fdn enabled * false for ICC fdn disabled */ - boolean getIccFdnEnabled (); + public boolean getIccFdnEnabled() { + return mIccFdnEnabled; + } - /** - * Set the ICC fdn enabled or disabled - * When the operation is complete, onComplete will be sent to its handler - * - * @param enabled "true" for locked "false" for unlocked. - * @param password needed to change the ICC fdn enable, aka Pin2 - * @param onComplete - * onComplete.obj will be an AsyncResult - * ((AsyncResult)onComplete.obj).exception == null on success - * ((AsyncResult)onComplete.obj).exception != null on fail - */ - void setIccFdnEnabled(boolean enabled, String password, Message onComplete); + /** + * Set the ICC pin lock enabled or disabled + * When the operation is complete, onComplete will be sent to its handler + * + * @param enabled "true" for locked "false" for unlocked. + * @param password needed to change the ICC pin state, aka. Pin1 + * @param onComplete + * onComplete.obj will be an AsyncResult + * ((AsyncResult)onComplete.obj).exception == null on success + * ((AsyncResult)onComplete.obj).exception != null on fail + */ + public void setIccLockEnabled (boolean enabled, + String password, Message onComplete) { + int serviceClassX; + serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + + CommandsInterface.SERVICE_CLASS_DATA + + CommandsInterface.SERVICE_CLASS_FAX; - /** - * Change the ICC password used in ICC fdn enable - * When the operation is complete, onComplete will be sent to its handler - * - * @param oldPassword is the old password - * @param newPassword is the new password - * @param onComplete - * onComplete.obj will be an AsyncResult - * ((AsyncResult)onComplete.obj).exception == null on success - * ((AsyncResult)onComplete.obj).exception != null on fail - */ - void changeIccFdnPassword(String oldPassword, String newPassword, - Message onComplete); + mDesiredPinLocked = enabled; + + mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM, + enabled, password, serviceClassX, + mHandler.obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete)); + } + + /** + * Set the ICC fdn enabled or disabled + * When the operation is complete, onComplete will be sent to its handler + * + * @param enabled "true" for locked "false" for unlocked. + * @param password needed to change the ICC fdn enable, aka Pin2 + * @param onComplete + * onComplete.obj will be an AsyncResult + * ((AsyncResult)onComplete.obj).exception == null on success + * ((AsyncResult)onComplete.obj).exception != null on fail + */ + public void setIccFdnEnabled (boolean enabled, + String password, Message onComplete) { + int serviceClassX; + serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + + CommandsInterface.SERVICE_CLASS_DATA + + CommandsInterface.SERVICE_CLASS_FAX + + CommandsInterface.SERVICE_CLASS_SMS; + + mDesiredFdnEnabled = enabled; + + mPhone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD, + enabled, password, serviceClassX, + mHandler.obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete)); + } + + /** + * Change the ICC password used in ICC pin lock + * When the operation is complete, onComplete will be sent to its handler + * + * @param oldPassword is the old password + * @param newPassword is the new password + * @param onComplete + * onComplete.obj will be an AsyncResult + * ((AsyncResult)onComplete.obj).exception == null on success + * ((AsyncResult)onComplete.obj).exception != null on fail + */ + public void changeIccLockPassword(String oldPassword, String newPassword, + Message onComplete) { + if(mDbg) log("Change Pin1 old: " + oldPassword + " new: " + newPassword); + mPhone.mCM.changeIccPin(oldPassword, newPassword, + mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete)); + + } + + /** + * Change the ICC password used in ICC fdn enable + * When the operation is complete, onComplete will be sent to its handler + * + * @param oldPassword is the old password + * @param newPassword is the new password + * @param onComplete + * onComplete.obj will be an AsyncResult + * ((AsyncResult)onComplete.obj).exception == null on success + * ((AsyncResult)onComplete.obj).exception != null on fail + */ + public void changeIccFdnPassword(String oldPassword, String newPassword, + Message onComplete) { + if(mDbg) log("Change Pin2 old: " + oldPassword + " new: " + newPassword); + mPhone.mCM.changeIccPin2(oldPassword, newPassword, + mHandler.obtainMessage(EVENT_CHANGE_ICC_PASSWORD_DONE, onComplete)); + + } - void supplyNetworkDepersonalization (String pin, Message onComplete); /** * Returns service provider name stored in ICC card. @@ -203,5 +373,301 @@ public interface IccCard { * yet available * */ - String getServiceProviderName(); + public abstract String getServiceProviderName(); + + protected void updateStateProperty() { + mPhone.setSystemProperty(TelephonyProperties.PROPERTY_SIM_STATE, getState().toString()); + } + + private void getIccCardStatusDone(AsyncResult ar) { + if (ar.exception != null) { + Log.e(mLogTag,"Error getting ICC status. " + + "RIL_REQUEST_GET_ICC_STATUS should " + + "never return an error", ar.exception); + return; + } + handleIccCardStatus((IccCardStatus) ar.result); + } + + private void handleIccCardStatus(IccCardStatus newCardStatus) { + boolean transitionedIntoPinLocked; + boolean transitionedIntoAbsent; + boolean transitionedIntoNetworkLocked; + + State oldState, newState; + + oldState = mState; + mIccCardStatus = newCardStatus; + newState = getIccCardState(); + mState = newState; + + updateStateProperty(); + + transitionedIntoPinLocked = ( + (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED) + || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED)); + transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT); + transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED + && newState == State.NETWORK_LOCKED); + + if (transitionedIntoPinLocked) { + if(mDbg) log("Notify SIM pin or puk locked."); + mPinLockedRegistrants.notifyRegistrants(); + broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED, + (newState == State.PIN_REQUIRED) ? + INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK); + } else if (transitionedIntoAbsent) { + if(mDbg) log("Notify SIM missing."); + mAbsentRegistrants.notifyRegistrants(); + broadcastIccStateChangedIntent(INTENT_VALUE_ICC_ABSENT, null); + } else if (transitionedIntoNetworkLocked) { + if(mDbg) log("Notify SIM network locked."); + mNetworkLockedRegistrants.notifyRegistrants(); + broadcastIccStateChangedIntent(INTENT_VALUE_ICC_LOCKED, + INTENT_VALUE_LOCKED_NETWORK); + } + } + + /** + * Interperate EVENT_QUERY_FACILITY_LOCK_DONE + * @param ar is asyncResult of Query_Facility_Locked + */ + private void onQueryFdnEnabled(AsyncResult ar) { + if(ar.exception != null) { + if(mDbg) log("Error in querying facility lock:" + ar.exception); + return; + } + + int[] ints = (int[])ar.result; + if(ints.length != 0) { + mIccFdnEnabled = (0!=ints[0]); + if(mDbg) log("Query facility lock : " + mIccFdnEnabled); + } else { + Log.e(mLogTag, "[IccCard] Bogus facility lock response"); + } + } + + /** + * Interperate EVENT_QUERY_FACILITY_LOCK_DONE + * @param ar is asyncResult of Query_Facility_Locked + */ + private void onQueryFacilityLock(AsyncResult ar) { + if(ar.exception != null) { + if (mDbg) log("Error in querying facility lock:" + ar.exception); + return; + } + + int[] ints = (int[])ar.result; + if(ints.length != 0) { + mIccPinLocked = (0!=ints[0]); + if(mDbg) log("Query facility lock : " + mIccPinLocked); + } else { + Log.e(mLogTag, "[IccCard] Bogus facility lock response"); + } + } + + public void broadcastIccStateChangedIntent(String value, String reason) { + Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + intent.putExtra(Phone.PHONE_NAME_KEY, mPhone.getPhoneName()); + intent.putExtra(INTENT_KEY_ICC_STATE, value); + intent.putExtra(INTENT_KEY_LOCKED_REASON, reason); + if(mDbg) log("Broadcasting intent ACTION_SIM_STATE_CHANGED " + value + + " reason " + reason); + ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE); + } + + protected Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg){ + AsyncResult ar; + int serviceClassX; + + serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + + CommandsInterface.SERVICE_CLASS_DATA + + CommandsInterface.SERVICE_CLASS_FAX; + + switch (msg.what) { + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: + mState = null; + updateStateProperty(); + broadcastIccStateChangedIntent(INTENT_VALUE_ICC_NOT_READY, null); + break; + case EVENT_ICC_READY: + //TODO: put facility read in SIM_READY now, maybe in REG_NW + mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); + mPhone.mCM.queryFacilityLock ( + CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, + obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); + mPhone.mCM.queryFacilityLock ( + CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX, + obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE)); + break; + case EVENT_ICC_LOCKED_OR_ABSENT: + mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE)); + mPhone.mCM.queryFacilityLock ( + CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, + obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); + break; + case EVENT_GET_ICC_STATUS_DONE: + ar = (AsyncResult)msg.obj; + + getIccCardStatusDone(ar); + break; + case EVENT_PINPUK_DONE: + // a PIN/PUK/PIN2/PUK2/Network Personalization + // request has completed. ar.userObj is the response Message + // Repoll before returning + ar = (AsyncResult)msg.obj; + // TODO should abstract these exceptions + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + mPhone.mCM.getIccCardStatus( + obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj)); + break; + case EVENT_REPOLL_STATUS_DONE: + // Finished repolling status after PIN operation + // ar.userObj is the response messaeg + // ar.userObj.obj is already an AsyncResult with an + // appropriate exception filled in if applicable + + ar = (AsyncResult)msg.obj; + getIccCardStatusDone(ar); + ((Message)ar.userObj).sendToTarget(); + break; + case EVENT_QUERY_FACILITY_LOCK_DONE: + ar = (AsyncResult)msg.obj; + onQueryFacilityLock(ar); + break; + case EVENT_QUERY_FACILITY_FDN_DONE: + ar = (AsyncResult)msg.obj; + onQueryFdnEnabled(ar); + break; + case EVENT_CHANGE_FACILITY_LOCK_DONE: + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + mIccPinLocked = mDesiredPinLocked; + if (mDbg) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " + + "mIccPinLocked= " + mIccPinLocked); + } else { + Log.e(mLogTag, "Error change facility lock with exception " + + ar.exception); + } + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + ((Message)ar.userObj).sendToTarget(); + break; + case EVENT_CHANGE_FACILITY_FDN_DONE: + ar = (AsyncResult)msg.obj; + + if (ar.exception == null) { + mIccFdnEnabled = mDesiredFdnEnabled; + if (mDbg) log("EVENT_CHANGE_FACILITY_FDN_DONE: " + + "mIccFdnEnabled=" + mIccFdnEnabled); + } else { + Log.e(mLogTag, "Error change facility fdn with exception " + + ar.exception); + } + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + ((Message)ar.userObj).sendToTarget(); + break; + case EVENT_CHANGE_ICC_PASSWORD_DONE: + ar = (AsyncResult)msg.obj; + if(ar.exception != null) { + Log.e(mLogTag, "Error in change sim password with exception" + + ar.exception); + } + AsyncResult.forMessage(((Message)ar.userObj)).exception + = ar.exception; + ((Message)ar.userObj).sendToTarget(); + break; + default: + Log.e(mLogTag, "[IccCard] Unknown Event " + msg.what); + } + } + }; + + public State getIccCardState() { + if (mIccCardStatus == null) { + Log.e(mLogTag, "[IccCard] IccCardStatus is null"); + return IccCard.State.ABSENT; + } + + // this is common for all radio technologies + if (!mIccCardStatus.getCardState().isCardPresent()) { + return IccCard.State.ABSENT; + } + + RadioState currentRadioState = mPhone.mCM.getRadioState(); + // check radio technology + if( currentRadioState == RadioState.RADIO_OFF || + currentRadioState == RadioState.RADIO_UNAVAILABLE || + currentRadioState == RadioState.SIM_NOT_READY || + currentRadioState == RadioState.RUIM_NOT_READY || + currentRadioState == RadioState.NV_NOT_READY || + currentRadioState == RadioState.NV_READY) { + return IccCard.State.NOT_READY; + } + + if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT || + currentRadioState == RadioState.SIM_READY || + currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT || + currentRadioState == RadioState.RUIM_READY) { + + int index; + + // check for CDMA radio technology + if (currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT || + currentRadioState == RadioState.RUIM_READY) { + index = mIccCardStatus.getCdmaSubscriptionAppIndex(); + } + else { + index = mIccCardStatus.getGsmUmtsSubscriptionAppIndex(); + } + + IccCardApplication app = mIccCardStatus.getApplication(index); + + if (app == null) { + Log.e(mLogTag, "[IccCard] Subscription Application in not present"); + return IccCard.State.ABSENT; + } + + // check if PIN required + if (app.app_state.isPinRequired()) { + return IccCard.State.PIN_REQUIRED; + } + if (app.app_state.isPukRequired()) { + return IccCard.State.PUK_REQUIRED; + } + if (app.app_state.isSubscriptionPersoEnabled()) { + return IccCard.State.NETWORK_LOCKED; + } + if (app.app_state.isAppReady()) { + return IccCard.State.READY; + } + if (app.app_state.isAppNotReady()) { + return IccCard.State.NOT_READY; + } + return IccCard.State.NOT_READY; + } + + return IccCard.State.ABSENT; + } + + + public boolean hasApplicationType(IccCardApplication.AppType type) { + if (mIccCardStatus == null) return false; + + for (int i = 0 ; i < mIccCardStatus.getNumApplications(); i++) { + IccCardApplication app = mIccCardStatus.getApplication(i); + if (app != null && app.app_type == type) { + return true; + } + } + return false; + } + + private void log(String msg) { + Log.d(mLogTag, "[IccCard] " + msg); + } } diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java index b602b1c..0e7bad7 100644 --- a/telephony/java/com/android/internal/telephony/IccCardStatus.java +++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java @@ -45,42 +45,89 @@ public class IccCardStatus { PINSTATE_ENABLED_PERM_BLOCKED }; - public CardState card_state; - public PinState universal_pin_state; - public int gsm_umts_subscription_app_index; - public int cdma_subscription_app_index; - public int num_applications; + private CardState mCardState; + private PinState mUniversalPinState; + private int mGsmUmtsSubscriptionAppIndex; + private int mCdmaSubscriptionAppIndex; + private int mNumApplications; - ArrayList<IccCardApplication> application = new ArrayList<IccCardApplication>(CARD_MAX_APPS); + private ArrayList<IccCardApplication> mApplications = + new ArrayList<IccCardApplication>(CARD_MAX_APPS); - CardState CardStateFromRILInt(int state) { - CardState newState; - /* RIL_CardState ril.h */ + public CardState getCardState() { + return mCardState; + } + + public void setCardState(int state) { switch(state) { - case 0: newState = CardState.CARDSTATE_ABSENT; break; - case 1: newState = CardState.CARDSTATE_PRESENT; break; - case 2: newState = CardState.CARDSTATE_ERROR; break; - default: - throw new RuntimeException( - "Unrecognized RIL_CardState: " +state); + case 0: + mCardState = CardState.CARDSTATE_ABSENT; + break; + case 1: + mCardState = CardState.CARDSTATE_PRESENT; + break; + case 2: + mCardState = CardState.CARDSTATE_ERROR; + break; + default: + throw new RuntimeException("Unrecognized RIL_CardState: " + state); } - return newState; } - PinState PinStateFromRILInt(int state) { - PinState newState; - /* RIL_PinState ril.h */ + public void setUniversalPinState(int state) { switch(state) { - case 0: newState = PinState.PINSTATE_UNKNOWN; break; - case 1: newState = PinState.PINSTATE_ENABLED_NOT_VERIFIED; break; - case 2: newState = PinState.PINSTATE_ENABLED_VERIFIED; break; - case 3: newState = PinState.PINSTATE_DISABLED; break; - case 4: newState = PinState.PINSTATE_ENABLED_BLOCKED; break; - case 5: newState = PinState.PINSTATE_ENABLED_PERM_BLOCKED; break; - default: - throw new RuntimeException( - "Unrecognized RIL_PinState: " +state); + case 0: + mUniversalPinState = PinState.PINSTATE_UNKNOWN; + break; + case 1: + mUniversalPinState = PinState.PINSTATE_ENABLED_NOT_VERIFIED; + break; + case 2: + mUniversalPinState = PinState.PINSTATE_ENABLED_VERIFIED; + break; + case 3: + mUniversalPinState = PinState.PINSTATE_DISABLED; + break; + case 4: + mUniversalPinState = PinState.PINSTATE_ENABLED_BLOCKED; + break; + case 5: + mUniversalPinState = PinState.PINSTATE_ENABLED_PERM_BLOCKED; + break; + default: + throw new RuntimeException("Unrecognized RIL_PinState: " + state); } - return newState; + } + + public int getGsmUmtsSubscriptionAppIndex() { + return mGsmUmtsSubscriptionAppIndex; + } + + public void setGsmUmtsSubscriptionAppIndex(int gsmUmtsSubscriptionAppIndex) { + mGsmUmtsSubscriptionAppIndex = gsmUmtsSubscriptionAppIndex; + } + + public int getCdmaSubscriptionAppIndex() { + return mCdmaSubscriptionAppIndex; + } + + public void setCdmaSubscriptionAppIndex(int cdmaSubscriptionAppIndex) { + mCdmaSubscriptionAppIndex = cdmaSubscriptionAppIndex; + } + + public int getNumApplications() { + return mNumApplications; + } + + public void setNumApplications(int numApplications) { + mNumApplications = numApplications; + } + + public void addApplication(IccCardApplication application) { + mApplications.add(application); + } + + public IccCardApplication getApplication(int index) { + return mApplications.get(index); } } diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java index 881ed2d..3e7094e 100644 --- a/telephony/java/com/android/internal/telephony/IccUtils.java +++ b/telephony/java/com/android/internal/telephony/IccUtils.java @@ -74,7 +74,7 @@ public class IccUtils { * exactly as received" */ public static int - bcdByteToInt(byte b) { + gsmBcdByteToInt(byte b) { int ret = 0; // treat out-of-range BCD values as 0 @@ -89,11 +89,14 @@ public class IccUtils { return ret; } - /** Decodes BCD byte like {@link bcdByteToInt}, but the most significant BCD - * digit is expected in the most significant nibble. + /** + * Decodes a CDMA style BCD byte like {@link gsmBcdByteToInt}, but + * opposite nibble format. The least significant BCD digit + * is in the least significant nibble and the most significant + * is in the most significant nibble. */ public static int - beBcdByteToInt(byte b) { + cdmaBcdByteToInt(byte b) { int ret = 0; // treat out-of-range BCD values as 0 diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index 7f2b849..e818175 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -22,6 +22,7 @@ import android.os.Handler; import android.os.Message; import android.preference.PreferenceManager; import android.telephony.CellLocation; +import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -98,8 +99,9 @@ public interface Phone { static final String PHONE_NAME_KEY = "phoneName"; static final String FAILURE_REASON_KEY = "reason"; static final String STATE_CHANGE_REASON_KEY = "reason"; - static final String DATA_APN_TYPE_KEY = "apnType"; + static final String DATA_APN_TYPES_KEY = "apnType"; static final String DATA_APN_KEY = "apn"; + static final String DATA_IFACE_NAME_KEY = "iface"; static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable"; static final String PHONE_IN_ECM_STATE = "phoneinECMState"; @@ -119,10 +121,16 @@ public interface Phone { static final String APN_TYPE_MMS = "mms"; /** APN type for SUPL assisted GPS */ static final String APN_TYPE_SUPL = "supl"; + /** APN type for DUN traffic */ + static final String APN_TYPE_DUN = "dun"; + /** APN type for HiPri traffic */ + static final String APN_TYPE_HIPRI = "hipri"; // "Features" accessible through the connectivity manager static final String FEATURE_ENABLE_MMS = "enableMMS"; static final String FEATURE_ENABLE_SUPL = "enableSUPL"; + static final String FEATURE_ENABLE_DUN = "enableDUN"; + static final String FEATURE_ENABLE_HIPRI = "enableHIPRI"; /** * Return codes for <code>enableApnType()</code> @@ -260,8 +268,8 @@ public interface Phone { /** * Get current coarse-grained voice call state. - * Use {@link #registerForPhoneStateChanged(Handler, int, Object) - * registerForPhoneStateChanged()} for change notification. <p> + * Use {@link #registerForPreciseCallStateChanged(Handler, int, Object) + * registerForPreciseCallStateChanged()} for change notification. <p> * If the phone has an active call and call waiting occurs, * then the phone state is RINGING not OFFHOOK * <strong>Note:</strong> @@ -315,18 +323,21 @@ public interface Phone { void unregisterForUnknownConnection(Handler h); /** - * Notifies when any aspect of the voice call state changes. + * Register for getting notifications for change in the Call State {@link Call.State} + * This is called PreciseCallState because the call state is more precise than the + * {@link Phone.State} which can be obtained using the {@link PhoneStateListener} + * * Resulting events will have an AsyncResult in <code>Message.obj</code>. * AsyncResult.userData will be set to the obj argument here. * The <em>h</em> parameter is held only by a weak reference. */ - void registerForPhoneStateChanged(Handler h, int what, Object obj); + void registerForPreciseCallStateChanged(Handler h, int what, Object obj); /** * Unregisters for voice call state change notifications. * Extraneous calls are tolerated silently. */ - void unregisterForPhoneStateChanged(Handler h); + void unregisterForPreciseCallStateChanged(Handler h); /** @@ -423,6 +434,20 @@ public interface Phone { void unregisterForMmiComplete(Handler h); /** + * Registration point for Ecm timer reset + * @param h handler to notify + * @param what user-defined message code + * @param obj placed in Message.obj + */ + public void registerForEcmTimerReset(Handler h, int what, Object obj); + + /** + * Unregister for notification for Ecm timer reset + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForEcmTimerReset(Handler h); + + /** * Returns a list of MMI codes that are pending. (They have initiated * but have not yet completed). * Presently there is only ever one. @@ -538,6 +563,20 @@ public interface Phone { void unregisterForCdmaOtaStatusChange(Handler h); /** + * Registration point for subscription info ready + * @param h handler to notify + * @param what what code of message when delivered + * @param obj placed in Message.obj + */ + public void registerForSubscriptionInfoReady(Handler h, int what, Object obj); + + /** + * Unregister for notifications for subscription info + * @param h Handler to be removed from the registrant list. + */ + public void unregisterForSubscriptionInfoReady(Handler h); + + /** * Returns SIM record load state. Use * <code>getSimCard().registerForReady()</code> for change notification. * @@ -556,8 +595,8 @@ public interface Phone { /** * Answers a ringing or waiting call. Active calls, if any, go on hold. * Answering occurs asynchronously, and final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. * * @exception CallStateException when no call is ringing or waiting */ @@ -567,8 +606,8 @@ public interface Phone { * Reject (ignore) a ringing call. In GSM, this means UDUB * (User Determined User Busy). Reject occurs asynchronously, * and final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. * * @exception CallStateException when no call is ringing or waiting */ @@ -578,8 +617,8 @@ public interface Phone { * Places any active calls on hold, and makes any held calls * active. Switch occurs asynchronously and may fail. * Final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. * * @exception CallStateException if a call is ringing, waiting, or * dialing/alerting. In these cases, this operation may not be performed. @@ -596,8 +635,8 @@ public interface Phone { /** * Conferences holding and active. Conference occurs asynchronously * and may fail. Final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. * * @exception CallStateException if canConference() would return false. * In these cases, this operation may not be performed. @@ -631,8 +670,8 @@ public interface Phone { * Connects the two calls and disconnects the subscriber from both calls * Explicit Call Transfer occurs asynchronously * and may fail. Final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. * * @exception CallStateException if canTransfer() would return false. * In these cases, this operation may not be performed. @@ -659,8 +698,8 @@ public interface Phone { * IDLE, ACTIVE, DIALING, ALERTING, or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. */ Call getForegroundCall(); @@ -676,8 +715,8 @@ public interface Phone { * IDLE, HOLDING or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. */ Call getBackgroundCall(); @@ -693,8 +732,8 @@ public interface Phone { * IDLE, INCOMING, WAITING or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()}. */ Call getRingingCall(); @@ -1067,8 +1106,8 @@ public interface Phone { /** * Gets current mute status. Use - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()} + * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPreciseCallStateChanged()} * as a change notifcation, although presently phone state changed is not * fired when setMute() is called. * @@ -1262,6 +1301,13 @@ public interface Phone { boolean disableDataConnectivity(); /** + * Report the current state of data connectivity (enabled or disabled) + * @return {@code false} if data connectivity has been explicitly disabled, + * {@code true} otherwise. + */ + boolean isDataConnectivityEnabled(); + + /** * Enables the specified APN type. Only works for "special" APN types, * i.e., not the default APN. * @param type The desired APN type. Cannot be {@link #APN_TYPE_DEFAULT}. @@ -1342,7 +1388,7 @@ public interface Phone { */ String getIccSerialNumber(); - //***** CDMA support methods + /* CDMA support methods */ /* * TODO(Moto) TODO(Teleca): can getCdmaMin, getEsn, getMeid use more generic calls @@ -1355,6 +1401,13 @@ public interface Phone { String getCdmaMin(); /** + * Check if subscription data has been assigned to mMin + * + * return true if MIN info is ready; false otherwise. + */ + boolean isMinInfoReady(); + + /** * Retrieves PRL Version for CDMA phones */ String getCdmaPrlVersion(); diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index bcb1ccc..e340f85 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -21,6 +21,7 @@ import android.app.IActivityManager; import android.content.Context; import android.content.res.Configuration; import android.content.SharedPreferences; +import android.net.wifi.WifiManager; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; @@ -28,8 +29,8 @@ import android.os.Message; import android.os.RegistrantList; import android.os.SystemProperties; import android.preference.PreferenceManager; +import android.provider.Settings; import android.telephony.ServiceState; -import android.telephony.SignalStrength; import android.text.TextUtils; import android.util.Log; @@ -53,17 +54,20 @@ import java.util.Locale; * */ -public abstract class PhoneBase implements Phone { +public abstract class PhoneBase extends Handler implements Phone { private static final String LOG_TAG = "PHONE"; private static final boolean LOCAL_DEBUG = true; - // Key used to read and write the saved network selection value + // Key used to read and write the saved network selection numeric value public static final String NETWORK_SELECTION_KEY = "network_selection_key"; + // Key used to read and write the saved network selection operator name + public static final String NETWORK_SELECTION_NAME_KEY = "network_selection_name_key"; - // Key used to read/write "disable data connection on boot" pref (used for testing) + + // Key used to read/write "disable data connection on boot" pref (used for testing) public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key"; - //***** Event Constants + /* Event Constants */ protected static final int EVENT_RADIO_AVAILABLE = 1; /** Supplementary Service Notification received. */ protected static final int EVENT_SSN = 2; @@ -79,20 +83,22 @@ public abstract class PhoneBase implements Phone { protected static final int EVENT_SET_CALL_FORWARD_DONE = 12; protected static final int EVENT_GET_CALL_FORWARD_DONE = 13; protected static final int EVENT_CALL_RING = 14; + protected static final int EVENT_CALL_RING_CONTINUE = 15; + // Used to intercept the carrier selection calls so that // we can save the values. - protected static final int EVENT_SET_NETWORK_MANUAL_COMPLETE = 15; - protected static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 16; - protected static final int EVENT_SET_CLIR_COMPLETE = 17; - protected static final int EVENT_REGISTERED_TO_NETWORK = 18; - protected static final int EVENT_SET_VM_NUMBER_DONE = 19; + protected static final int EVENT_SET_NETWORK_MANUAL_COMPLETE = 16; + protected static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 17; + protected static final int EVENT_SET_CLIR_COMPLETE = 18; + protected static final int EVENT_REGISTERED_TO_NETWORK = 19; + protected static final int EVENT_SET_VM_NUMBER_DONE = 20; // Events for CDMA support - protected static final int EVENT_GET_DEVICE_IDENTITY_DONE = 20; - protected static final int EVENT_RUIM_RECORDS_LOADED = 21; - protected static final int EVENT_NV_READY = 22; - protected static final int EVENT_SET_ENHANCED_VP = 23; - protected static final int EVENT_EMERGENCY_CALLBACK_MODE_ENTER = 24; - protected static final int EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE = 25; + protected static final int EVENT_GET_DEVICE_IDENTITY_DONE = 21; + protected static final int EVENT_RUIM_RECORDS_LOADED = 22; + protected static final int EVENT_NV_READY = 23; + protected static final int EVENT_SET_ENHANCED_VP = 24; + protected static final int EVENT_EMERGENCY_CALLBACK_MODE_ENTER = 25; + protected static final int EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE = 26; // Key used to read/write current CLIR setting public static final String CLIR_KEY = "clir_key"; @@ -100,10 +106,14 @@ public abstract class PhoneBase implements Phone { // Key used to read/write "disable DNS server check" pref (used for testing) public static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key"; - //***** Instance Variables + /* Instance Variables */ public CommandsInterface mCM; protected IccFileHandler mIccFileHandler; boolean mDnsCheckDisabled = false; + public DataConnectionTracker mDataConnection; + boolean mDoesRilSendMultipleCallRing; + int mCallRingContinueToken = 0; + int mCallRingDelay; /** * Set a system property, unless we're in unit test mode @@ -117,7 +127,7 @@ public abstract class PhoneBase implements Phone { } - protected final RegistrantList mPhoneStateRegistrants + protected final RegistrantList mPreciseCallStateRegistrants = new RegistrantList(); protected final RegistrantList mNewRingingConnectionRegistrants @@ -166,8 +176,8 @@ public abstract class PhoneBase implements Phone { * @param notifier An instance of DefaultPhoneNotifier, * unless unit testing. */ - protected PhoneBase(PhoneNotifier notifier, Context context) { - this(notifier, context, false); + protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci) { + this(notifier, context, ci, false); } /** @@ -179,18 +189,83 @@ public abstract class PhoneBase implements Phone { * @param unitTestMode when true, prevents notifications * of state change events */ - protected PhoneBase(PhoneNotifier notifier, Context context, + protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci, boolean unitTestMode) { this.mNotifier = notifier; this.mContext = context; mLooper = Looper.myLooper(); + mCM = ci; - setLocaleByCarrier(); + setPropertiesByCarrier(); setUnitTestMode(unitTestMode); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false); + mCM.setOnCallRing(this, EVENT_CALL_RING, null); + + /** + * Some RIL's don't always send RIL_UNSOL_CALL_RING so it needs + * to be generated locally. Ideally all ring tones should be loops + * and this wouldn't be necessary. But to minimize changes to upper + * layers it is requested that it be generated by lower layers. + * + * By default old phones won't have the property set but do generate + * the RIL_UNSOL_CALL_RING so the default if there is no property is + * true. + */ + mDoesRilSendMultipleCallRing = SystemProperties.getBoolean( + TelephonyProperties.PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING, true); + Log.d(LOG_TAG, "mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing); + + mCallRingDelay = SystemProperties.getInt( + TelephonyProperties.PROPERTY_CALL_RING_DELAY, 3000); + Log.d(LOG_TAG, "mCallRingDelay=" + mCallRingDelay); + } + + public void dispose() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + mCM.unSetOnCallRing(this); + } + } + + /** + * When overridden the derived class needs to call + * super.handleMessage(msg) so this method has a + * a chance to process the message. + * + * @param msg + */ + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + switch(msg.what) { + case EVENT_CALL_RING: + Log.d(LOG_TAG, "Event EVENT_CALL_RING Received state=" + getState()); + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + Phone.State state = getState(); + if ((!mDoesRilSendMultipleCallRing) + && ((state == Phone.State.RINGING) || (state == Phone.State.IDLE))) { + mCallRingContinueToken += 1; + sendIncomingCallRingNotification(mCallRingContinueToken); + } else { + notifyIncomingRing(); + } + } + break; + + case EVENT_CALL_RING_CONTINUE: + Log.d(LOG_TAG, "Event EVENT_CALL_RING_CONTINUE Received stat=" + getState()); + if (getState() == Phone.State.RINGING) { + sendIncomingCallRingNotification(msg.arg1); + } + break; + + default: + throw new RuntimeException("unexpected event not handled"); + } } // Inherited documentation suffices. @@ -219,25 +294,24 @@ public abstract class PhoneBase implements Phone { } // Inherited documentation suffices. - public void registerForPhoneStateChanged(Handler h, int what, Object obj) { + public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) { checkCorrectThread(h); - mPhoneStateRegistrants.addUnique(h, what, obj); + mPreciseCallStateRegistrants.addUnique(h, what, obj); } // Inherited documentation suffices. - public void unregisterForPhoneStateChanged(Handler h) { - mPhoneStateRegistrants.remove(h); + public void unregisterForPreciseCallStateChanged(Handler h) { + mPreciseCallStateRegistrants.remove(h); } /** - * Notify registrants of a PhoneStateChanged. * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ - protected void notifyCallStateChangedP() { + protected void notifyPreciseCallStateChangedP() { AsyncResult ar = new AsyncResult(null, this, null); - mPhoneStateRegistrants.notifyRegistrants(ar); + mPreciseCallStateRegistrants.notifyRegistrants(ar); } // Inherited documentation suffices. @@ -285,16 +359,6 @@ public abstract class PhoneBase implements Phone { mCM.unregisterForInCallVoicePrivacyOff(h); } - /** - * Notifiy registrants of a new ringing Connection. - * Subclasses of Phone probably want to replace this with a - * version scoped to their packages - */ - protected void notifyNewRingingConnectionP(Connection cn) { - AsyncResult ar = new AsyncResult(null, cn, null); - mNewRingingConnectionRegistrants.notifyRegistrants(ar); - } - // Inherited documentation suffices. public void registerForIncomingRing( Handler h, int what, Object obj) { @@ -450,10 +514,10 @@ public abstract class PhoneBase implements Phone { } /** - * Set the locale by matching the carrier string in + * Set the properties by matching the carrier string in * a string-array resource */ - private void setLocaleByCarrier() { + private void setPropertiesByCarrier() { String carrier = SystemProperties.get("ro.carrier"); if (null == carrier || 0 == carrier.length()) { @@ -461,18 +525,36 @@ public abstract class PhoneBase implements Phone { } CharSequence[] carrierLocales = mContext. - getResources().getTextArray(R.array.carrier_locales); + getResources().getTextArray(R.array.carrier_properties); - for (int i = 0; i < carrierLocales.length-1; i+=2) { + for (int i = 0; i < carrierLocales.length; i+=3) { String c = carrierLocales[i].toString(); - String l = carrierLocales[i+1].toString(); if (carrier.equals(c)) { + String l = carrierLocales[i+1].toString(); + int wifiChannels = 0; + try { + wifiChannels = Integer.parseInt( + carrierLocales[i+2].toString()); + } catch (NumberFormatException e) { } + String language = l.substring(0, 2); String country = ""; if (l.length() >=5) { country = l.substring(3, 5); } setSystemLocale(language, country); + + if (wifiChannels != 0) { + try { + Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS); + } catch (Settings.SettingNotFoundException e) { + // note this is not persisting + WifiManager wM = (WifiManager) + mContext.getSystemService(Context.WIFI_SERVICE); + wM.setNumAllowedChannels(wifiChannels, false); + } + } return; } } @@ -530,16 +612,22 @@ public abstract class PhoneBase implements Phone { } } - /* - * Retrieves the Handler of the Phone instance + /** + * Get state */ - public abstract Handler getHandler(); + public abstract Phone.State getState(); /** * Retrieves the IccFileHandler of the Phone instance */ public abstract IccFileHandler getIccFileHandler(); + /* + * Retrieves the Handler of the Phone instance + */ + public Handler getHandler() { + return this; + } /** * Query the status of the CDMA roaming preference @@ -595,7 +683,7 @@ public abstract class PhoneBase implements Phone { * This should only be called in GSM mode. * Only here for some backward compatibility * issues concerning the GSMPhone class. - * @deprecated + * @deprecated Always returns null. */ public List<PdpConnection> getCurrentPdpList() { return null; @@ -679,6 +767,12 @@ public abstract class PhoneBase implements Phone { return null; } + public boolean isMinInfoReady() { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + return false; + } + public String getCdmaPrlVersion(){ // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); @@ -705,6 +799,16 @@ public abstract class PhoneBase implements Phone { Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); } + public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + + public void unregisterForSubscriptionInfoReady(Handler h) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + public boolean isOtaSpNumber(String dialStr) { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); @@ -721,6 +825,16 @@ public abstract class PhoneBase implements Phone { Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); } + public void registerForEcmTimerReset(Handler h, int what, Object obj) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + + public void unregisterForEcmTimerReset(Handler h) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + } + public void registerForSignalInfo(Handler h, int what, Object obj) { mCM.registerForSignalInfo(h, what, obj); } @@ -786,4 +900,106 @@ public abstract class PhoneBase implements Phone { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); } + + public String getInterfaceName(String apnType) { + return mDataConnection.getInterfaceName(apnType); + } + + public String getIpAddress(String apnType) { + return mDataConnection.getIpAddress(apnType); + } + + public boolean isDataConnectivityEnabled() { + return mDataConnection.getDataEnabled(); + } + + public String getGateway(String apnType) { + return mDataConnection.getGateway(apnType); + } + + public String[] getDnsServers(String apnType) { + return mDataConnection.getDnsServers(apnType); + } + + public String[] getActiveApnTypes() { + return mDataConnection.getActiveApnTypes(); + } + + public String getActiveApn() { + return mDataConnection.getActiveApnString(); + } + + public int enableApnType(String type) { + return mDataConnection.enableApnType(type); + } + + public int disableApnType(String type) { + return mDataConnection.disableApnType(type); + } + + /** + * simulateDataConnection + * + * simulates various data connection states. This messes with + * DataConnectionTracker's internal states, but doesn't actually change + * the underlying radio connection states. + * + * @param state Phone.DataState enum. + */ + public void simulateDataConnection(Phone.DataState state) { + DataConnectionTracker.State dcState; + + switch (state) { + case CONNECTED: + dcState = DataConnectionTracker.State.CONNECTED; + break; + case SUSPENDED: + dcState = DataConnectionTracker.State.CONNECTED; + break; + case DISCONNECTED: + dcState = DataConnectionTracker.State.FAILED; + break; + default: + dcState = DataConnectionTracker.State.CONNECTING; + break; + } + + mDataConnection.setState(dcState); + notifyDataConnection(null); + } + + /** + * Notifiy registrants of a new ringing Connection. + * Subclasses of Phone probably want to replace this with a + * version scoped to their packages + */ + protected void notifyNewRingingConnectionP(Connection cn) { + AsyncResult ar = new AsyncResult(null, cn, null); + mNewRingingConnectionRegistrants.notifyRegistrants(ar); + } + + /** + * Notify registrants of a RING event. + */ + private void notifyIncomingRing() { + AsyncResult ar = new AsyncResult(null, this, null); + mIncomingRingRegistrants.notifyRegistrants(ar); + } + + /** + * Send the incoming call Ring notification if conditions are right. + */ + private void sendIncomingCallRingNotification(int token) { + if (!mDoesRilSendMultipleCallRing && (token == mCallRingContinueToken)) { + Log.d(LOG_TAG, "Sending notifyIncomingRing"); + notifyIncomingRing(); + sendMessageDelayed( + obtainMessage(EVENT_CALL_RING_CONTINUE, token, 0), mCallRingDelay); + } else { + Log.d(LOG_TAG, "Ignoring ring notification request," + + " mDoesRilSendMultipleCallRing=" + mDoesRilSendMultipleCallRing + + " token=" + token + + " mCallRingContinueToken=" + mCallRingContinueToken); + } + } } diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java index da00268..8683278 100644 --- a/telephony/java/com/android/internal/telephony/PhoneProxy.java +++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java @@ -25,6 +25,7 @@ import android.os.Handler; import android.os.Message; import android.preference.PreferenceManager; import android.telephony.CellLocation; +import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.util.Log; @@ -210,12 +211,12 @@ public class PhoneProxy extends Handler implements Phone { mActivePhone.unregisterForUnknownConnection(h); } - public void registerForPhoneStateChanged(Handler h, int what, Object obj) { - mActivePhone.registerForPhoneStateChanged(h, what, obj); + public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) { + mActivePhone.registerForPreciseCallStateChanged(h, what, obj); } - public void unregisterForPhoneStateChanged(Handler h) { - mActivePhone.unregisterForPhoneStateChanged(h); + public void unregisterForPreciseCallStateChanged(Handler h) { + mActivePhone.unregisterForPreciseCallStateChanged(h); } public void registerForNewRingingConnection(Handler h, int what, Object obj) { @@ -314,6 +315,22 @@ public class PhoneProxy extends Handler implements Phone { mActivePhone.unregisterForCdmaOtaStatusChange(h); } + public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) { + mActivePhone.registerForSubscriptionInfoReady(h, what, obj); + } + + public void unregisterForSubscriptionInfoReady(Handler h) { + mActivePhone.unregisterForSubscriptionInfoReady(h); + } + + public void registerForEcmTimerReset(Handler h, int what, Object obj) { + mActivePhone.registerForEcmTimerReset(h,what,obj); + } + + public void unregisterForEcmTimerReset(Handler h) { + mActivePhone.unregisterForEcmTimerReset(h); + } + public boolean getIccRecordsLoaded() { return mActivePhone.getIccRecordsLoaded(); } @@ -418,6 +435,10 @@ public class PhoneProxy extends Handler implements Phone { return mActivePhone.getCdmaMin(); } + public boolean isMinInfoReady() { + return mActivePhone.isMinInfoReady(); + } + public String getCdmaPrlVersion() { return mActivePhone.getCdmaPrlVersion(); } @@ -613,6 +634,10 @@ public class PhoneProxy extends Handler implements Phone { return mActivePhone.disableApnType(type); } + public boolean isDataConnectivityEnabled() { + return mActivePhone.isDataConnectivityEnabled(); + } + public boolean isDataConnectivityPossible() { return mActivePhone.isDataConnectivityPossible(); } diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index 690b38a..cd6340e 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -630,7 +630,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { } public void - getIccStatus(Message result) { + getIccCardStatus(Message result) { //Note: This RIL request has not been renamed to ICC, // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result); @@ -1237,10 +1237,17 @@ public final class RIL extends BaseCommands implements CommandsInterface { */ public void setupDefaultPDP(String apn, String user, String password, Message result) { - String radioTechnology = "1"; //0 for CDMA, 1 for GSM/UMTS + int radioTechnology; + int authType; String profile = ""; //profile number, NULL for GSM/UMTS - setupDataCall(radioTechnology, profile, apn, user, - password, result); + + radioTechnology = RILConstants.SETUP_DATA_TECH_GSM; + //TODO(): Add to the APN database, AuthType is set to CHAP/PAP + authType = (user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP + : RILConstants.SETUP_DATA_AUTH_NONE; + + setupDataCall(Integer.toString(radioTechnology), profile, apn, user, + password, Integer.toString(authType), result); } @@ -1259,7 +1266,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { */ public void setupDataCall(String radioTechnology, String profile, String apn, - String user, String password, Message result) { + String user, String password, String authType, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result); @@ -1270,15 +1277,12 @@ public final class RIL extends BaseCommands implements CommandsInterface { rr.mp.writeString(apn); rr.mp.writeString(user); rr.mp.writeString(password); - //TODO(): Add to the APN database, AuthType is set to CHAP/PAP - // 0 => Neither PAP nor CHAP will be performed, 3 => PAP / CHAP will be performed. - if (user != null) - rr.mp.writeString("3"); - else - rr.mp.writeString("0"); + rr.mp.writeString(authType); - if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " - + apn); + if (RILJ_LOGD) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + " " + radioTechnology + " " + + profile + " " + apn + " " + user + " " + + password + " " + authType); send(rr); } @@ -2507,6 +2511,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { mRestrictedStateRegistrant.notifyRegistrant( new AsyncResult (null, ret, null)); } + break; case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: if (RILJ_LOGD) unsljLog(response); @@ -2553,7 +2558,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { break; case RIL_UNSOL_CDMA_CALL_WAITING: - if (RILJ_LOGD) unsljLog(response); + if (RILJ_LOGD) unsljLogRet(response, ret); if (mCallWaitingInfoRegistrants != null) { mCallWaitingInfoRegistrants.notifyRegistrants( @@ -2735,24 +2740,22 @@ public final class RIL extends BaseCommands implements CommandsInterface { private Object responseIccCardStatus(Parcel p) { - RadioState currentRadioState; IccCardApplication ca; - currentRadioState = getRadioState(); - IccCardStatus status = new IccCardStatus(); - status.card_state = status.CardStateFromRILInt(p.readInt()); - status.universal_pin_state = status.PinStateFromRILInt(p.readInt()); - status.gsm_umts_subscription_app_index = p.readInt(); - status.cdma_subscription_app_index = p.readInt(); - status.num_applications = p.readInt(); + status.setCardState(p.readInt()); + status.setUniversalPinState(p.readInt()); + status.setGsmUmtsSubscriptionAppIndex(p.readInt()); + status.setCdmaSubscriptionAppIndex(p.readInt()); + int numApplications = p.readInt(); // limit to maximum allowed applications - if (status.num_applications > IccCardStatus.CARD_MAX_APPS) { - status.num_applications = IccCardStatus.CARD_MAX_APPS; + if (numApplications > IccCardStatus.CARD_MAX_APPS) { + numApplications = IccCardStatus.CARD_MAX_APPS; } + status.setNumApplications(numApplications); - for (int i = 0 ; i < status.num_applications ; i++) { + for (int i = 0 ; i < numApplications ; i++) { ca = new IccCardApplication(); ca.app_type = ca.AppTypeFromRILInt(p.readInt()); ca.app_state = ca.AppStateFromRILInt(p.readInt()); @@ -2762,62 +2765,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { ca.pin1_replaced = p.readInt(); ca.pin1 = p.readInt(); ca.pin2 = p.readInt(); - status.application.add(ca); - } - - // this is common for all radio technologies - if (!status.card_state.isCardPresent()) { - return IccStatus.ICC_ABSENT; - } - - // check radio technology - if( currentRadioState == RadioState.RADIO_OFF || - currentRadioState == RadioState.RADIO_UNAVAILABLE || - currentRadioState == RadioState.SIM_NOT_READY || - currentRadioState == RadioState.RUIM_NOT_READY || - currentRadioState == RadioState.NV_NOT_READY || - currentRadioState == RadioState.NV_READY ) { - return IccStatus.ICC_NOT_READY; + status.addApplication(ca); } - - if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT || - currentRadioState == RadioState.SIM_READY || - currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT || - currentRadioState == RadioState.RUIM_READY) { - - int index; - - // check for CDMA radio technology - if (currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT || - currentRadioState == RadioState.RUIM_READY) { - index = status.cdma_subscription_app_index; - } - else { - index = status.gsm_umts_subscription_app_index; - } - - // check if PIN required - if (status.application.get(index).app_state.isPinRequired()) { - return IccStatus.ICC_PIN; - } - if (status.application.get(index).app_state.isPukRequired()) { - return IccStatus.ICC_PUK; - } - if (status.application.get(index).app_state.isSubscriptionPersoEnabled()) { - return IccStatus.ICC_NETWORK_PERSONALIZATION; - } - if (status.application.get(index).app_state.isAppReady()) { - return IccStatus.ICC_READY; - } - if (status.application.get(index).app_state.isAppNotReady()) { - return IccStatus.ICC_NOT_READY; - } - return IccStatus.ICC_NOT_READY; - } - - // Unrecognized ICC status. Treat it like a missing ICC. - Log.e(LOG_TAG, "Unrecognized RIL_REQUEST_GET_SIM_STATUS result: " + status); - return IccStatus.ICC_ABSENT; + return status; } private Object @@ -3035,7 +2985,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { CdmaCallWaitingNotification notification = new CdmaCallWaitingNotification(); notification.number = p.readString(); - notification.numberPresentation = p.readInt(); + notification.numberPresentation = notification.presentationFromCLIP(p.readInt()); notification.name = p.readString(); notification.namePresentation = notification.numberPresentation; notification.isPresent = p.readInt(); diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index 0763e63..90a82f9 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -79,6 +79,14 @@ public interface RILConstants { int CDM_TTY_HCO_MODE = 2; int CDM_TTY_VCO_MODE = 3; + /* Setup a packet data connection. See ril.h RIL_REQUEST_SETUP_DATA_CALL */ + int SETUP_DATA_TECH_CDMA = 0; + int SETUP_DATA_TECH_GSM = 1; + int SETUP_DATA_AUTH_NONE = 0; + int SETUP_DATA_AUTH_PAP = 1; + int SETUP_DATA_AUTH_CHAP = 2; + int SETUP_DATA_AUTH_PAP_CHAP = 3; + /* cat include/telephony/ril.h | \ egrep '^#define' | \ diff --git a/telephony/java/com/android/internal/telephony/RetryManager.java b/telephony/java/com/android/internal/telephony/RetryManager.java new file mode 100644 index 0000000..385b191 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/RetryManager.java @@ -0,0 +1,392 @@ +/** + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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.util.Log; +import android.util.Pair; +import android.text.TextUtils; + +import java.util.Random; +import java.util.ArrayList; + +/** + * Retry manager allows a simple way to declare a series of + * retires timeouts. After creating a RetryManager the configure + * method is used to define the sequence. A simple linear series + * may be initialized using configure with three integer parameters + * The other configure method allows a series to be declared using + * a string. + *<p> + * The format of the configuration string is a series of parameters + * separated by a comma. There are two name value pair parameters plus a series + * of delay times. The units of of these delay times is unspecified. + * The name value pairs which may be specified are: + *<ul> + *<li>max_retries=<value> + *<li>default_randomizationTime=<value> + *</ul> + *<p> + * max_retries is the number of times that incrementRetryCount + * maybe called before isRetryNeeded will return false. if value + * is infinite then isRetryNeeded will always return true. + * + * default_randomizationTime will be used as the randomizationTime + * for delay times which have no supplied randomizationTime. If + * default_randomizationTime is not defined it defaults to 0. + *<p> + * The other parameters define The series of delay times and each + * may have an optional randomization value separated from the + * delay time by a colon. + *<p> + * Examples: + * <ul> + * <li>3 retires with no randomization value which means its 0: + * <ul><li><code>"1000, 2000, 3000"</code></ul> + * + * <li>10 retires with a 500 default randomization value for each and + * the 4..10 retries all using 3000 as the delay: + * <ul><li><code>"max_retries=10, default_randomization=500, 1000, 2000, 3000"</code></ul> + * + * <li>4 retires with a 100 as the default randomization value for the first 2 values and + * the other two having specified values of 500: + * <ul><li><code>"default_randomization=100, 1000, 2000, 4000:500, 5000:500"</code></ul> + * + * <li>Infinite number of retires with the first one at 1000, the second at 2000 all + * others will be at 3000. + * <ul><li><code>"max_retries=infinite,1000,2000,3000</code></ul> + * </ul> + * + * {@hide} + */ +public class RetryManager { + static public final String LOG_TAG = "RetryManager"; + static public final boolean DBG = false; + static public final int RETRYIES_NOT_STARTED = 0; + static public final int RETRYIES_ON_GOING = 1; + static public final int RETRYIES_COMPLETED = 2; + + /** + * Retry record with times in milli-seconds + */ + private static class RetryRec { + RetryRec(int delayTime, int randomizationTime) { + mDelayTime = delayTime; + mRandomizationTime = randomizationTime; + } + + int mDelayTime; + int mRandomizationTime; + } + + /** The array of retry records */ + private ArrayList<RetryRec> mRetryArray = new ArrayList<RetryRec>(); + + /** When true isRetryNeeded() will always return true */ + private boolean mRetryForever; + + /** + * The maximum number of retries to attempt before + * isRetryNeeded returns false + */ + private int mMaxRetryCount; + + /** The current number of retires */ + private int mRetryCount; + + /** Random number generator */ + private Random rng = new Random(); + + /** Constructor */ + public RetryManager() { + if (DBG) log("constructor"); + } + + /** + * Configure for a simple linear sequence of times plus + * a random value. + * + * @param maxRetryCount is the maximum number of retries + * before isRetryNeeded returns false. + * @param retryTime is a time that will be returned by getRetryTime. + * @param randomizationTime a random value between 0 and + * randomizationTime will be added to retryTime. this + * parameter may be 0. + * @return true if successfull + */ + public boolean configure(int maxRetryCount, int retryTime, int randomizationTime) { + Pair<Boolean, Integer> value; + + if (DBG) log("configure: " + maxRetryCount + ", " + retryTime + "," + randomizationTime); + + if (!validateNonNegativeInt("maxRetryCount", maxRetryCount)) { + return false; + } + + if (!validateNonNegativeInt("retryTime", retryTime)) { + return false; + } + + if (!validateNonNegativeInt("randomizationTime", randomizationTime)) { + return false; + } + + mMaxRetryCount = maxRetryCount; + resetRetryCount(); + mRetryArray.clear(); + mRetryArray.add(new RetryRec(retryTime, randomizationTime)); + + return true; + } + + /** + * Configure for using string which allow arbitary + * sequences of times. See class comments for the + * string format. + * + * @return true if successfull + */ + public boolean configure(String configStr) { + if (DBG) log("configure: '" + configStr + "'"); + + if (!TextUtils.isEmpty(configStr)) { + int defaultRandomization = 0; + + if (DBG) log("configure: not empty"); + + mMaxRetryCount = 0; + resetRetryCount(); + mRetryArray.clear(); + + String strArray[] = configStr.split(","); + for (int i = 0; i < strArray.length; i++) { + if (DBG) log("configure: strArray[" + i + "]='" + strArray[i] + "'"); + Pair<Boolean, Integer> value; + String splitStr[] = strArray[i].split("=", 2); + splitStr[0] = splitStr[0].trim(); + if (DBG) log("configure: splitStr[0]='" + splitStr[0] + "'"); + if (splitStr.length > 1) { + splitStr[1] = splitStr[1].trim(); + if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'"); + if (TextUtils.equals(splitStr[0], "default_randomization")) { + value = parseNonNegativeInt(splitStr[0], splitStr[1]); + if (!value.first) return false; + defaultRandomization = value.second; + } else if (TextUtils.equals(splitStr[0], "max_retries")) { + if (TextUtils.equals("infinite",splitStr[1])) { + mRetryForever = true; + } else { + value = parseNonNegativeInt(splitStr[0], splitStr[1]); + if (!value.first) return false; + mMaxRetryCount = value.second; + } + } else { + Log.e(LOG_TAG, "Unrecognized configuration name value pair: " + + strArray[i]); + return false; + } + } else { + /** + * Assume a retry time with an optional randomization value + * following a ":" + */ + splitStr = strArray[i].split(":", 2); + splitStr[0] = splitStr[0].trim(); + RetryRec rr = new RetryRec(0, 0); + value = parseNonNegativeInt("delayTime", splitStr[0]); + if (!value.first) return false; + rr.mDelayTime = value.second; + + // Check if optional randomization value present + if (splitStr.length > 1) { + splitStr[1] = splitStr[1].trim(); + if (DBG) log("configure: splitStr[1]='" + splitStr[1] + "'"); + value = parseNonNegativeInt("randomizationTime", splitStr[1]); + if (!value.first) return false; + rr.mRandomizationTime = value.second; + } else { + rr.mRandomizationTime = defaultRandomization; + } + mRetryArray.add(rr); + } + } + if (mRetryArray.size() > mMaxRetryCount) { + mMaxRetryCount = mRetryArray.size(); + if (DBG) log("configure: setting mMaxRetryCount=" + mMaxRetryCount); + } + if (DBG) log("configure: true"); + return true; + } else { + if (DBG) log("configure: false it's empty"); + return false; + } + } + + /** + * Report whether data reconnection should be retried + * + * @return {@code true} if the max retires has not been reached. {@code + * false} otherwise. + */ + public boolean isRetryNeeded() { + boolean retVal = mRetryForever || (mRetryCount < mMaxRetryCount); + if (DBG) log("isRetryNeeded: " + retVal); + return retVal; + } + + /** + * Return the timer that should be used to trigger the data reconnection + */ + public int getRetryTimer() { + int index; + if (mRetryCount < mRetryArray.size()) { + index = mRetryCount; + } else { + index = mRetryArray.size() - 1; + } + + int retVal; + if ((index >= 0) && (index < mRetryArray.size())) { + retVal = mRetryArray.get(index).mDelayTime + nextRandomizationTime(index); + } else { + retVal = 0; + } + + if (DBG) log("getRetryTimer: " + retVal); + return retVal; + } + + /** + * @return retry count + */ + public int getRetryCount() { + if (DBG) log("getRetryCount: " + mRetryCount); + return mRetryCount; + } + + /** + * Increase the retry counter, does not change retry forever. + */ + public void increaseRetryCount() { + mRetryCount++; + if (mRetryCount > mMaxRetryCount) { + mRetryCount = mMaxRetryCount; + } + if (DBG) log("increseRetryCount: " + mRetryCount); + } + + /** + * Set retry count to the specified value + * and turns off retrying forever. + */ + public void setRetryCount(int count) { + mRetryCount = count; + if (mRetryCount > mMaxRetryCount) { + mRetryCount = mMaxRetryCount; + } + + if (mRetryCount < 0) { + mRetryCount = 0; + } + + mRetryForever = false; + if (DBG) log("setRetryCount: " + mRetryCount); + } + + /** + * Reset network re-registration indicator and clear the data-retry counter + * and turns off retrying forever. + */ + public void resetRetryCount() { + mRetryCount = 0; + mRetryForever = false; + if (DBG) log("resetRetryCount: " + mRetryCount); + } + + /** + * Retry forever using last timeout time. + */ + public void retryForeverUsingLastTimeout() { + mRetryCount = mMaxRetryCount; + mRetryForever = true; + if (DBG) log("retryForeverUsingLastTimeout: " + mRetryForever + ", " + mRetryCount); + } + + /** + * @return true if retrying forever + */ + public boolean isRetryForever() { + if (DBG) log("isRetryForever: " + mRetryForever); + return mRetryForever; + } + + /** + * Parse an integer validating the value is not negative. + * + * @param name + * @param stringValue + * @return Pair.first == true if stringValue an integer >= 0 + */ + private Pair<Boolean, Integer> parseNonNegativeInt(String name, String stringValue) { + int value; + Pair<Boolean, Integer> retVal; + try { + value = Integer.parseInt(stringValue); + retVal = new Pair<Boolean, Integer>(validateNonNegativeInt(name, value), value); + } catch (NumberFormatException e) { + Log.e(LOG_TAG, name + " bad value: " + stringValue, e); + retVal = new Pair<Boolean, Integer>(false, 0); + } + if (DBG) log("parseNonNetativeInt: " + name + ", " + stringValue + ", " + + retVal.first + ", " + retVal.second); + return retVal; + } + + /** + * Validate an integer is >= 0 and logs an error if not + * + * @param name + * @param value + * @return Pair.first + */ + private boolean validateNonNegativeInt(String name, int value) { + boolean retVal; + if (value < 0) { + Log.e(LOG_TAG, name + " bad value: is < 0"); + retVal = false; + } else { + retVal = true; + } + if (DBG) log("validateNonNegative: " + name + ", " + value + ", " + retVal); + return retVal; + } + + /** + * Return next random number for the index + */ + private int nextRandomizationTime(int index) { + int randomTime = mRetryArray.get(index).mRandomizationTime; + if (randomTime == 0) { + return 0; + } else { + return rng.nextInt(randomTime); + } + } + + private void log(String s) { + Log.d(LOG_TAG, s); + } +} diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java index 890ea63..bbfc6c9 100644 --- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java @@ -61,6 +61,7 @@ import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE; import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE; import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU; import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF; +import static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED; public abstract class SMSDispatcher extends Handler { @@ -105,6 +106,9 @@ public abstract class SMSDispatcher extends Handler { /** Alert is timeout */ static final protected int EVENT_ALERT_TIMEOUT = 9; + /** Stop the sending */ + static final protected int EVENT_STOP_SENDING = 10; + protected Phone mPhone; protected Context mContext; protected ContentResolver mResolver; @@ -120,6 +124,8 @@ public abstract class SMSDispatcher extends Handler { private static final int SEND_RETRY_DELAY = 2000; /** single part SMS */ private static final int SINGLE_PART_SMS = 1; + /** Message sending queue limit */ + private static final int MO_MSG_QUEUE_LIMIT = 5; /** * Message reference for a CONCATENATED_8_BIT_REFERENCE or @@ -130,7 +136,7 @@ public abstract class SMSDispatcher extends Handler { private SmsCounter mCounter; - private SmsTracker mSTracker; + private ArrayList mSTrackers = new ArrayList(MO_MSG_QUEUE_LIMIT); /** Wake lock to ensure device stays awake while dispatching the SMS intent. */ private PowerManager.WakeLock mWakeLock; @@ -214,7 +220,6 @@ public abstract class SMSDispatcher extends Handler { mContext = phone.getContext(); mResolver = mContext.getContentResolver(); mCm = phone.mCM; - mSTracker = null; createWakelock(); @@ -330,17 +335,41 @@ public abstract class SMSDispatcher extends Handler { case EVENT_ALERT_TIMEOUT: ((AlertDialog)(msg.obj)).dismiss(); msg.obj = null; - mSTracker = null; + if (mSTrackers.isEmpty() == false) { + try { + SmsTracker sTracker = (SmsTracker)mSTrackers.remove(0); + sTracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED); + } catch (CanceledException ex) { + Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED"); + } + } + if (Config.LOGD) { + Log.d(TAG, "EVENT_ALERT_TIMEOUT, message stop sending"); + } break; case EVENT_SEND_CONFIRMED_SMS: - if (mSTracker!=null) { - if (isMultipartTracker(mSTracker)) { - sendMultipartSms(mSTracker); + if (mSTrackers.isEmpty() == false) { + SmsTracker sTracker = (SmsTracker)mSTrackers.remove(mSTrackers.size() - 1); + if (isMultipartTracker(sTracker)) { + sendMultipartSms(sTracker); } else { - sendSms(mSTracker); + sendSms(sTracker); + } + removeMessages(EVENT_ALERT_TIMEOUT, msg.obj); + } + break; + + case EVENT_STOP_SENDING: + if (mSTrackers.isEmpty() == false) { + // Remove the latest one. + try { + SmsTracker sTracker = (SmsTracker)mSTrackers.remove(mSTrackers.size() - 1); + sTracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED); + } catch (CanceledException ex) { + Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED"); } - mSTracker = null; + removeMessages(EVENT_ALERT_TIMEOUT, msg.obj); } break; } @@ -445,7 +474,11 @@ public abstract class SMSDispatcher extends Handler { } else if (tracker.mSentIntent != null) { // Done retrying; return an error to the app. try { - tracker.mSentIntent.send(RESULT_ERROR_GENERIC_FAILURE); + Intent fillIn = new Intent(); + if (ar.result != null) { + fillIn.putExtra("errorCode", ((SmsResponse)ar.result).errorCode); + } + tracker.mSentIntent.send(mContext, RESULT_ERROR_GENERIC_FAILURE, fillIn); } catch (CanceledException ex) {} } } @@ -689,6 +722,15 @@ public abstract class SMSDispatcher extends Handler { * An SmsTracker for the current message. */ protected void handleReachSentLimit(SmsTracker tracker) { + if (mSTrackers.size() >= MO_MSG_QUEUE_LIMIT) { + // Deny the sending when the queue limit is reached. + try { + tracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED); + } catch (CanceledException ex) { + Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED"); + } + return; + } Resources r = Resources.getSystem(); @@ -698,13 +740,13 @@ public abstract class SMSDispatcher extends Handler { .setTitle(r.getString(R.string.sms_control_title)) .setMessage(appName + " " + r.getString(R.string.sms_control_message)) .setPositiveButton(r.getString(R.string.sms_control_yes), mListener) - .setNegativeButton(r.getString(R.string.sms_control_no), null) + .setNegativeButton(r.getString(R.string.sms_control_no), mListener) .create(); d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); d.show(); - mSTracker = tracker; + mSTrackers.add(tracker); sendMessageDelayed ( obtainMessage(EVENT_ALERT_TIMEOUT, d), DEFAULT_SMS_TIMOUEOUT); } @@ -815,6 +857,9 @@ public abstract class SMSDispatcher extends Handler { if (which == DialogInterface.BUTTON_POSITIVE) { Log.d(TAG, "click YES to send out sms"); sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS)); + } else if (which == DialogInterface.BUTTON_NEGATIVE) { + Log.d(TAG, "click NO to stop sending"); + sendMessage(obtainMessage(EVENT_STOP_SENDING)); } } }; diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java index bdcf3f7..c74bb8d 100644 --- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java @@ -34,6 +34,14 @@ public abstract class ServiceStateTracker extends Handler { * 1 = GPRS only * 2 = EDGE * 3 = UMTS + * 4 = IS95A + * 5 = IS95B + * 6 = 1xRTT + * 7 = EvDo_0 + * 8 = EvDo_A + * 9 = HSDPA + * 10 = HSUPA + * 11 = HSPA */ protected static final int DATA_ACCESS_UNKNOWN = 0; protected static final int DATA_ACCESS_GPRS = 1; @@ -44,6 +52,9 @@ public abstract class ServiceStateTracker extends Handler { protected static final int DATA_ACCESS_CDMA_1xRTT = 6; protected static final int DATA_ACCESS_CDMA_EvDo_0 = 7; protected static final int DATA_ACCESS_CDMA_EvDo_A = 8; + protected static final int DATA_ACCESS_HSDPA = 9; + protected static final int DATA_ACCESS_HSUPA = 10; + protected static final int DATA_ACCESS_HSPA = 11; //***** Instance Variables protected CommandsInterface cm; @@ -77,7 +88,6 @@ public abstract class ServiceStateTracker extends Handler { // waiting period before recheck gprs and voice registration public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000; - public static final int MAX_NUM_DATA_STATE_READS = 15; public static final int DATA_STATE_POLL_SLEEP_MS = 100; //*****GSM events @@ -116,6 +126,8 @@ public abstract class ServiceStateTracker extends Handler { protected static final int EVENT_POLL_STATE_CDMA_SUBSCRIPTION = 34; protected static final int EVENT_NV_READY = 35; protected static final int EVENT_ERI_FILE_LOADED = 36; + protected static final int EVENT_OTA_PROVISION_STATUS_CHANGE = 37; + protected static final int EVENT_SET_RADIO_POWER_OFF = 38; //***** Time Zones protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java index 8b9ccb4..6177c8a 100644 --- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -353,60 +353,30 @@ public abstract class SmsMessageBase { } /** - * Try to parse this message as an email gateway message -> Neither - * of the standard ways are currently supported: There are two ways - * specified in TS 23.040 Section 3.8 (not supported via this mechanism) - - * SMS message "may have its TP-PID set for internet electronic mail - MT + * Try to parse this message as an email gateway message + * There are two ways specified in TS 23.040 Section 3.8 : + * - SMS message "may have its TP-PID set for internet electronic mail - MT * SMS format: [<from-address><space>]<message> - "Depending on the * nature of the gateway, the destination/origination address is either * derived from the content of the SMS TP-OA or TP-DA field, or the * TP-OA/TP-DA field contains a generic gateway address and the to/from - * address is added at the beginning as shown above." - multiple addreses - * separated by commas, no spaces - subject field delimited by '()' or '##' - * and '#' Section 9.2.3.24.11 + * address is added at the beginning as shown above." (which is supported here) + * - Multiple addreses separated by commas, no spaces, Subject field delimited + * by '()' or '##' and '#' Section 9.2.3.24.11 (which are NOT supported here) */ protected void extractEmailAddressFromMessageBody() { - /* - * a little guesswork here. I haven't found doc for this. - * the format could be either + /* Some carriers may use " /" delimiter as below * * 1. [x@y][ ]/[subject][ ]/[body] * -or- * 2. [x@y][ ]/[body] */ - int slash = 0, slash2 = 0, atSymbol = 0; - - try { - slash = messageBody.indexOf(" /"); - if (slash == -1) { - return; - } - - atSymbol = messageBody.indexOf('@'); - if (atSymbol == -1 || atSymbol > slash) { - return; - } - - emailFrom = messageBody.substring(0, slash); - - slash2 = messageBody.indexOf(" /", slash + 2); - - if (slash2 == -1) { - pseudoSubject = null; - emailBody = messageBody.substring(slash + 2); - } else { - pseudoSubject = messageBody.substring(slash + 2, slash2); - emailBody = messageBody.substring(slash2 + 2); - } - - isEmail = true; - } catch (Exception ex) { - Log.w(LOG_TAG, - "extractEmailAddressFromMessageBody: exception slash=" - + slash + ", atSymbol=" + atSymbol + ", slash2=" - + slash2, ex); - } + String[] parts = messageBody.split("( /)|( )", 2); + if (parts.length < 1 || parts[0].indexOf('@') == -1) return; + emailFrom = parts[0]; + emailBody = parts[1]; + isEmail = true; } } diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 02e9800..2216ec4 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -220,28 +220,4 @@ public class TelephonyIntents { */ public static final String ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS = "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS"; - - /** - * Broadcast Action: The MDN changed during the CDMA OTA Process - * The intent will have the following extra values:</p> - * <ul> - * <li><em>mdn</em> - An Integer of the updated MDN number.</li> - * </ul> - * - * <p class="note">This is a protected intent that can only be sent - * by the system. - * - * <p class="note"> - */ - // TODO(Moto): Generally broadcast intents are for use to allow entities which - // may not know about each other to "communicate". This seems quite specific - // and maybe using the registrant style would be better. - - // Moto: Since this is used for apps not in the same process of phone, can the - // registrant style be used? (Ling Li says: Maybe the "app" can request rather - // than save the MDN each time and this intent would not be necessary?) - // Moto response: Moto internal discussion is on-going. - public static final String ACTION_CDMA_OTA_MDN_CHANGED - = "android.intent.action.ACTION_MDN_STATE_CHANGED"; - } diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index 5ec4020..de5bbc1 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -109,4 +109,25 @@ public interface TelephonyProperties /** The international dialing prefix conversion string */ static final String PROPERTY_IDP_STRING = "ro.cdma.idpstring"; + + /** + * Defines the schema for the carrier specified OTASP number + */ + static final String PROPERTY_OTASP_NUM_SCHEMA = "ro.cdma.otaspnumschema"; + + /** + * Disable all calls including Emergency call when it set to true. + */ + static final String PROPERTY_DISABLE_CALL = "ro.telephony.disable-call"; + + /** + * Set to true for vendor RIL's that send multiple UNSOL_CALL_RING notifications. + */ + static final String PROPERTY_RIL_SENDS_MULTIPLE_CALL_RING = + "ro.telephony.call_ring.multiple"; + + /** + * The number of milli-seconds between CALL_RING notifications. + */ + static final String PROPERTY_CALL_RING_DELAY = "ro.telephony.call_ring.delay"; } diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java index 23eedfe..ebe3e096 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java @@ -26,14 +26,14 @@ import android.database.SQLException; import android.net.Uri; import android.os.AsyncResult; import android.os.Handler; -import android.os.Looper; import android.os.Message; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; import android.os.Registrant; import android.os.RegistrantList; import android.os.RemoteException; import android.os.SystemProperties; import android.preference.PreferenceManager; -import android.provider.Settings; import android.provider.Telephony; import android.telephony.CellLocation; import android.telephony.PhoneNumberUtils; @@ -42,6 +42,7 @@ import android.telephony.SignalStrength; import android.text.TextUtils; import android.util.Log; +import com.android.internal.telephony.Call; import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; @@ -71,34 +72,41 @@ import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OP import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; import java.util.List; -import java.util.Timer; -import java.util.TimerTask; + + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * {@hide} */ public class CDMAPhone extends PhoneBase { static final String LOG_TAG = "CDMA"; - private static final boolean LOCAL_DEBUG = true; + private static final boolean DBG = true; // Default Emergency Callback Mode exit timer - private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 30000; + private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000; + static final String VM_COUNT_CDMA = "vm_count_key_cdma"; private static final String VM_NUMBER_CDMA = "vm_number_key_cdma"; private String mVmNumber = null; - //***** Instance Variables + static final int RESTART_ECM_TIMER = 0; // restart Ecm timer + static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer + + // Instance Variables CdmaCallTracker mCT; CdmaSMSDispatcher mSMS; CdmaServiceStateTracker mSST; - CdmaDataConnectionTracker mDataConnection; RuimFileHandler mRuimFileHandler; RuimRecords mRuimRecords; RuimCard mRuimCard; - MyHandler h; RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager; RuimSmsInterfaceManager mRuimSmsInterfaceManager; PhoneSubInfo mSubInfo; EriManager mEriManager; + WakeLock mWakeLock; + // mNvLoadedRegistrants are informed after the EVENT_NV_READY private RegistrantList mNvLoadedRegistrants = new RegistrantList(); @@ -106,15 +114,20 @@ public class CDMAPhone extends PhoneBase { // mEriFileLoadedRegistrants are informed after the ERI text has been loaded private RegistrantList mEriFileLoadedRegistrants = new RegistrantList(); - // mECMExitRespRegistrant is informed after the phone has been exited + // mEcmTimerResetRegistrants are informed after Ecm timer is canceled or re-started + private RegistrantList mEcmTimerResetRegistrants = new RegistrantList(); + + // mEcmExitRespRegistrant is informed after the phone has been exited //the emergency callback mode //keep track of if phone is in emergency callback mode - private boolean mIsPhoneInECMState; - private Registrant mECMExitRespRegistrant; + private boolean mIsPhoneInEcmState; + private Registrant mEcmExitRespRegistrant; private String mEsn; private String mMeid; + // string to define how the carrier specifies its own ota sp number + private String mCarrierOtaSpNumSchema; - // A runnable which is used to automatically exit from ECM after a period of time. + // A runnable which is used to automatically exit from Ecm after a period of time. private Runnable mExitEcmRunnable = new Runnable() { public void run() { exitEmergencyCallbackMode(); @@ -124,17 +137,14 @@ public class CDMAPhone extends PhoneBase { Registrant mPostDialHandler; - //***** Constructors + // Constructors public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) { this(context,ci,notifier, false); } public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) { - super(notifier, context, unitTestMode); - - h = new MyHandler(); - mCM = ci; + super(notifier, context, ci, unitTestMode); mCM.setPhoneType(RILConstants.CDMA_PHONE); mCT = new CdmaCallTracker(this); @@ -149,16 +159,18 @@ public class CDMAPhone extends PhoneBase { mSubInfo = new PhoneSubInfo(this); mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML); - mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null); - mRuimRecords.registerForRecordsLoaded(h, EVENT_RUIM_RECORDS_LOADED, null); - mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - mCM.registerForOn(h, EVENT_RADIO_ON, null); - mCM.setOnSuppServiceNotification(h, EVENT_SSN, null); - mCM.setOnCallRing(h, EVENT_CALL_RING, null); - mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null); - mCM.registerForNVReady(h, EVENT_NV_READY, null); - mCM.setEmergencyCallbackMode(h, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null); + mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); + mRuimRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null); + mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + mCM.registerForOn(this, EVENT_RADIO_ON, null); + mCM.setOnSuppServiceNotification(this, EVENT_SSN, null); + mSST.registerForNetworkAttach(this, EVENT_REGISTERED_TO_NETWORK, null); + mCM.registerForNVReady(this, EVENT_NV_READY, null); + mCM.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null); + PowerManager pm + = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,LOG_TAG); //Change the system setting SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE, @@ -166,7 +178,11 @@ public class CDMAPhone extends PhoneBase { // This is needed to handle phone process crashes String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); - mIsPhoneInECMState = inEcm.equals("true"); + mIsPhoneInEcmState = inEcm.equals("true"); + + // get the string that specifies the carrier OTA Sp number + mCarrierOtaSpNumSchema = SystemProperties.get( + TelephonyProperties.PROPERTY_OTASP_NUM_SCHEMA,""); // Sets operator alpha property by retrieving from build-time system property String operatorAlpha = SystemProperties.get("ro.cdma.home.operator.alpha"); @@ -185,23 +201,23 @@ public class CDMAPhone extends PhoneBase { // Updates MCC MNC device configuration information updateMccMncConfiguration(operatorNumeric); + // Notify voicemails. notifier.notifyMessageWaitingChanged(this); } public void dispose() { synchronized(PhoneProxy.lockForRadioTechnologyChange) { + super.dispose(); //Unregister from all former registered events - mRuimRecords.unregisterForRecordsLoaded(h); //EVENT_RUIM_RECORDS_LOADED - mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE - mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE - mCM.unregisterForOn(h); //EVENT_RADIO_ON - mCM.unregisterForNVReady(h); //EVENT_NV_READY - mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK - mCM.unSetOnSuppServiceNotification(h); - mCM.unSetOnCallRing(h); - + mRuimRecords.unregisterForRecordsLoaded(this); //EVENT_RUIM_RECORDS_LOADED + mCM.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE + mCM.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE + mCM.unregisterForOn(this); //EVENT_RADIO_ON + mCM.unregisterForNVReady(this); //EVENT_NV_READY + mSST.unregisterForNetworkAttach(this); //EVENT_REGISTERED_TO_NETWORK + mCM.unSetOnSuppServiceNotification(this); //Force all referenced classes to unregister their former registered events mCT.dispose(); @@ -233,11 +249,13 @@ public class CDMAPhone extends PhoneBase { } protected void finalize() { - if(LOCAL_DEBUG) Log.d(LOG_TAG, "CDMAPhone finalized"); + if(DBG) Log.d(LOG_TAG, "CDMAPhone finalized"); + if (mWakeLock.isHeld()) { + Log.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing."); + mWakeLock.release(); + } } - - //***** Overridden from Phone public ServiceState getServiceState() { return mSST.ss; } @@ -358,42 +376,11 @@ public class CDMAPhone extends PhoneBase { return mCT.backgroundCall; } - public String getGateway(String apnType) { - return mDataConnection.getGateway(); - } - public boolean handleInCallMmiCommands(String dialString) { Log.e(LOG_TAG, "method handleInCallMmiCommands is NOT supported in CDMA!"); return false; } - public int enableApnType(String type) { - // This request is mainly used to enable MMS APN - // In CDMA there is no need to enable/disable a different APN for MMS - Log.d(LOG_TAG, "Request to enableApnType("+type+")"); - if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { - return Phone.APN_ALREADY_ACTIVE; - } else { - return Phone.APN_REQUEST_FAILED; - } - } - - public int disableApnType(String type) { - // This request is mainly used to disable MMS APN - // In CDMA there is no need to enable/disable a different APN for MMS - Log.d(LOG_TAG, "Request to disableApnType("+type+")"); - if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { - return Phone.APN_REQUEST_STARTED; - } else { - return Phone.APN_REQUEST_FAILED; - } - } - - public String getActiveApn() { - Log.d(LOG_TAG, "Request to getActiveApn()"); - return null; - } - public void setNetworkSelectionModeAutomatic(Message response) { Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!"); @@ -423,13 +410,17 @@ public class CDMAPhone extends PhoneBase { } public String getCdmaPrlVersion(){ - return mRuimRecords.getPrlVersion(); + return mSST.getPrlVersion(); } - public String getCdmaMIN() { + public String getCdmaMin() { return mSST.getCdmaMin(); } + public boolean isMinInfoReady() { + return mSST.isMinInfoReady(); + } + public void getCallWaiting(Message onComplete) { mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete); } @@ -466,10 +457,6 @@ public class CDMAPhone extends PhoneBase { return false; } - public String getInterfaceName(String apnType) { - return mDataConnection.getInterfaceName(); - } - public CellLocation getCellLocation() { return mSST.cellLoc; } @@ -509,10 +496,6 @@ public class CDMAPhone extends PhoneBase { Log.e(LOG_TAG, "setLine1Number: not possible in CDMA"); } - public String[] getDnsServers(String apnType) { - return mDataConnection.getDnsServers(); - } - public IccCard getIccCard() { return mRuimCard; } @@ -541,12 +524,20 @@ public class CDMAPhone extends PhoneBase { mCM.unregisterForCdmaOtaProvision(h); } + public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) { + mSST.registerForSubscriptionInfoReady(h, what, obj); + } + + public void unregisterForSubscriptionInfoReady(Handler h) { + mSST.unregisterForSubscriptionInfoReady(h); + } + public void setOnEcbModeExitResponse(Handler h, int what, Object obj) { - mECMExitRespRegistrant = new Registrant (h, what, obj); + mEcmExitRespRegistrant = new Registrant (h, what, obj); } public void unsetOnEcbModeExitResponse(Handler h) { - mECMExitRespRegistrant.clear(); + mEcmExitRespRegistrant.clear(); } public void registerForCallWaiting(Handler h, int what, Object obj) { @@ -557,10 +548,6 @@ public class CDMAPhone extends PhoneBase { mCT.unregisterForCallWaiting(h); } - public String getIpAddress(String apnType) { - return mDataConnection.getIpAddress(); - } - public void getNeighboringCids(Message response) { /* @@ -674,14 +661,6 @@ public class CDMAPhone extends PhoneBase { Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA"); } - public String[] getActiveApnTypes() { - String[] result; - Log.d(LOG_TAG, "Request to getActiveApn()"); - result = new String[1]; - result[0] = Phone.APN_TYPE_DEFAULT; - return result; - } - public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) { Log.e(LOG_TAG, "setOutgoingCallerIdDisplay: not possible in CDMA"); } @@ -714,7 +693,7 @@ public class CDMAPhone extends PhoneBase { Message onComplete) { Message resp; mVmNumber = voiceMailNumber; - resp = h.obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete); + resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete); mRuimRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp); } @@ -758,10 +737,13 @@ public class CDMAPhone extends PhoneBase { public boolean enableDataConnectivity() { // block data activities when phone is in emergency callback mode - if (mIsPhoneInECMState) { + if (mIsPhoneInEcmState) { Intent intent = new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS); ActivityManagerNative.broadcastStickyIntent(intent, null); return false; + } else if ((mCT.state == Phone.State.OFFHOOK) && mCT.isInEmergencyCall()) { + // Do not allow data call to be enabled when emergency call is going on + return false; } else { return mDataConnection.setDataEnabled(true); } @@ -808,19 +790,19 @@ public class CDMAPhone extends PhoneBase { } /** - * Notify any interested party of a Phone state change. + * Notify any interested party of a Phone state change {@link Phone.State} */ /*package*/ void notifyPhoneStateChanged() { mNotifier.notifyPhoneState(this); } /** - * Notifies registrants (ie, activities in the Phone app) about - * changes to call state (including Phone and Connection changes). + * Notify registrants of a change in the call state. This notifies changes in {@link Call.State} + * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged. */ - /*package*/ void notifyCallStateChanged() { + /*package*/ void notifyPreciseCallStateChanged() { /* we'd love it if this was package-scoped*/ - super.notifyCallStateChangedP(); + super.notifyPreciseCallStateChangedP(); } void notifyServiceStateChanged(ServiceState ss) { @@ -836,14 +818,6 @@ public class CDMAPhone extends PhoneBase { super.notifyNewRingingConnectionP(c); } - /** - * Notifiy registrants of a RING event. - */ - void notifyIncomingRing() { - AsyncResult ar = new AsyncResult(null, this, null); - mIncomingRingRegistrants.notifyRegistrants(ar); - } - /*package*/ void notifyDisconnect(Connection cn) { mDisconnectRegistrants.notifyResult(cn); } @@ -855,8 +829,9 @@ public class CDMAPhone extends PhoneBase { void sendEmergencyCallbackModeChange(){ //Send an Intent Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); - intent.putExtra(PHONE_IN_ECM_STATE, mIsPhoneInECMState); + intent.putExtra(PHONE_IN_ECM_STATE, mIsPhoneInEcmState); ActivityManagerNative.broadcastStickyIntent(intent,null); + if (DBG) Log.d(LOG_TAG, "sendEmergencyCallbackModeChange"); } /*package*/ void @@ -888,15 +863,21 @@ public class CDMAPhone extends PhoneBase { @Override public void exitEmergencyCallbackMode() { + if (mWakeLock.isHeld()) { + mWakeLock.release(); + } // Send a message which will invoke handleExitEmergencyCallbackMode - mCM.exitEmergencyCallbackMode(h.obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE)); + mCM.exitEmergencyCallbackMode(obtainMessage(EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE)); } private void handleEnterEmergencyCallbackMode(Message msg) { - Log.d(LOG_TAG, "Event EVENT_EMERGENCY_CALLBACK_MODE Received"); - // if phone is not in ECM mode, and it's changed to ECM mode - if (mIsPhoneInECMState == false) { - mIsPhoneInECMState = true; + if (DBG) { + Log.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= " + + mIsPhoneInEcmState); + } + // if phone is not in Ecm mode, and it's changed to Ecm mode + if (mIsPhoneInEcmState == false) { + mIsPhoneInEcmState = true; // notify change sendEmergencyCallbackModeChange(); setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true"); @@ -905,147 +886,175 @@ public class CDMAPhone extends PhoneBase { // if no one invokes exitEmergencyCallbackMode() directly. long delayInMillis = SystemProperties.getLong( TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE); - h.postDelayed(mExitEcmRunnable, delayInMillis); + postDelayed(mExitEcmRunnable, delayInMillis); + // We don't want to go to sleep while in Ecm + mWakeLock.acquire(); } } private void handleExitEmergencyCallbackMode(Message msg) { - Log.d(LOG_TAG, "Event EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE Received"); AsyncResult ar = (AsyncResult)msg.obj; + if (DBG) { + Log.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , mIsPhoneInEcmState " + + ar.exception + mIsPhoneInEcmState); + } + // Remove pending exit Ecm runnable, if any + removeCallbacks(mExitEcmRunnable); - // Remove pending exit ECM runnable, if any - h.removeCallbacks(mExitEcmRunnable); - - if (mECMExitRespRegistrant != null) { - mECMExitRespRegistrant.notifyRegistrant(ar); + if (mEcmExitRespRegistrant != null) { + mEcmExitRespRegistrant.notifyRegistrant(ar); } // if exiting ecm success if (ar.exception == null) { - if (mIsPhoneInECMState) { - mIsPhoneInECMState = false; + if (mIsPhoneInEcmState) { + mIsPhoneInEcmState = false; setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false"); } // send an Intent sendEmergencyCallbackModeChange(); + // Re-initiate data connection + mDataConnection.setDataEnabled(true); } } - //***** Inner Classes - class MyHandler extends Handler { - MyHandler() { + /** + * Handle to cancel or restart Ecm timer in emergency call back mode + * if action is CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled; + * otherwise, restart Ecm timer and notify apps the timer is restarted. + */ + void handleTimerInEmergencyCallbackMode(int action) { + switch(action) { + case CANCEL_ECM_TIMER: + removeCallbacks(mExitEcmRunnable); + mEcmTimerResetRegistrants.notifyResult(new Boolean(true)); + break; + case RESTART_ECM_TIMER: + long delayInMillis = SystemProperties.getLong( + TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE); + postDelayed(mExitEcmRunnable, delayInMillis); + mEcmTimerResetRegistrants.notifyResult(new Boolean(false)); + break; + default: + Log.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action); } + } - MyHandler(Looper l) { - super(l); - } + /** + * Registration point for Ecm timer reset + * @param h handler to notify + * @param what User-defined message code + * @param obj placed in Message.obj + */ + public void registerForEcmTimerReset(Handler h, int what, Object obj) { + mEcmTimerResetRegistrants.addUnique(h, what, obj); + } - @Override - public void handleMessage(Message msg) { - AsyncResult ar; - Message onComplete; + public void unregisterForEcmTimerReset(Handler h) { + mEcmTimerResetRegistrants.remove(h); + } - switch(msg.what) { - case EVENT_RADIO_AVAILABLE: { - mCM.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE)); + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + Message onComplete; - mCM.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE)); - } - break; + switch(msg.what) { + case EVENT_RADIO_AVAILABLE: { + mCM.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE)); - case EVENT_GET_BASEBAND_VERSION_DONE:{ - ar = (AsyncResult)msg.obj; + mCM.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE)); + } + break; - if (ar.exception != null) { - break; - } + case EVENT_GET_BASEBAND_VERSION_DONE:{ + ar = (AsyncResult)msg.obj; - if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result); - setSystemProperty(TelephonyProperties.PROPERTY_BASEBAND_VERSION, (String)ar.result); + if (ar.exception != null) { + break; } - break; - case EVENT_GET_DEVICE_IDENTITY_DONE:{ - ar = (AsyncResult)msg.obj; + if (DBG) Log.d(LOG_TAG, "Baseband version: " + ar.result); + setSystemProperty(TelephonyProperties.PROPERTY_BASEBAND_VERSION, (String)ar.result); + } + break; - if (ar.exception != null) { - break; - } - String[] respId = (String[])ar.result; - mEsn = respId[2]; - mMeid = respId[3]; - } - break; + case EVENT_GET_DEVICE_IDENTITY_DONE:{ + ar = (AsyncResult)msg.obj; - case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{ - handleEnterEmergencyCallbackMode(msg); + if (ar.exception != null) { + break; } - break; + String[] respId = (String[])ar.result; + mEsn = respId[2]; + mMeid = respId[3]; + } + break; - case EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{ - handleExitEmergencyCallbackMode(msg); - } - break; + case EVENT_EMERGENCY_CALLBACK_MODE_ENTER:{ + handleEnterEmergencyCallbackMode(msg); + } + break; - case EVENT_RUIM_RECORDS_LOADED:{ - Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received"); - } - break; + case EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE:{ + handleExitEmergencyCallbackMode(msg); + } + break; - case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:{ - Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received"); - } - break; + case EVENT_RUIM_RECORDS_LOADED:{ + Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received"); + } + break; - case EVENT_RADIO_ON:{ - Log.d(LOG_TAG, "Event EVENT_RADIO_ON Received"); - } - break; + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:{ + Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received"); + } + break; - case EVENT_SSN:{ - Log.d(LOG_TAG, "Event EVENT_SSN Received"); - } - break; + case EVENT_RADIO_ON:{ + Log.d(LOG_TAG, "Event EVENT_RADIO_ON Received"); + } + break; - case EVENT_CALL_RING:{ - Log.d(LOG_TAG, "Event EVENT_CALL_RING Received"); - } - break; + case EVENT_SSN:{ + Log.d(LOG_TAG, "Event EVENT_SSN Received"); + } + break; - case EVENT_REGISTERED_TO_NETWORK:{ - Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received"); + case EVENT_REGISTERED_TO_NETWORK:{ + Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received"); + } + break; + + case EVENT_NV_READY:{ + Log.d(LOG_TAG, "Event EVENT_NV_READY Received"); + //Inform the Service State Tracker + mEriManager.loadEriFile(); + mNvLoadedRegistrants.notifyRegistrants(); + if(mEriManager.isEriFileLoaded()) { + // when the ERI file is loaded + Log.d(LOG_TAG, "ERI read, notify registrants"); + mEriFileLoadedRegistrants.notifyRegistrants(); } - break; + setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE,"false"); + } + break; - case EVENT_NV_READY:{ - Log.d(LOG_TAG, "Event EVENT_NV_READY Received"); - //Inform the Service State Tracker - mEriManager.loadEriFile(); - mNvLoadedRegistrants.notifyRegistrants(); - if(mEriManager.isEriFileLoaded()) { - // when the ERI file is loaded - Log.d(LOG_TAG, "ERI read, notify registrants"); - mEriFileLoadedRegistrants.notifyRegistrants(); - } - setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE,"false"); + case EVENT_SET_VM_NUMBER_DONE:{ + ar = (AsyncResult)msg.obj; + if (IccException.class.isInstance(ar.exception)) { + storeVoiceMailNumber(mVmNumber); + ar.exception = null; } - break; - - case EVENT_SET_VM_NUMBER_DONE:{ - ar = (AsyncResult)msg.obj; - if (IccException.class.isInstance(ar.exception)) { - storeVoiceMailNumber(mVmNumber); - ar.exception = null; - } - onComplete = (Message) ar.userObj; - if (onComplete != null) { - AsyncResult.forMessage(onComplete, ar.result, ar.exception); - onComplete.sendToTarget(); - } + onComplete = (Message) ar.userObj; + if (onComplete != null) { + AsyncResult.forMessage(onComplete, ar.result, ar.exception); + onComplete.sendToTarget(); } + } + break; - default:{ - throw new RuntimeException("unexpected event not handled"); - } + default:{ + super.handleMessage(msg); } } } @@ -1100,13 +1109,6 @@ public class CDMAPhone extends PhoneBase { /** * {@inheritDoc} */ - public Handler getHandler() { - return h; - } - - /** - * {@inheritDoc} - */ public IccFileHandler getIccFileHandler() { return this.mIccFileHandler; } @@ -1153,10 +1155,10 @@ public class CDMAPhone extends PhoneBase { mSMS.setCellBroadcastConfig(configValuesArray, response); } - public static final String IS683A_FEATURE_CODE = "*228" ; - public static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4 ; - public static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2 ; - public static final int IS683A_SYS_SEL_CODE_OFFSET = 4; + private static final String IS683A_FEATURE_CODE = "*228"; + private static final int IS683A_FEATURE_CODE_NUM_DIGITS = 4; + private static final int IS683A_SYS_SEL_CODE_NUM_DIGITS = 2; + private static final int IS683A_SYS_SEL_CODE_OFFSET = 4; private static final int IS683_CONST_800MHZ_A_BAND = 0; private static final int IS683_CONST_800MHZ_B_BAND = 1; @@ -1166,6 +1168,7 @@ public class CDMAPhone extends PhoneBase { private static final int IS683_CONST_1900MHZ_D_BLOCK = 5; private static final int IS683_CONST_1900MHZ_E_BLOCK = 6; private static final int IS683_CONST_1900MHZ_F_BLOCK = 7; + private static final int INVALID_SYSTEM_SELECTION_CODE = -1; private boolean isIs683OtaSpDialStr(String dialStr) { int sysSelCodeInt; @@ -1176,58 +1179,168 @@ public class CDMAPhone extends PhoneBase { if (dialStr.equals(IS683A_FEATURE_CODE)) { isOtaspDialString = true; } - } else if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE, 0, - IS683A_FEATURE_CODE_NUM_DIGITS) == true) - && (dialStrLen >= - (IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS))) { - StringBuilder sb = new StringBuilder(dialStr); - // Separate the System Selection Code into its own string - char[] sysSel = new char[2]; - sb.delete(0, IS683A_SYS_SEL_CODE_OFFSET); - sb.getChars(0, IS683A_SYS_SEL_CODE_NUM_DIGITS, sysSel, 0); - - if ((PhoneNumberUtils.isISODigit(sysSel[0])) - && (PhoneNumberUtils.isISODigit(sysSel[1]))) { - String sysSelCode = new String(sysSel); - sysSelCodeInt = Integer.parseInt((String)sysSelCode); - switch (sysSelCodeInt) { - case IS683_CONST_800MHZ_A_BAND: - case IS683_CONST_800MHZ_B_BAND: - case IS683_CONST_1900MHZ_A_BLOCK: - case IS683_CONST_1900MHZ_B_BLOCK: - case IS683_CONST_1900MHZ_C_BLOCK: - case IS683_CONST_1900MHZ_D_BLOCK: - case IS683_CONST_1900MHZ_E_BLOCK: - case IS683_CONST_1900MHZ_F_BLOCK: - isOtaspDialString = true; - break; + } else { + sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr); + switch (sysSelCodeInt) { + case IS683_CONST_800MHZ_A_BAND: + case IS683_CONST_800MHZ_B_BAND: + case IS683_CONST_1900MHZ_A_BLOCK: + case IS683_CONST_1900MHZ_B_BLOCK: + case IS683_CONST_1900MHZ_C_BLOCK: + case IS683_CONST_1900MHZ_D_BLOCK: + case IS683_CONST_1900MHZ_E_BLOCK: + case IS683_CONST_1900MHZ_F_BLOCK: + isOtaspDialString = true; + break; + default: + break; + } + } + return isOtaspDialString; + } + /** + * This function extracts the system selection code from the dial string. + */ + private int extractSelCodeFromOtaSpNum(String dialStr) { + int dialStrLen = dialStr.length(); + int sysSelCodeInt = INVALID_SYSTEM_SELECTION_CODE; + + if ((dialStr.regionMatches(0, IS683A_FEATURE_CODE, + 0, IS683A_FEATURE_CODE_NUM_DIGITS)) && + (dialStrLen >= (IS683A_FEATURE_CODE_NUM_DIGITS + + IS683A_SYS_SEL_CODE_NUM_DIGITS))) { + // Since we checked the condition above, the system selection code + // extracted from dialStr will not cause any exception + sysSelCodeInt = Integer.parseInt ( + dialStr.substring (IS683A_FEATURE_CODE_NUM_DIGITS, + IS683A_FEATURE_CODE_NUM_DIGITS + IS683A_SYS_SEL_CODE_NUM_DIGITS)); + } + if (DBG) Log.d(LOG_TAG, "extractSelCodeFromOtaSpNum " + sysSelCodeInt); + return sysSelCodeInt; + } - default: + /** + * This function checks if the system selection code extracted from + * the dial string "sysSelCodeInt' is the system selection code specified + * in the carrier ota sp number schema "sch". + */ + private boolean + checkOtaSpNumBasedOnSysSelCode (int sysSelCodeInt, String sch[]) { + boolean isOtaSpNum = false; + try { + // Get how many number of system selection code ranges + int selRc = Integer.parseInt((String)sch[1]); + for (int i = 0; i < selRc; i++) { + if (!TextUtils.isEmpty(sch[i+2]) && !TextUtils.isEmpty(sch[i+3])) { + int selMin = Integer.parseInt((String)sch[i+2]); + int selMax = Integer.parseInt((String)sch[i+3]); + // Check if the selection code extracted from the dial string falls + // within any of the range pairs specified in the schema. + if ((sysSelCodeInt >= selMin) && (sysSelCodeInt <= selMax)) { + isOtaSpNum = true; break; + } } } + } catch (NumberFormatException ex) { + // If the carrier ota sp number schema is not correct, we still allow dial + // and only log the error: + Log.e(LOG_TAG, "checkOtaSpNumBasedOnSysSelCode, error", ex); } - return isOtaspDialString; + return isOtaSpNum; } - /** - * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier - * OTASP dial string. - * - * @param dialStr the number to look up. - * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string - */ + // Define the pattern/format for carrier specified OTASP number schema. + // It separates by comma and/or whitespace. + private static Pattern pOtaSpNumSchema = Pattern.compile("[,\\s]+"); + + /** + * The following function checks if a dial string is a carrier specified + * OTASP number or not by checking against the OTASP number schema stored + * in PROPERTY_OTASP_NUM_SCHEMA. + * + * Currently, there are 2 schemas for carriers to specify the OTASP number: + * 1) Use system selection code: + * The schema is: + * SELC,the # of code pairs,min1,max1,min2,max2,... + * e.g "SELC,3,10,20,30,40,60,70" indicates that there are 3 pairs of + * selection codes, and they are {10,20}, {30,40} and {60,70} respectively. + * + * 2) Use feature code: + * The schema is: + * "FC,length of feature code,feature code". + * e.g "FC,2,*2" indicates that the length of the feature code is 2, + * and the code itself is "*2". + */ + private boolean isCarrierOtaSpNum(String dialStr) { + boolean isOtaSpNum = false; + int sysSelCodeInt = extractSelCodeFromOtaSpNum(dialStr); + if (sysSelCodeInt == INVALID_SYSTEM_SELECTION_CODE) { + return isOtaSpNum; + } + // mCarrierOtaSpNumSchema is retrieved from PROPERTY_OTASP_NUM_SCHEMA: + if (!TextUtils.isEmpty(mCarrierOtaSpNumSchema)) { + Matcher m = pOtaSpNumSchema.matcher(mCarrierOtaSpNumSchema); + if (DBG) { + Log.d(LOG_TAG, "isCarrierOtaSpNum,schema" + mCarrierOtaSpNumSchema); + } + + if (m.find()) { + String sch[] = pOtaSpNumSchema.split(mCarrierOtaSpNumSchema); + // If carrier uses system selection code mechanism + if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("SELC")) { + if (sysSelCodeInt!=INVALID_SYSTEM_SELECTION_CODE) { + isOtaSpNum=checkOtaSpNumBasedOnSysSelCode(sysSelCodeInt,sch); + } else { + if (DBG) { + Log.d(LOG_TAG, "isCarrierOtaSpNum,sysSelCodeInt is invalid"); + } + } + } else if (!TextUtils.isEmpty(sch[0]) && sch[0].equals("FC")) { + int fcLen = Integer.parseInt((String)sch[1]); + String fc = (String)sch[2]; + if (dialStr.regionMatches(0,fc,0,fcLen)) { + isOtaSpNum = true; + } else { + if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,not otasp number"); + } + } else { + if (DBG) { + Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema not supported" + sch[0]); + } + } + } else { + if (DBG) { + Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern not right" + + mCarrierOtaSpNumSchema); + } + } + } else { + if (DBG) Log.d(LOG_TAG, "isCarrierOtaSpNum,ota schema pattern empty"); + } + return isOtaSpNum; + } + + /** + * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier + * OTASP dial string. + * + * @param dialStr the number to look up. + * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string + */ @Override - public boolean isOtaSpNumber(String dialStr){ - boolean isOtaSpNum = false; - if(dialStr != null){ - isOtaSpNum=isIs683OtaSpDialStr(dialStr); - if(isOtaSpNum == false){ - //TO DO:Add carrier specific OTASP number detection here. - } - } - return isOtaSpNum; - } + public boolean isOtaSpNumber(String dialStr){ + boolean isOtaSpNum = false; + String dialableStr = PhoneNumberUtils.extractNetworkPortion(dialStr); + if (dialableStr != null) { + isOtaSpNum = isIs683OtaSpDialStr(dialableStr); + if (isOtaSpNum == false) { + isOtaSpNum = isCarrierOtaSpNum(dialableStr); + } + } + if (DBG) Log.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum); + return isOtaSpNum; + } @Override public int getCdmaEriIconIndex() { diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java index e8724c2..c3bb01f 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java @@ -24,6 +24,7 @@ import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.Connection; import com.android.internal.telephony.DriverCall; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.Call.State; /** * {@hide} @@ -186,6 +187,7 @@ public final class CdmaCall extends Call { cn.onHangupLocal(); } + state = State.DISCONNECTING; } /** diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java index ed2ea90..806c31d 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java @@ -72,7 +72,8 @@ public final class CdmaCallTracker extends CallTracker { CdmaConnection pendingMO; boolean hangupPendingMO; - boolean pendingCallInECM=false; + boolean pendingCallInEcm=false; + boolean mIsInEmergencyCall = false; CDMAPhone phone; boolean desiredMute = false; // false = mute off @@ -80,6 +81,7 @@ public final class CdmaCallTracker extends CallTracker { int pendingCallClirMode; Phone.State state = Phone.State.IDLE; + private boolean mIsEcmTimerCanceled = false; // boolean needsPoll; @@ -182,6 +184,14 @@ public final class CdmaCallTracker extends CallTracker { throw new CallStateException("cannot dial in current state"); } + String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); + boolean isPhoneInEcmMode = inEcm.equals("true"); + boolean isEmergencyCall = PhoneNumberUtils.isEmergencyNumber(dialString); + + // Cancel Ecm timer if a second emergency call is originating in Ecm mode + if (isPhoneInEcmMode && isEmergencyCall) { + handleEcmTimer(phone.CANCEL_ECM_TIMER); + } // We are initiating a call therefore even if we previously // didn't know the state (i.e. Generic was true) we now know @@ -210,19 +220,22 @@ public final class CdmaCallTracker extends CallTracker { // Always unmute when initiating a new call setMute(false); - String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); - if(inEcm.equals("false")) { + // Check data call + disableDataCallInEmergencyCall(dialString); + + // In Ecm mode, if another emergency call is dialed, Ecm mode will not exit. + if(!isPhoneInEcmMode || (isPhoneInEcmMode && isEmergencyCall)) { cm.dial(pendingMO.address, clirMode, obtainCompleteMessage()); } else { phone.exitEmergencyCallbackMode(); phone.setOnEcbModeExitResponse(this,EVENT_EXIT_ECM_RESPONSE_CDMA, null); pendingCallClirMode=clirMode; - pendingCallInECM=true; + pendingCallInEcm=true; } } updatePhoneState(); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); return pendingMO; } @@ -236,6 +249,9 @@ public final class CdmaCallTracker extends CallTracker { private Connection dialThreeWay (String dialString) { if (!foregroundCall.isIdle()) { + // Check data call + disableDataCallInEmergencyCall(dialString); + // Attach the new connection to foregroundCall pendingMO = new CdmaConnection(phone.getContext(), dialString, this, foregroundCall); @@ -262,6 +278,7 @@ public final class CdmaCallTracker extends CallTracker { // triggered by updateParent. cwConn.updateParent(ringingCall, foregroundCall); cwConn.onConnectedInOrOut(); + updatePhoneState(); switchWaitingOrHoldingAndActive(); } else { throw new CallStateException("phone not ringing"); @@ -284,8 +301,14 @@ public final class CdmaCallTracker extends CallTracker { // Should we bother with this check? if (ringingCall.getState() == CdmaCall.State.INCOMING) { throw new CallStateException("cannot be in the incoming state"); - } else { + } else if (foregroundCall.getConnections().size() > 1) { flashAndSetGenericTrue(); + } else { + // Send a flash command to CDMA network for putting the other party on hold. + // For CDMA networks which do not support this the user would just hear a beep + // from the network. For CDMA networks which do support it will put the other + // party on hold. + cm.sendCDMAFeatureCode("", obtainMessage(EVENT_SWITCH_RESULT)); } } @@ -305,7 +328,7 @@ public final class CdmaCallTracker extends CallTracker { internalClearDisconnected(); updatePhoneState(); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); } boolean @@ -320,13 +343,16 @@ public final class CdmaCallTracker extends CallTracker { canDial() { boolean ret; int serviceState = phone.getServiceState().getState(); + String disableCall = SystemProperties.get( + TelephonyProperties.PROPERTY_DISABLE_CALL, "false"); - ret = (serviceState != ServiceState.STATE_POWER_OFF) && - pendingMO == null + ret = (serviceState != ServiceState.STATE_POWER_OFF) + && pendingMO == null && !ringingCall.isRinging() + && !disableCall.equals("true") && (!foregroundCall.getState().isAlive() - || (foregroundCall.getState() == CdmaCall.State.ACTIVE) - || !backgroundCall.getState().isAlive()); + || (foregroundCall.getState() == CdmaCall.State.ACTIVE) + || !backgroundCall.getState().isAlive()); return ret; } @@ -475,6 +501,11 @@ public final class CdmaCallTracker extends CallTracker { // Someone has already asked to hangup this call if (hangupPendingMO) { hangupPendingMO = false; + // Re-start Ecm timer when an uncompleted emergency call ends + if (mIsEcmTimerCanceled) { + handleEcmTimer(phone.RESTART_ECM_TIMER); + } + try { if (Phone.DEBUG_PHONE) log( "poll: hangupPendingMO, hangup conn " + i); @@ -528,20 +559,17 @@ public final class CdmaCallTracker extends CallTracker { } } foregroundCall.setGeneric(false); + + // Re-start Ecm timer when the connected emergency call ends + if (mIsEcmTimerCanceled) { + handleEcmTimer(phone.RESTART_ECM_TIMER); + } else { + mIsInEmergencyCall = false; + } + // Dropped connections are removed from the CallTracker // list but kept in the Call list connections[i] = null; - } else if (conn != null && dc != null && !conn.compareTo(dc)) { - // Connection in CLCC response does not match what - // we were tracking. Assume dropped call and new call - - droppedDuringPoll.add(conn); - connections[i] = new CdmaConnection (phone.getContext(), dc, this, i); - - if (connections[i].getCall() == ringingCall) { - newRinging = connections[i]; - } // else something strange happened - hasNonHangupStateChanged = true; } else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */ boolean changed; changed = conn.update(dc); @@ -578,8 +606,8 @@ public final class CdmaCallTracker extends CallTracker { droppedDuringPoll.add(pendingMO); pendingMO = null; hangupPendingMO = false; - if( pendingCallInECM) { - pendingCallInECM = false; + if( pendingCallInEcm) { + pendingCallInEcm = false; } } @@ -644,7 +672,7 @@ public final class CdmaCallTracker extends CallTracker { } if (hasNonHangupStateChanged || newRinging != null) { - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); } //dumpState(); @@ -678,7 +706,8 @@ public final class CdmaCallTracker extends CallTracker { // the hangup reason is user ignoring or timing out. So conn.onDisconnect() // is not called here. Instead, conn.onLocalDisconnect() is called. conn.onLocalDisconnect(); - phone.notifyCallStateChanged(); + updatePhoneState(); + phone.notifyPreciseCallStateChanged(); return; } else { try { @@ -760,6 +789,7 @@ public final class CdmaCallTracker extends CallTracker { } call.onHangupLocal(); + phone.notifyPreciseCallStateChanged(); } /* package */ @@ -821,7 +851,7 @@ public final class CdmaCallTracker extends CallTracker { // the status of the call is after a call waiting is answered, // 3 way call merged or a switch between calls. foregroundCall.setGeneric(true); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); } private Phone.SuppService getFailedService(int what) { @@ -865,6 +895,7 @@ public final class CdmaCallTracker extends CallTracker { // Create a new CdmaConnection which attaches itself to ringingCall. ringingCall.setGeneric(false); new CdmaConnection(phone.getContext(), cw, this, ringingCall); + updatePhoneState(); // Finally notify application notifyCallWaitingInfo(cw); @@ -926,7 +957,7 @@ public final class CdmaCallTracker extends CallTracker { updatePhoneState(); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); droppedDuringPoll.clear(); break; @@ -945,9 +976,9 @@ public final class CdmaCallTracker extends CallTracker { case EVENT_EXIT_ECM_RESPONSE_CDMA: //no matter the result, we still do the same here - if (pendingCallInECM) { + if (pendingCallInEcm) { cm.dial(pendingMO.address, pendingCallClirMode, obtainCompleteMessage()); - pendingCallInECM = false; + pendingCallInEcm = false; } phone.unsetOnEcbModeExitResponse(this); break; @@ -965,6 +996,7 @@ public final class CdmaCallTracker extends CallTracker { if (ar.exception == null) { // Assume 3 way call is connected pendingMO.onConnectedInOrOut(); + pendingMO = null; } break; @@ -974,6 +1006,39 @@ public final class CdmaCallTracker extends CallTracker { } } + /** + * Handle Ecm timer to be canceled or re-started + */ + private void handleEcmTimer(int action) { + phone.handleTimerInEmergencyCallbackMode(action); + switch(action) { + case CDMAPhone.CANCEL_ECM_TIMER: mIsEcmTimerCanceled = true; break; + case CDMAPhone.RESTART_ECM_TIMER: mIsEcmTimerCanceled = false; break; + default: + Log.e(LOG_TAG, "handleEcmTimer, unsupported action " + action); + } + } + + /** + * Disable data call when emergency call is connected + */ + private void disableDataCallInEmergencyCall(String dialString) { + if (PhoneNumberUtils.isEmergencyNumber(dialString)) { + phone.disableDataConnectivity(); + mIsInEmergencyCall = true; + } + } + + /** + * Check if current call is in emergency call + * + * @return true if it is in emergency call + * false if it is not in emergency call + */ + boolean isInEmergencyCall() { + return mIsInEmergencyCall; + } + protected void log(String msg) { Log.d(LOG_TAG, "[CdmaCallTracker] " + msg); } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java index 54dec48..f4119ad 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallWaitingNotification.java @@ -16,12 +16,16 @@ package com.android.internal.telephony.cdma; +import android.util.Log; +import com.android.internal.telephony.Connection; + /** * Represents a Supplementary Service Notification received from the network. * * {@hide} */ public class CdmaCallWaitingNotification { + static final String LOG_TAG = "CDMA"; public String number =null; public int numberPresentation = 0; public String name = null; @@ -31,7 +35,6 @@ public class CdmaCallWaitingNotification { public int alertPitch = 0; public int signal = 0; - public String toString() { return super.toString() + "Call Waiting Notification " @@ -45,4 +48,17 @@ public class CdmaCallWaitingNotification { + " signal: " + signal ; } + public static int + presentationFromCLIP(int cli) + { + switch(cli) { + case 0: return Connection.PRESENTATION_ALLOWED; + case 1: return Connection.PRESENTATION_RESTRICTED; + case 2: return Connection.PRESENTATION_UNKNOWN; + default: + // This shouldn't happen, just log an error and treat as Unknown + Log.d(LOG_TAG, "Unexpected presentation " + cli); + return Connection.PRESENTATION_UNKNOWN; + } + } } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java index 025382d..0c94e6a 100644..100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java @@ -161,8 +161,8 @@ public class CdmaConnection extends Connection { isIncoming = false; cnapName = null; - cnapNamePresentation = 0; - numberPresentation = 0; + cnapNamePresentation = Connection.PRESENTATION_ALLOWED; + numberPresentation = Connection.PRESENTATION_ALLOWED; createTime = System.currentTimeMillis(); if (parent != null) { @@ -435,8 +435,10 @@ public class CdmaConnection extends Connection { } else if (phone.mCM.getRadioState() != CommandsInterface.RadioState.NV_READY && phone.getIccCard().getState() != RuimCard.State.READY) { return DisconnectCause.ICC_ERROR; - } else { + } else if (causeCode==CallFailCause.NORMAL_CLEARING) { return DisconnectCause.NORMAL; + } else { + return DisconnectCause.ERROR_UNSPECIFIED; } } } @@ -816,15 +818,12 @@ public class CdmaConnection extends Connection { return c == PhoneNumberUtils.WAIT; } - - - // This function is to find the next PAUSE character index if // multiple pauses in a row. Otherwise it finds the next non PAUSE or // non WAIT character index. private static int findNextPCharOrNonPOrNonWCharIndex(String phoneNumber, int currIndex) { - boolean wMatched = false; + boolean wMatched = isWait(phoneNumber.charAt(currIndex)); int index = currIndex + 1; int length = phoneNumber.length(); while (index < length) { @@ -861,17 +860,17 @@ public class CdmaConnection extends Connection { // Append the PW char ret = (isPause(c)) ? PhoneNumberUtils.PAUSE : PhoneNumberUtils.WAIT; - // if there is a PAUSE in at the begining of PW character sequences, and this - // PW character sequences has more than 2 PAUSE and WAIT Characters,skip P, append W - if (isPause(c) && (nextNonPwCharIndex > (currPwIndex + 1))) { + // if there is a PAUSE in at the beginning of PW character sequences, and this + // PW character sequences has more than 2 PAUSE and WAIT Characters,skip PAUSE, + // append WAIT. + if (isPause(c) && (nextNonPwCharIndex > (currPwIndex + 2))) { ret = PhoneNumberUtils.WAIT; } return ret; } - /** - * format orignal dial string + * format original dial string * 1) convert international dialing prefix "+" to * string specified per region * @@ -890,20 +889,10 @@ public class CdmaConnection extends Connection { StringBuilder ret = new StringBuilder(); char c; int currIndex = 0; + while (currIndex < length) { c = phoneNumber.charAt(currIndex); - if (PhoneNumberUtils.isDialable(c)) { - if (c == '+') { - String ps = null; - SystemProperties.get(TelephonyProperties.PROPERTY_IDP_STRING, ps); - if (TextUtils.isEmpty(ps)) { - ps = "011"; - } - ret.append(ps); - } else { - ret.append(c); - } - } else if (isPause(c) || isWait(c)) { + if (isPause(c) || isWait(c)) { if (currIndex < length - 1) { // if PW not at the end int nextIndex = findNextPCharOrNonPOrNonWCharIndex(phoneNumber, currIndex); @@ -911,8 +900,10 @@ public class CdmaConnection extends Connection { if (nextIndex < length) { char pC = findPOrWCharToAppend(phoneNumber, currIndex, nextIndex); ret.append(pC); - // If PW char is immediately followed by non-PW char - if (nextIndex > (currIndex + 1)) { + // If PW char sequence has more than 2 PW characters, + // skip to the last character since the sequence already be + // converted to WAIT character + if (nextIndex > (currIndex + 2)) { currIndex = nextIndex - 1; } } else if (nextIndex == length) { @@ -925,7 +916,7 @@ public class CdmaConnection extends Connection { } currIndex++; } - return ret.toString(); + return PhoneNumberUtils.cdmaCheckAndProcessPlusCode(ret.toString()); } private void log(String msg) { diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java index fef6d3c..4588f36 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java @@ -143,9 +143,10 @@ public class CdmaDataConnection extends DataConnection { lastFailTime = -1; lastFailCause = FailCause.NONE; receivedDisconnectReq = false; - phone.mCM.setupDataCall(Integer.toString(RILConstants.CDMA_PHONE), + phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_CDMA), Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), null, null, - null, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE)); + null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP), + obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE)); } private void tearDownData(Message msg) { diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java index c3818f5..ffaa1cd 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -31,6 +31,7 @@ import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; +import android.os.SystemProperties; import android.preference.PreferenceManager; import android.provider.Checkin; import android.telephony.ServiceState; @@ -45,7 +46,9 @@ import com.android.internal.telephony.DataCallState; import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.DataConnection.FailCause; import com.android.internal.telephony.DataConnectionTracker; +import com.android.internal.telephony.RetryManager; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.TelephonyEventLog; import java.util.ArrayList; @@ -54,15 +57,12 @@ import java.util.ArrayList; * {@hide} */ public final class CdmaDataConnectionTracker extends DataConnectionTracker { - private static final String LOG_TAG = "CDMA"; - private static final boolean DBG = true; + protected final String LOG_TAG = "CDMA"; private CDMAPhone mCdmaPhone; // Indicates baseband will not auto-attach private boolean noAutoAttach = false; - long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - private boolean mReregisterOnReconnectFailure = false; private boolean mIsScreenOn = true; //useful for debugging @@ -76,11 +76,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** Currently active CdmaDataConnection */ private CdmaDataConnection mActiveDataConnection; - /** Defined cdma connection profiles */ - private static final int EXTERNAL_NETWORK_DEFAULT_ID = 0; - private static final int EXTERNAL_NETWORK_NUM_TYPES = 1; - - private boolean[] dataEnabled = new boolean[EXTERNAL_NETWORK_NUM_TYPES]; + private boolean mPendingRestartRadio = false; + private static final int TIME_DELAYED_TO_RESTART_RADIO = + SystemProperties.getInt("ro.cdma.timetoradiorestart", 20000); /** * Pool size of CdmaDataConnection objects. @@ -100,6 +98,11 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { private static final int DATA_CONNECTION_ACTIVE_PH_LINK_DOWN = 1; private static final int DATA_CONNECTION_ACTIVE_PH_LINK_UP = 2; + private static final String[] mSupportedApnTypes = { + Phone.APN_TYPE_DEFAULT, + Phone.APN_TYPE_MMS, + Phone.APN_TYPE_HIPRI }; + // Possibly promoate to base class, the only difference is // the INTENT_RECONNECT_ALARM action is a different string. // Do consider technology changes if it is promoted. @@ -143,7 +146,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { }; - //***** Constructor + /* Constructor */ CdmaDataConnectionTracker(CDMAPhone p) { super(p); @@ -160,6 +163,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { p.mSST.registerForCdmaDataConnectionDetached(this, EVENT_CDMA_DATA_DETACHED, null); p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null); p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); + p.mCM.registerForCdmaOtaProvision(this, EVENT_CDMA_OTA_PROVISION, null); this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat")); @@ -170,7 +174,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - p.getContext().registerReceiver(mIntentReceiver, filter, null, p.h); + // TODO: Why is this registering the phone as the receiver of the intent + // and not its own handler? + p.getContext().registerReceiver(mIntentReceiver, filter, null, p); mDataConnectionTracker = this; @@ -180,13 +186,25 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { // and 2) whether the RIL will setup the baseband to auto-PS attach. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext()); - dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID] = + dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false); - noAutoAttach = !dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]; + if (dataEnabled[APN_DEFAULT_ID]) { + enabledCount++; + } + noAutoAttach = !dataEnabled[APN_DEFAULT_ID]; + + if (!mRetryMgr.configure(SystemProperties.get("ro.cdma.data_retry_config"))) { + if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) { + // Should never happen, log an error and default to a simple linear sequence. + Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG=" + + DEFAULT_DATA_RETRY_CONFIG); + mRetryMgr.configure(20, 2000, 1000); + } + } } public void dispose() { - //Unregister from all events + // Unregister from all events phone.mCM.unregisterForAvailable(this); phone.mCM.unregisterForOffOrNotAvailable(this); mCdmaPhone.mRuimRecords.unregisterForRecordsLoaded(this); @@ -198,6 +216,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { mCdmaPhone.mSST.unregisterForCdmaDataConnectionDetached(this); mCdmaPhone.mSST.unregisterForRoamingOn(this); mCdmaPhone.mSST.unregisterForRoamingOff(this); + phone.mCM.unregisterForCdmaOtaProvision(this); phone.getContext().unregisterReceiver(this.mIntentReceiver); destroyAllDataConnectionList(); @@ -207,7 +226,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { if(DBG) Log.d(LOG_TAG, "CdmaDataConnectionTracker finalized"); } - void setState(State s) { + protected void setState(State s) { if (DBG) log ("setState: " + s); if (state != s) { if (s == State.INITING) { // request Data connection context @@ -224,39 +243,33 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { state = s; } - public int enableApnType(String type) { - // This request is mainly used to enable MMS APN - // In CDMA there is no need to enable/disable a different APN for MMS - Log.d(LOG_TAG, "Request to enableApnType("+type+")"); - if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { - return Phone.APN_ALREADY_ACTIVE; - } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) { - Log.w(LOG_TAG, "Phone.APN_TYPE_SUPL not enabled for CDMA"); - return Phone.APN_REQUEST_FAILED; - } else { - return Phone.APN_REQUEST_FAILED; - } + @Override + protected boolean isApnTypeActive(String type) { + return (isApnTypeAvailable(type) && + mCdmaPhone.mSST.getCurrentCdmaDataConnectionState() == + ServiceState.STATE_IN_SERVICE); } - public int disableApnType(String type) { - // This request is mainly used to disable MMS APN - // In CDMA there is no need to enable/disable a different APN for MMS - Log.d(LOG_TAG, "Request to disableApnType("+type+")"); - if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { - return Phone.APN_REQUEST_STARTED; - } else { - return Phone.APN_REQUEST_FAILED; + @Override + protected boolean isApnTypeAvailable(String type) { + for (String s : mSupportedApnTypes) { + if (TextUtils.equals(type, s)) { + return true; + } } + return false; } - private boolean isEnabled(int cdmaDataProfile) { - return dataEnabled[cdmaDataProfile]; + protected String[] getActiveApnTypes() { + if (mCdmaPhone.mSST.getCurrentCdmaDataConnectionState() == + ServiceState.STATE_IN_SERVICE) { + return mSupportedApnTypes.clone(); + } + return new String[0]; } - private void setEnabled(int cdmaDataProfile, boolean enable) { - Log.d(LOG_TAG, "setEnabled(" + cdmaDataProfile + ", " + enable + ')'); - dataEnabled[cdmaDataProfile] = enable; - Log.d(LOG_TAG, "dataEnabled[DEFAULT_PROFILE]=" + dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]); + protected String getActiveApnString() { + return null; } /** @@ -282,54 +295,6 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { return true; } - /** - * Prevent mobile data connections from being established, - * or once again allow mobile data connections. If the state - * toggles, then either tear down or set up data, as - * appropriate to match the new state. - * <p>This operation only affects the default connection - * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data - * @return {@code true} if the operation succeeded - */ - public boolean setDataEnabled(boolean enable) { - - boolean isEnabled = isEnabled(EXTERNAL_NETWORK_DEFAULT_ID); - - Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled); - if (!isEnabled && enable) { - setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, true); - sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); - } else if (!enable) { - setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, false); - Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); - msg.arg1 = 1; // tearDown is true - msg.obj = Phone.REASON_DATA_DISABLED; - sendMessage(msg); - } - return true; - } - - /** - * Report the current state of data connectivity (enabled or disabled) - * @return {@code false} if data connectivity has been explicitly disabled, - * {@code true} otherwise. - */ - public boolean getDataEnabled() { - return dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]; - } - - /** - * Report on whether data connectivity is enabled - * @return {@code false} if data connectivity has been explicitly disabled, - * {@code true} otherwise. - */ - public boolean getAnyDataEnabled() { - for (int i=0; i < EXTERNAL_NETWORK_NUM_TYPES; i++) { - if (isEnabled(i)) return true; - } - return false; - } - private boolean isDataAllowed() { boolean roaming = phone.getServiceState().getRoaming(); return getAnyDataEnabled() && (!roaming || getDataOnRoamingEnabled()); @@ -359,7 +324,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { && (mCdmaPhone.mSST.isConcurrentVoiceAndData() || phone.getState() == Phone.State.IDLE ) && isDataAllowed() - && desiredPowerState) { + && desiredPowerState + && !mPendingRestartRadio) { return setupData(reason); @@ -375,7 +341,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { " dataEnabled=" + getAnyDataEnabled() + " roaming=" + roaming + " dataOnRoamingEnable=" + getDataOnRoamingEnabled() + - " desiredPowerState=" + desiredPowerState); + " desiredPowerState=" + desiredPowerState + + " PendingRestartRadio=" + mPendingRestartRadio); } return false; } @@ -459,9 +426,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { setState(State.CONNECTED); phone.notifyDataConnection(reason); startNetStatPoll(); - // reset reconnect timer - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - mReregisterOnReconnectFailure = false; + mRetryMgr.resetRetryCount(); } private void resetPollStats() { @@ -488,16 +453,11 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } protected void restartRadio() { - Log.d(LOG_TAG, "************TURN OFF RADIO**************"); + if (DBG) log("Cleanup connection and wait " + + (TIME_DELAYED_TO_RESTART_RADIO / 1000) + "s to restart radio"); cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); - phone.mCM.setRadioPower(false, null); - /* Note: no need to call setRadioPower(true). Assuming the desired - * radio power state is still ON (as tracked by ServiceStateTracker), - * ServiceStateTracker will call setRadioPower when it receives the - * RADIO_STATE_CHANGED notification for the power off. And if the - * desired power state has changed in the interim, we don't want to - * override it with an unconditional power on. - */ + sendEmptyMessageDelayed(EVENT_RESTART_RADIO, TIME_DELAYED_TO_RESTART_RADIO); + mPendingRestartRadio = true; } private Runnable mPollNetStat = new Runnable() { @@ -541,10 +501,10 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { sentSinceLastRecv = 0; newActivity = Activity.DATAIN; } else if (sent == 0 && received == 0) { - newActivity = Activity.NONE; + newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE; } else { sentSinceLastRecv = 0; - newActivity = Activity.NONE; + newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE; } if (activity != newActivity) { @@ -608,8 +568,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { private boolean retryAfterDisconnected(String reason) { boolean retry = true; - if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) || - Phone.REASON_DATA_DISABLED.equals(reason) ) { + if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ) { retry = false; } return retry; @@ -617,21 +576,13 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { if (state == State.FAILED) { - if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) { - if (mReregisterOnReconnectFailure) { - // We have already tried to re-register to the network. - // This might be a problem with the data network. - nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS; - } else { - // Try to Re-register to the network. - Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network"); - mReregisterOnReconnectFailure = true; - mCdmaPhone.mSST.reRegisterNetwork(null); - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - return; - } - } - + /** + * For now With CDMA we never try to reconnect on + * error and instead just continue to retry + * at the last time until the state is changed. + * TODO: Make this configurable? + */ + int nextReconnectDelay = mRetryMgr.getRetryTimer(); Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); @@ -645,8 +596,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { SystemClock.elapsedRealtime() + nextReconnectDelay, mReconnectIntent); - // double it for next time - nextReconnectDelay *= 2; + mRetryMgr.increaseRetryCount(); if (!shouldPostNotification(lastFailCauseCode)) { Log.d(LOG_TAG,"NOT Posting Data Connection Unavailable notification " @@ -678,8 +628,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ - protected void onTrySetupData(String reason) { - trySetupData(reason); + protected boolean onTrySetupData(String reason) { + return trySetupData(reason); } /** @@ -723,10 +673,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { * @override com.android.internal.telephony.DataConnectionTracker */ protected void onRadioOffOrNotAvailable() { - // Make sure our reconnect delay starts at the initial value - // next time the radio comes on - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - mReregisterOnReconnectFailure = false; + mRetryMgr.resetRetryCount(); if (phone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator @@ -773,6 +720,20 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { reason = (String) ar.userObj; } setState(State.IDLE); + + // Since the pending request to turn off or restart radio will be processed here, + // remove the pending event to restart radio from the message queue. + if (mPendingRestartRadio) removeMessages(EVENT_RESTART_RADIO); + + // Process the pending request to turn off radio in ServiceStateTracker first. + // If radio is turned off in ServiceStateTracker, ignore the pending event to restart radio. + CdmaServiceStateTracker ssTracker = mCdmaPhone.mSST; + if (ssTracker.processPendingRadioPowerOffAfterDataOff()) { + mPendingRestartRadio = false; + } else { + onRestartRadio(); + } + phone.notifyDataConnection(reason); if (retryAfterDisconnected(reason)) { trySetupData(reason); @@ -802,9 +763,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { resetPollStats(); } } else { - // reset reconnect timer - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - mReregisterOnReconnectFailure = false; + mRetryMgr.resetRetryCount(); // in case data setup was attempted when we were on a voice call trySetupData(Phone.REASON_VOICE_CALL_ENDED); } @@ -840,7 +799,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } else { if (state == State.FAILED) { cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED); - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation()); int bsid = (loc != null) ? loc.getBaseStationId() : -1; @@ -853,6 +812,37 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } } + private void onCdmaOtaProvision(AsyncResult ar) { + if (ar.exception != null) { + int [] otaPrivision = (int [])ar.result; + if ((otaPrivision != null) && (otaPrivision.length > 1)) { + switch (otaPrivision[0]) { + case Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED: + case Phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED: + mRetryMgr.resetRetryCount(); + break; + default: + break; + } + } + } + } + + private void onRestartRadio() { + if (mPendingRestartRadio) { + Log.d(LOG_TAG, "************TURN OFF RADIO**************"); + phone.mCM.setRadioPower(false, null); + /* Note: no need to call setRadioPower(true). Assuming the desired + * radio power state is still ON (as tracked by ServiceStateTracker), + * ServiceStateTracker will call setRadioPower when it receives the + * RADIO_STATE_CHANGED notification for the power off. And if the + * desired power state has changed in the interim, we don't want to + * override it with an unconditional power on. + */ + mPendingRestartRadio = false; + } + } + private void writeEventLogCdmaDataDrop() { CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation()); int bsid = (loc != null) ? loc.getBaseStationId() : -1; @@ -905,28 +895,28 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } } - String getInterfaceName() { + protected String getInterfaceName(String apnType) { if (mActiveDataConnection != null) { return mActiveDataConnection.getInterface(); } return null; } - protected String getIpAddress() { + protected String getIpAddress(String apnType) { if (mActiveDataConnection != null) { return mActiveDataConnection.getIpAddress(); } return null; } - String getGateway() { + protected String getGateway(String apnType) { if (mActiveDataConnection != null) { return mActiveDataConnection.getGatewayAddress(); } return null; } - protected String[] getDnsServers() { + protected String[] getDnsServers(String apnType) { if (mActiveDataConnection != null) { return mActiveDataConnection.getDnsServers(); } @@ -961,6 +951,15 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { onDataStateChanged((AsyncResult) msg.obj); break; + case EVENT_CDMA_OTA_PROVISION: + onCdmaOtaProvision((AsyncResult) msg.obj); + break; + + case EVENT_RESTART_RADIO: + if (DBG) log("EVENT_RESTART_RADIO"); + onRestartRadio(); + break; + default: // handle the message in the super class DataConnectionTracker super.handleMessage(msg); diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java index ecdc8f6..88cccd3 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -19,18 +19,22 @@ package com.android.internal.telephony.cdma; import android.app.Activity; import android.app.PendingIntent; +import android.app.PendingIntent.CanceledException; import android.content.ContentValues; import android.content.SharedPreferences; import android.database.Cursor; import android.database.SQLException; import android.os.AsyncResult; import android.os.Message; +import android.os.SystemProperties; import android.provider.Telephony; import android.provider.Telephony.Sms.Intents; import android.preference.PreferenceManager; import android.util.Config; import android.util.Log; +import android.telephony.SmsManager; +import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; @@ -43,6 +47,7 @@ import com.android.internal.util.HexDump; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.HashMap; +import java.lang.Boolean; final class CdmaSMSDispatcher extends SMSDispatcher { @@ -75,13 +80,19 @@ final class CdmaSMSDispatcher extends SMSDispatcher { return Intents.RESULT_SMS_GENERIC_ERROR; } + String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); + if (inEcm.equals("true")) { + return Intents.RESULT_SMS_GENERIC_ERROR; + } + // Decode BD stream and set sms variables. SmsMessage sms = (SmsMessage) smsb; sms.parseSms(); int teleService = sms.getTeleService(); boolean handled = false; - if (sms.getUserData() == null) { + if ((sms.getUserData() == null) && (SmsEnvelope.TELESERVICE_MWI != teleService) && + (SmsEnvelope.TELESERVICE_VMN != teleService)) { if (Config.LOGD) { Log.d(TAG, "Received SMS without user data"); } @@ -92,10 +103,11 @@ final class CdmaSMSDispatcher extends SMSDispatcher { return Intents.RESULT_SMS_HANDLED; } - if (SmsEnvelope.TELESERVICE_WAP == teleService){ + if (SmsEnvelope.TELESERVICE_WAP == teleService) { return processCdmaWapPdu(sms.getUserData(), sms.messageRef, sms.getOriginatingAddress()); - } else if (SmsEnvelope.TELESERVICE_VMN == teleService) { + } else if ((SmsEnvelope.TELESERVICE_VMN == teleService) || + (SmsEnvelope.TELESERVICE_MWI == teleService)) { // handling Voicemail int voicemailCount = sms.getNumOfVoicemails(); Log.d(TAG, "Voicemail count=" + voicemailCount); @@ -323,6 +335,24 @@ final class CdmaSMSDispatcher extends SMSDispatcher { sentIntent, deliveryIntent); } + protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + PendingIntent deliveryIntent) { + String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE); + if (Boolean.parseBoolean(inEcm)) { + if (sentIntent != null) { + try { + sentIntent.send(SmsManager.RESULT_ERROR_NO_SERVICE); + } catch (CanceledException ex) {} + } + if (Config.LOGD) { + Log.d(TAG, "Block SMS in Emergency Callback mode"); + } + return; + } + + super.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); + } + /** {@inheritDoc} */ protected void sendSms(SmsTracker tracker) { HashMap map = tracker.mData; @@ -343,6 +373,12 @@ final class CdmaSMSDispatcher extends SMSDispatcher { /** {@inheritDoc} */ protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){ // FIXME unit test leaves cm == null. this should change + + String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false"); + if (inEcm.equals("true")) { + return; + } + if (mCm != null) { mCm.acknowledgeLastIncomingCdmaSms(success, resultToCause(result), response); } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index 23a0520..b4de09b 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -93,6 +93,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { private int mRegistrationState = -1; private RegistrantList cdmaDataConnectionAttachedRegistrants = new RegistrantList(); private RegistrantList cdmaDataConnectionDetachedRegistrants = new RegistrantList(); + private RegistrantList cdmaForSubscriptionInfoReadyRegistrants = new RegistrantList(); // Sometimes we get the NITZ time before we know what country we are in. // Keep the time zone information from the NITZ string so we can fix @@ -121,13 +122,17 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { private int curSpnRule = 0; private String mMdn; - private int mHomeSystemId; - private int mHomeNetworkId; + private int mHomeSystemId[] = null; + private int mHomeNetworkId[] = null; private String mMin; + private String mPrlVersion; + private boolean mIsMinInfoReady = false; private boolean isEriTextLoaded = false; private boolean isSubscriptionFromRuim = false; + private boolean mPendingRadioPowerOffAfterDataOff = false; + // Registration Denied Reason, General/Authentication Failure, used only for debugging purposes private String mRegistrationDeniedReason; @@ -175,6 +180,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { cm.registerForNVReady(this, EVENT_NV_READY, null); phone.registerForEriFileLoaded(this, EVENT_ERI_FILE_LOADED, null); + cm.registerForCdmaOtaProvision(this,EVENT_OTA_PROVISION_STATUS_CHANGE, null); // system setting property AIRPLANE_MODE_ON is set in Settings. int airplaneMode = Settings.System.getInt( @@ -198,6 +204,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { cm.unregisterForNetworkStateChanged(this); cm.unregisterForRUIMReady(this); cm.unregisterForNVReady(this); + cm.unregisterForCdmaOtaProvision(this); phone.unregisterForEriFileLoaded(this); phone.mRuimRecords.unregisterForRecordsLoaded(this); cm.unSetOnSignalStrengthUpdate(this); @@ -261,6 +268,25 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { cdmaDataConnectionDetachedRegistrants.remove(h); } + /** + * Registration point for subscription info ready + * @param h handler to notify + * @param what what code of message when delivered + * @param obj placed in Message.obj + */ + public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + cdmaForSubscriptionInfoReadyRegistrants.add(r); + + if (isMinInfoReady()) { + r.notifyRegistrant(); + } + } + + public void unregisterForSubscriptionInfoReady(Handler h) { + cdmaForSubscriptionInfoReadyRegistrants.remove(h); + } + //***** Called from CDMAPhone public void getLacAndCid(Message onComplete) { @@ -290,6 +316,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { EVENT_RUIM_RECORDS_LOADED, null); mNeedToRegForRuimLoaded = false; } + + cm.getCDMASubscription(obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION)); + if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription."); + // restore the previous network selection. pollState(); @@ -299,6 +329,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { case EVENT_NV_READY: isSubscriptionFromRuim = false; + // For Non-RUIM phones, the subscription information is stored in + // Non Volatile. Here when Non-Volatile is ready, we can poll the CDMA + // subscription info. + cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION)); pollState(); // Signal strength polling stops when radio is off queueNextSignalStrengthPoll(); @@ -376,11 +410,59 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { case EVENT_POLL_STATE_REGISTRATION_CDMA: case EVENT_POLL_STATE_OPERATOR_CDMA: - case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: ar = (AsyncResult) msg.obj; handlePollStateResult(msg.what, ar); break; + case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: // Handle RIL_CDMA_SUBSCRIPTION + ar = (AsyncResult) msg.obj; + + if (ar.exception == null) { + String cdmaSubscription[] = (String[])ar.result; + if (cdmaSubscription != null && cdmaSubscription.length >= 5) { + mMdn = cdmaSubscription[0]; + if (cdmaSubscription[1] != null) { + String[] sid = cdmaSubscription[1].split(","); + mHomeSystemId = new int[sid.length]; + for (int i = 0; i < sid.length; i++) { + try { + mHomeSystemId[i] = Integer.parseInt(sid[i]); + } catch (NumberFormatException ex) { + Log.e(LOG_TAG, "error parsing system id: ", ex); + } + } + } + Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION SID=" + cdmaSubscription[1] ); + + if (cdmaSubscription[2] != null) { + String[] nid = cdmaSubscription[2].split(","); + mHomeNetworkId = new int[nid.length]; + for (int i = 0; i < nid.length; i++) { + try { + mHomeNetworkId[i] = Integer.parseInt(nid[i]); + } catch (NumberFormatException ex) { + Log.e(LOG_TAG, "error parsing network id: ", ex); + } + } + } + Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION NID=" + cdmaSubscription[2] ); + mMin = cdmaSubscription[3]; + mPrlVersion = cdmaSubscription[4]; + Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION MDN=" + mMdn); + //Notify apps subscription info is ready + if (cdmaForSubscriptionInfoReadyRegistrants != null) { + cdmaForSubscriptionInfoReadyRegistrants.notifyRegistrants(); + } + if (!mIsMinInfoReady) { + mIsMinInfoReady = true; + } + } else { + Log.w(LOG_TAG,"error parsing cdmaSubscription params num=" + + cdmaSubscription.length); + } + } + break; + case EVENT_POLL_SIGNAL_STRENGTH: // Just poll signal strength...not part of pollState() @@ -427,6 +509,29 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { pollState(); break; + case EVENT_OTA_PROVISION_STATUS_CHANGE: + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + ints = (int[]) ar.result; + int otaStatus = ints[0]; + if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_COMMITTED + || otaStatus == phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED) { + Log.d(LOG_TAG, "Received OTA_PROGRAMMING Complete,Reload MDN "); + cm.getCDMASubscription( obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION)); + } + } + break; + + case EVENT_SET_RADIO_POWER_OFF: + synchronized(this) { + if (mPendingRadioPowerOffAfterDataOff) { + if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now."); + cm.setRadioPower(false, null); + mPendingRadioPowerOffAfterDataOff = false; + } + } + break; + default: Log.e(LOG_TAG, "Unhandled message with number: " + msg.what); break; @@ -455,19 +560,23 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF; dcTracker.sendMessage(msg); - // Poll data state up to 15 times, with a 100ms delay - // totaling 1.5 sec. Normal data disable action will finish in 100ms. - for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) { - DataConnectionTracker.State currentState = dcTracker.getState(); - if (currentState != DataConnectionTracker.State.CONNECTED - && currentState != DataConnectionTracker.State.DISCONNECTING) { - if (DBG) log("Data shutdown complete."); - break; + synchronized(this) { + if (!mPendingRadioPowerOffAfterDataOff) { + DataConnectionTracker.State currentState = dcTracker.getState(); + if (currentState != DataConnectionTracker.State.CONNECTED + && currentState != DataConnectionTracker.State.DISCONNECTING) { + if (DBG) log("Data disconnected, turn off radio right away."); + cm.setRadioPower(false, null); + } + else if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 5000)) { + if (DBG) log("Wait 5 sec for data to be disconnected, then turn off radio."); + mPendingRadioPowerOffAfterDataOff = true; + } else { + Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away."); + cm.setRadioPower(false, null); + } } - SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS); } - // If it's on and available and we want it off.. - cm.setRadioPower(false, null); } // Otherwise, we're in the desired state } @@ -589,7 +698,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } mRegistrationState = registrationState; - mCdmaRoaming = regCodeIsRoaming(registrationState); + // mCdmaRoaming is true when registration state is roaming and TSB58 roaming + // indicator is not in the carrier-specified list of ERIs for home system + mCdmaRoaming = + regCodeIsRoaming(registrationState) && !isRoamIndForHomeSystem(states[10]); newSS.setState (regCodeToServiceState(registrationState)); this.newCdmaDataConnectionState = radioTechnologyToDataServiceState(radioTechnology); @@ -636,27 +748,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } break; - case EVENT_POLL_STATE_CDMA_SUBSCRIPTION: // Handle RIL_CDMA_SUBSCRIPTION - String cdmaSubscription[] = (String[])ar.result; - - if (cdmaSubscription != null && cdmaSubscription.length >= 4) { - mMdn = cdmaSubscription[0]; - // TODO: Only grabbing the first SID/NID for now. - if (cdmaSubscription[1] != null) { - String[] sid = cdmaSubscription[1].split(","); - mHomeSystemId = sid.length > 0 ? Integer.parseInt(sid[0]) : 0; - } - if (cdmaSubscription[2] != null) { - String[] nid = cdmaSubscription[2].split(","); - mHomeNetworkId = nid.length > 0 ? Integer.parseInt(nid[0]) : 0; - } - mMin = cdmaSubscription[3]; - - } else { - Log.w(LOG_TAG, "error parsing cdmaSubscription"); - } - break; - default: Log.e(LOG_TAG, "RIL response handle in wrong phone!" + " Expected CDMA RIL request and get GSM RIL request."); @@ -672,7 +763,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { if (pollingContext[0] == 0) { boolean namMatch = false; - if ((mHomeSystemId != 0) && (mHomeSystemId == newSS.getSystemId()) ) { + if (!isSidsAllZeros() && isHomeSid(newSS.getSystemId())) { namMatch = true; } @@ -684,33 +775,43 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } // Setting SS CdmaRoamingIndicator and CdmaDefaultRoamingIndicator - // TODO(Teleca): Validate this is correct. - if (mIsInPrl) { - if (namMatch && (mRoamingIndicator <= 2)) { - // System is acquired, prl match, nam match and mRoamingIndicator <= 2 - newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF); - } else { - // System is acquired, prl match, no nam match or mRoamingIndicator > 2 - newSS.setCdmaRoamingIndicator(mRoamingIndicator); - } - } else { - if (mRegistrationState == 5) { - // System is acquired but prl not loaded or no prl match + newSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator); + newSS.setCdmaRoamingIndicator(mRoamingIndicator); + boolean isPrlLoaded = true; + if (TextUtils.isEmpty(mPrlVersion)) { + isPrlLoaded = false; + } + if (!isPrlLoaded) { + newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH); + } else if (!isSidsAllZeros()) { + if (!namMatch && !mIsInPrl) { + // Use default + newSS.setCdmaRoamingIndicator(mDefaultRoamingIndicator); + } else if (namMatch && !mIsInPrl) { newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH); + } else if (!namMatch && mIsInPrl) { + // Use the one from PRL/ERI + newSS.setCdmaRoamingIndicator(mRoamingIndicator); } else { - // Use the default indicator + // It means namMatch && mIsInPrl + if ((mRoamingIndicator <= 2)) { + newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF); + } else { + // Use the one from PRL/ERI + newSS.setCdmaRoamingIndicator(mRoamingIndicator); + } } } - newSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator); // NOTE: Some operator may require to override the mCdmaRoaming (set by the modem) // depending on the mRoamingIndicator. if (DBG) { log("Set CDMA Roaming Indicator to: " + newSS.getCdmaRoamingIndicator() - + ". mCdmaRoaming = " + mCdmaRoaming + ", namMatch = " + namMatch - + ", mIsInPrl = " + mIsInPrl + ", mRoamingIndicator = " + mRoamingIndicator + + ". mCdmaRoaming = " + mCdmaRoaming + ", isPrlLoaded = " + isPrlLoaded + + ". namMatch = " + namMatch + " , mIsInPrl = " + mIsInPrl + + ", mRoamingIndicator = " + mRoamingIndicator + ", mDefaultRoamingIndicator= " + mDefaultRoamingIndicator); } pollStateDone(); @@ -773,11 +874,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { // are allowed to arrive out-of-order pollingContext[0]++; - // RIL_REQUEST_CDMA_SUBSCRIPTION is necessary for CDMA - cm.getCDMASubscription( - obtainMessage(EVENT_POLL_STATE_CDMA_SUBSCRIPTION, pollingContext)); - - pollingContext[0]++; // RIL_REQUEST_OPERATOR is necessary for CDMA cm.getOperator( obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext)); @@ -972,7 +1068,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { cdmaDataConnectionDetachedRegistrants.notifyRegistrants(); } - if (hasCdmaDataConnectionChanged) { + if (hasCdmaDataConnectionChanged || hasNetworkTypeChanged) { phone.notifyDataConnection(null); } @@ -1047,7 +1143,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { /** * send signal-strength-changed notification if changed - * Called both for solicited and unsolicited signal stength updates + * Called both for solicited and unsolicited signal strength updates */ private void onSignalStrengthResult(AsyncResult ar) { @@ -1060,15 +1156,15 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { int[] ints = (int[])ar.result; int offset = 2; - int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -1; - int cdmaEcio = (ints[offset+1] > 0) ? -ints[offset+1] : -1; + int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -120; + int cdmaEcio = (ints[offset+1] > 0) ? -ints[offset+1] : -160; int evdoRssi = -1; int evdoEcio = -1; int evdoSnr = -1; if ((networkType == ServiceState.RADIO_TECHNOLOGY_EVDO_0) || (networkType == ServiceState.RADIO_TECHNOLOGY_EVDO_A)) { - evdoRssi = (ints[offset+2] > 0) ? -ints[offset+2] : -1; + evdoRssi = (ints[offset+2] > 0) ? -ints[offset+2] : -120; evdoEcio = (ints[offset+3] > 0) ? -ints[offset+3] : -1; evdoSnr = ((ints[offset+4] > 0) && (ints[offset+4] <= 8)) ? ints[offset+4] : -1; } @@ -1152,6 +1248,33 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } /** + * Determine whether a roaming indicator is in the carrier-specified list of ERIs for + * home system + * + * @param roamInd roaming indicator in String + * @return true if the roamInd is in the carrier-specified list of ERIs for home network + */ + private boolean isRoamIndForHomeSystem(String roamInd) { + // retrieve the carrier-specified list of ERIs for home system + String homeRoamIndcators = SystemProperties.get("ro.cdma.homesystem"); + + if (!TextUtils.isEmpty(homeRoamIndcators)) { + // searches through the comma-separated list for a match, + // return true if one is found. + for (String homeRoamInd : homeRoamIndcators.split(",")) { + if (homeRoamInd.equals(roamInd)) { + return true; + } + } + // no matches found against the list! + return false; + } + + // no system property found for the roaming indicators for home system + return false; + } + + /** * Set roaming state when cdmaRoaming is true and ons is different from spn * @param cdmaRoaming TS 27.007 7.2 CREG registered roaming * @param s ServiceState hold current ons @@ -1396,6 +1519,31 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } } + private boolean isSidsAllZeros() { + if (mHomeSystemId != null) { + for (int i=0; i < mHomeSystemId.length; i++) { + if (mHomeSystemId[i] != 0) { + return false; + } + } + } + return true; + } + + /** + * Check whether a specified system ID that matches one of the home system IDs. + */ + private boolean isHomeSid(int sid) { + if (mHomeSystemId != null) { + for (int i=0; i < mHomeSystemId.length; i++) { + if (sid == mHomeSystemId[i]) { + return true; + } + } + } + return false; + } + /** * @return true if phone is camping on a technology * that could support voice and data simultaneously. @@ -1420,6 +1568,11 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { return mMin; } + /** Returns null if NV is not yet ready */ + public String getPrlVersion() { + return mPrlVersion; + } + /** * Returns IMSI as MCC + MNC + MIN */ @@ -1435,4 +1588,31 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { return null; } } + + /** + * Check if subscription data has been assigned to mMin + * + * return true if MIN info is ready; false otherwise. + */ + public boolean isMinInfoReady() { + return mIsMinInfoReady; + } + + /** + * process the pending request to turn radio off after data is disconnected + * + * return true if there is pending request to process; false otherwise. + */ + public boolean processPendingRadioPowerOffAfterDataOff() { + synchronized(this) { + if (mPendingRadioPowerOffAfterDataOff) { + if (DBG) log("Process pending request to turn radio off."); + removeMessages(EVENT_SET_RADIO_POWER_OFF); + cm.setRadioPower(false, null); + mPendingRadioPowerOffAfterDataOff = false; + return true; + } + return false; + } + } } diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java index 9d9f479..734badd 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java @@ -16,507 +16,34 @@ package com.android.internal.telephony.cdma; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Message; -import android.os.Registrant; -import android.os.RegistrantList; -import android.os.RemoteException; -import android.util.Log; - -import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneProxy; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.TelephonyProperties; - -import android.app.ActivityManagerNative; -import android.content.Intent; -import android.content.res.Configuration; - -import static android.Manifest.permission.READ_PHONE_STATE; /** * Note: this class shares common code with SimCard, consider a base class to minimize code * duplication. * {@hide} */ -public final class RuimCard extends Handler implements IccCard { - static final String LOG_TAG="CDMA"; - - //***** Instance Variables - private static final boolean DBG = true; - - private CDMAPhone phone; - - private CommandsInterface.IccStatus status = null; - private boolean mDesiredPinLocked; - private boolean mDesiredFdnEnabled; - private boolean mRuimPinLocked = true; // default to locked - private boolean mRuimFdnEnabled = false; // Default to disabled. - // Will be updated when RUIM_READY. -// //***** Constants - -// // FIXME I hope this doesn't conflict with the Dialer's notifications -// Nobody is using this at the moment -// static final int NOTIFICATION_ID_ICC_STATUS = 33456; - - //***** Event Constants - - static final int EVENT_RUIM_LOCKED_OR_ABSENT = 1; - static final int EVENT_GET_RUIM_STATUS_DONE = 2; - static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3; - static final int EVENT_PINPUK_DONE = 4; - static final int EVENT_REPOLL_STATUS_DONE = 5; - static final int EVENT_RUIM_READY = 6; - static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7; - static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8; - static final int EVENT_CHANGE_RUIM_PASSWORD_DONE = 9; - static final int EVENT_QUERY_FACILITY_FDN_DONE = 10; - static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11; - - - //***** Constructor +public final class RuimCard extends IccCard { RuimCard(CDMAPhone phone) { - this.phone = phone; - - phone.mCM.registerForRUIMLockedOrAbsent( - this, EVENT_RUIM_LOCKED_OR_ABSENT, null); - - phone.mCM.registerForOffOrNotAvailable( - this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - - phone.mCM.registerForRUIMReady( - this, EVENT_RUIM_READY, null); - + super(phone, "CDMA", true); + mPhone.mCM.registerForRUIMLockedOrAbsent(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null); + mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + mPhone.mCM.registerForRUIMReady(mHandler, EVENT_ICC_READY, null); updateStateProperty(); } - //***** RuimCard implementation - - public State - getState() { - if (status == null) { - switch(phone.mCM.getRadioState()) { - /* This switch block must not return anything in - * State.isLocked() or State.ABSENT. - * If it does, handleSimStatus() may break - */ - case RADIO_OFF: - case RADIO_UNAVAILABLE: - case RUIM_NOT_READY: - return State.UNKNOWN; - case RUIM_LOCKED_OR_ABSENT: - //this should be transient-only - return State.UNKNOWN; - case RUIM_READY: - return State.READY; - case NV_READY: - case NV_NOT_READY: - return State.ABSENT; - } - } else { - switch (status) { - case ICC_ABSENT: return State.ABSENT; - case ICC_NOT_READY: return State.UNKNOWN; - case ICC_READY: return State.READY; - case ICC_PIN: return State.PIN_REQUIRED; - case ICC_PUK: return State.PUK_REQUIRED; - case ICC_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED; - } - } - - Log.e(LOG_TAG, "RuimCard.getState(): case should never be reached"); - return State.UNKNOWN; - } - + @Override public void dispose() { //Unregister for all events - phone.mCM.unregisterForRUIMLockedOrAbsent(this); - phone.mCM.unregisterForOffOrNotAvailable(this); - phone.mCM.unregisterForRUIMReady(this); - } - - protected void finalize() { - if(DBG) Log.d(LOG_TAG, "RuimCard finalized"); - } - - private RegistrantList absentRegistrants = new RegistrantList(); - private RegistrantList pinLockedRegistrants = new RegistrantList(); - private RegistrantList networkLockedRegistrants = new RegistrantList(); - - - public void registerForAbsent(Handler h, int what, Object obj) { - Registrant r = new Registrant (h, what, obj); - - absentRegistrants.add(r); - - if (getState() == State.ABSENT) { - r.notifyRegistrant(); - } - } - - public void unregisterForAbsent(Handler h) { - absentRegistrants.remove(h); - } - - public void registerForNetworkLocked(Handler h, int what, Object obj) { - Registrant r = new Registrant (h, what, obj); - - networkLockedRegistrants.add(r); - - if (getState() == State.NETWORK_LOCKED) { - r.notifyRegistrant(); - } - } - - public void unregisterForNetworkLocked(Handler h) { - networkLockedRegistrants.remove(h); - } - - public void registerForLocked(Handler h, int what, Object obj) { - Registrant r = new Registrant (h, what, obj); - - pinLockedRegistrants.add(r); - - if (getState().isPinLocked()) { - r.notifyRegistrant(); - } - } - - public void unregisterForLocked(Handler h) { - pinLockedRegistrants.remove(h); - } - - public void supplyPin (String pin, Message onComplete) { - phone.mCM.supplyIccPin(pin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); - } - - public void supplyPuk (String puk, String newPin, Message onComplete) { - phone.mCM.supplyIccPuk(puk, newPin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); - } - - public void supplyPin2 (String pin2, Message onComplete) { - phone.mCM.supplyIccPin2(pin2, obtainMessage(EVENT_PINPUK_DONE, onComplete)); - } - - public void supplyPuk2 (String puk2, String newPin2, Message onComplete) { - phone.mCM.supplyIccPuk2(puk2, newPin2, obtainMessage(EVENT_PINPUK_DONE, onComplete)); - } - - public void supplyNetworkDepersonalization (String pin, Message onComplete) { - if(DBG) log("Network Despersonalization: " + pin); - phone.mCM.supplyNetworkDepersonalization(pin, - obtainMessage(EVENT_PINPUK_DONE, onComplete)); - } - - public boolean getIccLockEnabled() { - return mRuimPinLocked; - } - - public boolean getIccFdnEnabled() { - return mRuimFdnEnabled; - } - - public void setIccLockEnabled (boolean enabled, - String password, Message onComplete) { - int serviceClassX; - serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + - CommandsInterface.SERVICE_CLASS_DATA + - CommandsInterface.SERVICE_CLASS_FAX; - - mDesiredPinLocked = enabled; - - phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM, - enabled, password, serviceClassX, - obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete)); - } - - public void setIccFdnEnabled (boolean enabled, - String password, Message onComplete) { - int serviceClassX; - serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + - CommandsInterface.SERVICE_CLASS_DATA + - CommandsInterface.SERVICE_CLASS_FAX + - CommandsInterface.SERVICE_CLASS_SMS; - - mDesiredFdnEnabled = enabled; - - phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD, - enabled, password, serviceClassX, - obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete)); + mPhone.mCM.unregisterForRUIMLockedOrAbsent(mHandler); + mPhone.mCM.unregisterForOffOrNotAvailable(mHandler); + mPhone.mCM.unregisterForRUIMReady(mHandler); } - public void changeIccLockPassword(String oldPassword, String newPassword, - Message onComplete) { - if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword); - phone.mCM.changeIccPin(oldPassword, newPassword, - obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete)); - } - - public void changeIccFdnPassword(String oldPassword, String newPassword, - Message onComplete) { - if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword); - phone.mCM.changeIccPin2(oldPassword, newPassword, - obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete)); - } - - public String getServiceProviderName() { - return phone.mRuimRecords.getServiceProviderName(); - } - - //***** Handler implementation @Override - public void handleMessage(Message msg){ - AsyncResult ar; - int serviceClassX; - - serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + - CommandsInterface.SERVICE_CLASS_DATA + - CommandsInterface.SERVICE_CLASS_FAX; - - switch (msg.what) { - case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: - Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received"); - status = null; - updateStateProperty(); - broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_NOT_READY, null); - break; - case EVENT_RUIM_READY: - Log.d(LOG_TAG, "Event EVENT_RUIM_READY Received"); - //TODO: put facility read in SIM_READY now, maybe in REG_NW - phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE)); - phone.mCM.queryFacilityLock ( - CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, - obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); - phone.mCM.queryFacilityLock ( - CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX, - obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE)); - break; - case EVENT_RUIM_LOCKED_OR_ABSENT: - Log.d(LOG_TAG, "Event EVENT_RUIM_LOCKED_OR_ABSENT Received"); - phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE)); - phone.mCM.queryFacilityLock ( - CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, - obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); - break; - case EVENT_GET_RUIM_STATUS_DONE: - Log.d(LOG_TAG, "Event EVENT_GET_RUIM_STATUS_DONE Received"); - ar = (AsyncResult)msg.obj; - - getRuimStatusDone(ar); - break; - case EVENT_PINPUK_DONE: - Log.d(LOG_TAG, "Event EVENT_PINPUK_DONE Received"); - // a PIN/PUK/PIN2/PUK2/Network Personalization - // request has completed. ar.userObj is the response Message - // Repoll before returning - ar = (AsyncResult)msg.obj; - // TODO should abstract these exceptions - AsyncResult.forMessage(((Message)ar.userObj)).exception - = ar.exception; - phone.mCM.getIccStatus( - obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj)); - break; - case EVENT_REPOLL_STATUS_DONE: - Log.d(LOG_TAG, "Event EVENT_REPOLL_STATUS_DONE Received"); - // Finished repolling status after PIN operation - // ar.userObj is the response messaeg - // ar.userObj.obj is already an AsyncResult with an - // appropriate exception filled in if applicable - - ar = (AsyncResult)msg.obj; - getRuimStatusDone(ar); - ((Message)ar.userObj).sendToTarget(); - break; - case EVENT_QUERY_FACILITY_LOCK_DONE: - Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_LOCK_DONE Received"); - ar = (AsyncResult)msg.obj; - onQueryFacilityLock(ar); - break; - case EVENT_QUERY_FACILITY_FDN_DONE: - Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_FDN_DONE Received"); - ar = (AsyncResult)msg.obj; - onQueryFdnEnabled(ar); - break; - case EVENT_CHANGE_FACILITY_LOCK_DONE: - Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_LOCK_DONE Received"); - ar = (AsyncResult)msg.obj; - if (ar.exception == null) { - mRuimPinLocked = mDesiredPinLocked; - if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " + - "mRuimPinLocked= " + mRuimPinLocked); - } else { - Log.e(LOG_TAG, "Error change facility lock with exception " - + ar.exception); - } - AsyncResult.forMessage(((Message)ar.userObj)).exception - = ar.exception; - ((Message)ar.userObj).sendToTarget(); - break; - case EVENT_CHANGE_FACILITY_FDN_DONE: - Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_FDN_DONE Received"); - ar = (AsyncResult)msg.obj; - - if (ar.exception == null) { - mRuimFdnEnabled = mDesiredFdnEnabled; - if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " + - "mRuimFdnEnabled=" + mRuimFdnEnabled); - } else { - Log.e(LOG_TAG, "Error change facility fdn with exception " - + ar.exception); - } - AsyncResult.forMessage(((Message)ar.userObj)).exception - = ar.exception; - ((Message)ar.userObj).sendToTarget(); - break; - case EVENT_CHANGE_RUIM_PASSWORD_DONE: - Log.d(LOG_TAG, "Event EVENT_CHANGE_RUIM_PASSWORD_DONE Received"); - ar = (AsyncResult)msg.obj; - if(ar.exception != null) { - Log.e(LOG_TAG, "Error in change sim password with exception" - + ar.exception); - } - AsyncResult.forMessage(((Message)ar.userObj)).exception - = ar.exception; - ((Message)ar.userObj).sendToTarget(); - break; - default: - Log.e(LOG_TAG, "[CdmaRuimCard] Unknown Event " + msg.what); - } - } - - //***** Private methods - - /** - * Interpret EVENT_QUERY_FACILITY_LOCK_DONE - * @param ar is asyncResult of Query_Facility_Locked - */ - private void onQueryFacilityLock(AsyncResult ar) { - if(ar.exception != null) { - if (DBG) log("Error in querying facility lock:" + ar.exception); - return; - } - - int[] ints = (int[])ar.result; - if(ints.length != 0) { - mRuimPinLocked = (0!=ints[0]); - if(DBG) log("Query facility lock : " + mRuimPinLocked); - } else { - Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response"); - } - } - - /** - * Interpret EVENT_QUERY_FACILITY_LOCK_DONE - * @param ar is asyncResult of Query_Facility_Locked - */ - private void onQueryFdnEnabled(AsyncResult ar) { - if(ar.exception != null) { - if(DBG) log("Error in querying facility lock:" + ar.exception); - return; - } - - int[] ints = (int[])ar.result; - if(ints.length != 0) { - mRuimFdnEnabled = (0!=ints[0]); - if(DBG) log("Query facility lock : " + mRuimFdnEnabled); - } else { - Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response"); - } - } - - private void - getRuimStatusDone(AsyncResult ar) { - if (ar.exception != null) { - Log.e(LOG_TAG,"Error getting SIM status. " - + "RIL_REQUEST_GET_SIM_STATUS should " - + "never return an error", ar.exception); - return; - } - - CommandsInterface.IccStatus newStatus - = (CommandsInterface.IccStatus) ar.result; - - handleRuimStatus(newStatus); - } - - private void - handleRuimStatus(CommandsInterface.IccStatus newStatus) { - boolean transitionedIntoPinLocked; - boolean transitionedIntoAbsent; - boolean transitionedIntoNetworkLocked; - - RuimCard.State oldState, newState; - - oldState = getState(); - status = newStatus; - newState = getState(); - - updateStateProperty(); - - transitionedIntoPinLocked = ( - (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED) - || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED)); - transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT); - transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED - && newState == State.NETWORK_LOCKED); - - if (transitionedIntoPinLocked) { - if(DBG) log("Notify RUIM pin or puk locked."); - pinLockedRegistrants.notifyRegistrants(); - broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED, - (newState == State.PIN_REQUIRED) ? - INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK); - } else if (transitionedIntoAbsent) { - if(DBG) log("Notify RUIM missing."); - absentRegistrants.notifyRegistrants(); - broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_ABSENT, null); - } else if (transitionedIntoNetworkLocked) { - if(DBG) log("Notify RUIM network locked."); - networkLockedRegistrants.notifyRegistrants(); - broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED, - INTENT_VALUE_LOCKED_NETWORK); - } - } - - public void broadcastRuimStateChangedIntent(String value, String reason) { - Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); - intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName()); - intent.putExtra(RuimCard.INTENT_KEY_ICC_STATE, value); - intent.putExtra(RuimCard.INTENT_KEY_LOCKED_REASON, reason); - if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " + value - + " reason " + reason); - ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE); - } - - public void updateImsiConfiguration(String imsi) { - if (imsi.length() >= 6) { - Configuration config = new Configuration(); - config.mcc = ((imsi.charAt(0)-'0')*100) - + ((imsi.charAt(1)-'0')*10) - + (imsi.charAt(2)-'0'); - config.mnc = ((imsi.charAt(3)-'0')*100) - + ((imsi.charAt(4)-'0')*10) - + (imsi.charAt(5)-'0'); - try { - ActivityManagerNative.getDefault().updateConfiguration(config); - } catch (RemoteException e) { - } - } - } - - private void - updateStateProperty() { - phone.setSystemProperty( - TelephonyProperties.PROPERTY_SIM_STATE, - getState().toString()); - } - - private void log(String msg) { - Log.d(LOG_TAG, "[RuimCard] " + msg); + public String getServiceProviderName () { + return ((CDMAPhone)mPhone).mRuimRecords.getServiceProviderName(); } -} + } diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java index 55f48b1..7c74314 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java @@ -37,10 +37,6 @@ import com.android.internal.telephony.IccRecords; import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.PhoneProxy; -import com.android.internal.telephony.TelephonyIntents; -import android.app.ActivityManagerNative; -import android.content.Intent; - /** * {@hide} @@ -65,7 +61,6 @@ public final class RuimRecords extends IccRecords { private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2; private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4; private static final int EVENT_GET_ICCID_DONE = 5; - private static final int EVENT_NV_READY = 9; private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10; private static final int EVENT_UPDATE_DONE = 14; private static final int EVENT_GET_SST_DONE = 17; @@ -76,7 +71,7 @@ public final class RuimRecords extends IccRecords { private static final int EVENT_GET_SMS_DONE = 22; private static final int EVENT_RUIM_REFRESH = 31; - private static final int EVENT_OTA_PROVISION_STATUS_CHANGE = 32; + RuimRecords(CDMAPhone p) { super(p); @@ -90,14 +85,12 @@ public final class RuimRecords extends IccRecords { p.mCM.registerForRUIMReady(this, EVENT_RUIM_READY, null); - p.mCM.registerForNVReady(this, EVENT_NV_READY, null); p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); // NOTE the EVENT_SMS_ON_RUIM is not registered p.mCM.setOnIccRefresh(this, EVENT_RUIM_REFRESH, null); // Start off by setting empty state onRadioOffOrNotAvailable(); - p.mCM.registerForCdmaOtaProvision(this,EVENT_OTA_PROVISION_STATUS_CHANGE, null); } @@ -106,8 +99,6 @@ public final class RuimRecords extends IccRecords { phone.mCM.unregisterForRUIMReady(this); phone.mCM.unregisterForOffOrNotAvailable( this); phone.mCM.unSetOnIccRefresh(this); - phone.mCM.unregisterForNVReady(this); - phone.mCM.unregisterForCdmaOtaProvision(this); } @Override @@ -202,9 +193,7 @@ public final class RuimRecords extends IccRecords { case EVENT_RUIM_READY: onRuimReady(); break; - case EVENT_NV_READY: - onNvReady(); - break; + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: onRadioOffOrNotAvailable(); break; @@ -221,15 +210,7 @@ public final class RuimRecords extends IccRecords { if (ar.exception != null) { break; } - if (m_ota_commited) { - if (mMyMobileNumber != localTemp[0]) { - Intent intent = new Intent(TelephonyIntents.ACTION_CDMA_OTA_MDN_CHANGED); - intent.putExtra("mdn", localTemp[0]); - Log.d(LOG_TAG,"Broadcasting intent MDN Change in OTA "); - ActivityManagerNative.broadcastStickyIntent(intent, null); - } - m_ota_commited = false; - } + mMyMobileNumber = localTemp[0]; mMin2Min1 = localTemp[3]; mPrlVersion = localTemp[4]; @@ -281,21 +262,6 @@ public final class RuimRecords extends IccRecords { } break; - case EVENT_OTA_PROVISION_STATUS_CHANGE: - m_ota_commited=false; - ar = (AsyncResult)msg.obj; - if (ar.exception == null) { - int[] ints = (int[]) ar.result; - int otaStatus = ints[0]; - if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_COMMITTED) { - m_ota_commited=true; - phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); - } else if (otaStatus == phone.CDMA_OTA_PROVISION_STATUS_OTAPA_STOPPED) { - phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); - } - } - break; - }}catch (RuntimeException exc) { // I don't want these exceptions to be fatal Log.w(LOG_TAG, "Exception parsing RUIM record", exc); @@ -329,7 +295,7 @@ public final class RuimRecords extends IccRecords { recordsLoadedRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); - ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent( + ((CDMAPhone) phone).mRuimCard.broadcastIccStateChangedIntent( RuimCard.INTENT_VALUE_ICC_LOADED, null); } @@ -338,7 +304,7 @@ public final class RuimRecords extends IccRecords { READY is sent before IMSI ready */ - ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent( + ((CDMAPhone) phone).mRuimCard.broadcastIccStateChangedIntent( RuimCard.INTENT_VALUE_ICC_READY, null); fetchRuimRecords(); @@ -347,10 +313,6 @@ public final class RuimRecords extends IccRecords { } - private void onNvReady() { - phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); - - } private void fetchRuimRecords() { recordsRequested = true; diff --git a/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java index 44958e9..4b88057 100644 --- a/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java +++ b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java @@ -35,7 +35,12 @@ public class SignalToneUtil { static public final int IS95_CONST_IR_ALERT_MED = 0; static public final int IS95_CONST_IR_ALERT_HIGH = 1; static public final int IS95_CONST_IR_ALERT_LOW = 2; - static public final int TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN = 255; + + // Based on 3GPP2 C.S0005-E, seciton 3.7.5.5 Signal, + // set TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN to 0 to avoid + // the alert pitch to be involved in hash calculation for + // signal type other than IS54B. + static public final int TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN = 0; // public final int int IS95_CONST_IR_SIGNAL_TYPE; static public final int IS95_CONST_IR_SIG_ISDN_NORMAL = 0; @@ -81,6 +86,15 @@ public class SignalToneUtil { (alertPitch < 0) || (signal > 256) || (signal < 0)) { return new Integer(CDMA_INVALID_TONE); } + // Based on 3GPP2 C.S0005-E, seciton 3.7.5.5 Signal, + // the alert pitch field is ignored by the mobile station unless + // SIGNAL_TYPE is '10',IS-54B Alerting. + // Set alert pitch to TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN + // so the alert pitch is not involved in hash calculation + // when signal type is not IS-54B. + if (signalType != IS95_CONST_IR_SIGNAL_IS54B) { + alertPitch = TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN; + } return new Integer(signalType * 256 * 256 + alertPitch * 256 + signal); } diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java index 3a92064..1597427 100644..100755 --- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -29,6 +29,7 @@ import com.android.internal.telephony.cdma.sms.BearerData; import com.android.internal.telephony.cdma.sms.CdmaSmsAddress; import com.android.internal.telephony.cdma.sms.SmsEnvelope; import com.android.internal.telephony.cdma.sms.UserData; +import com.android.internal.util.HexDump; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -67,6 +68,7 @@ import static android.telephony.SmsMessage.MessageClass; */ public class SmsMessage extends SmsMessageBase { static final String LOG_TAG = "CDMA"; + private final static Boolean DBG_SMS = false; /** * Status of a previously submitted SMS. @@ -518,6 +520,7 @@ public class SmsMessage extends SmsMessageBase { originatingAddress = addr; env.origAddress = addr; mEnvelope = env; + mPdu = pdu; parseSms(); } @@ -526,7 +529,25 @@ public class SmsMessage extends SmsMessageBase { * Parses a SMS message from its BearerData stream. (mobile-terminated only) */ protected void parseSms() { + // Message Waiting Info Record defined in 3GPP2 C.S-0005, 3.7.5.6 + // It contains only an 8-bit number with the number of messages waiting + if (mEnvelope.teleService == SmsEnvelope.TELESERVICE_MWI) { + mBearerData = new BearerData(); + if (mEnvelope.bearerData != null) { + mBearerData.numberOfMessages = 0x000000FF & mEnvelope.bearerData[0]; + } + if (Config.DEBUG) { + Log.d(LOG_TAG, "parseSms: get MWI " + + Integer.toString(mBearerData.numberOfMessages)); + } + return; + } mBearerData = BearerData.decode(mEnvelope.bearerData); + if (DBG_SMS) { + Log.d(LOG_TAG, "MT raw BearerData = '" + + HexDump.toHexString(mEnvelope.bearerData) + "'"); + Log.d(LOG_TAG, "MT (decoded) BearerData = " + mBearerData); + } messageRef = mBearerData.messageId; if (mBearerData.userData != null) { userData = mBearerData.userData.payload; @@ -583,23 +604,6 @@ public class SmsMessage extends SmsMessageBase { } } - private static CdmaSmsAddress parseCdmaSmsAddr(String addrStr) { - // see C.S0015-B, v2.0, 3.4.3.3 - CdmaSmsAddress addr = new CdmaSmsAddress(); - addr.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR; - try { - addr.origBytes = addrStr.getBytes("UTF-8"); - } catch (java.io.UnsupportedEncodingException ex) { - Log.e(LOG_TAG, "CDMA address parsing failed: " + ex); - return null; - } - addr.numberOfDigits = (byte)addr.origBytes.length; - addr.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK; - addr.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY; - addr.ton = CdmaSmsAddress.TON_INTERNATIONAL_OR_IP; - return addr; - } - /** * Set the nextMessageId to a random value between 0 and 65536 * See C.S0015-B, v2.0, 4.3.1.5 @@ -626,7 +630,13 @@ public class SmsMessage extends SmsMessageBase { * TODO(cleanup): give this function a more meaningful name. */ - CdmaSmsAddress destAddr = parseCdmaSmsAddr(destAddrStr); + /** + * TODO(cleanup): Make returning null from the getSubmitPdu + * variations meaningful -- clean up the error feedback + * mechanism, and avoid null pointer exceptions. + */ + + CdmaSmsAddress destAddr = CdmaSmsAddress.parse(destAddrStr); if (destAddr == null) return null; BearerData bearerData = new BearerData(); @@ -641,14 +651,17 @@ public class SmsMessage extends SmsMessageBase { bearerData.reportReq = false; bearerData.userData = userData; - bearerData.hasUserDataHeader = (userData.userDataHeader != null); - - int teleservice = bearerData.hasUserDataHeader ? - SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT; byte[] encodedBearerData = BearerData.encode(bearerData); + if (DBG_SMS) { + Log.d(LOG_TAG, "MO (encoded) BearerData = " + bearerData); + Log.d(LOG_TAG, "MO raw BearerData = '" + HexDump.toHexString(encodedBearerData) + "'"); + } if (encodedBearerData == null) return null; + int teleservice = bearerData.hasUserDataHeader ? + SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT; + SmsEnvelope envelope = new SmsEnvelope(); envelope.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT; envelope.teleService = teleservice; @@ -728,9 +741,8 @@ public class SmsMessage extends SmsMessageBase { dos.close(); /** - * TODO(cleanup) -- This is the only place where mPdu is - * defined, and this is not obviously the only place where - * it needs to be defined. It would be much nicer if + * TODO(cleanup) -- The mPdu field is managed in + * a fragile manner, and it would be much nicer if * accessing the serialized representation used a less * fragile mechanism. Maybe the getPdu method could * generate a representation if there was not yet one? diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java index ef3afff..721729d 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -233,22 +233,22 @@ public final class BearerData { public static TimeStamp fromByteArray(byte[] data) { TimeStamp ts = new TimeStamp(); // C.S0015-B v2.0, 4.5.4: range is 1996-2095 - int year = IccUtils.beBcdByteToInt(data[0]); + int year = IccUtils.cdmaBcdByteToInt(data[0]); if (year > 99 || year < 0) return null; ts.year = year >= 96 ? year + 1900 : year + 2000; - int month = IccUtils.beBcdByteToInt(data[1]); + int month = IccUtils.cdmaBcdByteToInt(data[1]); if (month < 1 || month > 12) return null; ts.month = month - 1; - int day = IccUtils.beBcdByteToInt(data[2]); + int day = IccUtils.cdmaBcdByteToInt(data[2]); if (day < 1 || day > 31) return null; ts.monthDay = day; - int hour = IccUtils.beBcdByteToInt(data[3]); + int hour = IccUtils.cdmaBcdByteToInt(data[3]); if (hour < 0 || hour > 23) return null; ts.hour = hour; - int minute = IccUtils.beBcdByteToInt(data[4]); + int minute = IccUtils.cdmaBcdByteToInt(data[4]); if (minute < 0 || minute > 59) return null; ts.minute = minute; - int second = IccUtils.beBcdByteToInt(data[5]); + int second = IccUtils.cdmaBcdByteToInt(data[5]); if (second < 0 || second > 59) return null; ts.second = second; return ts; @@ -455,53 +455,117 @@ public final class BearerData { } } - private static int calcUdhSeptetPadding(int userDataHeaderLen) { - int udhBits = userDataHeaderLen * 8; - int udhSeptets = (udhBits + 6) / 7; - int paddingBits = (udhSeptets * 7) - udhBits; - return paddingBits; + private static class Gsm7bitCodingResult { + int septets; + byte[] data; } - private static byte[] encode7bitGsm(String msg, int paddingBits) + private static Gsm7bitCodingResult encode7bitGsm(String msg, int septetOffset, boolean force) throws CodingException { try { /* * TODO(cleanup): It would be nice if GsmAlphabet provided * an option to produce just the data without prepending - * the length. + * the septet count, as this function is really just a + * wrapper to strip that off. Not to mention that the + * septet count is generally known prior to invocation of + * the encoder. Note that it cannot be derived from the + * resulting array length, since that cannot distinguish + * if the last contains either 1 or 8 valid bits. + * + * TODO(cleanup): The BitwiseXStreams could also be + * extended with byte-wise reversed endianness read/write + * routines to allow a corresponding implementation of + * stringToGsm7BitPacked, and potentially directly support + * access to the main bitwise stream from encode/decode. */ - byte []fullData = GsmAlphabet.stringToGsm7BitPacked(msg, 0, -1, paddingBits, true); - byte []data = new byte[fullData.length - 1]; - System.arraycopy(fullData, 1, data, 0, fullData.length - 1); - return data; + byte[] fullData = GsmAlphabet.stringToGsm7BitPacked(msg, septetOffset, !force); + Gsm7bitCodingResult result = new Gsm7bitCodingResult(); + result.data = new byte[fullData.length - 1]; + System.arraycopy(fullData, 1, result.data, 0, fullData.length - 1); + result.septets = fullData[0] & 0x00FF; + return result; } catch (com.android.internal.telephony.EncodeException ex) { throw new CodingException("7bit GSM encode failed: " + ex); } } + private static void encode7bitEms(UserData uData, byte[] udhData, boolean force) + throws CodingException + { + int udhBytes = udhData.length + 1; // Add length octet. + int udhSeptets = ((udhBytes * 8) + 6) / 7; + Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, udhSeptets, force); + uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; + uData.msgEncodingSet = true; + uData.numFields = gcr.septets; + uData.payload = gcr.data; + uData.payload[0] = (byte)udhData.length; + System.arraycopy(udhData, 0, uData.payload, 1, udhData.length); + } + + private static void encode16bitEms(UserData uData, byte[] udhData) + throws CodingException + { + byte[] payload = encodeUtf16(uData.payloadStr); + int udhBytes = udhData.length + 1; // Add length octet. + int udhCodeUnits = (udhBytes + 1) / 2; + int udhPadding = udhBytes % 2; + int payloadCodeUnits = payload.length / 2; + uData.msgEncoding = UserData.ENCODING_UNICODE_16; + uData.msgEncodingSet = true; + uData.numFields = udhCodeUnits + payloadCodeUnits; + uData.payload = new byte[uData.numFields * 2]; + uData.payload[0] = (byte)udhData.length; + System.arraycopy(udhData, 0, uData.payload, 1, udhData.length); + System.arraycopy(payload, 0, uData.payload, udhBytes + udhPadding, payload.length); + } + + private static void encodeEmsUserDataPayload(UserData uData) + throws CodingException + { + byte[] headerData = SmsHeader.toByteArray(uData.userDataHeader); + if (uData.msgEncodingSet) { + if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) { + encode7bitEms(uData, headerData, true); + } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) { + encode16bitEms(uData, headerData); + } else { + throw new CodingException("unsupported EMS user data encoding (" + + uData.msgEncoding + ")"); + } + } else { + try { + encode7bitEms(uData, headerData, false); + } catch (CodingException ex) { + encode16bitEms(uData, headerData); + } + } + } + private static void encodeUserDataPayload(UserData uData) throws CodingException { - // TODO(cleanup): UDH can only occur in EMS mode, meaning - // encapsulation of GSM encoding, and so the logic here should - // be refactored to more cleanly reflect this constraint. + if ((uData.payloadStr == null) && (uData.msgEncoding != UserData.ENCODING_OCTET)) { + Log.e(LOG_TAG, "user data with null payloadStr"); + uData.payloadStr = ""; + } - byte[] headerData = null; - if (uData.userDataHeader != null) headerData = SmsHeader.toByteArray(uData.userDataHeader); - int headerDataLen = (headerData == null) ? 0 : headerData.length + 1; // + length octet + if (uData.userDataHeader != null) { + encodeEmsUserDataPayload(uData); + return; + } - byte[] payloadData; - int codeUnitCount; if (uData.msgEncodingSet) { if (uData.msgEncoding == UserData.ENCODING_OCTET) { if (uData.payload == null) { Log.e(LOG_TAG, "user data with octet encoding but null payload"); - payloadData = new byte[0]; - codeUnitCount = 0; + uData.payload = new byte[0]; + uData.numFields = 0; } else { - payloadData = uData.payload; - codeUnitCount = uData.payload.length; + uData.payload = uData.payload; + uData.numFields = uData.payload.length; } } else { if (uData.payloadStr == null) { @@ -509,67 +573,52 @@ public final class BearerData { uData.payloadStr = ""; } if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) { - int paddingBits = calcUdhSeptetPadding(headerDataLen); - payloadData = encode7bitGsm(uData.payloadStr, paddingBits); - codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7; + Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, 0, true); + uData.payload = gcr.data; + uData.numFields = gcr.septets; } else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) { - payloadData = encode7bitAscii(uData.payloadStr, true); - codeUnitCount = uData.payloadStr.length(); + uData.payload = encode7bitAscii(uData.payloadStr, true); + uData.numFields = uData.payloadStr.length(); } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) { - payloadData = encodeUtf16(uData.payloadStr); - codeUnitCount = uData.payloadStr.length(); + uData.payload = encodeUtf16(uData.payloadStr); + uData.numFields = uData.payloadStr.length(); } else { throw new CodingException("unsupported user data encoding (" + uData.msgEncoding + ")"); } } } else { - if (uData.payloadStr == null) { - Log.e(LOG_TAG, "user data with null payloadStr"); - uData.payloadStr = ""; - } try { - if (headerData == null) { - payloadData = encode7bitAscii(uData.payloadStr, false); - codeUnitCount = uData.payloadStr.length(); - uData.msgEncoding = UserData.ENCODING_7BIT_ASCII; - } else { - // If there is a header, we are in EMS mode, in - // which case we use GSM encodings. - int paddingBits = calcUdhSeptetPadding(headerDataLen); - payloadData = encode7bitGsm(uData.payloadStr, paddingBits); - codeUnitCount = ((payloadData.length + headerDataLen) * 8) / 7; - uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; - } + uData.payload = encode7bitAscii(uData.payloadStr, false); + uData.msgEncoding = UserData.ENCODING_7BIT_ASCII; } catch (CodingException ex) { - payloadData = encodeUtf16(uData.payloadStr); - codeUnitCount = uData.payloadStr.length(); + uData.payload = encodeUtf16(uData.payloadStr); uData.msgEncoding = UserData.ENCODING_UNICODE_16; } + uData.numFields = uData.payloadStr.length(); uData.msgEncodingSet = true; } - - int totalLength = payloadData.length + headerDataLen; - if (totalLength > SmsMessage.MAX_USER_DATA_BYTES) { - throw new CodingException("encoded user data too large (" + totalLength + - " > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)"); - } - - uData.numFields = codeUnitCount; - uData.payload = new byte[totalLength]; - if (headerData != null) { - uData.payload[0] = (byte)headerData.length; - System.arraycopy(headerData, 0, uData.payload, 1, headerData.length); - } - System.arraycopy(payloadData, 0, uData.payload, headerDataLen, payloadData.length); } private static void encodeUserData(BearerData bData, BitwiseOutputStream outStream) throws BitwiseOutputStream.AccessException, CodingException { + /* + * TODO(cleanup): Do we really need to set userData.payload as + * a side effect of encoding? If not, we could avoid data + * copies by passing outStream directly. + */ encodeUserDataPayload(bData.userData); - /** - * XXX/TODO: figure out what the right answer is WRT padding bits + bData.hasUserDataHeader = bData.userData.userDataHeader != null; + + if (bData.userData.payload.length > SmsMessage.MAX_USER_DATA_BYTES) { + throw new CodingException("encoded user data too large (" + + bData.userData.payload.length + + " > " + SmsMessage.MAX_USER_DATA_BYTES + " bytes)"); + } + + /* + * TODO(cleanup): figure out what the right answer is WRT paddingBits field * * userData.paddingBits = (userData.payload.length * 8) - (userData.numFields * 7); * userData.paddingBits = 0; // XXX this seems better, but why? @@ -624,6 +673,12 @@ public final class BearerData { return rawData; } + /* + * TODO(cleanup): CdmaSmsAddress encoding should make use of + * CdmaSmsAddress.parse provided that DTMF encoding is unified, + * and the difference in 4bit vs 8bit is resolved. + */ + private static void encodeCdmaSmsAddress(CdmaSmsAddress addr) throws CodingException { if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) { try { @@ -792,23 +847,34 @@ public final class BearerData { return null; } - private static void decodeMessageId(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeMessageId(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 3) { - throw new CodingException("MESSAGE_IDENTIFIER subparam size incorrect"); - } - bData.messageType = inStream.read(4); - bData.messageId = inStream.read(8) << 8; - bData.messageId |= inStream.read(8); - bData.hasUserDataHeader = (inStream.read(1) == 1); - inStream.skip(3); + final int EXPECTED_PARAM_SIZE = 3 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.messageType = inStream.read(4); + bData.messageId = inStream.read(8) << 8; + bData.messageId |= inStream.read(8); + bData.hasUserDataHeader = (inStream.read(1) == 1); + inStream.skip(3); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "MESSAGE_IDENTIFIER decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); + } + inStream.skip(paramBits); + return decodeSuccess; } - private static void decodeUserData(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeUserData(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException { - int paramBytes = inStream.read(8); + int paramBits = inStream.read(8) * 8; bData.userData = new UserData(); bData.userData.msgEncoding = inStream.read(5); bData.userData.msgEncodingSet = true; @@ -821,13 +887,17 @@ public final class BearerData { } bData.userData.numFields = inStream.read(8); consumedBits += 8; - int dataBits = (paramBytes * 8) - consumedBits; + int dataBits = paramBits - consumedBits; bData.userData.payload = inStream.readByteArray(dataBits); + return true; } private static String decodeUtf16(byte[] data, int offset, int numFields) throws CodingException { + // Start reading from the next 16-bit aligned boundry after offset. + int padding = offset % 2; + numFields -= (offset + padding) / 2; try { return new String(data, offset, numFields * 2, "utf-16be"); } catch (java.io.UnsupportedEncodingException ex) { @@ -835,7 +905,7 @@ public final class BearerData { } } - private static String decodeIa5(byte[] data, int offset, int numFields) + private static String decode7bitAscii(byte[] data, int offset, int numFields) throws CodingException { try { @@ -850,38 +920,20 @@ public final class BearerData { inStream.skip(offset); for (int i = 0; i < numFields; i++) { int charCode = inStream.read(7); - if ((charCode < UserData.IA5_MAP_BASE_INDEX) || - (charCode > UserData.IA5_MAP_MAX_INDEX)) { - throw new CodingException("unsupported AI5 character code (" + charCode + ")"); + if ((charCode >= UserData.ASCII_MAP_BASE_INDEX) && + (charCode <= UserData.ASCII_MAP_MAX_INDEX)) { + strBuf.append(UserData.ASCII_MAP[charCode - UserData.ASCII_MAP_BASE_INDEX]); + } else if (charCode == UserData.ASCII_NL_INDEX) { + strBuf.append('\n'); + } else if (charCode == UserData.ASCII_CR_INDEX) { + strBuf.append('\r'); + } else { + /* For other charCodes, they are unprintable, and so simply use SPACE. */ + strBuf.append(' '); } - strBuf.append(UserData.IA5_MAP[charCode - UserData.IA5_MAP_BASE_INDEX]); } return strBuf.toString(); } catch (BitwiseInputStream.AccessException ex) { - throw new CodingException("AI5 decode failed: " + ex); - } - } - - private static String decode7bitAscii(byte[] data, int offset, int numFields) - throws CodingException - { - try { - offset *= 8; - BitwiseInputStream inStream = new BitwiseInputStream(data); - int wantedBits = offset + (numFields * 7); - if (inStream.available() < wantedBits) { - throw new CodingException("insufficient data (wanted " + wantedBits + - " bits, but only have " + inStream.available() + ")"); - } - inStream.skip(offset); - byte[] expandedData = new byte[numFields]; - for (int i = 0; i < numFields; i++) { - expandedData[i] = (byte)inStream.read(7); - } - return new String(expandedData, 0, numFields, "US-ASCII"); - } catch (java.io.UnsupportedEncodingException ex) { - throw new CodingException("7bit ASCII decode failed: " + ex); - } catch (BitwiseInputStream.AccessException ex) { throw new CodingException("7bit ASCII decode failed: " + ex); } } @@ -889,11 +941,11 @@ public final class BearerData { private static String decode7bitGsm(byte[] data, int offset, int numFields) throws CodingException { - int paddingBits = calcUdhSeptetPadding(offset); - numFields -= (((offset * 8) + paddingBits) / 7); - // TODO: It seems wrong that only Gsm7 bit encodings would - // take into account the header in numFields calculations. - // This should be verified. + // Start reading from the next 7-bit aligned boundry after offset. + int offsetBits = offset * 8; + int offsetSeptets = (offsetBits + 6) / 7; + numFields -= offsetSeptets; + int paddingBits = (offsetSeptets * 7) - offsetBits; String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields, paddingBits); if (result == null) { throw new CodingException("7bit GSM decoding failed"); @@ -901,6 +953,16 @@ public final class BearerData { return result; } + private static String decodeLatin(byte[] data, int offset, int numFields) + throws CodingException + { + try { + return new String(data, offset, numFields - offset, "ISO-8859-1"); + } catch (java.io.UnsupportedEncodingException ex) { + throw new CodingException("ISO-8859-1 decode failed: " + ex); + } + } + private static void decodeUserDataPayload(UserData userData, boolean hasUserDataHeader) throws CodingException { @@ -914,19 +976,33 @@ public final class BearerData { } switch (userData.msgEncoding) { case UserData.ENCODING_OCTET: + // Strip off any padding bytes, meaning any differences between the length of the + // array and the target length specified by numFields. This is to avoid any confusion + // by code elsewhere that only considers the payload array length. + byte[] payload = new byte[userData.numFields]; + int copyLen = userData.numFields < userData.payload.length + ? userData.numFields : userData.payload.length; + + System.arraycopy(userData.payload, 0, payload, 0, copyLen); + userData.payload = payload; + + // There are many devices in the market that send 8bit text sms (latin encoded) as + // octet encoded. + userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields); break; + case UserData.ENCODING_IA5: case UserData.ENCODING_7BIT_ASCII: userData.payloadStr = decode7bitAscii(userData.payload, offset, userData.numFields); break; - case UserData.ENCODING_IA5: - userData.payloadStr = decodeIa5(userData.payload, offset, userData.numFields); - break; case UserData.ENCODING_UNICODE_16: userData.payloadStr = decodeUtf16(userData.payload, offset, userData.numFields); break; case UserData.ENCODING_GSM_7BIT_ALPHABET: userData.payloadStr = decode7bitGsm(userData.payload, offset, userData.numFields); break; + case UserData.ENCODING_LATIN: + userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields); + break; default: throw new CodingException("unsupported user data encoding (" + userData.msgEncoding + ")"); @@ -959,7 +1035,7 @@ public final class BearerData { try { StringBuffer strbuf = new StringBuffer(dataLen); while (inStream.available() >= 6) { - strbuf.append(UserData.IA5_MAP[inStream.read(6)]); + strbuf.append(UserData.ASCII_MAP[inStream.read(6)]); } String data = strbuf.toString(); bData.numberOfMessages = Integer.parseInt(data.substring(0, 2)); @@ -1001,7 +1077,7 @@ public final class BearerData { } StringBuffer strbuf = new StringBuffer(dataLen); for (int i = 0; i < numFields; i++) { - strbuf.append(UserData.IA5_MAP[inStream.read(6)]); + strbuf.append(UserData.ASCII_MAP[inStream.read(6)]); } bData.userData.payloadStr = strbuf.toString(); } @@ -1049,36 +1125,68 @@ public final class BearerData { } } - private static void decodeReplyOption(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeReplyOption(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - int paramBytes = inStream.read(8); - if (paramBytes != 1) { - throw new CodingException("REPLY_OPTION subparam size incorrect"); - } - bData.userAckReq = (inStream.read(1) == 1); - bData.deliveryAckReq = (inStream.read(1) == 1); - bData.readAckReq = (inStream.read(1) == 1); - bData.reportReq = (inStream.read(1) == 1); - inStream.skip(4); + final int EXPECTED_PARAM_SIZE = 1 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.userAckReq = (inStream.read(1) == 1); + bData.deliveryAckReq = (inStream.read(1) == 1); + bData.readAckReq = (inStream.read(1) == 1); + bData.reportReq = (inStream.read(1) == 1); + inStream.skip(4); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "REPLY_OPTION decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); + } + inStream.skip(paramBits); + return decodeSuccess; } - private static void decodeMsgCount(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeMsgCount(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 1) { - throw new CodingException("NUMBER_OF_MESSAGES subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 1 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.numberOfMessages = IccUtils.cdmaBcdByteToInt((byte)inStream.read(8)); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "NUMBER_OF_MESSAGES decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.numberOfMessages = inStream.read(8); + inStream.skip(paramBits); + return decodeSuccess; } - private static void decodeDepositIndex(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeDepositIndex(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 2) { - throw new CodingException("MESSAGE_DEPOSIT_INDEX subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 2 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "MESSAGE_DEPOSIT_INDEX decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8); + inStream.skip(paramBits); + return decodeSuccess; } private static String decodeDtmfSmsAddress(byte[] rawData, int numFields) @@ -1112,10 +1220,10 @@ public final class BearerData { } } - private static void decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - int paramBytes = inStream.read(8); + int paramBits = inStream.read(8) * 8; CdmaSmsAddress addr = new CdmaSmsAddress(); addr.digitMode = inStream.read(1); byte fieldBits = 4; @@ -1128,140 +1236,274 @@ public final class BearerData { } addr.numberOfDigits = inStream.read(8); consumedBits += 8; - int remainingBits = (paramBytes * 8) - consumedBits; + int remainingBits = paramBits - consumedBits; int dataBits = addr.numberOfDigits * fieldBits; int paddingBits = remainingBits - dataBits; if (remainingBits < dataBits) { throw new CodingException("CALLBACK_NUMBER subparam encoding size error (" + - "remainingBits " + remainingBits + ", dataBits " + - dataBits + ", paddingBits " + paddingBits + ")"); + "remainingBits + " + remainingBits + ", dataBits + " + + dataBits + ", paddingBits + " + paddingBits + ")"); } addr.origBytes = inStream.readByteArray(dataBits); inStream.skip(paddingBits); decodeSmsAddress(addr); bData.callbackNumber = addr; + return true; } - private static void decodeMsgStatus(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeMsgStatus(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 1) { - throw new CodingException("MESSAGE_STATUS subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 1 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.errorClass = inStream.read(2); + bData.messageStatus = inStream.read(6); } - bData.errorClass = inStream.read(2); - bData.messageStatus = inStream.read(6); - bData.messageStatusSet = true; + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "MESSAGE_STATUS decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); + } + inStream.skip(paramBits); + bData.messageStatusSet = decodeSuccess; + return decodeSuccess; } - private static void decodeMsgCenterTimeStamp(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeMsgCenterTimeStamp(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 6) { - throw new CodingException("MESSAGE_CENTER_TIME_STAMP subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 6 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8)); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "MESSAGE_CENTER_TIME_STAMP decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8)); + inStream.skip(paramBits); + return decodeSuccess; } - private static void decodeValidityAbs(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeValidityAbs(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 6) { - throw new CodingException("VALIDITY_PERIOD_ABSOLUTE subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 6 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8)); } - bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8)); + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "VALIDITY_PERIOD_ABSOLUTE decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); + } + inStream.skip(paramBits); + return decodeSuccess; } - private static void decodeDeferredDeliveryAbs(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeDeferredDeliveryAbs(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 6) { - throw new CodingException("DEFERRED_DELIVERY_TIME_ABSOLUTE subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 6 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray( + inStream.readByteArray(6 * 8)); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_ABSOLUTE decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8)); + inStream.skip(paramBits); + return decodeSuccess; } - private static void decodeValidityRel(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeValidityRel(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 1) { - throw new CodingException("VALIDITY_PERIOD_RELATIVE subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 1 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.deferredDeliveryTimeRelative = inStream.read(8); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "VALIDITY_PERIOD_RELATIVE decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.deferredDeliveryTimeRelative = inStream.read(8); - bData.deferredDeliveryTimeRelativeSet = true; + inStream.skip(paramBits); + bData.deferredDeliveryTimeRelativeSet = decodeSuccess; + return decodeSuccess; } - private static void decodeDeferredDeliveryRel(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeDeferredDeliveryRel(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 1) { - throw new CodingException("DEFERRED_DELIVERY_TIME_RELATIVE subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 1 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.validityPeriodRelative = inStream.read(8); } - bData.validityPeriodRelative = inStream.read(8); - bData.validityPeriodRelativeSet = true; + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_RELATIVE decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); + } + inStream.skip(paramBits); + bData.validityPeriodRelativeSet = decodeSuccess; + return decodeSuccess; } - private static void decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream) + private static boolean decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 1) { - throw new CodingException("PRIVACY_INDICATOR subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 1 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.privacy = inStream.read(2); + inStream.skip(6); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "PRIVACY_INDICATOR decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.privacy = inStream.read(2); - inStream.skip(6); - bData.privacyIndicatorSet = true; + inStream.skip(paramBits); + bData.privacyIndicatorSet = decodeSuccess; + return decodeSuccess; } - private static void decodeLanguageIndicator(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeLanguageIndicator(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 1) { - throw new CodingException("LANGUAGE_INDICATOR subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 1 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.language = inStream.read(8); } - bData.language = inStream.read(8); - bData.languageIndicatorSet = true; + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "LANGUAGE_INDICATOR decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); + } + inStream.skip(paramBits); + bData.languageIndicatorSet = decodeSuccess; + return decodeSuccess; } - private static void decodeDisplayMode(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeDisplayMode(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 1) { - throw new CodingException("DISPLAY_MODE subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 1 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.displayMode = inStream.read(2); + inStream.skip(6); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "DISPLAY_MODE decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.displayMode = inStream.read(2); - inStream.skip(6); - bData.displayModeSet = true; + inStream.skip(paramBits); + bData.displayModeSet = decodeSuccess; + return decodeSuccess; } - private static void decodePriorityIndicator(BearerData bData, BitwiseInputStream inStream) + private static boolean decodePriorityIndicator(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 1) { - throw new CodingException("PRIORITY_INDICATOR subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 1 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.priority = inStream.read(2); + inStream.skip(6); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "PRIORITY_INDICATOR decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.priority = inStream.read(2); - inStream.skip(6); - bData.priorityIndicatorSet = true; + inStream.skip(paramBits); + bData.priorityIndicatorSet = decodeSuccess; + return decodeSuccess; } - private static void decodeMsgDeliveryAlert(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeMsgDeliveryAlert(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 1) { - throw new CodingException("ALERT_ON_MESSAGE_DELIVERY subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 1 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.alert = inStream.read(2); + inStream.skip(6); } - bData.alert = inStream.read(2); - inStream.skip(6); - bData.alertIndicatorSet = true; + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "ALERT_ON_MESSAGE_DELIVERY decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); + } + inStream.skip(paramBits); + bData.alertIndicatorSet = decodeSuccess; + return decodeSuccess; } - private static void decodeUserResponseCode(BearerData bData, BitwiseInputStream inStream) + private static boolean decodeUserResponseCode(BearerData bData, BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException { - if (inStream.read(8) != 1) { - throw new CodingException("USER_REPONSE_CODE subparam size incorrect"); + final int EXPECTED_PARAM_SIZE = 1 * 8; + boolean decodeSuccess = false; + int paramBits = inStream.read(8) * 8; + if (paramBits >= EXPECTED_PARAM_SIZE) { + paramBits -= EXPECTED_PARAM_SIZE; + decodeSuccess = true; + bData.userResponseCode = inStream.read(8); + } + if ((! decodeSuccess) || (paramBits > 0)) { + Log.d(LOG_TAG, "USER_REPONSE_CODE decode " + + (decodeSuccess ? "succeeded" : "failed") + + " (extra bits = " + paramBits + ")"); } - bData.userResponseCode = inStream.read(8); - bData.userResponseCodeSet = true; + inStream.skip(paramBits); + bData.userResponseCodeSet = decodeSuccess; + return decodeSuccess; } /** @@ -1278,72 +1520,73 @@ public final class BearerData { BearerData bData = new BearerData(); int foundSubparamMask = 0; while (inStream.available() > 0) { + boolean decodeSuccess = false; int subparamId = inStream.read(8); int subparamIdBit = 1 << subparamId; if ((foundSubparamMask & subparamIdBit) != 0) { throw new CodingException("illegal duplicate subparameter (" + subparamId + ")"); } - foundSubparamMask |= subparamIdBit; switch (subparamId) { case SUBPARAM_MESSAGE_IDENTIFIER: - decodeMessageId(bData, inStream); + decodeSuccess = decodeMessageId(bData, inStream); break; case SUBPARAM_USER_DATA: - decodeUserData(bData, inStream); + decodeSuccess = decodeUserData(bData, inStream); break; case SUBPARAM_USER_REPONSE_CODE: - decodeUserResponseCode(bData, inStream); + decodeSuccess = decodeUserResponseCode(bData, inStream); break; case SUBPARAM_REPLY_OPTION: - decodeReplyOption(bData, inStream); + decodeSuccess = decodeReplyOption(bData, inStream); break; case SUBPARAM_NUMBER_OF_MESSAGES: - decodeMsgCount(bData, inStream); + decodeSuccess = decodeMsgCount(bData, inStream); break; case SUBPARAM_CALLBACK_NUMBER: - decodeCallbackNumber(bData, inStream); + decodeSuccess = decodeCallbackNumber(bData, inStream); break; case SUBPARAM_MESSAGE_STATUS: - decodeMsgStatus(bData, inStream); + decodeSuccess = decodeMsgStatus(bData, inStream); break; case SUBPARAM_MESSAGE_CENTER_TIME_STAMP: - decodeMsgCenterTimeStamp(bData, inStream); + decodeSuccess = decodeMsgCenterTimeStamp(bData, inStream); break; case SUBPARAM_VALIDITY_PERIOD_ABSOLUTE: - decodeValidityAbs(bData, inStream); + decodeSuccess = decodeValidityAbs(bData, inStream); break; case SUBPARAM_VALIDITY_PERIOD_RELATIVE: - decodeValidityRel(bData, inStream); + decodeSuccess = decodeValidityRel(bData, inStream); break; case SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE: - decodeDeferredDeliveryAbs(bData, inStream); + decodeSuccess = decodeDeferredDeliveryAbs(bData, inStream); break; case SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE: - decodeDeferredDeliveryRel(bData, inStream); + decodeSuccess = decodeDeferredDeliveryRel(bData, inStream); break; case SUBPARAM_PRIVACY_INDICATOR: - decodePrivacyIndicator(bData, inStream); + decodeSuccess = decodePrivacyIndicator(bData, inStream); break; case SUBPARAM_LANGUAGE_INDICATOR: - decodeLanguageIndicator(bData, inStream); + decodeSuccess = decodeLanguageIndicator(bData, inStream); break; case SUBPARAM_MESSAGE_DISPLAY_MODE: - decodeDisplayMode(bData, inStream); + decodeSuccess = decodeDisplayMode(bData, inStream); break; case SUBPARAM_PRIORITY_INDICATOR: - decodePriorityIndicator(bData, inStream); + decodeSuccess = decodePriorityIndicator(bData, inStream); break; case SUBPARAM_ALERT_ON_MESSAGE_DELIVERY: - decodeMsgDeliveryAlert(bData, inStream); + decodeSuccess = decodeMsgDeliveryAlert(bData, inStream); break; case SUBPARAM_MESSAGE_DEPOSIT_INDEX: - decodeDepositIndex(bData, inStream); + decodeSuccess = decodeDepositIndex(bData, inStream); break; default: throw new CodingException("unsupported bearer data subparameter (" + subparamId + ")"); } + if (decodeSuccess) foundSubparamMask |= subparamIdBit; } if ((foundSubparamMask & (1 << SUBPARAM_MESSAGE_IDENTIFIER)) == 0) { throw new CodingException("missing MESSAGE_IDENTIFIER subparam"); diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java index 4d79966..d9cc2c6 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java @@ -16,7 +16,10 @@ package com.android.internal.telephony.cdma.sms; +import android.util.SparseBooleanArray; + import com.android.internal.telephony.SmsAddress; +import com.android.internal.telephony.cdma.sms.UserData; import com.android.internal.util.HexDump; public class CdmaSmsAddress extends SmsAddress { @@ -43,7 +46,8 @@ public class CdmaSmsAddress extends SmsAddress { /** * Number Types for data networks. - * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + * (See 3GPP2 C.S005-D, table2.7.1.3.2.4-2 for complete table) + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3 for data network subset) * NOTE: value is stored in the parent class ton field. */ static public final int TON_UNKNOWN = 0x00; @@ -98,10 +102,127 @@ public class CdmaSmsAddress extends SmsAddress { builder.append(", numberPlan=" + numberPlan); builder.append(", numberOfDigits=" + numberOfDigits); builder.append(", ton=" + ton); - builder.append(", address=" + address); + builder.append(", address=\"" + address + "\""); builder.append(", origBytes=" + HexDump.toHexString(origBytes)); builder.append(" }"); return builder.toString(); } + /* + * TODO(cleanup): Refactor the parsing for addresses to better + * share code and logic with GSM. Also, gather all DTMF/BCD + * processing code in one place. + */ + + private static byte[] parseToDtmf(String address) { + int digits = address.length(); + byte[] result = new byte[digits]; + for (int i = 0; i < digits; i++) { + char c = address.charAt(i); + int val = 0; + if ((c >= '1') && (c <= '9')) val = c - '0'; + else if (c == '0') val = 10; + else if (c == '*') val = 11; + else if (c == '#') val = 12; + else return null; + result[i] = (byte)val; + } + return result; + } + + private static final char[] numericCharsDialable = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#' + }; + + private static final char[] numericCharsSugar = { + '(', ')', ' ', '-', '+' + }; + + private static final SparseBooleanArray numericCharDialableMap = new SparseBooleanArray ( + numericCharsDialable.length + numericCharsSugar.length); + static { + for (int i = 0; i < numericCharsDialable.length; i++) { + numericCharDialableMap.put(numericCharsDialable[i], true); + } + for (int i = 0; i < numericCharsSugar.length; i++) { + numericCharDialableMap.put(numericCharsSugar[i], false); + } + } + + /** + * Given a numeric address string, return the string without + * syntactic sugar, meaning parens, spaces, hyphens/minuses, or + * plus signs. If the input string contains non-numeric + * non-punctuation characters, return null. + */ + private static String filterNumericSugar(String address) { + StringBuilder builder = new StringBuilder(); + int len = address.length(); + for (int i = 0; i < len; i++) { + char c = address.charAt(i); + int mapIndex = numericCharDialableMap.indexOfKey(c); + if (mapIndex < 0) return null; + if (! numericCharDialableMap.valueAt(mapIndex)) continue; + builder.append(c); + } + return builder.toString(); + } + + /** + * Given a string, return the string without whitespace, + * including CR/LF. + */ + private static String filterWhitespace(String address) { + StringBuilder builder = new StringBuilder(); + int len = address.length(); + for (int i = 0; i < len; i++) { + char c = address.charAt(i); + if ((c == ' ') || (c == '\r') || (c == '\n') || (c == '\t')) continue; + builder.append(c); + } + return builder.toString(); + } + + /** + * Given a string, create a corresponding CdmaSmsAddress object. + * + * The result will be null if the input string is not + * representable using printable ASCII. + * + * For numeric addresses, the string is cleaned up by removing + * common punctuation. For alpha addresses, the string is cleaned + * up by removing whitespace. + */ + public static CdmaSmsAddress parse(String address) { + CdmaSmsAddress addr = new CdmaSmsAddress(); + addr.address = address; + addr.ton = CdmaSmsAddress.TON_UNKNOWN; + byte[] origBytes = null; + String filteredAddr = filterNumericSugar(address); + if (filteredAddr != null) { + origBytes = parseToDtmf(filteredAddr); + } + if (origBytes != null) { + addr.digitMode = DIGIT_MODE_4BIT_DTMF; + addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK; + if (address.indexOf('+') != -1) { + addr.ton = TON_INTERNATIONAL_OR_IP; + } + } else { + filteredAddr = filterWhitespace(address); + origBytes = UserData.stringToAscii(filteredAddr); + if (origBytes == null) { + return null; + } + addr.digitMode = DIGIT_MODE_8BIT_CHAR; + addr.numberMode = NUMBER_MODE_DATA_NETWORK; + if (address.indexOf('@') != -1) { + addr.ton = TON_NATIONAL_OR_EMAIL; + } + } + addr.origBytes = origBytes; + addr.numberOfDigits = origBytes.length; + return addr; + } + } diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java index f80e8c0..0dcacc1 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java @@ -36,6 +36,14 @@ public final class SmsEnvelope{ static public final int TELESERVICE_WAP = 0x1004; static public final int TELESERVICE_WEMT = 0x1005; + /** + * The following are defined as extensions to the standard teleservices + */ + // Voice mail notification through Message Waiting Indication in CDMA mode or Analog mode. + // Defined in 3GPP2 C.S-0005, 3.7.5.6, an Info Record containing an 8-bit number with the + // number of messages waiting, it's used by some CDMA carriers for a voice mail count. + static public final int TELESERVICE_MWI = 0x40000; + // ServiceCategories for Cell Broadcast, see 3GPP2 C.R1001 table 9.3.1-1 //static public final int SERVICECATEGORY_EMERGENCY = 0x0010; //... diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java index 34cbbfa..d93852c 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java @@ -35,7 +35,7 @@ public class UserData { //public static final int ENCODING_SHIFT_JIS = 0x05; //public static final int ENCODING_KOREAN = 0x06; //public static final int ENCODING_LATIN_HEBREW = 0x07; - //public static final int ENCODING_LATIN = 0x08; + public static final int ENCODING_LATIN = 0x08; public static final int ENCODING_GSM_7BIT_ALPHABET = 0x09; public static final int ENCODING_GSM_DCS = 0x0A; @@ -49,19 +49,20 @@ public class UserData { public static final int IS91_MSG_TYPE_SHORT_MESSAGE = 0x85; /** - * IA5 data encoding character mappings. - * (See CCITT Rec. T.50 Tables 1 and 3) + * US ASCII character mapping table. * - * Note this mapping is the the same as for printable ASCII - * characters, with a 0x20 offset, meaning that the ASCII SPACE - * character occurs with code 0x20. + * This table contains only the printable ASCII characters, with a + * 0x20 offset, meaning that the ASCII SPACE character is at index + * 0, with the resulting code of 0x20. * - * Note this mapping is also equivalent to that used by the IS-91 - * protocol, except for the latter using only 6 bits, and hence - * mapping only entries up to the '_' character. + * Note this mapping is also equivalent to that used by both the + * IS5 and the IS-91 encodings. For the former this is defined + * using CCITT Rec. T.50 Tables 1 and 3. For the latter IS 637 B, + * Table 4.3.1.4.1-1 -- and note the encoding uses only 6 bits, + * and hence only maps entries up to the '_' character. * */ - public static final char[] IA5_MAP = { + public static final char[] ASCII_MAP = { ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', @@ -81,23 +82,43 @@ public class UserData { * Only elements between these indices in the ASCII table are printable. */ public static final int PRINTABLE_ASCII_MIN_INDEX = 0x20; - public static final int ASCII_LF_INDEX = 0x0A; + public static final int ASCII_NL_INDEX = 0x0A; public static final int ASCII_CR_INDEX = 0x0D; public static final SparseIntArray charToAscii = new SparseIntArray(); static { - for (int i = 0; i < IA5_MAP.length; i++) { - charToAscii.put(IA5_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i); + for (int i = 0; i < ASCII_MAP.length; i++) { + charToAscii.put(ASCII_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i); } - charToAscii.put('\r', ASCII_LF_INDEX); - charToAscii.put('\n', ASCII_CR_INDEX); + charToAscii.put('\n', ASCII_NL_INDEX); + charToAscii.put('\r', ASCII_CR_INDEX); + } + + /* + * TODO(cleanup): Move this very generic functionality somewhere + * more general. + */ + /** + * Given a string generate a corresponding ASCII-encoded byte + * array, but limited to printable characters. If the input + * contains unprintable characters, return null. + */ + public static byte[] stringToAscii(String str) { + int len = str.length(); + byte[] result = new byte[len]; + for (int i = 0; i < len; i++) { + int charCode = charToAscii.get(str.charAt(i), -1); + if (charCode == -1) return null; + result[i] = (byte)charCode; + } + return result; } /** - * Mapping for IA5 values less than 32 are flow control signals + * Mapping for ASCII values less than 32 are flow control signals * and not used here. */ - public static final int IA5_MAP_BASE_INDEX = 0x20; - public static final int IA5_MAP_MAX_INDEX = IA5_MAP_BASE_INDEX + IA5_MAP.length - 1; + public static final int ASCII_MAP_BASE_INDEX = 0x20; + public static final int ASCII_MAP_MAX_INDEX = ASCII_MAP_BASE_INDEX + ASCII_MAP.length - 1; /** * Contains the data header of the user data @@ -133,7 +154,7 @@ public class UserData { builder.append("{ msgEncoding=" + (msgEncodingSet ? msgEncoding : "unset")); builder.append(", msgType=" + msgType); builder.append(", paddingBits=" + paddingBits); - builder.append(", numFields=" + (int)numFields); + builder.append(", numFields=" + numFields); builder.append(", userDataHeader=" + userDataHeader); builder.append(", payload='" + HexDump.toHexString(payload) + "'"); builder.append(", payloadStr='" + payloadStr + "'"); diff --git a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java index 3ca39de..dc6f92d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java +++ b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java @@ -72,7 +72,10 @@ public class ApnSetting { boolean canHandleType(String type) { for (String t : types) { - if (t.equals(type) || t.equals(Phone.APN_TYPE_ALL)) { + // DEFAULT handles all, and HIPRI is handled by DEFAULT + if (t.equals(type) || t.equals(Phone.APN_TYPE_ALL) || + (t.equals(Phone.APN_TYPE_DEFAULT) && + type.equals(Phone.APN_TYPE_HIPRI))) { return true; } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index d1e4b4f..ac7331e 100755 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -23,13 +23,11 @@ import android.database.SQLException; import android.net.Uri; import android.os.AsyncResult; import android.os.Handler; -import android.os.Looper; import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.os.SystemProperties; import android.preference.PreferenceManager; -import android.provider.Settings; import android.provider.Telephony; import android.telephony.CellLocation; import android.telephony.PhoneNumberUtils; @@ -51,6 +49,7 @@ import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDI import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION; +import com.android.internal.telephony.Call; import com.android.internal.telephony.CallForwardInfo; import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.CommandsInterface; @@ -97,15 +96,13 @@ public class GSMPhone extends PhoneBase { // Key used to read/write the SIM IMSI used for storing the voice mail public static final String VM_SIM_IMSI = "vm_sim_imsi_key"; - //***** Instance Variables + // Instance Variables GsmCallTracker mCT; GsmServiceStateTracker mSST; GsmSMSDispatcher mSMS; - GsmDataConnectionTracker mDataConnection; SIMRecords mSIMRecords; SimCard mSimCard; StkService mStkService; - MyHandler h; ArrayList <GsmMmiCode> mPendingMMIs = new ArrayList<GsmMmiCode>(); SimPhoneBookInterfaceManager mSimPhoneBookIntManager; SimSmsInterfaceManager mSimSmsIntManager; @@ -129,7 +126,7 @@ public class GSMPhone extends PhoneBase { private String mVmNumber; - //***** Constructors + // Constructors public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier) { @@ -138,9 +135,7 @@ public class GSMPhone extends PhoneBase { public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) { - super(notifier, context, unitTestMode); - h = new MyHandler(); - mCM = ci; + super(notifier, context, ci, unitTestMode); if (ci instanceof SimulatedRadioControl) { mSimulatedRadioControl = (SimulatedRadioControl) ci; @@ -162,14 +157,13 @@ public class GSMPhone extends PhoneBase { mStkService = StkService.getInstance(mCM, mSIMRecords, mContext, (SIMFileHandler)mIccFileHandler, mSimCard); - mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null); - mSIMRecords.registerForRecordsLoaded(h, EVENT_SIM_RECORDS_LOADED, null); - mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - mCM.registerForOn(h, EVENT_RADIO_ON, null); - mCM.setOnUSSD(h, EVENT_USSD, null); - mCM.setOnSuppServiceNotification(h, EVENT_SSN, null); - mCM.setOnCallRing(h, EVENT_CALL_RING, null); - mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null); + mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); + mSIMRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null); + mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + mCM.registerForOn(this, EVENT_RADIO_ON, null); + mCM.setOnUSSD(this, EVENT_USSD, null); + mCM.setOnSuppServiceNotification(this, EVENT_SSN, null); + mSST.registerForNetworkAttach(this, EVENT_REGISTERED_TO_NETWORK, null); if (false) { try { @@ -212,15 +206,16 @@ public class GSMPhone extends PhoneBase { public void dispose() { synchronized(PhoneProxy.lockForRadioTechnologyChange) { + super.dispose(); + //Unregister from all former registered events - mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE - mSIMRecords.unregisterForRecordsLoaded(h); //EVENT_SIM_RECORDS_LOADED - mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE - mCM.unregisterForOn(h); //EVENT_RADIO_ON - mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK - mCM.unSetOnUSSD(h); - mCM.unSetOnSuppServiceNotification(h); - mCM.unSetOnCallRing(h); + mCM.unregisterForAvailable(this); //EVENT_RADIO_AVAILABLE + mSIMRecords.unregisterForRecordsLoaded(this); //EVENT_SIM_RECORDS_LOADED + mCM.unregisterForOffOrNotAvailable(this); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE + mCM.unregisterForOn(this); //EVENT_RADIO_ON + mSST.unregisterForNetworkAttach(this); //EVENT_REGISTERED_TO_NETWORK + mCM.unSetOnUSSD(this); + mCM.unSetOnSuppServiceNotification(this); mPendingMMIs.clear(); @@ -258,8 +253,6 @@ public class GSMPhone extends PhoneBase { } - //***** Overridden from Phone - public ServiceState getServiceState() { return mSST.ss; @@ -279,14 +272,6 @@ public class GSMPhone extends PhoneBase { return "GSM"; } - public String[] getActiveApnTypes() { - return mDataConnection.getActiveApnTypes(); - } - - public String getActiveApn() { - return mDataConnection.getActiveApnString(); - } - public SignalStrength getSignalStrength() { return mSST.mSignalStrength; } @@ -378,20 +363,19 @@ public class GSMPhone extends PhoneBase { } /** - * Notify any interested party of a Phone state change. + * Notify any interested party of a Phone state change {@link Phone.State} */ /*package*/ void notifyPhoneStateChanged() { mNotifier.notifyPhoneState(this); } /** - * Notifies registrants (ie, activities in the Phone app) about - * changes to call state (including Phone and Connection changes). + * Notify registrants of a change in the call state. This notifies changes in {@link Call.State} + * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged. */ - /*package*/ void - notifyCallStateChanged() { + /*package*/ void notifyPreciseCallStateChanged() { /* we'd love it if this was package-scoped*/ - super.notifyCallStateChangedP(); + super.notifyPreciseCallStateChangedP(); } /*package*/ void @@ -400,14 +384,6 @@ public class GSMPhone extends PhoneBase { super.notifyNewRingingConnectionP(c); } - /** - * Notifiy registrants of a RING event. - */ - void notifyIncomingRing() { - AsyncResult ar = new AsyncResult(null, this, null); - mIncomingRingRegistrants.notifyRegistrants(ar); - } - /*package*/ void notifyDisconnect(Connection cn) { mDisconnectRegistrants.notifyResult(cn); @@ -926,7 +902,7 @@ public class GSMPhone extends PhoneBase { Message resp; mVmNumber = voiceMailNumber; - resp = h.obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete); + resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete); mSIMRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp); } @@ -965,7 +941,7 @@ public class GSMPhone extends PhoneBase { if (LOCAL_DEBUG) Log.d(LOG_TAG, "requesting call forwarding query."); Message resp; if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) { - resp = h.obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete); + resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete); } else { resp = onComplete; } @@ -983,7 +959,7 @@ public class GSMPhone extends PhoneBase { Message resp; if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) { - resp = h.obtainMessage(EVENT_SET_CALL_FORWARD_DONE, + resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE, isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, onComplete); } else { resp = onComplete; @@ -1004,7 +980,7 @@ public class GSMPhone extends PhoneBase { public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) { mCM.setCLIR(commandInterfaceCLIRMode, - h.obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete)); + obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete)); } public void getCallWaiting(Message onComplete) { @@ -1032,11 +1008,13 @@ public class GSMPhone extends PhoneBase { /** * Small container class used to hold information relevant to * the carrier selection process. operatorNumeric can be "" - * if we are looking for automatic selection. + * if we are looking for automatic selection. operatorAlphaLong is the + * corresponding operator name. */ private static class NetworkSelectMessage { public Message message; public String operatorNumeric; + public String operatorAlphaLong; } public void @@ -1047,9 +1025,10 @@ public class GSMPhone extends PhoneBase { NetworkSelectMessage nsm = new NetworkSelectMessage(); nsm.message = response; nsm.operatorNumeric = ""; + nsm.operatorAlphaLong = ""; // get the message - Message msg = h.obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm); + Message msg = obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm); if (LOCAL_DEBUG) Log.d(LOG_TAG, "wrapping and sending message to connect automatically"); @@ -1064,9 +1043,10 @@ public class GSMPhone extends PhoneBase { NetworkSelectMessage nsm = new NetworkSelectMessage(); nsm.message = response; nsm.operatorNumeric = network.operatorNumeric; + nsm.operatorAlphaLong = network.operatorAlphaLong; // get the message - Message msg = h.obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm); + Message msg = obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm); mCM.setNetworkSelectionModeManual(network.operatorNumeric, msg); } @@ -1089,8 +1069,9 @@ public class GSMPhone extends PhoneBase { } /** - * @deprecated + * @deprecated Do not use. */ + @Deprecated public void getPdpContextList(Message response) { getDataCallList(response); } @@ -1100,8 +1081,9 @@ public class GSMPhone extends PhoneBase { } /** - * @deprecated + * @deprecated Do not use. */ + @Deprecated public List<PdpConnection> getCurrentPdpList() { ArrayList<DataConnection> connections = new ArrayList<DataConnection>(); ArrayList<PdpConnection> pdp_list = new ArrayList<PdpConnection>(); @@ -1141,34 +1123,10 @@ public class GSMPhone extends PhoneBase { return mDataConnection.setDataEnabled(true); } - public int enableApnType(String type) { - return mDataConnection.enableApnType(type); - } - - public int disableApnType(String type) { - return mDataConnection.disableApnType(type); - } - public boolean disableDataConnectivity() { return mDataConnection.setDataEnabled(false); } - public String getInterfaceName(String apnType) { - return mDataConnection.getInterfaceName(apnType); - } - - public String getIpAddress(String apnType) { - return mDataConnection.getIpAddress(apnType); - } - - public String getGateway(String apnType) { - return mDataConnection.getGateway(apnType); - } - - public String[] getDnsServers(String apnType) { - return mDataConnection.getDnsServers(apnType); - } - /** * The only circumstances under which we report that data connectivity is not * possible are @@ -1274,178 +1232,163 @@ public class GSMPhone extends PhoneBase { } } - //***** Inner Classes + @Override + public void handleMessage (Message msg) { + AsyncResult ar; + Message onComplete; - class MyHandler extends Handler { - MyHandler() { - } + switch (msg.what) { + case EVENT_RADIO_AVAILABLE: { + mCM.getBasebandVersion( + obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE)); - MyHandler(Looper l) { - super(l); - } - - public void - handleMessage (Message msg) { - AsyncResult ar; - Message onComplete; - - switch (msg.what) { - case EVENT_RADIO_AVAILABLE: { - mCM.getBasebandVersion( - obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE)); + mCM.getIMEI(obtainMessage(EVENT_GET_IMEI_DONE)); + mCM.getIMEISV(obtainMessage(EVENT_GET_IMEISV_DONE)); + } + break; - mCM.getIMEI(obtainMessage(EVENT_GET_IMEI_DONE)); - mCM.getIMEISV(obtainMessage(EVENT_GET_IMEISV_DONE)); - } - break; + case EVENT_RADIO_ON: + break; - case EVENT_RADIO_ON: + case EVENT_REGISTERED_TO_NETWORK: + syncClirSetting(); break; - case EVENT_REGISTERED_TO_NETWORK: - syncClirSetting(); - break; - - case EVENT_SIM_RECORDS_LOADED: - updateCurrentCarrierInProvider(); + case EVENT_SIM_RECORDS_LOADED: + updateCurrentCarrierInProvider(); - // Check if this is a different SIM than the previous one. If so unset the - // voice mail number. - String imsi = getVmSimImsi(); - if (imsi != null && !getSubscriberId().equals(imsi)) { - storeVoiceMailNumber(null); - setVmSimImsi(null); - } + // Check if this is a different SIM than the previous one. If so unset the + // voice mail number. + String imsi = getVmSimImsi(); + if (imsi != null && !getSubscriberId().equals(imsi)) { + storeVoiceMailNumber(null); + setVmSimImsi(null); + } - break; + break; - case EVENT_GET_BASEBAND_VERSION_DONE: - ar = (AsyncResult)msg.obj; + case EVENT_GET_BASEBAND_VERSION_DONE: + ar = (AsyncResult)msg.obj; - if (ar.exception != null) { - break; - } + if (ar.exception != null) { + break; + } - if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result); - setSystemProperty(PROPERTY_BASEBAND_VERSION, (String)ar.result); - break; + if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result); + setSystemProperty(PROPERTY_BASEBAND_VERSION, (String)ar.result); + break; - case EVENT_GET_IMEI_DONE: - ar = (AsyncResult)msg.obj; + case EVENT_GET_IMEI_DONE: + ar = (AsyncResult)msg.obj; - if (ar.exception != null) { - break; - } + if (ar.exception != null) { + break; + } - mImei = (String)ar.result; - break; + mImei = (String)ar.result; + break; - case EVENT_GET_IMEISV_DONE: - ar = (AsyncResult)msg.obj; + case EVENT_GET_IMEISV_DONE: + ar = (AsyncResult)msg.obj; - if (ar.exception != null) { - break; - } + if (ar.exception != null) { + break; + } - mImeiSv = (String)ar.result; - break; + mImeiSv = (String)ar.result; + break; - case EVENT_USSD: - ar = (AsyncResult)msg.obj; + case EVENT_USSD: + ar = (AsyncResult)msg.obj; - String[] ussdResult = (String[]) ar.result; + String[] ussdResult = (String[]) ar.result; - if (ussdResult.length > 1) { - try { - onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]); - } catch (NumberFormatException e) { - Log.w(LOG_TAG, "error parsing USSD"); - } + if (ussdResult.length > 1) { + try { + onIncomingUSSD(Integer.parseInt(ussdResult[0]), ussdResult[1]); + } catch (NumberFormatException e) { + Log.w(LOG_TAG, "error parsing USSD"); } - break; + } + break; - case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: - // Some MMI requests (eg USSD) are not completed - // within the course of a CommandsInterface request - // If the radio shuts off or resets while one of these - // is pending, we need to clean up. + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: + // Some MMI requests (eg USSD) are not completed + // within the course of a CommandsInterface request + // If the radio shuts off or resets while one of these + // is pending, we need to clean up. - for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) { - if (mPendingMMIs.get(i).isPendingUSSD()) { - mPendingMMIs.get(i).onUssdFinishedError(); - } + for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) { + if (mPendingMMIs.get(i).isPendingUSSD()) { + mPendingMMIs.get(i).onUssdFinishedError(); } + } + break; + + case EVENT_SSN: + ar = (AsyncResult)msg.obj; + SuppServiceNotification not = (SuppServiceNotification) ar.result; + mSsnRegistrants.notifyRegistrants(ar); + break; + + case EVENT_SET_CALL_FORWARD_DONE: + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + mSIMRecords.setVoiceCallForwardingFlag(1, msg.arg1 == 1); + } + onComplete = (Message) ar.userObj; + if (onComplete != null) { + AsyncResult.forMessage(onComplete, ar.result, ar.exception); + onComplete.sendToTarget(); + } break; - case EVENT_SSN: - ar = (AsyncResult)msg.obj; - SuppServiceNotification not = (SuppServiceNotification) ar.result; - mSsnRegistrants.notifyRegistrants(ar); + case EVENT_SET_VM_NUMBER_DONE: + ar = (AsyncResult)msg.obj; + if (IccVmNotSupportedException.class.isInstance(ar.exception)) { + storeVoiceMailNumber(mVmNumber); + ar.exception = null; + } + onComplete = (Message) ar.userObj; + if (onComplete != null) { + AsyncResult.forMessage(onComplete, ar.result, ar.exception); + onComplete.sendToTarget(); + } break; - case EVENT_SET_CALL_FORWARD_DONE: - ar = (AsyncResult)msg.obj; - if (ar.exception == null) { - mSIMRecords.setVoiceCallForwardingFlag(1, msg.arg1 == 1); - } - onComplete = (Message) ar.userObj; - if (onComplete != null) { - AsyncResult.forMessage(onComplete, ar.result, ar.exception); - onComplete.sendToTarget(); - } - break; - - case EVENT_SET_VM_NUMBER_DONE: - ar = (AsyncResult)msg.obj; - if (IccVmNotSupportedException.class.isInstance(ar.exception)) { - storeVoiceMailNumber(mVmNumber); - ar.exception = null; - } - onComplete = (Message) ar.userObj; - if (onComplete != null) { - AsyncResult.forMessage(onComplete, ar.result, ar.exception); - onComplete.sendToTarget(); - } - break; - - case EVENT_GET_CALL_FORWARD_DONE: - ar = (AsyncResult)msg.obj; - if (ar.exception == null) { - handleCfuQueryResult((CallForwardInfo[])ar.result); - } - onComplete = (Message) ar.userObj; - if (onComplete != null) { - AsyncResult.forMessage(onComplete, ar.result, ar.exception); - onComplete.sendToTarget(); - } - break; + case EVENT_GET_CALL_FORWARD_DONE: + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + handleCfuQueryResult((CallForwardInfo[])ar.result); + } + onComplete = (Message) ar.userObj; + if (onComplete != null) { + AsyncResult.forMessage(onComplete, ar.result, ar.exception); + onComplete.sendToTarget(); + } + break; - case EVENT_CALL_RING: - ar = (AsyncResult)msg.obj; - if (ar.exception == null) { - notifyIncomingRing(); - } - break; + // handle the select network completion callbacks. + case EVENT_SET_NETWORK_MANUAL_COMPLETE: + case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE: + handleSetSelectNetwork((AsyncResult) msg.obj); + break; - // handle the select network completion callbacks. - case EVENT_SET_NETWORK_MANUAL_COMPLETE: - case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE: - handleSetSelectNetwork((AsyncResult) msg.obj); - break; + case EVENT_SET_CLIR_COMPLETE: + ar = (AsyncResult)msg.obj; + if (ar.exception == null) { + saveClirSetting(msg.arg1); + } + onComplete = (Message) ar.userObj; + if (onComplete != null) { + AsyncResult.forMessage(onComplete, ar.result, ar.exception); + onComplete.sendToTarget(); + } + break; - case EVENT_SET_CLIR_COMPLETE: - ar = (AsyncResult)msg.obj; - if (ar.exception == null) { - saveClirSetting(msg.arg1); - } - onComplete = (Message) ar.userObj; - if (onComplete != null) { - AsyncResult.forMessage(onComplete, ar.result, ar.exception); - onComplete.sendToTarget(); - } - break; - } + default: + super.handleMessage(msg); } } @@ -1495,6 +1438,7 @@ public class GSMPhone extends PhoneBase { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences.Editor editor = sp.edit(); editor.putString(NETWORK_SELECTION_KEY, nsm.operatorNumeric); + editor.putString(NETWORK_SELECTION_NAME_KEY, nsm.operatorAlphaLong); // commit and log the result. if (! editor.commit()) { @@ -1534,36 +1478,6 @@ public class GSMPhone extends PhoneBase { } } } - /** - * simulateDataConnection - * - * simulates various data connection states. This messes with - * DataConnectionTracker's internal states, but doesn't actually change - * the underlying radio connection states. - * - * @param state Phone.DataState enum. - */ - public void simulateDataConnection(Phone.DataState state) { - DataConnectionTracker.State dcState; - - switch (state) { - case CONNECTED: - dcState = DataConnectionTracker.State.CONNECTED; - break; - case SUSPENDED: - dcState = DataConnectionTracker.State.CONNECTED; - break; - case DISCONNECTED: - dcState = DataConnectionTracker.State.FAILED; - break; - default: - dcState = DataConnectionTracker.State.CONNECTING; - break; - } - - mDataConnection.setState(dcState); - notifyDataConnection(null); - } /** * Retrieves the PhoneSubInfo of the GSMPhone @@ -1589,13 +1503,6 @@ public class GSMPhone extends PhoneBase { /** * {@inheritDoc} */ - public Handler getHandler(){ - return h; - } - - /** - * {@inheritDoc} - */ public IccFileHandler getIccFileHandler(){ return this.mIccFileHandler; } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCall.java b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java index a92e52d..9542d20 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmCall.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java @@ -185,6 +185,7 @@ class GsmCall extends Call { cn.onHangupLocal(); } + state = State.DISCONNECTING; } /** diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java index 5c5090f..91c089e 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java @@ -212,7 +212,7 @@ public final class GsmCallTracker extends CallTracker { } updatePhoneState(); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); return pendingMO; } @@ -279,7 +279,7 @@ public final class GsmCallTracker extends CallTracker { internalClearDisconnected(); updatePhoneState(); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); } boolean @@ -294,12 +294,15 @@ public final class GsmCallTracker extends CallTracker { canDial() { boolean ret; int serviceState = phone.getServiceState().getState(); + String disableCall = SystemProperties.get( + TelephonyProperties.PROPERTY_DISABLE_CALL, "false"); - ret = (serviceState != ServiceState.STATE_POWER_OFF) && - pendingMO == null + ret = (serviceState != ServiceState.STATE_POWER_OFF) + && pendingMO == null && !ringingCall.isRinging() + && !disableCall.equals("true") && (!foregroundCall.getState().isAlive() - || !backgroundCall.getState().isAlive()); + || !backgroundCall.getState().isAlive()); return ret; } @@ -600,7 +603,7 @@ public final class GsmCallTracker extends CallTracker { } if (hasNonHangupStateChanged || newRinging != null) { - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); } //dumpState(); @@ -738,6 +741,7 @@ public final class GsmCallTracker extends CallTracker { } call.onHangupLocal(); + phone.notifyPreciseCallStateChanged(); } /* package */ @@ -883,7 +887,7 @@ public final class GsmCallTracker extends CallTracker { updatePhoneState(); - phone.notifyCallStateChanged(); + phone.notifyPreciseCallStateChanged(); droppedDuringPoll.clear(); break; diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java index d93ca1d..2091fb6 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java @@ -381,10 +381,14 @@ public class GsmConnection extends Connection { } else if (phone.mSST.rs.isCsNormalRestricted()) { return DisconnectCause.CS_RESTRICTED_NORMAL; } else { - return DisconnectCause.NORMAL; + return DisconnectCause.ERROR_UNSPECIFIED; } - } else { + } else if (causeCode == CallFailCause.NORMAL_CLEARING) { return DisconnectCause.NORMAL; + } else { + // If nothing else matches, report unknown call drop reason + // to app, not NORMAL call end. + return DisconnectCause.ERROR_UNSPECIFIED; } } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index d48c941..0215ab2 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -52,6 +52,7 @@ import com.android.internal.telephony.DataCallState; import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.RetryManager; import com.android.internal.telephony.TelephonyEventLog; import com.android.internal.telephony.DataConnection.FailCause; @@ -62,8 +63,7 @@ import java.util.ArrayList; * {@hide} */ public final class GsmDataConnectionTracker extends DataConnectionTracker { - private static final String LOG_TAG = "GSM"; - private static final boolean DBG = true; + protected final String LOG_TAG = "GSM"; private GSMPhone mGsmPhone; /** @@ -85,7 +85,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { INetStatService netstat; // Indicates baseband will not auto-attach private boolean noAutoAttach = false; - long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + private boolean mReregisterOnReconnectFailure = false; private ContentResolver mResolver; @@ -95,6 +95,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private int mPdpResetCount = 0; private boolean mIsScreenOn = true; + /** Delay between APN attempts */ + protected static final int APN_DELAY_MILLIS = 5000; + //useful for debugging boolean failNextConnect = false; @@ -115,27 +118,17 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private ApnSetting preferredApn = null; + /* Currently active APN */ + protected ApnSetting mActiveApn; + /** * pdpList holds all the PDP connection, i.e. IP Link in GPRS */ private ArrayList<DataConnection> pdpList; - /** Currently requested APN type */ - private String mRequestedApnType = Phone.APN_TYPE_DEFAULT; - - /** Currently active APN */ - private ApnSetting mActiveApn; - /** Currently active PdpConnection */ private PdpConnection mActivePdp; - private static int APN_DEFAULT_ID = 0; - private static int APN_MMS_ID = 1; - private static int APN_SUPL_ID = 2; - private static int APN_NUM_TYPES = 3; - - private boolean[] dataEnabled = new boolean[APN_NUM_TYPES]; - /** Is packet service restricted by network */ private boolean mIsPsRestricted = false; @@ -207,7 +200,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { GsmDataConnectionTracker(GSMPhone p) { super(p); mGsmPhone = p; - p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); p.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); @@ -230,7 +222,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - p.getContext().registerReceiver(mIntentReceiver, filter, null, p.h); + // TODO: Why is this registering the phone as the receiver of the intent + // and not its own handler? + p.getContext().registerReceiver(mIntentReceiver, filter, null, p); mDataConnectionTracker = this; @@ -246,7 +240,19 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // and 2) whether the RIL will setup the baseband to auto-PS attach. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext()); dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false); + if (dataEnabled[APN_DEFAULT_ID]) { + enabledCount++; + } noAutoAttach = !dataEnabled[APN_DEFAULT_ID]; + + if (!mRetryMgr.configure(SystemProperties.get("ro.gsm.data_retry_config"))) { + if (!mRetryMgr.configure(DEFAULT_DATA_RETRY_CONFIG)) { + // Should never happen, log an error and default to a simple linear sequence. + Log.e(LOG_TAG, "Could not configure using DEFAULT_DATA_RETRY_CONFIG=" + + DEFAULT_DATA_RETRY_CONFIG); + mRetryMgr.configure(20, 2000, 1000); + } + } } public void dispose() { @@ -274,7 +280,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if(DBG) Log.d(LOG_TAG, "GsmDataConnectionTracker finalized"); } - void setState(State s) { + protected void setState(State s) { if (DBG) log ("setState: " + s); if (state != s) { if (s == State.INITING) { // request PDP context @@ -298,7 +304,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } - String[] getActiveApnTypes() { + public String[] getActiveApnTypes() { String[] result; if (mActiveApn != null) { result = mActiveApn.types; @@ -318,91 +324,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } /** - * Ensure that we are connected to an APN of the specified type. - * @param type the APN type (currently the only valid values - * are {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}) - * @return the result of the operation. Success is indicated by - * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or - * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast - * will be sent by the ConnectivityManager when a connection to - * the APN has been established. - */ - protected int enableApnType(String type) { - if (!TextUtils.equals(type, Phone.APN_TYPE_MMS) && - !TextUtils.equals(type, Phone.APN_TYPE_SUPL)) { - return Phone.APN_REQUEST_FAILED; - } - - // If already active, return - Log.d(LOG_TAG, "enableApnType("+type+")"); - if (isApnTypeActive(type)) { - setEnabled(type, true); - removeMessages(EVENT_RESTORE_DEFAULT_APN); - /** - * We're being asked to enable a non-default APN that's already in use. - * This means we should restart the timer that will automatically - * switch back to the default APN and disable the non-default APN - * when it expires. - */ - sendMessageDelayed( - obtainMessage(EVENT_RESTORE_DEFAULT_APN), - getRestoreDefaultApnDelay()); - if (state == State.INITING) return Phone.APN_REQUEST_STARTED; - else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE; - } - - if (!isApnTypeAvailable(type)) { - return Phone.APN_TYPE_NOT_AVAILABLE; - } - - setEnabled(type, true); - mRequestedApnType = type; - sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN)); - return Phone.APN_REQUEST_STARTED; - } - - /** - * The APN of the specified type is no longer needed. Ensure that if - * use of the default APN has not been explicitly disabled, we are connected - * to the default APN. - * @param type the APN type. The only valid values are currently - * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}. - * @return - */ - protected int disableApnType(String type) { - Log.d(LOG_TAG, "disableApnType("+type+")"); - if ((TextUtils.equals(type, Phone.APN_TYPE_MMS) || - TextUtils.equals(type, Phone.APN_TYPE_SUPL)) - && isEnabled(type)) { - removeMessages(EVENT_RESTORE_DEFAULT_APN); - setEnabled(type, false); - if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { - mRequestedApnType = Phone.APN_TYPE_DEFAULT; - if (dataEnabled[APN_DEFAULT_ID]) { - return Phone.APN_ALREADY_ACTIVE; - } else { - Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); - msg.arg1 = 1; // tearDown is true; - msg.obj = Phone.REASON_DATA_DISABLED; - sendMessage(msg); - return Phone.APN_REQUEST_STARTED; - } - } else { - /* - * Note that if default data is disabled, the following - * has the effect of disabling the MMS APN, and then - * ignoring the request to enable the default APN. - * The net result is that data is completely disabled. - */ - sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN)); - return Phone.APN_REQUEST_STARTED; - } - } else { - return Phone.APN_REQUEST_FAILED; - } - } - - /** * The data connection is expected to be setup while device * 1. has sim card * 2. registered to gprs service @@ -428,12 +349,14 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return mGsmPhone.mSST.getDataRoaming(); } - private boolean isApnTypeActive(String type) { - // TODO: to support simultaneous, mActiveApn can be a List instead. + @Override + protected boolean isApnTypeActive(String type) { + // TODO: support simultaneous with List instead return mActiveApn != null && mActiveApn.canHandleType(type); } - private boolean isApnTypeAvailable(String type) { + @Override + protected boolean isApnTypeAvailable(String type) { if (allApns != null) { for (ApnSetting apn : allApns) { if (apn.canHandleType(type)) { @@ -444,90 +367,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return false; } - private boolean isEnabled(String apnType) { - if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) { - return dataEnabled[APN_DEFAULT_ID]; - } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) { - return dataEnabled[APN_MMS_ID]; - } else if (TextUtils.equals(apnType, Phone.APN_TYPE_SUPL)) { - return dataEnabled[APN_SUPL_ID]; - } else { - return false; - } - } - - private void setEnabled(String apnType, boolean enable) { - Log.d(LOG_TAG, "setEnabled(" + apnType + ", " + enable + ')'); - if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) { - dataEnabled[APN_DEFAULT_ID] = enable; - } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) { - dataEnabled[APN_MMS_ID] = enable; - } else if (TextUtils.equals(apnType, Phone.APN_TYPE_SUPL)) { - dataEnabled[APN_SUPL_ID] = enable; - } - Log.d(LOG_TAG, "dataEnabled[DEFAULT_APN]=" + dataEnabled[APN_DEFAULT_ID] + - " dataEnabled[MMS_APN]=" + dataEnabled[APN_MMS_ID] + - " dataEnabled[SUPL_APN]=" + dataEnabled[APN_SUPL_ID]); - } - - /** - * Prevent mobile data connections from being established, - * or once again allow mobile data connections. If the state - * toggles, then either tear down or set up data, as - * appropriate to match the new state. - * <p>This operation only affects the default APN, and if the same APN is - * currently being used for MMS traffic, the teardown will not happen - * even when {@code enable} is {@code false}.</p> - * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data - * @return {@code true} if the operation succeeded - */ - public boolean setDataEnabled(boolean enable) { - boolean isEnabled = isEnabled(Phone.APN_TYPE_DEFAULT); - Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled); - if (!isEnabled && enable) { - setEnabled(Phone.APN_TYPE_DEFAULT, true); - // trySetupData() will be a no-op if we are currently - // connected to the MMS APN - sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); - return true; - } else if (!enable) { - setEnabled(Phone.APN_TYPE_DEFAULT, false); - // Don't tear down if there is an active APN and it handles MMS or SUPL. - // TODO: This isn't very general. - if ((isApnTypeActive(Phone.APN_TYPE_MMS) && isEnabled(Phone.APN_TYPE_MMS)) || - (isApnTypeActive(Phone.APN_TYPE_SUPL) && isEnabled(Phone.APN_TYPE_SUPL))) { - return false; - } - Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); - msg.arg1 = 1; // tearDown is true - msg.obj = Phone.REASON_DATA_DISABLED; - sendMessage(msg); - return true; - } else { - // isEnabled && enable - return true; - } - } - - /** - * Report the current state of data connectivity (enabled or disabled) for - * the default APN. - * @return {@code false} if data connectivity has been explicitly disabled, - * {@code true} otherwise. - */ - public boolean getDataEnabled() { - return dataEnabled[APN_DEFAULT_ID]; - } - - /** - * Report on whether data connectivity is enabled for any APN. - * @return {@code false} if data connectivity has been explicitly disabled, - * {@code true} otherwise. - */ - public boolean getAnyDataEnabled() { - return dataEnabled[APN_DEFAULT_ID] || dataEnabled[APN_MMS_ID] || dataEnabled[APN_SUPL_ID]; - } - /** * Formerly this method was ArrayList<PdpConnection> getAllPdps() */ @@ -562,7 +401,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } else { if (state == State.FAILED) { cleanUpConnection(false, Phone.REASON_GPRS_ATTACHED); - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); } trySetupData(Phone.REASON_GPRS_ATTACHED); } @@ -607,7 +446,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } if (DBG) { - log ("Setup watingApns : " + apnListToString(waitingApns)); + log ("Setup waitngApns : " + apnListToString(waitingApns)); } return setupData(reason); } else { @@ -618,6 +457,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { " sim=" + mGsmPhone.mSIMRecords.getRecordsLoaded() + " UMTS=" + mGsmPhone.mSST.isConcurrentVoiceAndData() + " phoneState=" + phone.getState() + + " isDataAllowed=" + isDataAllowed() + " dataEnabled=" + getAnyDataEnabled() + " roaming=" + roaming + " dataOnRoamingEnable=" + getDataOnRoamingEnabled() + @@ -742,7 +582,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return true; } - String getInterfaceName(String apnType) { + protected String getInterfaceName(String apnType) { if (mActivePdp != null && (apnType == null || mActiveApn.canHandleType(apnType))) { return mActivePdp.getInterface(); @@ -758,7 +598,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return null; } - String getGateway(String apnType) { + public String getGateway(String apnType) { if (mActivePdp != null && (apnType == null || mActiveApn.canHandleType(apnType))) { return mActivePdp.getGatewayAddress(); @@ -812,7 +652,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED); if (!isConnected) { // reset reconnect timer - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; trySetupData(Phone.REASON_APN_CHANGED); } @@ -893,7 +733,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { phone.notifyDataConnection(reason); startNetStatPoll(); // reset reconnect timer - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; } @@ -1170,8 +1010,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private boolean retryAfterDisconnected(String reason) { boolean retry = true; - if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) || - Phone.REASON_DATA_DISABLED.equals(reason) ) { + if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ) { retry = false; } return retry; @@ -1179,20 +1018,21 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { if (state == State.FAILED) { - if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) { + if (!mRetryMgr.isRetryNeeded()) { if (mReregisterOnReconnectFailure) { - // We have already tried to re-register to the network. - // This might be a problem with the data network. - nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS; + // We've re-registerd once now just retry forever. + mRetryMgr.retryForeverUsingLastTimeout(); } else { - // Try to Re-register to the network. + // Try to re-register to the network. Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network"); mReregisterOnReconnectFailure = true; mGsmPhone.mSST.reRegisterNetwork(null); - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); return; } } + + int nextReconnectDelay = mRetryMgr.getRetryTimer(); Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); @@ -1206,8 +1046,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { SystemClock.elapsedRealtime() + nextReconnectDelay, mReconnectIntent); - // double it for next time - nextReconnectDelay *= 2; + mRetryMgr.increaseRetryCount(); if (!shouldPostNotification(lastFailCauseCode)) { Log.d(LOG_TAG,"NOT Posting GPRS Unavailable notification " @@ -1236,17 +1075,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { cleanUpConnection(true, Phone.REASON_APN_SWITCHED); } - protected void onTrySetupData(String reason) { - trySetupData(reason); - } - - protected void onRestoreDefaultApn() { - if (DBG) Log.d(LOG_TAG, "Restore default APN"); - setEnabled(Phone.APN_TYPE_MMS, false); - mRequestedApnType = Phone.APN_TYPE_DEFAULT; - if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { - cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN); - } + protected boolean onTrySetupData(String reason) { + return trySetupData(reason); } /** @@ -1302,7 +1132,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { protected void onRadioOffOrNotAvailable() { // Make sure our reconnect delay starts at the initial value // next time the radio comes on - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; if (phone.getSimulatedRadioControl() != null) { @@ -1324,22 +1154,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (ar.exception == null) { // everything is setup - - /* - * We may have switched away from the default PDP context - * in order to enable a "special" APN (e.g., for MMS - * traffic). Set a timer to switch back and/or disable the - * special APN, so that a negligient application doesn't - * permanently prevent data connectivity. What we are - * protecting against here is not malicious apps, but - * rather an app that inadvertantly fails to reset to the - * default APN, or that dies before doing so. - */ - if (dataEnabled[APN_MMS_ID] || dataEnabled[APN_SUPL_ID]) { - removeMessages(EVENT_RESTORE_DEFAULT_APN); - sendMessageDelayed(obtainMessage(EVENT_RESTORE_DEFAULT_APN), - getRestoreDefaultApnDelay()); - } if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { SystemProperties.set("gsm.defaultpdpcontext.active", "true"); if (canSetPreferApn && preferredApn == null) { @@ -1387,8 +1201,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { setState(State.SCANNING); // Wait a bit before trying the next APN, so that // we're not tying up the RIL command channel - sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), - RECONNECT_DELAY_INITIAL_MILLIS); + sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), APN_DELAY_MILLIS); } } } @@ -1433,7 +1246,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } else { // reset reconnect timer - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; // in case data setup was attempted when we were on a voice call trySetupData(Phone.REASON_VOICE_CALL_ENDED); @@ -1444,18 +1257,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { cleanUpConnection(tearDown, reason); } - private int getRestoreDefaultApnDelay() { - String restoreApnDelayStr = SystemProperties.get(APN_RESTORE_DELAY_PROP_NAME); - - if (restoreApnDelayStr != null && restoreApnDelayStr.length() != 0) { - try { - return Integer.valueOf(restoreApnDelayStr); - } catch (NumberFormatException e) { - } - } - return RESTORE_DEFAULT_APN_DELAY; - } - /** * Based on the sim operator numeric, create a list for all possible pdps * with all apns associated with that pdp @@ -1580,10 +1381,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private void startDelayedRetry(PdpConnection.FailCause cause, String reason) { notifyNoData(cause); - if (mRequestedApnType != Phone.APN_TYPE_DEFAULT) { - sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN)); - } - else { + if (mRequestedApnType == Phone.APN_TYPE_DEFAULT) { reconnectAfterFail(cause, reason); } } @@ -1638,7 +1436,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } public void handleMessage (Message msg) { - + if (DBG) Log.d(LOG_TAG,"GSMDataConnTrack handleMessage "+msg); switch (msg.what) { case EVENT_RECORDS_LOADED: onRecordsLoaded(); @@ -1648,10 +1446,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { onEnableNewApn(); break; - case EVENT_RESTORE_DEFAULT_APN: - onRestoreDefaultApn(); - break; - case EVENT_GPRS_DETACHED: onGprsDetached(); break; @@ -1710,7 +1504,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } else { if (state == State.FAILED) { cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED); - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; } trySetupData(Phone.REASON_PS_RESTRICT_ENABLED); diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index 60d4e8f..e7406e2 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -154,6 +154,8 @@ final class GsmServiceStateTracker extends ServiceStateTracker { static final int PS_NOTIFICATION = 888; //id to update and cancel PS restricted static final int CS_NOTIFICATION = 999; //id to update and cancel CS restricted + static final int MAX_NUM_DATA_STATE_READS = 15; + private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { @@ -675,6 +677,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { newGPRSState = regCodeToServiceState(regState); newDataRoaming = regCodeIsRoaming(regState); newNetworkType = type; + newSS.setRadioTechnology(type); break; case EVENT_POLL_STATE_OPERATOR: @@ -808,6 +811,15 @@ final class GsmServiceStateTracker extends ServiceStateTracker { case DATA_ACCESS_UMTS: ret = "UMTS"; break; + case DATA_ACCESS_HSDPA: + ret = "HSDPA"; + break; + case DATA_ACCESS_HSUPA: + ret = "HSUPA"; + break; + case DATA_ACCESS_HSPA: + ret = "HSPA"; + break; default: Log.e(LOG_TAG, "Wrong network type: " + Integer.toString(type)); break; @@ -1286,7 +1298,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { * that could support voice and data simultaniously. */ boolean isConcurrentVoiceAndData() { - return (networkType == DATA_ACCESS_UMTS); + return (networkType >= DATA_ACCESS_UMTS); } /** diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/gsm/MccTable.java index e18da56..9343f44 100644 --- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java +++ b/telephony/java/com/android/internal/telephony/gsm/MccTable.java @@ -16,391 +16,541 @@ package com.android.internal.telephony.gsm; -import java.util.ArrayList; -import java.util.Collections; +import java.util.Arrays; /** - * Mobile Country Code + * The table below is built from two resources: * - * {@hide} - */ -public final class MccTable -{ - static ArrayList<MccEntry> table; + * 1) ITU "Mobile Network Code (MNC) for the international + * identification plan for mobile terminals and mobile users" + * which is available as an annex to the ITU operational bulletin + * available here: http://www.itu.int/itu-t/bulletin/annex.html + * + * 2) The ISO 3166 country codes list, available here: + * http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/index.html + * + * This table was verified (28 Aug 2009) against + * http://en.wikipedia.org/wiki/List_of_mobile_country_codes with the + * only unresolved discrepancy being that this list has an extra entry + * (461) for China. + * + * TODO: Complete the mappings for timezones and language/locale codes. + * + * The actual table data used in the Java code is generated from the + * below Python code for efficiency. The information is expected to + * be static, but if changes are required, the table in the python + * code can be modified and the trailing code run to re-generate the + * tables that are to be used by Java. - static class MccEntry implements Comparable<MccEntry> - { - int mcc; - String iso; - int smallestDigitsMnc; - String timezone; - String language; +mcc_table = [ + (202, 'gr', 2, 'Greece'), + (204, 'nl', 2, 'Europe/Amsterdam', 'nl', 13, 'Netherlands (Kingdom of the)'), + (206, 'be', 2, 'Belgium'), + (208, 'fr', 2, 'Europe/Paris', 'fr', 'France'), + (212, 'mc', 2, 'Monaco (Principality of)'), + (213, 'ad', 2, 'Andorra (Principality of)'), + (214, 'es', 2, 'Europe/Madrid', 'es', 'Spain'), + (216, 'hu', 2, 'Hungary (Republic of)'), + (218, 'ba', 2, 'Bosnia and Herzegovina'), + (219, 'hr', 2, 'Croatia (Republic of)'), + (220, 'rs', 2, 'Serbia and Montenegro'), + (222, 'it', 2, 'Europe/Rome', 'it', 'Italy'), + (225, 'va', 2, 'Europe/Rome', 'it', 'Vatican City State'), + (226, 'ro', 2, 'Romania'), + (228, 'ch', 2, 'Europe/Zurich', 'de', 'Switzerland (Confederation of)'), + (230, 'cz', 2, 'Europe/Prague', 'cs', 13, 'Czech Republic'), + (231, 'sk', 2, 'Slovak Republic'), + (232, 'at', 2, 'Europe/Vienna', 'de', 13, 'Austria'), + (234, 'gb', 2, 'Europe/London', 'en', 13, 'United Kingdom of Great Britain and Northern Ireland'), + (235, 'gb', 2, 'Europe/London', 'en', 13, 'United Kingdom of Great Britain and Northern Ireland'), + (238, 'dk', 2, 'Denmark'), + (240, 'se', 2, 'Sweden'), + (242, 'no', 2, 'Norway'), + (244, 'fi', 2, 'Finland'), + (246, 'lt', 2, 'Lithuania (Republic of)'), + (247, 'lv', 2, 'Latvia (Republic of)'), + (248, 'ee', 2, 'Estonia (Republic of)'), + (250, 'ru', 2, 'Russian Federation'), + (255, 'ua', 2, 'Ukraine'), + (257, 'by', 2, 'Belarus (Republic of)'), + (259, 'md', 2, 'Moldova (Republic of)'), + (260, 'pl', 2, 'Europe/Warsaw', 'Poland (Republic of)'), + (262, 'de', 2, 'Europe/Berlin', 'de', 13, 'Germany (Federal Republic of)'), + (266, 'gi', 2, 'Gibraltar'), + (268, 'pt', 2, 'Portugal'), + (270, 'lu', 2, 'Luxembourg'), + (272, 'ie', 2, 'Europe/Dublin', 'en', 'Ireland'), + (274, 'is', 2, 'Iceland'), + (276, 'al', 2, 'Albania (Republic of)'), + (278, 'mt', 2, 'Malta'), + (280, 'cy', 2, 'Cyprus (Republic of)'), + (282, 'ge', 2, 'Georgia'), + (283, 'am', 2, 'Armenia (Republic of)'), + (284, 'bg', 2, 'Bulgaria (Republic of)'), + (286, 'tr', 2, 'Turkey'), + (288, 'fo', 2, 'Faroe Islands'), + (289, 'ge', 2, 'Abkhazia (Georgia)'), + (290, 'gl', 2, 'Greenland (Denmark)'), + (292, 'sm', 2, 'San Marino (Republic of)'), + (293, 'sl', 2, 'Slovenia (Republic of)'), + (294, 'mk', 2, 'The Former Yugoslav Republic of Macedonia'), + (295, 'li', 2, 'Liechtenstein (Principality of)'), + (297, 'me', 2, 'Montenegro (Republic of)'), + (302, 'ca', 2, '', '', 11, 'Canada'), + (308, 'pm', 2, 'Saint Pierre and Miquelon (Collectivit territoriale de la Rpublique franaise)'), + (310, 'us', 3, '', 'en', 11, 'United States of America'), + (311, 'us', 3, '', 'en', 11, 'United States of America'), + (312, 'us', 3, '', 'en', 11, 'United States of America'), + (313, 'us', 3, '', 'en', 11, 'United States of America'), + (314, 'us', 3, '', 'en', 11, 'United States of America'), + (315, 'us', 3, '', 'en', 11, 'United States of America'), + (316, 'us', 3, '', 'en', 11, 'United States of America'), + (330, 'pr', 2, 'Puerto Rico'), + (332, 'vi', 2, 'United States Virgin Islands'), + (334, 'mx', 3, 'Mexico'), + (338, 'jm', 3, 'Jamaica'), + (340, 'gp', 2, 'Guadeloupe (French Department of)'), + (342, 'bb', 3, 'Barbados'), + (344, 'ag', 3, 'Antigua and Barbuda'), + (346, 'ky', 3, 'Cayman Islands'), + (348, 'vg', 3, 'British Virgin Islands'), + (350, 'bm', 2, 'Bermuda'), + (352, 'gd', 2, 'Grenada'), + (354, 'ms', 2, 'Montserrat'), + (356, 'kn', 2, 'Saint Kitts and Nevis'), + (358, 'lc', 2, 'Saint Lucia'), + (360, 'vc', 2, 'Saint Vincent and the Grenadines'), + (362, 'nl', 2, 'Netherlands Antilles'), + (363, 'aw', 2, 'Aruba'), + (364, 'bs', 2, 'Bahamas (Commonwealth of the)'), + (365, 'ai', 3, 'Anguilla'), + (366, 'dm', 2, 'Dominica (Commonwealth of)'), + (368, 'cu', 2, 'Cuba'), + (370, 'do', 2, 'Dominican Republic'), + (372, 'ht', 2, 'Haiti (Republic of)'), + (374, 'tt', 2, 'Trinidad and Tobago'), + (376, 'tc', 2, 'Turks and Caicos Islands'), + (400, 'az', 2, 'Azerbaijani Republic'), + (401, 'kz', 2, 'Kazakhstan (Republic of)'), + (402, 'bt', 2, 'Bhutan (Kingdom of)'), + (404, 'in', 2, 'India (Republic of)'), + (405, 'in', 2, 'India (Republic of)'), + (410, 'pk', 2, 'Pakistan (Islamic Republic of)'), + (412, 'af', 2, 'Afghanistan'), + (413, 'lk', 2, 'Sri Lanka (Democratic Socialist Republic of)'), + (414, 'mm', 2, 'Myanmar (Union of)'), + (415, 'lb', 2, 'Lebanon'), + (416, 'jo', 2, 'Jordan (Hashemite Kingdom of)'), + (417, 'sy', 2, 'Syrian Arab Republic'), + (418, 'iq', 2, 'Iraq (Republic of)'), + (419, 'kw', 2, 'Kuwait (State of)'), + (420, 'sa', 2, 'Saudi Arabia (Kingdom of)'), + (421, 'ye', 2, 'Yemen (Republic of)'), + (422, 'om', 2, 'Oman (Sultanate of)'), + (423, 'ps', 2, 'Palestine'), + (424, 'ae', 2, 'United Arab Emirates'), + (425, 'il', 2, 'Israel (State of)'), + (426, 'bh', 2, 'Bahrain (Kingdom of)'), + (427, 'qa', 2, 'Qatar (State of)'), + (428, 'mn', 2, 'Mongolia'), + (429, 'np', 2, 'Nepal'), + (430, 'ae', 2, 'United Arab Emirates'), + (431, 'ae', 2, 'United Arab Emirates'), + (432, 'ir', 2, 'Iran (Islamic Republic of)'), + (434, 'uz', 2, 'Uzbekistan (Republic of)'), + (436, 'tj', 2, 'Tajikistan (Republic of)'), + (437, 'kg', 2, 'Kyrgyz Republic'), + (438, 'tm', 2, 'Turkmenistan'), + (440, 'jp', 2, 'Asia/Tokyo', 'ja', 14, 'Japan'), + (441, 'jp', 2, 'Asia/Tokyo', 'ja', 14, 'Japan'), + (450, 'kr', 2, 'Korea (Republic of)'), + (452, 'vn', 2, 'Viet Nam (Socialist Republic of)'), + (454, 'hk', 2, '"Hong Kong, China"'), + (455, 'mo', 2, '"Macao, China"'), + (456, 'kh', 2, 'Cambodia (Kingdom of)'), + (457, 'la', 2, "Lao People's Democratic Republic"), + (460, 'cn', 2, "China (People's Republic of)"), + (461, 'cn', 2, "China (People's Republic of)"), + (466, 'tw', 2, "Taiwan (Republic of China)"), + (467, 'kp', 2, "Democratic People's Republic of Korea"), + (470, 'bd', 2, "Bangladesh (People's Republic of)"), + (472, 'mv', 2, 'Maldives (Republic of)'), + (502, 'my', 2, 'Malaysia'), + (505, 'au', 2, 'Australia/Sydney', 'en', 11, 'Australia'), + (510, 'id', 2, 'Indonesia (Republic of)'), + (514, 'tl', 2, 'Democratic Republic of Timor-Leste'), + (515, 'ph', 2, 'Philippines (Republic of the)'), + (520, 'th', 2, 'Thailand'), + (525, 'sg', 2, 'Singapore', 'en', 11, 'Singapore (Republic of)'), + (528, 'bn', 2, 'Brunei Darussalam'), + (530, 'nz', 2, 'Pacific/Auckland', 'en', 'New Zealand'), + (534, 'mp', 2, 'Northern Mariana Islands (Commonwealth of the)'), + (535, 'gu', 2, 'Guam'), + (536, 'nr', 2, 'Nauru (Republic of)'), + (537, 'pg', 2, 'Papua New Guinea'), + (539, 'to', 2, 'Tonga (Kingdom of)'), + (540, 'sb', 2, 'Solomon Islands'), + (541, 'vu', 2, 'Vanuatu (Republic of)'), + (542, 'fj', 2, 'Fiji (Republic of)'), + (543, 'wf', 2, "Wallis and Futuna (Territoire franais d'outre-mer)"), + (544, 'as', 2, 'American Samoa'), + (545, 'ki', 2, 'Kiribati (Republic of)'), + (546, 'nc', 2, "New Caledonia (Territoire franais d'outre-mer)"), + (547, 'pf', 2, "French Polynesia (Territoire franais d'outre-mer)"), + (548, 'ck', 2, 'Cook Islands'), + (549, 'ws', 2, 'Samoa (Independent State of)'), + (550, 'fm', 2, 'Micronesia (Federated States of)'), + (551, 'mh', 2, 'Marshall Islands (Republic of the)'), + (552, 'pw', 2, 'Palau (Republic of)'), + (602, 'eg', 2, 'Egypt (Arab Republic of)'), + (603, 'dz', 2, "Algeria (People's Democratic Republic of)"), + (604, 'ma', 2, 'Morocco (Kingdom of)'), + (605, 'tn', 2, 'Tunisia'), + (606, 'ly', 2, "Libya (Socialist People's Libyan Arab Jamahiriya)"), + (607, 'gm', 2, 'Gambia (Republic of the)'), + (608, 'sn', 2, 'Senegal (Republic of)'), + (609, 'mr', 2, 'Mauritania (Islamic Republic of)'), + (610, 'ml', 2, 'Mali (Republic of)'), + (611, 'gn', 2, 'Guinea (Republic of)'), + (612, 'ci', 2, "Cte d'Ivoire (Republic of)"), + (613, 'bf', 2, 'Burkina Faso'), + (614, 'ne', 2, 'Niger (Republic of the)'), + (615, 'tg', 2, 'Togolese Republic'), + (616, 'bj', 2, 'Benin (Republic of)'), + (617, 'mu', 2, 'Mauritius (Republic of)'), + (618, 'lr', 2, 'Liberia (Republic of)'), + (619, 'sl', 2, 'Sierra Leone'), + (620, 'gh', 2, 'Ghana'), + (621, 'ng', 2, 'Nigeria (Federal Republic of)'), + (622, 'td', 2, 'Chad (Republic of)'), + (623, 'cf', 2, 'Central African Republic'), + (624, 'cm', 2, 'Cameroon (Republic of)'), + (625, 'cv', 2, 'Cape Verde (Republic of)'), + (626, 'st', 2, 'Sao Tome and Principe (Democratic Republic of)'), + (627, 'gq', 2, 'Equatorial Guinea (Republic of)'), + (628, 'ga', 2, 'Gabonese Republic'), + (629, 'cg', 2, 'Congo (Republic of the)'), + (630, 'cg', 2, 'Democratic Republic of the Congo'), + (631, 'ao', 2, 'Angola (Republic of)'), + (632, 'gw', 2, 'Guinea-Bissau (Republic of)'), + (633, 'sc', 2, 'Seychelles (Republic of)'), + (634, 'sd', 2, 'Sudan (Republic of the)'), + (635, 'rw', 2, 'Rwanda (Republic of)'), + (636, 'et', 2, 'Ethiopia (Federal Democratic Republic of)'), + (637, 'so', 2, 'Somali Democratic Republic'), + (638, 'dj', 2, 'Djibouti (Republic of)'), + (639, 'ke', 2, 'Kenya (Republic of)'), + (640, 'tz', 2, 'Tanzania (United Republic of)'), + (641, 'ug', 2, 'Uganda (Republic of)'), + (642, 'bi', 2, 'Burundi (Republic of)'), + (643, 'mz', 2, 'Mozambique (Republic of)'), + (645, 'zm', 2, 'Zambia (Republic of)'), + (646, 'mg', 2, 'Madagascar (Republic of)'), + (647, 're', 2, 'Reunion (French Department of)'), + (648, 'zw', 2, 'Zimbabwe (Republic of)'), + (649, 'na', 2, 'Namibia (Republic of)'), + (650, 'mw', 2, 'Malawi'), + (651, 'ls', 2, 'Lesotho (Kingdom of)'), + (652, 'bw', 2, 'Botswana (Republic of)'), + (653, 'sz', 2, 'Swaziland (Kingdom of)'), + (654, 'km', 2, 'Comoros (Union of the)'), + (655, 'za', 2, 'Africa/Johannesburg', 'en', 'South Africa (Republic of)'), + (657, 'er', 2, 'Eritrea'), + (702, 'bz', 2, 'Belize'), + (704, 'gt', 2, 'Guatemala (Republic of)'), + (706, 'sv', 2, 'El Salvador (Republic of)'), + (708, 'hn', 3, 'Honduras (Republic of)'), + (710, 'ni', 2, 'Nicaragua'), + (712, 'cr', 2, 'Costa Rica'), + (714, 'pa', 2, 'Panama (Republic of)'), + (716, 'pe', 2, 'Peru'), + (722, 'ar', 3, 'Argentine Republic'), + (724, 'br', 2, 'Brazil (Federative Republic of)'), + (730, 'cl', 2, 'Chile'), + (732, 'co', 3, 'Colombia (Republic of)'), + (734, 've', 2, 'Venezuela (Bolivarian Republic of)'), + (736, 'bo', 2, 'Bolivia (Republic of)'), + (738, 'gy', 2, 'Guyana'), + (740, 'ec', 2, 'Ecuador'), + (742, 'gf', 2, 'French Guiana (French Department of)'), + (744, 'py', 2, 'Paraguay (Republic of)'), + (746, 'sr', 2, 'Suriname (Republic of)'), + (748, 'uy', 2, 'Uruguay (Eastern Republic of)'), + (750, 'fk', 2, 'Falkland Islands (Malvinas)')] - MccEntry(int mnc, String iso, int smallestDigitsMCC) { - this(mnc, iso, smallestDigitsMCC, null); - } +get_mcc = lambda elt: elt[0] +get_iso = lambda elt: elt[1] +get_sd = lambda elt: elt[2] +get_tz = lambda elt: len(elt) > 4 and elt[3] or '' +get_lang = lambda elt: len(elt) > 5 and elt[4] or '' +get_wifi = lambda elt: len(elt) > 6 and elt[5] or 0 - MccEntry(int mnc, String iso, int smallestDigitsMCC, String timezone) { - this(mnc, iso, smallestDigitsMCC, timezone, null); - } +mcc_codes = ['0x%04x' % get_mcc(elt) for elt in mcc_table] +tz_set = sorted(x for x in set(get_tz(elt) for elt in mcc_table)) +lang_set = sorted(x for x in set(get_lang(elt) for elt in mcc_table)) - MccEntry(int mnc, String iso, int smallestDigitsMCC, String timezone, String language) { - this.mcc = mnc; - this.iso = iso; - this.smallestDigitsMnc = smallestDigitsMCC; - this.timezone = timezone; - this.language = language; - } +def mk_ind_code(elt): + iso = get_iso(elt) + iso_code = ((ord(iso[0]) << 8) | ord(iso[1])) & 0xFFFF # 16 bits + wifi = get_wifi(elt) & 0x000F # 4 bits + sd = get_sd(elt) & 0x0003 # 2 bits + tz_ind = tz_set.index(get_tz(elt)) & 0x001F # 5 bits + lang_ind = lang_set.index(get_lang(elt)) & 0x000F # 4 bits + return (iso_code << 16) | (wifi << 11) | (sd << 9) | (tz_ind << 4) | lang_ind - public int compareTo(MccEntry o) - { - return mcc - o.mcc; - } - } +ind_codes = ['0x%08x' % mk_ind_code(elt) for elt in mcc_table] - private static MccEntry - entryForMcc(int mcc) - { - int index; +def fmt_list(title, l, batch_sz): + sl = [] + for i in range(len(l) / batch_sz + (len(l) % batch_sz and 1 or 0)): + j = i * batch_sz + sl.append((' ' * 8) + ', '.join(l[j:j + batch_sz])) + return ' private static final %s = {\n' % title + ',\n'.join(sl) + '\n };\n' - MccEntry m; +def do_autogen_comment(extra_desc=[]): + print ' /' + '**\n * AUTO GENERATED (by the Python code above)' + for line in extra_desc: + print ' * %s' % line + print ' *' + '/' - m = new MccEntry(mcc, null, 0); +do_autogen_comment() +print fmt_list('String[] TZ_STRINGS', ['"%s"' % x for x in tz_set], 1) +do_autogen_comment() +print fmt_list('String[] LANG_STRINGS', ['"%s"' % x for x in lang_set], 10) +do_autogen_comment(['This table is a list of MCC codes. The index in this table', + 'of a given MCC code is the index of extra information about', + 'that MCC in the IND_CODES table.']) +print fmt_list('short[] MCC_CODES', mcc_codes, 10) +do_autogen_comment(['The values in this table are broken down as follows (msb to lsb):', + ' iso country code 16 bits', + ' (unused) 1 bit', + ' wifi channel 4 bits', + ' smalled digit 2 bits', + ' default timezone 5 bits', + ' default language 4 bits']) +print fmt_list('int[] IND_CODES', ind_codes, 6) - index = Collections.binarySearch(table, m); +def parse_ind_code(ind): + mcc = eval(mcc_codes[ind]) + code = eval(ind_codes[ind]) + iso_lsb = int((code >> 16) & 0x00FF) + iso_msb = int((code >> 24) & 0x00FF) + iso = '%s%s' % (chr(iso_msb), chr(iso_lsb)) + wifi = int((code >> 11) & 0x000F) + sd = int((code >> 9) & 0x0003) + tz_ind = (code >> 4) & 0x001F + lang_ind = (code >> 0) & 0x000F + return (mcc, iso, sd, tz_set[tz_ind], lang_set[lang_ind], wifi) - if (index < 0) { - return null; - } else { - return table.get(index); - } - } +fmt_str = 'mcc = %s, iso = %s, sd = %s, tz = %s, lang = %s, wifi = %s' +orig_table = [fmt_str % (get_mcc(elt), get_iso(elt), get_sd(elt), + get_tz(elt), get_lang(elt), get_wifi(elt)) + for elt in mcc_table] +derived_table = [fmt_str % parse_ind_code(i) for i in range(len(ind_codes))] +for i in range(len(orig_table)): + if orig_table[i] == derived_table[i]: continue + print 'MISMATCH ERROR : ', orig_table[i], " != ", derived_table[i] + +*/ +/** + * Mobile Country Code + * + * {@hide} + */ +public final class MccTable +{ /** - * Returns a default time zone ID for the given MCC. - * @param mcc Mobile Country Code - * @return default TimeZone ID, or null if not specified - */ - /* package */ static String defaultTimeZoneForMcc(int mcc) { - MccEntry entry; + * AUTO GENERATED (by the Python code above) + */ + private static final String[] TZ_STRINGS = { + "", + "Africa/Johannesburg", + "Asia/Tokyo", + "Australia/Sydney", + "Europe/Amsterdam", + "Europe/Berlin", + "Europe/Dublin", + "Europe/London", + "Europe/Madrid", + "Europe/Paris", + "Europe/Prague", + "Europe/Rome", + "Europe/Vienna", + "Europe/Warsaw", + "Europe/Zurich", + "Pacific/Auckland", + "Singapore" + }; - entry = entryForMcc(mcc); + /** + * AUTO GENERATED (by the Python code above) + */ + private static final String[] LANG_STRINGS = { + "", "cs", "de", "en", "es", "fr", "it", "ja", "nl" + }; - if (entry == null) { + /** + * AUTO GENERATED (by the Python code above) + * This table is a list of MCC codes. The index in this table + * of a given MCC code is the index of extra information about + * that MCC in the IND_CODES table. + */ + private static final short[] MCC_CODES = { + 0x00ca, 0x00cc, 0x00ce, 0x00d0, 0x00d4, 0x00d5, 0x00d6, 0x00d8, 0x00da, 0x00db, + 0x00dc, 0x00de, 0x00e1, 0x00e2, 0x00e4, 0x00e6, 0x00e7, 0x00e8, 0x00ea, 0x00eb, + 0x00ee, 0x00f0, 0x00f2, 0x00f4, 0x00f6, 0x00f7, 0x00f8, 0x00fa, 0x00ff, 0x0101, + 0x0103, 0x0104, 0x0106, 0x010a, 0x010c, 0x010e, 0x0110, 0x0112, 0x0114, 0x0116, + 0x0118, 0x011a, 0x011b, 0x011c, 0x011e, 0x0120, 0x0121, 0x0122, 0x0124, 0x0125, + 0x0126, 0x0127, 0x0129, 0x012e, 0x0134, 0x0136, 0x0137, 0x0138, 0x0139, 0x013a, + 0x013b, 0x013c, 0x014a, 0x014c, 0x014e, 0x0152, 0x0154, 0x0156, 0x0158, 0x015a, + 0x015c, 0x015e, 0x0160, 0x0162, 0x0164, 0x0166, 0x0168, 0x016a, 0x016b, 0x016c, + 0x016d, 0x016e, 0x0170, 0x0172, 0x0174, 0x0176, 0x0178, 0x0190, 0x0191, 0x0192, + 0x0194, 0x0195, 0x019a, 0x019c, 0x019d, 0x019e, 0x019f, 0x01a0, 0x01a1, 0x01a2, + 0x01a3, 0x01a4, 0x01a5, 0x01a6, 0x01a7, 0x01a8, 0x01a9, 0x01aa, 0x01ab, 0x01ac, + 0x01ad, 0x01ae, 0x01af, 0x01b0, 0x01b2, 0x01b4, 0x01b5, 0x01b6, 0x01b8, 0x01b9, + 0x01c2, 0x01c4, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01cc, 0x01cd, 0x01d2, 0x01d3, + 0x01d6, 0x01d8, 0x01f6, 0x01f9, 0x01fe, 0x0202, 0x0203, 0x0208, 0x020d, 0x0210, + 0x0212, 0x0216, 0x0217, 0x0218, 0x0219, 0x021b, 0x021c, 0x021d, 0x021e, 0x021f, + 0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0226, 0x0227, 0x0228, 0x025a, + 0x025b, 0x025c, 0x025d, 0x025e, 0x025f, 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, + 0x0265, 0x0266, 0x0267, 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, + 0x026f, 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, 0x0278, + 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, 0x0280, 0x0281, 0x0282, + 0x0283, 0x0285, 0x0286, 0x0287, 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, + 0x028e, 0x028f, 0x0291, 0x02be, 0x02c0, 0x02c2, 0x02c4, 0x02c6, 0x02c8, 0x02ca, + 0x02cc, 0x02d2, 0x02d4, 0x02da, 0x02dc, 0x02de, 0x02e0, 0x02e2, 0x02e4, 0x02e6, + 0x02e8, 0x02ea, 0x02ec, 0x02ee + }; + + /** + * AUTO GENERATED (by the Python code above) + * The values in this table are broken down as follows (msb to lsb): + * iso country code 16 bits + * (unused) 1 bit + * wifi channel 4 bits + * smalled digit 2 bits + * default timezone 5 bits + * default language 4 bits + */ + private static final int[] IND_CODES = { + 0x67720400, 0x6e6c6c48, 0x62650400, 0x66720495, 0x6d630400, 0x61640400, + 0x65730484, 0x68750400, 0x62610400, 0x68720400, 0x72730400, 0x697404b6, + 0x766104b6, 0x726f0400, 0x636804e2, 0x637a6ca1, 0x736b0400, 0x61746cc2, + 0x67626c73, 0x67626c73, 0x646b0400, 0x73650400, 0x6e6f0400, 0x66690400, + 0x6c740400, 0x6c760400, 0x65650400, 0x72750400, 0x75610400, 0x62790400, + 0x6d640400, 0x706c04d0, 0x64656c52, 0x67690400, 0x70740400, 0x6c750400, + 0x69650463, 0x69730400, 0x616c0400, 0x6d740400, 0x63790400, 0x67650400, + 0x616d0400, 0x62670400, 0x74720400, 0x666f0400, 0x67650400, 0x676c0400, + 0x736d0400, 0x736c0400, 0x6d6b0400, 0x6c690400, 0x6d650400, 0x63615c00, + 0x706d0400, 0x75735e03, 0x75735e03, 0x75735e03, 0x75735e03, 0x75735e03, + 0x75735e03, 0x75735e03, 0x70720400, 0x76690400, 0x6d780600, 0x6a6d0600, + 0x67700400, 0x62620600, 0x61670600, 0x6b790600, 0x76670600, 0x626d0400, + 0x67640400, 0x6d730400, 0x6b6e0400, 0x6c630400, 0x76630400, 0x6e6c0400, + 0x61770400, 0x62730400, 0x61690600, 0x646d0400, 0x63750400, 0x646f0400, + 0x68740400, 0x74740400, 0x74630400, 0x617a0400, 0x6b7a0400, 0x62740400, + 0x696e0400, 0x696e0400, 0x706b0400, 0x61660400, 0x6c6b0400, 0x6d6d0400, + 0x6c620400, 0x6a6f0400, 0x73790400, 0x69710400, 0x6b770400, 0x73610400, + 0x79650400, 0x6f6d0400, 0x70730400, 0x61650400, 0x696c0400, 0x62680400, + 0x71610400, 0x6d6e0400, 0x6e700400, 0x61650400, 0x61650400, 0x69720400, + 0x757a0400, 0x746a0400, 0x6b670400, 0x746d0400, 0x6a707427, 0x6a707427, + 0x6b720400, 0x766e0400, 0x686b0400, 0x6d6f0400, 0x6b680400, 0x6c610400, + 0x636e0400, 0x636e0400, 0x74770400, 0x6b700400, 0x62640400, 0x6d760400, + 0x6d790400, 0x61755c33, 0x69640400, 0x746c0400, 0x70680400, 0x74680400, + 0x73675d03, 0x626e0400, 0x6e7a04f3, 0x6d700400, 0x67750400, 0x6e720400, + 0x70670400, 0x746f0400, 0x73620400, 0x76750400, 0x666a0400, 0x77660400, + 0x61730400, 0x6b690400, 0x6e630400, 0x70660400, 0x636b0400, 0x77730400, + 0x666d0400, 0x6d680400, 0x70770400, 0x65670400, 0x647a0400, 0x6d610400, + 0x746e0400, 0x6c790400, 0x676d0400, 0x736e0400, 0x6d720400, 0x6d6c0400, + 0x676e0400, 0x63690400, 0x62660400, 0x6e650400, 0x74670400, 0x626a0400, + 0x6d750400, 0x6c720400, 0x736c0400, 0x67680400, 0x6e670400, 0x74640400, + 0x63660400, 0x636d0400, 0x63760400, 0x73740400, 0x67710400, 0x67610400, + 0x63670400, 0x63670400, 0x616f0400, 0x67770400, 0x73630400, 0x73640400, + 0x72770400, 0x65740400, 0x736f0400, 0x646a0400, 0x6b650400, 0x747a0400, + 0x75670400, 0x62690400, 0x6d7a0400, 0x7a6d0400, 0x6d670400, 0x72650400, + 0x7a770400, 0x6e610400, 0x6d770400, 0x6c730400, 0x62770400, 0x737a0400, + 0x6b6d0400, 0x7a610413, 0x65720400, 0x627a0400, 0x67740400, 0x73760400, + 0x686e0600, 0x6e690400, 0x63720400, 0x70610400, 0x70650400, 0x61720600, + 0x62720400, 0x636c0400, 0x636f0600, 0x76650400, 0x626f0400, 0x67790400, + 0x65630400, 0x67660400, 0x70790400, 0x73720400, 0x75790400, 0x666b0400 + }; + + /** + * Given a GSM Mobile Country Code, returns a default time zone ID + * if available. Returns null if unavailable. + */ + public static String defaultTimeZoneForMcc(int mcc) { + int index = Arrays.binarySearch(MCC_CODES, (short)mcc); + if (index < 0) { + return null; + } + int indCode = IND_CODES[index]; + int tzInd = (indCode >>> 4) & 0x001F; + String tz = TZ_STRINGS[tzInd]; + if (tz == "") { return null; - } else { - return entry.timezone; } + return tz; } /** - * Given a GSM Mobile Country Code, returns - * an ISO two-character country code if available. - * Returns "" if unavailable. + * Given a GSM Mobile Country Code, returns an ISO two-character + * country code if available. Returns "" if unavailable. */ - public static String - countryCodeForMcc(int mcc) - { - MccEntry entry; - - entry = entryForMcc(mcc); - - if (entry == null) { + public static String countryCodeForMcc(int mcc) { + int index = Arrays.binarySearch(MCC_CODES, (short)mcc); + if (index < 0) { return ""; - } else { - return entry.iso; } + int indCode = IND_CODES[index]; + byte[] iso = {(byte)((indCode >>> 24) & 0x00FF), (byte)((indCode >>> 16) & 0x00FF)}; + return new String(iso); } /** - * Given a GSM Mobile Country Code, returns - * an ISO 2-3 character language code if available. - * Returns null if unavailable. + * Given a GSM Mobile Country Code, returns an ISO 2-3 character + * language code if available. Returns null if unavailable. */ - /* package */ static String defaultLanguageForMcc(int mcc) { - MccEntry entry; - - entry = entryForMcc(mcc); - - if (entry == null) { + public static String defaultLanguageForMcc(int mcc) { + int index = Arrays.binarySearch(MCC_CODES, (short)mcc); + if (index < 0) { return null; - } else { - return entry.language; } + int indCode = IND_CODES[index]; + int langInd = indCode & 0x000F; + String lang = LANG_STRINGS[langInd]; + if (lang == "") { + return null; + } + return lang; } /** - * Given a GSM Mobile Country Code, returns - * the smallest number of digits that M if available. - * Returns "" if unavailable. + * Given a GSM Mobile Country Code, returns the corresponding + * smallest number of digits field. Returns 2 if unavailable. */ - public static int - smallestDigitsMccForMnc(int mcc) - { - MccEntry entry; - - entry = entryForMcc(mcc); - - if (entry == null) { + public static int smallestDigitsMccForMnc(int mcc) { + int index = Arrays.binarySearch(MCC_CODES, (short)mcc); + if (index < 0) { return 2; - } else { - return entry.smallestDigitsMnc; } + int indCode = IND_CODES[index]; + int smDig = (indCode >>> 9) & 0x0003; + return smDig; } - static { - table = new ArrayList<MccEntry>(240); - - - /* - * The table below is built from two resources: - * - * 1) ITU "Mobile Network Code (MNC) for the international - * identification plan for mobile terminals and mobile users" - * which is available as an annex to the ITU operational bulletin - * available here: http://www.itu.int/itu-t/bulletin/annex.html - * - * 2) The ISO 3166 country codes list, available here: - * http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/index.html - * - * This table has not been verified. - * - * FIXME(mkf) this should be stored in a more efficient representation - */ - - table.add(new MccEntry(202,"gr",2)); //Greece - table.add(new MccEntry(204,"nl",2,"Europe/Amsterdam","nl")); //Netherlands (Kingdom of the) - table.add(new MccEntry(206,"be",2)); //Belgium - table.add(new MccEntry(208,"fr",2,"Europe/Paris","fr")); //France - table.add(new MccEntry(212,"mc",2)); //Monaco (Principality of) - table.add(new MccEntry(213,"ad",2)); //Andorra (Principality of) - table.add(new MccEntry(214,"es",2,"Europe/Madrid","es")); //Spain - table.add(new MccEntry(216,"hu",2)); //Hungary (Republic of) - table.add(new MccEntry(218,"ba",2)); //Bosnia and Herzegovina - table.add(new MccEntry(219,"hr",2)); //Croatia (Republic of) - table.add(new MccEntry(220,"rs",2)); //Serbia and Montenegro - table.add(new MccEntry(222,"it",2,"Europe/Rome","it")); //Italy - table.add(new MccEntry(225,"va",2,"Europe/Rome","it")); //Vatican City State - table.add(new MccEntry(226,"ro",2)); //Romania - table.add(new MccEntry(228,"ch",2,"Europe/Zurich","de")); //Switzerland (Confederation of) - table.add(new MccEntry(230,"cz",2,"Europe/Prague","cs")); //Czech Republic - table.add(new MccEntry(231,"sk",2)); //Slovak Republic - table.add(new MccEntry(232,"at",2,"Europe/Vienna","de")); //Austria - table.add(new MccEntry(234,"gb",2,"Europe/London","en")); //United Kingdom of Great Britain and Northern Ireland - table.add(new MccEntry(235,"gb",2,"Europe/London","en")); //United Kingdom of Great Britain and Northern Ireland - table.add(new MccEntry(238,"dk",2)); //Denmark - table.add(new MccEntry(240,"se",2)); //Sweden - table.add(new MccEntry(242,"no",2)); //Norway - table.add(new MccEntry(244,"fi",2)); //Finland - table.add(new MccEntry(246,"lt",2)); //Lithuania (Republic of) - table.add(new MccEntry(247,"lv",2)); //Latvia (Republic of) - table.add(new MccEntry(248,"ee",2)); //Estonia (Republic of) - table.add(new MccEntry(250,"ru",2)); //Russian Federation - table.add(new MccEntry(255,"ua",2)); //Ukraine - table.add(new MccEntry(257,"by",2)); //Belarus (Republic of) - table.add(new MccEntry(259,"md",2)); //Moldova (Republic of) - table.add(new MccEntry(260,"pl",2,"Europe/Warsaw")); //Poland (Republic of) - table.add(new MccEntry(262,"de",2,"Europe/Berlin","de")); //Germany (Federal Republic of) - table.add(new MccEntry(266,"gi",2)); //Gibraltar - table.add(new MccEntry(268,"pt",2)); //Portugal - table.add(new MccEntry(270,"lu",2)); //Luxembourg - table.add(new MccEntry(272,"ie",2,"Europe/Dublin","en")); //Ireland - table.add(new MccEntry(274,"is",2)); //Iceland - table.add(new MccEntry(276,"al",2)); //Albania (Republic of) - table.add(new MccEntry(278,"mt",2)); //Malta - table.add(new MccEntry(280,"cy",2)); //Cyprus (Republic of) - table.add(new MccEntry(282,"ge",2)); //Georgia - table.add(new MccEntry(283,"am",2)); //Armenia (Republic of) - table.add(new MccEntry(284,"bg",2)); //Bulgaria (Republic of) - table.add(new MccEntry(286,"tr",2)); //Turkey - table.add(new MccEntry(288,"fo",2)); //Faroe Islands - table.add(new MccEntry(290,"gl",2)); //Greenland (Denmark) - table.add(new MccEntry(292,"sm",2)); //San Marino (Republic of) - table.add(new MccEntry(293,"sl",2)); //Slovenia (Republic of) - table.add(new MccEntry(294,"mk",2)); //The Former Yugoslav Republic of Macedonia - table.add(new MccEntry(295,"li",2)); //Liechtenstein (Principality of) - table.add(new MccEntry(302,"ca",2)); //Canada - table.add(new MccEntry(308,"pm",2)); //Saint Pierre and Miquelon (Collectivit territoriale de la Rpublique franaise) - table.add(new MccEntry(310,"us",3,"","en")); //United States of America - table.add(new MccEntry(311,"us",3,"","en")); //United States of America - table.add(new MccEntry(312,"us",3,"","en")); //United States of America - table.add(new MccEntry(313,"us",3,"","en")); //United States of America - table.add(new MccEntry(314,"us",3,"","en")); //United States of America - table.add(new MccEntry(315,"us",3,"","en")); //United States of America - table.add(new MccEntry(316,"us",3,"","en")); //United States of America - table.add(new MccEntry(330,"pr",2)); //Puerto Rico - table.add(new MccEntry(332,"vi",2)); //United States Virgin Islands - table.add(new MccEntry(334,"mx",3)); //Mexico - table.add(new MccEntry(338,"jm",3)); //Jamaica - table.add(new MccEntry(340,"gp",2)); //Guadeloupe (French Department of) - table.add(new MccEntry(342,"bb",3)); //Barbados - table.add(new MccEntry(344,"ag",3)); //Antigua and Barbuda - table.add(new MccEntry(346,"ky",3)); //Cayman Islands - table.add(new MccEntry(348,"vg",3)); //British Virgin Islands - table.add(new MccEntry(350,"bm",2)); //Bermuda - table.add(new MccEntry(352,"gd",2)); //Grenada - table.add(new MccEntry(354,"ms",2)); //Montserrat - table.add(new MccEntry(356,"kn",2)); //Saint Kitts and Nevis - table.add(new MccEntry(358,"lc",2)); //Saint Lucia - table.add(new MccEntry(360,"vc",2)); //Saint Vincent and the Grenadines - table.add(new MccEntry(362,"nl",2)); //Netherlands Antilles - table.add(new MccEntry(363,"aw",2)); //Aruba - table.add(new MccEntry(364,"bs",2)); //Bahamas (Commonwealth of the) - table.add(new MccEntry(365,"ai",3)); //Anguilla - table.add(new MccEntry(366,"dm",2)); //Dominica (Commonwealth of) - table.add(new MccEntry(368,"cu",2)); //Cuba - table.add(new MccEntry(370,"do",2)); //Dominican Republic - table.add(new MccEntry(372,"ht",2)); //Haiti (Republic of) - table.add(new MccEntry(374,"tt",2)); //Trinidad and Tobago - table.add(new MccEntry(376,"tc",2)); //Turks and Caicos Islands - table.add(new MccEntry(400,"az",2)); //Azerbaijani Republic - table.add(new MccEntry(401,"kz",2)); //Kazakhstan (Republic of) - table.add(new MccEntry(402,"bt",2)); //Bhutan (Kingdom of) - table.add(new MccEntry(404,"in",2)); //India (Republic of) - table.add(new MccEntry(405,"in",2)); //India (Republic of) - table.add(new MccEntry(410,"pk",2)); //Pakistan (Islamic Republic of) - table.add(new MccEntry(412,"af",2)); //Afghanistan - table.add(new MccEntry(413,"lk",2)); //Sri Lanka (Democratic Socialist Republic of) - table.add(new MccEntry(414,"mm",2)); //Myanmar (Union of) - table.add(new MccEntry(415,"lb",2)); //Lebanon - table.add(new MccEntry(416,"jo",2)); //Jordan (Hashemite Kingdom of) - table.add(new MccEntry(417,"sy",2)); //Syrian Arab Republic - table.add(new MccEntry(418,"iq",2)); //Iraq (Republic of) - table.add(new MccEntry(419,"kw",2)); //Kuwait (State of) - table.add(new MccEntry(420,"sa",2)); //Saudi Arabia (Kingdom of) - table.add(new MccEntry(421,"ye",2)); //Yemen (Republic of) - table.add(new MccEntry(422,"om",2)); //Oman (Sultanate of) - table.add(new MccEntry(424,"ae",2)); //United Arab Emirates - table.add(new MccEntry(425,"il",2)); //Israel (State of) - table.add(new MccEntry(426,"bh",2)); //Bahrain (Kingdom of) - table.add(new MccEntry(427,"qa",2)); //Qatar (State of) - table.add(new MccEntry(428,"mn",2)); //Mongolia - table.add(new MccEntry(429,"np",2)); //Nepal - table.add(new MccEntry(430,"ae",2)); //United Arab Emirates - table.add(new MccEntry(431,"ae",2)); //United Arab Emirates - table.add(new MccEntry(432,"ir",2)); //Iran (Islamic Republic of) - table.add(new MccEntry(434,"uz",2)); //Uzbekistan (Republic of) - table.add(new MccEntry(436,"tj",2)); //Tajikistan (Republic of) - table.add(new MccEntry(437,"kg",2)); //Kyrgyz Republic - table.add(new MccEntry(438,"tm",2)); //Turkmenistan - table.add(new MccEntry(440,"jp",2,"Asia/Tokyo","ja")); //Japan - table.add(new MccEntry(441,"jp",2,"Asia/Tokyo","ja")); //Japan - table.add(new MccEntry(450,"kr",2)); //Korea (Republic of) - table.add(new MccEntry(452,"vn",2)); //Viet Nam (Socialist Republic of) - table.add(new MccEntry(454,"hk",2)); //"Hong Kong, China" - table.add(new MccEntry(455,"mo",2)); //"Macao, China" - table.add(new MccEntry(456,"kh",2)); //Cambodia (Kingdom of) - table.add(new MccEntry(457,"la",2)); //Lao People's Democratic Republic - table.add(new MccEntry(460,"cn",2)); //China (People's Republic of) - table.add(new MccEntry(461,"cn",2)); //China (People's Republic of) - table.add(new MccEntry(466,"tw",2)); //"Taiwan, China" - table.add(new MccEntry(467,"kp",2)); //Democratic People's Republic of Korea - table.add(new MccEntry(470,"bd",2)); //Bangladesh (People's Republic of) - table.add(new MccEntry(472,"mv",2)); //Maldives (Republic of) - table.add(new MccEntry(502,"my",2)); //Malaysia - table.add(new MccEntry(505,"au",2,"Australia/Sydney","en")); //Australia - table.add(new MccEntry(510,"id",2)); //Indonesia (Republic of) - table.add(new MccEntry(514,"tl",2)); //Democratic Republic of Timor-Leste - table.add(new MccEntry(515,"ph",2)); //Philippines (Republic of the) - table.add(new MccEntry(520,"th",2)); //Thailand - table.add(new MccEntry(525,"sg",2,"Singapore","en")); //Singapore (Republic of) - table.add(new MccEntry(528,"bn",2)); //Brunei Darussalam - table.add(new MccEntry(530,"nz",2,"Pacific/Auckland", "en")); //New Zealand - table.add(new MccEntry(534,"mp",2)); //Northern Mariana Islands (Commonwealth of the) - table.add(new MccEntry(535,"gu",2)); //Guam - table.add(new MccEntry(536,"nr",2)); //Nauru (Republic of) - table.add(new MccEntry(537,"pg",2)); //Papua New Guinea - table.add(new MccEntry(539,"to",2)); //Tonga (Kingdom of) - table.add(new MccEntry(540,"sb",2)); //Solomon Islands - table.add(new MccEntry(541,"vu",2)); //Vanuatu (Republic of) - table.add(new MccEntry(542,"fj",2)); //Fiji (Republic of) - table.add(new MccEntry(543,"wf",2)); //Wallis and Futuna (Territoire franais d'outre-mer) - table.add(new MccEntry(544,"as",2)); //American Samoa - table.add(new MccEntry(545,"ki",2)); //Kiribati (Republic of) - table.add(new MccEntry(546,"nc",2)); //New Caledonia (Territoire franais d'outre-mer) - table.add(new MccEntry(547,"pf",2)); //French Polynesia (Territoire franais d'outre-mer) - table.add(new MccEntry(548,"ck",2)); //Cook Islands - table.add(new MccEntry(549,"ws",2)); //Samoa (Independent State of) - table.add(new MccEntry(550,"fm",2)); //Micronesia (Federated States of) - table.add(new MccEntry(551,"mh",2)); //Marshall Islands (Republic of the) - table.add(new MccEntry(552,"pw",2)); //Palau (Republic of) - table.add(new MccEntry(602,"eg",2)); //Egypt (Arab Republic of) - table.add(new MccEntry(603,"dz",2)); //Algeria (People's Democratic Republic of) - table.add(new MccEntry(604,"ma",2)); //Morocco (Kingdom of) - table.add(new MccEntry(605,"tn",2)); //Tunisia - table.add(new MccEntry(606,"ly",2)); //Libya (Socialist People's Libyan Arab Jamahiriya) - table.add(new MccEntry(607,"gm",2)); //Gambia (Republic of the) - table.add(new MccEntry(608,"sn",2)); //Senegal (Republic of) - table.add(new MccEntry(609,"mr",2)); //Mauritania (Islamic Republic of) - table.add(new MccEntry(610,"ml",2)); //Mali (Republic of) - table.add(new MccEntry(611,"gn",2)); //Guinea (Republic of) - table.add(new MccEntry(612,"ci",2)); //Cte d'Ivoire (Republic of) - table.add(new MccEntry(613,"bf",2)); //Burkina Faso - table.add(new MccEntry(614,"ne",2)); //Niger (Republic of the) - table.add(new MccEntry(615,"tg",2)); //Togolese Republic - table.add(new MccEntry(616,"bj",2)); //Benin (Republic of) - table.add(new MccEntry(617,"mu",2)); //Mauritius (Republic of) - table.add(new MccEntry(618,"lr",2)); //Liberia (Republic of) - table.add(new MccEntry(619,"sl",2)); //Sierra Leone - table.add(new MccEntry(620,"gh",2)); //Ghana - table.add(new MccEntry(621,"ng",2)); //Nigeria (Federal Republic of) - table.add(new MccEntry(622,"td",2)); //Chad (Republic of) - table.add(new MccEntry(623,"cf",2)); //Central African Republic - table.add(new MccEntry(624,"cm",2)); //Cameroon (Republic of) - table.add(new MccEntry(625,"cv",2)); //Cape Verde (Republic of) - table.add(new MccEntry(626,"st",2)); //Sao Tome and Principe (Democratic Republic of) - table.add(new MccEntry(627,"gq",2)); //Equatorial Guinea (Republic of) - table.add(new MccEntry(628,"ga",2)); //Gabonese Republic - table.add(new MccEntry(629,"cg",2)); //Congo (Republic of the) - table.add(new MccEntry(630,"cg",2)); //Democratic Republic of the Congo - table.add(new MccEntry(631,"ao",2)); //Angola (Republic of) - table.add(new MccEntry(632,"gw",2)); //Guinea-Bissau (Republic of) - table.add(new MccEntry(633,"sc",2)); //Seychelles (Republic of) - table.add(new MccEntry(634,"sd",2)); //Sudan (Republic of the) - table.add(new MccEntry(635,"rw",2)); //Rwanda (Republic of) - table.add(new MccEntry(636,"et",2)); //Ethiopia (Federal Democratic Republic of) - table.add(new MccEntry(637,"so",2)); //Somali Democratic Republic - table.add(new MccEntry(638,"dj",2)); //Djibouti (Republic of) - table.add(new MccEntry(639,"ke",2)); //Kenya (Republic of) - table.add(new MccEntry(640,"tz",2)); //Tanzania (United Republic of) - table.add(new MccEntry(641,"ug",2)); //Uganda (Republic of) - table.add(new MccEntry(642,"bi",2)); //Burundi (Republic of) - table.add(new MccEntry(643,"mz",2)); //Mozambique (Republic of) - table.add(new MccEntry(645,"zm",2)); //Zambia (Republic of) - table.add(new MccEntry(646,"mg",2)); //Madagascar (Republic of) - table.add(new MccEntry(647,"re",2)); //Reunion (French Department of) - table.add(new MccEntry(648,"zw",2)); //Zimbabwe (Republic of) - table.add(new MccEntry(649,"na",2)); //Namibia (Republic of) - table.add(new MccEntry(650,"mw",2)); //Malawi - table.add(new MccEntry(651,"ls",2)); //Lesotho (Kingdom of) - table.add(new MccEntry(652,"bw",2)); //Botswana (Republic of) - table.add(new MccEntry(653,"sz",2)); //Swaziland (Kingdom of) - table.add(new MccEntry(654,"km",2)); //Comoros (Union of the) - table.add(new MccEntry(655,"za",2,"Africa/Johannesburg","en")); //South Africa (Republic of) - table.add(new MccEntry(657,"er",2)); //Eritrea - table.add(new MccEntry(702,"bz",2)); //Belize - table.add(new MccEntry(704,"gt",2)); //Guatemala (Republic of) - table.add(new MccEntry(706,"sv",2)); //El Salvador (Republic of) - table.add(new MccEntry(708,"hn",3)); //Honduras (Republic of) - table.add(new MccEntry(710,"ni",2)); //Nicaragua - table.add(new MccEntry(712,"cr",2)); //Costa Rica - table.add(new MccEntry(714,"pa",2)); //Panama (Republic of) - table.add(new MccEntry(716,"pe",2)); //Peru - table.add(new MccEntry(722,"ar",3)); //Argentine Republic - table.add(new MccEntry(724,"br",2)); //Brazil (Federative Republic of) - table.add(new MccEntry(730,"cl",2)); //Chile - table.add(new MccEntry(732,"co",3)); //Colombia (Republic of) - table.add(new MccEntry(734,"ve",2)); //Venezuela (Bolivarian Republic of) - table.add(new MccEntry(736,"bo",2)); //Bolivia (Republic of) - table.add(new MccEntry(738,"gy",2)); //Guyana - table.add(new MccEntry(740,"ec",2)); //Ecuador - table.add(new MccEntry(742,"gf",2)); //French Guiana (French Department of) - table.add(new MccEntry(744,"py",2)); //Paraguay (Republic of) - table.add(new MccEntry(746,"sr",2)); //Suriname (Republic of) - table.add(new MccEntry(748,"uy",2)); //Uruguay (Eastern Republic of) - table.add(new MccEntry(750,"fk",2)); //Falkland Islands (Malvinas) - //table.add(new MccEntry(901,"",2)); //"International Mobile, shared code" - - Collections.sort(table); + /** + * Given a GSM Mobile Country Code, returns the number of wifi + * channels allowed in that country. Returns 0 if unavailable. + */ + public static int wifiChannelsForMcc(int mcc) { + int index = Arrays.binarySearch(MCC_CODES, (short)mcc); + if (index < 0) { + return 0; + } + int indCode = IND_CODES[index]; + int wifi = (indCode >>> 11) & 0x000F; + return wifi; } + } diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java index 89de867..224419e 100644 --- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java @@ -84,9 +84,13 @@ public class PdpConnection extends DataConnection { lastFailCause = FailCause.NONE; receivedDisconnectReq = false; - phone.mCM.setupDataCall(Integer.toString(RILConstants.GSM_PHONE), + int authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP : + RILConstants.SETUP_DATA_AUTH_NONE; + + phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_GSM), Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), apn.apn, apn.user, - apn.password, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE)); + apn.password, Integer.toString(authType), + obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE)); } private void tearDownData(Message msg) { diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java index e25de81..4272faa 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java +++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java @@ -16,39 +16,29 @@ package com.android.internal.telephony.gsm; -import android.app.ActivityManagerNative; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; import android.app.AlarmManager; -import android.app.IActivityManager; import android.content.Context; -import android.content.res.Configuration; +import android.net.wifi.WifiManager; import android.os.AsyncResult; -import android.os.Handler; import android.os.Message; import android.os.SystemProperties; -import android.os.Registrant; +import android.provider.Settings; import android.util.Log; -import java.util.ArrayList; - - -import static com.android.internal.telephony.TelephonyProperties.*; import com.android.internal.telephony.AdnRecord; import com.android.internal.telephony.AdnRecordCache; import com.android.internal.telephony.AdnRecordLoader; import com.android.internal.telephony.CommandsInterface; -import com.android.internal.telephony.gsm.SimCard; -import com.android.internal.telephony.gsm.SmsMessage; import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccRecords; import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.IccVmFixedException; import com.android.internal.telephony.IccVmNotSupportedException; -import com.android.internal.telephony.PhoneProxy; - - - - +import java.util.ArrayList; /** @@ -512,6 +502,29 @@ public final class SIMRecords extends IccRecords { phone.setSystemLocale(language, country); } + /** + * If the number of allowed wifi channels has not been set, set it based on + * the MCC of the SIM. + * @param mcc Mobile Country Code of the SIM + */ + private void setWifiChannelsFromMccIfNeeded(int mcc) { + int wifiChannels = MccTable.wifiChannelsForMcc(mcc); + + if (wifiChannels != 0) { + Context context = phone.getContext(); + // only set to this default if the user hasn't manually set it + try { + Settings.Secure.getInt(context.getContentResolver(), + Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS); + } catch (Settings.SettingNotFoundException e) { + WifiManager wM = (WifiManager) + context.getSystemService(Context.WIFI_SERVICE); + // don't persist + wM.setNumAllowedChannels(wifiChannels, false); + } + } + } + //***** Overridden from Handler public void handleMessage(Message msg) { AsyncResult ar; @@ -552,12 +565,13 @@ public final class SIMRecords extends IccRecords { Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxxxx"); ((GSMPhone) phone).mSimCard.updateImsiConfiguration(imsi); - ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( + ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent( SimCard.INTENT_VALUE_ICC_IMSI, null); int mcc = Integer.parseInt(imsi.substring(0, 3)); setTimezoneFromMccIfNeeded(mcc); setLocaleFromMccIfNeeded(mcc); + setWifiChannelsFromMccIfNeeded(mcc); break; case EVENT_GET_MBI_DONE: @@ -1178,7 +1192,7 @@ public final class SIMRecords extends IccRecords { recordsLoadedRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); - ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( + ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent( SimCard.INTENT_VALUE_ICC_LOADED, null); } @@ -1203,7 +1217,7 @@ public final class SIMRecords extends IccRecords { /* broadcast intent SIM_READY here so that we can make sure READY is sent before IMSI ready */ - ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( + ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent( SimCard.INTENT_VALUE_ICC_READY, null); fetchSimRecords(); diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java index 9af3aa6..6c56682 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java @@ -17,469 +17,37 @@ package com.android.internal.telephony.gsm; import android.app.ActivityManagerNative; -import android.content.Intent; import android.content.res.Configuration; -import android.os.AsyncResult; import android.os.RemoteException; -import android.os.Handler; -import android.os.Message; -import android.os.Registrant; -import android.os.RegistrantList; import android.util.Log; -import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.PhoneProxy; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.TelephonyProperties; - -import static android.Manifest.permission.READ_PHONE_STATE; /** - * Note: this class shares common code with RuimCard, consider a base class to minimize code - * duplication. * {@hide} */ -public final class SimCard extends Handler implements IccCard { - static final String LOG_TAG="GSM"; - - //***** Instance Variables - private static final boolean DBG = true; - - private GSMPhone phone; - private CommandsInterface.IccStatus status = null; - private boolean mDesiredPinLocked; - private boolean mDesiredFdnEnabled; - private boolean mSimPinLocked = true; // Default to locked - private boolean mSimFdnEnabled = false; // Default to disabled. - // Will be updated when SIM_READY. - - //***** Constants - - // FIXME I hope this doesn't conflict with the Dialer's notifications - static final int NOTIFICATION_ID_SIM_STATUS = 33456; - - //***** Event Constants - - static final int EVENT_SIM_LOCKED_OR_ABSENT = 1; - static final int EVENT_GET_SIM_STATUS_DONE = 2; - static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3; - static final int EVENT_PINPUK_DONE = 4; - static final int EVENT_REPOLL_STATUS_DONE = 5; - static final int EVENT_SIM_READY = 6; - static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7; - static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8; - static final int EVENT_CHANGE_SIM_PASSWORD_DONE = 9; - static final int EVENT_QUERY_FACILITY_FDN_DONE = 10; - static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11; - - - //***** Constructor +public final class SimCard extends IccCard { SimCard(GSMPhone phone) { - this.phone = phone; - - phone.mCM.registerForSIMLockedOrAbsent( - this, EVENT_SIM_LOCKED_OR_ABSENT, null); - - phone.mCM.registerForOffOrNotAvailable( - this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - - phone.mCM.registerForSIMReady( - this, EVENT_SIM_READY, null); + super(phone, "GSM", true); + mPhone.mCM.registerForSIMLockedOrAbsent(mHandler, EVENT_ICC_LOCKED_OR_ABSENT, null); + mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + mPhone.mCM.registerForSIMReady(mHandler, EVENT_ICC_READY, null); updateStateProperty(); } + @Override public void dispose() { //Unregister for all events - phone.mCM.unregisterForSIMLockedOrAbsent(this); - phone.mCM.unregisterForOffOrNotAvailable(this); - phone.mCM.unregisterForSIMReady(this); - } - - protected void finalize() { - if(DBG) Log.d(LOG_TAG, "SimCard finalized"); - } - - //***** SimCard implementation - - public State - getState() { - if (status == null) { - switch(phone.mCM.getRadioState()) { - /* This switch block must not return anything in - * State.isLocked() or State.ABSENT. - * If it does, handleSimStatus() may break - */ - case RADIO_OFF: - case RADIO_UNAVAILABLE: - case SIM_NOT_READY: - return State.UNKNOWN; - case SIM_LOCKED_OR_ABSENT: - //this should be transient-only - return State.UNKNOWN; - case SIM_READY: - return State.READY; - } - } else { - switch (status) { - case ICC_ABSENT: return State.ABSENT; - case ICC_NOT_READY: return State.UNKNOWN; - case ICC_READY: return State.READY; - case ICC_PIN: return State.PIN_REQUIRED; - case ICC_PUK: return State.PUK_REQUIRED; - case ICC_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED; - } - } - - Log.e(LOG_TAG, "GsmSimCard.getState(): case should never be reached"); - return State.UNKNOWN; - } - - private RegistrantList absentRegistrants = new RegistrantList(); - private RegistrantList pinLockedRegistrants = new RegistrantList(); - private RegistrantList networkLockedRegistrants = new RegistrantList(); - - - public void registerForAbsent(Handler h, int what, Object obj) { - Registrant r = new Registrant (h, what, obj); - - absentRegistrants.add(r); - - if (getState() == State.ABSENT) { - r.notifyRegistrant(); - } - } - - public void unregisterForAbsent(Handler h) { - absentRegistrants.remove(h); - } - - public void registerForNetworkLocked(Handler h, int what, Object obj) { - Registrant r = new Registrant (h, what, obj); - - networkLockedRegistrants.add(r); - - if (getState() == State.NETWORK_LOCKED) { - r.notifyRegistrant(); - } - } - - public void unregisterForNetworkLocked(Handler h) { - networkLockedRegistrants.remove(h); - } - - public void registerForLocked(Handler h, int what, Object obj) { - Registrant r = new Registrant (h, what, obj); - - pinLockedRegistrants.add(r); - - if (getState().isPinLocked()) { - r.notifyRegistrant(); - } - } - - public void unregisterForLocked(Handler h) { - pinLockedRegistrants.remove(h); - } - - - public void supplyPin (String pin, Message onComplete) { - phone.mCM.supplyIccPin(pin, - obtainMessage(EVENT_PINPUK_DONE, onComplete)); - } - - public void supplyPuk (String puk, String newPin, Message onComplete) { - phone.mCM.supplyIccPuk(puk, newPin, - obtainMessage(EVENT_PINPUK_DONE, onComplete)); - } - public void supplyPin2 (String pin2, Message onComplete) { - phone.mCM.supplyIccPin2(pin2, - obtainMessage(EVENT_PINPUK_DONE, onComplete)); - } - public void supplyPuk2 (String puk2, String newPin2, Message onComplete) { - phone.mCM.supplyIccPuk2(puk2, newPin2, - obtainMessage(EVENT_PINPUK_DONE, onComplete)); - } - - public void supplyNetworkDepersonalization (String pin, Message onComplete) { - if(DBG) log("Network Despersonalization: " + pin); - phone.mCM.supplyNetworkDepersonalization(pin, - obtainMessage(EVENT_PINPUK_DONE, onComplete)); - } - - public boolean getIccLockEnabled() { - return mSimPinLocked; - } - - public boolean getIccFdnEnabled() { - return mSimFdnEnabled; + mPhone.mCM.unregisterForSIMLockedOrAbsent(mHandler); + mPhone.mCM.unregisterForOffOrNotAvailable(mHandler); + mPhone.mCM.unregisterForSIMReady(mHandler); } - public void setIccLockEnabled (boolean enabled, - String password, Message onComplete) { - int serviceClassX; - serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + - CommandsInterface.SERVICE_CLASS_DATA + - CommandsInterface.SERVICE_CLASS_FAX; - - mDesiredPinLocked = enabled; - - phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM, - enabled, password, serviceClassX, - obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete)); - } - - public void setIccFdnEnabled (boolean enabled, - String password, Message onComplete) { - int serviceClassX; - serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + - CommandsInterface.SERVICE_CLASS_DATA + - CommandsInterface.SERVICE_CLASS_FAX + - CommandsInterface.SERVICE_CLASS_SMS; - - mDesiredFdnEnabled = enabled; - - phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD, - enabled, password, serviceClassX, - obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete)); - } - - public void changeIccLockPassword(String oldPassword, String newPassword, - Message onComplete) { - if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword); - phone.mCM.changeIccPin(oldPassword, newPassword, - obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete)); - - } - - public void changeIccFdnPassword(String oldPassword, String newPassword, - Message onComplete) { - if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword); - phone.mCM.changeIccPin2(oldPassword, newPassword, - obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete)); - - } - - public String getServiceProviderName () { - return phone.mSIMRecords.getServiceProviderName(); - } - - //***** Handler implementation @Override - public void handleMessage(Message msg){ - AsyncResult ar; - int serviceClassX; - - serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE + - CommandsInterface.SERVICE_CLASS_DATA + - CommandsInterface.SERVICE_CLASS_FAX; - - switch (msg.what) { - case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: - status = null; - updateStateProperty(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_NOT_READY, null); - break; - case EVENT_SIM_READY: - //TODO: put facility read in SIM_READY now, maybe in REG_NW - phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE)); - phone.mCM.queryFacilityLock ( - CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, - obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); - phone.mCM.queryFacilityLock ( - CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX, - obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE)); - break; - case EVENT_SIM_LOCKED_OR_ABSENT: - phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE)); - phone.mCM.queryFacilityLock ( - CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, - obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); - break; - case EVENT_GET_SIM_STATUS_DONE: - ar = (AsyncResult)msg.obj; - - getSimStatusDone(ar); - break; - case EVENT_PINPUK_DONE: - // a PIN/PUK/PIN2/PUK2/Network Personalization - // request has completed. ar.userObj is the response Message - // Repoll before returning - ar = (AsyncResult)msg.obj; - // TODO should abstract these exceptions - AsyncResult.forMessage(((Message)ar.userObj)).exception - = ar.exception; - phone.mCM.getIccStatus( - obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj)); - break; - case EVENT_REPOLL_STATUS_DONE: - // Finished repolling status after PIN operation - // ar.userObj is the response messaeg - // ar.userObj.obj is already an AsyncResult with an - // appropriate exception filled in if applicable - - ar = (AsyncResult)msg.obj; - getSimStatusDone(ar); - ((Message)ar.userObj).sendToTarget(); - break; - case EVENT_QUERY_FACILITY_LOCK_DONE: - ar = (AsyncResult)msg.obj; - onQueryFacilityLock(ar); - break; - case EVENT_QUERY_FACILITY_FDN_DONE: - ar = (AsyncResult)msg.obj; - onQueryFdnEnabled(ar); - break; - case EVENT_CHANGE_FACILITY_LOCK_DONE: - ar = (AsyncResult)msg.obj; - if (ar.exception == null) { - mSimPinLocked = mDesiredPinLocked; - if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " + - "mSimPinLocked= " + mSimPinLocked); - } else { - Log.e(LOG_TAG, "Error change facility lock with exception " - + ar.exception); - } - AsyncResult.forMessage(((Message)ar.userObj)).exception - = ar.exception; - ((Message)ar.userObj).sendToTarget(); - break; - case EVENT_CHANGE_FACILITY_FDN_DONE: - ar = (AsyncResult)msg.obj; - - if (ar.exception == null) { - mSimFdnEnabled = mDesiredFdnEnabled; - if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " + - "mSimFdnEnabled=" + mSimFdnEnabled); - } else { - Log.e(LOG_TAG, "Error change facility fdn with exception " - + ar.exception); - } - AsyncResult.forMessage(((Message)ar.userObj)).exception - = ar.exception; - ((Message)ar.userObj).sendToTarget(); - break; - case EVENT_CHANGE_SIM_PASSWORD_DONE: - ar = (AsyncResult)msg.obj; - if(ar.exception != null) { - Log.e(LOG_TAG, "Error in change sim password with exception" - + ar.exception); - } - AsyncResult.forMessage(((Message)ar.userObj)).exception - = ar.exception; - ((Message)ar.userObj).sendToTarget(); - break; - default: - Log.e(LOG_TAG, "[GsmSimCard] Unknown Event " + msg.what); - } - } - - - //***** Private methods - - /** - * Interperate EVENT_QUERY_FACILITY_LOCK_DONE - * @param ar is asyncResult of Query_Facility_Locked - */ - private void onQueryFacilityLock(AsyncResult ar) { - if(ar.exception != null) { - if (DBG) log("Error in querying facility lock:" + ar.exception); - return; - } - - int[] ints = (int[])ar.result; - if(ints.length != 0) { - mSimPinLocked = (0!=ints[0]); - if(DBG) log("Query facility lock : " + mSimPinLocked); - } else { - Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response"); - } - } - - /** - * Interperate EVENT_QUERY_FACILITY_LOCK_DONE - * @param ar is asyncResult of Query_Facility_Locked - */ - private void onQueryFdnEnabled(AsyncResult ar) { - if(ar.exception != null) { - if(DBG) log("Error in querying facility lock:" + ar.exception); - return; - } - - int[] ints = (int[])ar.result; - if(ints.length != 0) { - mSimFdnEnabled = (0!=ints[0]); - if(DBG) log("Query facility lock : " + mSimFdnEnabled); - } else { - Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response"); - } - } - - private void - getSimStatusDone(AsyncResult ar) { - if (ar.exception != null) { - Log.e(LOG_TAG,"Error getting ICC status. " - + "RIL_REQUEST_GET_ICC_STATUS should " - + "never return an error", ar.exception); - return; - } - - CommandsInterface.IccStatus newStatus - = (CommandsInterface.IccStatus) ar.result; - - handleSimStatus(newStatus); - } - - private void - handleSimStatus(CommandsInterface.IccStatus newStatus) { - boolean transitionedIntoPinLocked; - boolean transitionedIntoAbsent; - boolean transitionedIntoNetworkLocked; - - SimCard.State oldState, newState; - - oldState = getState(); - status = newStatus; - newState = getState(); - - updateStateProperty(); - - transitionedIntoPinLocked = ( - (oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED) - || (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED)); - transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT); - transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED - && newState == State.NETWORK_LOCKED); - - if (transitionedIntoPinLocked) { - if(DBG) log("Notify SIM pin or puk locked."); - pinLockedRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED, - (newState == State.PIN_REQUIRED) ? - INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK); - } else if (transitionedIntoAbsent) { - if(DBG) log("Notify SIM missing."); - absentRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_ABSENT, null); - } else if (transitionedIntoNetworkLocked) { - if(DBG) log("Notify SIM network locked."); - networkLockedRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED, - INTENT_VALUE_LOCKED_NETWORK); - } - } - - public void broadcastSimStateChangedIntent(String value, String reason) { - Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); - intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName()); - intent.putExtra(SimCard.INTENT_KEY_ICC_STATE, value); - intent.putExtra(SimCard.INTENT_KEY_LOCKED_REASON, reason); - if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " + value - + " reason " + reason); - ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE); + public String getServiceProviderName () { + return ((GSMPhone)mPhone).mSIMRecords.getServiceProviderName(); } public void updateImsiConfiguration(String imsi) { @@ -494,19 +62,8 @@ public final class SimCard extends Handler implements IccCard { try { ActivityManagerNative.getDefault().updateConfiguration(config); } catch (RemoteException e) { + Log.e(mLogTag, "[SimCard] Remote Exception when updating imsi configuration"); } } } - - private void - updateStateProperty() { - phone.setSystemProperty( - TelephonyProperties.PROPERTY_SIM_STATE, - getState().toString()); - } - - private void log(String msg) { - Log.d(LOG_TAG, "[GsmSimCard] " + msg); - } } - diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java index af59126..93721ff 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java @@ -519,12 +519,12 @@ public class SmsMessage extends SmsMessageBase{ long getSCTimestampMillis() { // TP-Service-Centre-Time-Stamp - int year = IccUtils.bcdByteToInt(pdu[cur++]); - int month = IccUtils.bcdByteToInt(pdu[cur++]); - int day = IccUtils.bcdByteToInt(pdu[cur++]); - int hour = IccUtils.bcdByteToInt(pdu[cur++]); - int minute = IccUtils.bcdByteToInt(pdu[cur++]); - int second = IccUtils.bcdByteToInt(pdu[cur++]); + int year = IccUtils.gsmBcdByteToInt(pdu[cur++]); + int month = IccUtils.gsmBcdByteToInt(pdu[cur++]); + int day = IccUtils.gsmBcdByteToInt(pdu[cur++]); + int hour = IccUtils.gsmBcdByteToInt(pdu[cur++]); + int minute = IccUtils.gsmBcdByteToInt(pdu[cur++]); + int second = IccUtils.gsmBcdByteToInt(pdu[cur++]); // For the timezone, the most significant bit of the // least signficant nibble is the sign byte @@ -534,11 +534,9 @@ public class SmsMessage extends SmsMessageBase{ byte tzByte = pdu[cur++]; // Mask out sign bit. - int timezoneOffset = IccUtils - .bcdByteToInt((byte) (tzByte & (~0x08))); + int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08))); - timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset - : -timezoneOffset; + timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset; Time time = new Time(Time.TIMEZONE_UTC); diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java index f71ea48..11b3fd6 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java @@ -27,10 +27,11 @@ import com.android.internal.telephony.BaseCommands; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.DataCallState; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.Phone; import com.android.internal.telephony.gsm.CallFailCause; import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; import com.android.internal.telephony.gsm.SuppServiceNotification; -import com.android.internal.telephony.Phone; import java.util.ArrayList; @@ -103,39 +104,8 @@ public final class SimulatedCommands extends BaseCommands //***** CommandsInterface implementation - public void getIccStatus(Message result) { - switch (mState) { - case SIM_READY: - resultSuccess(result, IccStatus.ICC_READY); - break; - - case SIM_LOCKED_OR_ABSENT: - returnSimLockedStatus(result); - break; - - default: - resultSuccess(result, IccStatus.ICC_NOT_READY); - break; - } - } - - private void returnSimLockedStatus(Message result) { - switch (mSimLockedState) { - case REQUIRE_PIN: - Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PIN"); - resultSuccess(result, IccStatus.ICC_PIN); - break; - - case REQUIRE_PUK: - Log.i(LOG_TAG, "[SimCmd] returnSimLockedStatus: ICC_PUK"); - resultSuccess(result, IccStatus.ICC_PUK); - break; - - default: - Log.i(LOG_TAG, - "[SimCmd] returnSimLockedStatus: mSimLockedState==NONE !?"); - break; - } + public void getIccCardStatus(Message result) { + unimplemented(result); } public void supplyIccPin(String pin, Message result) { @@ -974,7 +944,7 @@ public final class SimulatedCommands extends BaseCommands } public void setupDataCall(String radioTechnology, String profile, String apn, String user, - String password, Message result) { + String password, String authType, Message result) { unimplemented(result); } |