diff options
Diffstat (limited to 'telephony/java')
51 files changed, 2377 insertions, 1767 deletions
diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java index 2f7666d..0f9a3b9 100644 --- a/telephony/java/android/telephony/NeighboringCellInfo.java +++ b/telephony/java/android/telephony/NeighboringCellInfo.java @@ -127,7 +127,7 @@ public class NeighboringCellInfo implements Parcelable location = "0" + location; } } - + // TODO - handle LTE and eHRPD (or find they can't be supported) try {// set LAC/CID or PSC based on radioType switch (radioType) { case NETWORK_TYPE_GPRS: diff --git a/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java b/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java index 8a47339..ffabb7b 100644 --- a/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java +++ b/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java @@ -16,83 +16,200 @@ package android.telephony; +import com.google.i18n.phonenumbers.AsYouTypeFormatter; +import com.google.i18n.phonenumbers.PhoneNumberUtil; + +import android.telephony.PhoneNumberUtils; import android.text.Editable; import android.text.Selection; import android.text.TextWatcher; -import android.widget.TextView; import java.util.Locale; /** - * Watches a {@link TextView} and if a phone number is entered will format it using - * {@link PhoneNumberUtils#formatNumber(Editable, int)}. The formatting is based on - * the current system locale when this object is created and future locale changes - * may not take effect on this instance. + * Watches a {@link android.widget.TextView} and if a phone number is entered + * will format it. + * <p> + * Stop formatting when the user + * <ul> + * <li>Inputs non-dialable characters</li> + * <li>Removes the separator in the middle of string.</li> + * </ul> + * <p> + * The formatting will be restarted once the text is cleared. */ public class PhoneNumberFormattingTextWatcher implements TextWatcher { + /** + * One or more characters were removed from the end. + */ + private final static int STATE_REMOVE_LAST = 0; + + /** + * One or more characters were appended. + */ + private final static int STATE_APPEND = 1; + + /** + * One or more digits were changed in the beginning or the middle of text. + */ + private final static int STATE_MODIFY_DIGITS = 2; + + /** + * The changes other than the above. + */ + private final static int STATE_OTHER = 3; - static private int sFormatType; - static private Locale sCachedLocale; - private boolean mFormatting; - private boolean mDeletingHyphen; - private int mHyphenStart; - private boolean mDeletingBackward; + /** + * The state of this change could be one value of the above + */ + private int mState; + /** + * Indicates the change was caused by ourselves. + */ + private boolean mSelfChange = false; + + /** + * Indicates the formatting has been stopped. + */ + private boolean mStopFormatting; + + private AsYouTypeFormatter mFormatter; + + /** + * The formatting is based on the current system locale and future locale changes + * may not take effect on this instance. + */ public PhoneNumberFormattingTextWatcher() { - if (sCachedLocale == null || sCachedLocale != Locale.getDefault()) { - sCachedLocale = Locale.getDefault(); - sFormatType = PhoneNumberUtils.getFormatTypeForLocale(sCachedLocale); + this(Locale.getDefault().getCountry()); + } + + /** + * The formatting is based on the given <code>countryCode</code>. + * + * @param countryCode the ISO 3166-1 two-letter country code that indicates the country/region + * where the phone number is being entered. + * + * @hide + */ + public PhoneNumberFormattingTextWatcher(String countryCode) { + if (countryCode == null) throw new IllegalArgumentException(); + mFormatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(countryCode); + } + + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + if (mSelfChange || mStopFormatting) { + return; + } + if (count == 0 && s.length() == start) { + // Append one or more new chars + mState = STATE_APPEND; + } else if (after == 0 && start + count == s.length() && count > 0) { + // Remove one or more chars from the end of string. + mState = STATE_REMOVE_LAST; + } else if (count > 0 && !hasSeparator(s, start, count)) { + // Remove the dialable chars in the begin or middle of text. + mState = STATE_MODIFY_DIGITS; + } else { + mState = STATE_OTHER; } } - public synchronized void afterTextChanged(Editable text) { - // Make sure to ignore calls to afterTextChanged caused by the work done below - if (!mFormatting) { - mFormatting = true; - - // If deleting the hyphen, also delete the char before or after that - if (mDeletingHyphen && mHyphenStart > 0) { - if (mDeletingBackward) { - if (mHyphenStart - 1 < text.length()) { - text.delete(mHyphenStart - 1, mHyphenStart); - } - } else if (mHyphenStart < text.length()) { - text.delete(mHyphenStart, mHyphenStart + 1); - } + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (mSelfChange || mStopFormatting) { + return; + } + if (mState == STATE_OTHER) { + if (count > 0 && !hasSeparator(s, start, count)) { + // User inserted the dialable characters in the middle of text. + mState = STATE_MODIFY_DIGITS; } + } + // Check whether we should stop formatting. + if (mState == STATE_APPEND && count > 0 && hasSeparator(s, start, count)) { + // User appended the non-dialable character, stop formatting. + stopFormatting(); + } else if (mState == STATE_OTHER) { + // User must insert or remove the non-dialable characters in the begin or middle of + // number, stop formatting. + stopFormatting(); + } + } - PhoneNumberUtils.formatNumber(text, sFormatType); - - mFormatting = false; + public synchronized void afterTextChanged(Editable s) { + if (mStopFormatting) { + // Restart the formatting when all texts were clear. + mStopFormatting = !(s.length() == 0); + return; + } + if (mSelfChange) { + // Ignore the change caused by s.replace(). + return; + } + String formatted = reformat(s, Selection.getSelectionEnd(s)); + if (formatted != null) { + int rememberedPos = mFormatter.getRememberedPosition(); + mSelfChange = true; + s.replace(0, s.length(), formatted, 0, formatted.length()); + // The text could be changed by other TextWatcher after we changed it. If we found the + // text is not the one we were expecting, just give up calling setSelection(). + if (formatted.equals(s.toString())) { + Selection.setSelection(s, rememberedPos); + } + mSelfChange = false; } } - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - // Check if the user is deleting a hyphen - if (!mFormatting) { - // Make sure user is deleting one char, without a selection - final int selStart = Selection.getSelectionStart(s); - final int selEnd = Selection.getSelectionEnd(s); - if (s.length() > 1 // Can delete another character - && count == 1 // Deleting only one character - && after == 0 // Deleting - && s.charAt(start) == '-' // a hyphen - && selStart == selEnd) { // no selection - mDeletingHyphen = true; - mHyphenStart = start; - // Check if the user is deleting forward or backward - if (selStart == start + 1) { - mDeletingBackward = true; - } else { - mDeletingBackward = false; + /** + * Generate the formatted number by ignoring all non-dialable chars and stick the cursor to the + * nearest dialable char to the left. For instance, if the number is (650) 123-45678 and '4' is + * removed then the cursor should be behind '3' instead of '-'. + */ + private String reformat(CharSequence s, int cursor) { + // The index of char to the leftward of the cursor. + int curIndex = cursor - 1; + String formatted = null; + mFormatter.clear(); + char lastNonSeparator = 0; + boolean hasCursor = false; + int len = s.length(); + for (int i = 0; i < len; i++) { + char c = s.charAt(i); + if (PhoneNumberUtils.isNonSeparator(c)) { + if (lastNonSeparator != 0) { + formatted = getFormattedNumber(lastNonSeparator, hasCursor); + hasCursor = false; } - } else { - mDeletingHyphen = false; + lastNonSeparator = c; } + if (i == curIndex) { + hasCursor = true; + } + } + if (lastNonSeparator != 0) { + formatted = getFormattedNumber(lastNonSeparator, hasCursor); } + return formatted; } - public void onTextChanged(CharSequence s, int start, int before, int count) { - // Does nothing + private String getFormattedNumber(char lastNonSeparator, boolean hasCursor) { + return hasCursor ? mFormatter.inputDigitAndRememberPosition(lastNonSeparator) + : mFormatter.inputDigit(lastNonSeparator); + } + + private void stopFormatting() { + mStopFormatting = true; + mFormatter.clear(); + } + + private boolean hasSeparator(final CharSequence s, final int start, final int count) { + for (int i = start; i < start + count; i++) { + char c = s.charAt(i); + if (!PhoneNumberUtils.isNonSeparator(c)) { + return true; + } + } + return false; } } diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index 8e4f6fc..893ae88 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -16,6 +16,11 @@ package android.telephony; +import com.google.i18n.phonenumbers.NumberParseException; +import com.google.i18n.phonenumbers.PhoneNumberUtil; +import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; +import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber; + import android.content.Context; import android.content.Intent; import android.database.Cursor; @@ -617,7 +622,7 @@ public class PhoneNumberUtils } } else { // In the US, 1-650-555-1234 must be equal to 650-555-1234, - // while 090-1234-1234 must not be equalt to 90-1234-1234 in Japan. + // while 090-1234-1234 must not be equal to 90-1234-1234 in Japan. // This request exists just in US (with 1 trunk (NDD) prefix). // In addition, "011 11 7005554141" must not equal to "+17005554141", // while "011 1 7005554141" must equal to "+17005554141" @@ -779,10 +784,10 @@ public class PhoneNumberUtils if (prependPlus) { // This is an "international number" and should have // a plus prepended to the dialing number. But there - // can also be Gsm MMI codes as defined in TS 22.030 6.5.2 + // can also be GSM MMI codes as defined in TS 22.030 6.5.2 // so we need to handle those also. // - // http://web.telia.com/~u47904776/gsmkode.htm is a + // http://web.telia.com/~u47904776/gsmkode.htm // has a nice list of some of these GSM codes. // // Examples are: @@ -870,10 +875,10 @@ public class PhoneNumberUtils // FIXME(mkf) TS 23.040 9.1.2.3 says // "if a mobile receives 1111 in a position prior to - // the last semi-octet then processing shall commense with + // the last semi-octet then processing shall commence with // the next semi-octet and the intervening // semi-octet shall be ignored" - // How does this jive with 24,008 10.5.4.7 + // How does this jive with 24.008 10.5.4.7 b = (byte)((bytes[i] >> 4) & 0xf); @@ -1004,7 +1009,7 @@ public class PhoneNumberUtils * Convert a dialing number to BCD byte array * * @param number dialing number string - * if the dialing number starts with '+', set to internationl TOA + * if the dialing number starts with '+', set to international TOA * @return BCD byte array */ public static byte[] @@ -1108,10 +1113,10 @@ public class PhoneNumberUtils * * @param source the phone number to format * @param defaultFormattingType The default formatting rules to apply if the number does - * not begin with +<country_code> + * not begin with +[country_code] * @return The phone number formatted with the given formatting type. * - * @hide TODO:Shuold be unhidden. + * @hide TODO: Should be unhidden. */ public static String formatNumber(String source, int defaultFormattingType) { SpannableStringBuilder text = new SpannableStringBuilder(source); @@ -1138,7 +1143,7 @@ public class PhoneNumberUtils * * @param text The number to be formatted, will be modified with the formatting * @param defaultFormattingType The default formatting rules to apply if the number does - * not begin with +<country_code> + * not begin with +[country_code] */ public static void formatNumber(Editable text, int defaultFormattingType) { int formatType = defaultFormattingType; @@ -1319,6 +1324,132 @@ public class PhoneNumberUtils } } + /** + * Format the given phoneNumber to the E.164 representation. + * <p> + * The given phone number must have an area code and could have a country + * code. + * <p> + * The defaultCountryIso is used to validate the given number and generate + * the E.164 phone number if the given number doesn't have a country code. + * + * @param phoneNumber + * the phone number to format + * @param defaultCountryIso + * the ISO 3166-1 two letters country code + * @return the E.164 representation, or null if the given phone number is + * not valid. + * + * @hide + */ + public static String formatNumberToE164(String phoneNumber, String defaultCountryIso) { + PhoneNumberUtil util = PhoneNumberUtil.getInstance(); + String result = null; + try { + PhoneNumber pn = util.parse(phoneNumber, defaultCountryIso); + if (util.isValidNumber(pn)) { + result = util.format(pn, PhoneNumberFormat.E164); + } + } catch (NumberParseException e) { + } + return result; + } + + /** + * Format a phone number. + * <p> + * If the given number doesn't have the country code, the phone will be + * formatted to the default country's convention. + * + * @param phoneNumber + * the number to be formatted. + * @param defaultCountryIso + * the ISO 3166-1 two letters country code whose convention will + * be used if the given number doesn't have the country code. + * @return the formatted number, or null if the given number is not valid. + * + * @hide + */ + public static String formatNumber(String phoneNumber, String defaultCountryIso) { + PhoneNumberUtil util = PhoneNumberUtil.getInstance(); + String result = null; + try { + PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso); + result = util.formatInOriginalFormat(pn, defaultCountryIso); + } catch (NumberParseException e) { + } + return result; + } + + /** + * Format the phone number only if the given number hasn't been formatted. + * <p> + * The number which has only dailable character is treated as not being + * formatted. + * + * @param phoneNumber + * the number to be formatted. + * @param phoneNumberE164 + * the E164 format number whose country code is used if the given + * phoneNumber doesn't have the country code. + * @param defaultCountryIso + * the ISO 3166-1 two letters country code whose convention will + * be used if the phoneNumberE164 is null or invalid. + * @return the formatted number if the given number has been formatted, + * otherwise, return the given number. + * + * @hide + */ + public static String formatNumber( + String phoneNumber, String phoneNumberE164, String defaultCountryIso) { + int len = phoneNumber.length(); + for (int i = 0; i < len; i++) { + if (!isDialable(phoneNumber.charAt(i))) { + return phoneNumber; + } + } + PhoneNumberUtil util = PhoneNumberUtil.getInstance(); + // Get the country code from phoneNumberE164 + if (phoneNumberE164 != null && phoneNumberE164.length() >= 2 + && phoneNumberE164.charAt(0) == '+') { + try { + PhoneNumber pn = util.parse(phoneNumberE164, defaultCountryIso); + String regionCode = util.getRegionCodeForNumber(pn); + if (!TextUtils.isEmpty(regionCode)) { + defaultCountryIso = regionCode; + } + } catch (NumberParseException e) { + } + } + String result = formatNumber(phoneNumber, defaultCountryIso); + return result != null ? result : phoneNumber; + } + + /** + * Normalize a phone number by removing the characters other than digits. If + * the given number has keypad letters, the letters will be converted to + * digits first. + * + * @param phoneNumber + * the number to be normalized. + * @return the normalized number. + * + * @hide + */ + public static String normalizeNumber(String phoneNumber) { + StringBuilder sb = new StringBuilder(); + int len = phoneNumber.length(); + for (int i = 0; i < len; i++) { + char c = phoneNumber.charAt(i); + if ((i == 0 && c == '+') || PhoneNumberUtils.isISODigit(c)) { + sb.append(c); + } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + return normalizeNumber(PhoneNumberUtils.convertKeypadLettersToDigits(phoneNumber)); + } + } + return sb.toString(); + } + // Three and four digit phone numbers for either special services, // or 3-6 digit addresses from the network (eg carrier-originated SMS messages) should // not match. @@ -1546,7 +1677,7 @@ public class PhoneNumberUtils * @hide */ public static String - cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int currFormat,int defaultFormt) { + cdmaCheckAndProcessPlusCodeByNumberFormat(String dialStr,int currFormat,int defaultFormat) { String retStr = dialStr; // Checks if the plus sign character is in the passed-in dial string @@ -1554,7 +1685,7 @@ public class PhoneNumberUtils 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)) { + if ((currFormat == defaultFormat) && (currFormat == FORMAT_NANP)) { // Handle case where default and current telephone numbering plans are NANP. String postDialStr = null; String tempDialStr = dialStr; @@ -1748,7 +1879,7 @@ public class PhoneNumberUtils return -1; } - // This function appends the non-diablable P/W character to the original + // This function appends the non-dialable 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) { @@ -1768,7 +1899,7 @@ public class PhoneNumberUtils return retStr; } - //===== Begining of utility methods used in compareLoosely() ===== + //===== Beginning of utility methods used in compareLoosely() ===== /** * Phone numbers are stored in "lookup" form in the database @@ -1890,12 +2021,12 @@ public class PhoneNumberUtils //===== End of utility methods used only in compareLoosely() ===== - //===== Beggining of utility methods used only in compareStrictly() ==== + //===== Beginning of utility methods used only in compareStrictly() ==== /* * If true, the number is country calling code. */ - private static final boolean COUNTLY_CALLING_CALL[] = { + private static final boolean COUNTRY_CALLING_CALL[] = { true, true, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, true, true, false, @@ -1907,18 +2038,18 @@ public class PhoneNumberUtils false, true, true, true, true, false, true, false, false, true, true, true, true, true, true, true, false, false, true, false, }; - private static final int CCC_LENGTH = COUNTLY_CALLING_CALL.length; + private static final int CCC_LENGTH = COUNTRY_CALLING_CALL.length; /** * @return true when input is valid Country Calling Code. */ private static boolean isCountryCallingCode(int countryCallingCodeCandidate) { return countryCallingCodeCandidate > 0 && countryCallingCodeCandidate < CCC_LENGTH && - COUNTLY_CALLING_CALL[countryCallingCodeCandidate]; + COUNTRY_CALLING_CALL[countryCallingCodeCandidate]; } /** - * Returns interger corresponding to the input if input "ch" is + * Returns integer corresponding to the input if input "ch" is * ISO-LATIN characters 0-9. * Returns -1 otherwise */ @@ -2053,7 +2184,7 @@ public class PhoneNumberUtils /** * Return true if the prefix of "str" is "ignorable". Here, "ignorable" means - * that "str" has only one digit and separater characters. The one digit is + * that "str" has only one digit and separator characters. The one digit is * assumed to be trunk prefix. */ private static boolean checkPrefixIsIgnorable(final String str, diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 830af47..eda9b71 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -25,6 +25,7 @@ import android.telephony.CellLocation; import android.util.Log; import com.android.internal.telephony.IPhoneStateListener; +import com.android.internal.telephony.Phone; /** * A listener class for monitoring changes in specific telephony states @@ -147,6 +148,14 @@ public class PhoneStateListener { */ public static final int LISTEN_SIGNAL_STRENGTHS = 0x00000100; + /** + * Listen for changes to OTASP mode. + * + * @see #onOtaspChanged + * @hide + */ + public static final int LISTEN_OTASP_CHANGED = 0x00000200; + public PhoneStateListener() { } @@ -251,6 +260,21 @@ public class PhoneStateListener { // default implementation empty } + + /** + * The Over The Air Service Provisioning (OTASP) has changed. Requires + * the READ_PHONE_STATE permission. + * @param otaspMode is integer <code>OTASP_UNKNOWN=1<code> + * means the value is currently unknown and the system should wait until + * <code>OTASP_NEEDED=2<code> or <code>OTASP_NOT_NEEDED=3<code> is received before + * making the decisision to perform OTASP or not. + * + * @hide + */ + public void onOtaspChanged(int otaspMode) { + // default implementation empty + } + /** * The callback methods need to be called on the handler thread where * this object was created. If the binder did that for us it'd be nice. @@ -284,16 +308,21 @@ public class PhoneStateListener { } public void onDataConnectionStateChanged(int state, int networkType) { - Message.obtain(mHandler, LISTEN_DATA_CONNECTION_STATE, state, networkType, null). + Message.obtain(mHandler, LISTEN_DATA_CONNECTION_STATE, state, networkType). sendToTarget(); } public void onDataActivity(int direction) { Message.obtain(mHandler, LISTEN_DATA_ACTIVITY, direction, 0, null).sendToTarget(); } + public void onSignalStrengthsChanged(SignalStrength signalStrength) { Message.obtain(mHandler, LISTEN_SIGNAL_STRENGTHS, 0, 0, signalStrength).sendToTarget(); } + + public void onOtaspChanged(int otaspMode) { + Message.obtain(mHandler, LISTEN_OTASP_CHANGED, otaspMode, 0).sendToTarget(); + } }; Handler mHandler = new Handler() { @@ -328,6 +357,9 @@ public class PhoneStateListener { case LISTEN_SIGNAL_STRENGTHS: PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj); break; + case LISTEN_OTASP_CHANGED: + PhoneStateListener.this.onOtaspChanged(msg.arg1); + break; } } }; diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index f5e9751..953696b 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -21,7 +21,6 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.text.TextUtils; -import com.android.internal.telephony.EncodeException; import com.android.internal.telephony.ISms; import com.android.internal.telephony.IccConstants; import com.android.internal.telephony.SmsRawData; @@ -33,7 +32,7 @@ import java.util.List; /* * TODO(code review): Curious question... Why are a lot of these * methods not declared as static, since they do not seem to require - * any local object state? Assumedly this cannot be changed without + * any local object state? Presumably this cannot be changed without * interfering with the API... */ @@ -42,7 +41,8 @@ import java.util.List; * Get this object by calling the static method SmsManager.getDefault(). */ public final class SmsManager { - private static SmsManager sInstance; + /** Singleton object constructed during class initialization. */ + private static final SmsManager sInstance = new SmsManager(); /** * Send a text based SMS. @@ -52,8 +52,8 @@ public final class SmsManager { * the current default SMSC * @param text the body of the message to send * @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, + * 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:<br> * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> * <code>RESULT_ERROR_RADIO_OFF</code><br> @@ -116,7 +116,7 @@ public final class SmsManager { * @param sentIntents if not null, an <code>ArrayList</code> of * <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, + * The result code will be <code>Activity.RESULT_OK</code> for success, * or one of these errors:<br> * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> * <code>RESULT_ERROR_RADIO_OFF</code><br> @@ -125,7 +125,7 @@ public final class SmsManager { * 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, + * is NULL the caller will be checked against all unknown applications, * which cause smaller number of SMS to be sent in checking period. * @param deliveryIntents if not null, an <code>ArrayList</code> of * <code>PendingIntent</code>s (one for each message part) that is @@ -178,8 +178,8 @@ public final class SmsManager { * @param destinationPort the port to deliver the message to * @param data the body of the message to send * @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, + * 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:<br> * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> * <code>RESULT_ERROR_RADIO_OFF</code><br> @@ -188,7 +188,7 @@ public final class SmsManager { * 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, + * is NULL the caller will be checked against all unknown applications, * which cause smaller number of SMS to be sent in checking period. * @param deliveryIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is delivered to the recipient. The @@ -224,9 +224,6 @@ public final class SmsManager { * @return the default instance of the SmsManager */ public static SmsManager getDefault() { - if (sInstance == null) { - sInstance = new SmsManager(); - } return sInstance; } diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index a284ea5..0746562 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -20,7 +20,6 @@ import android.os.Parcel; import android.util.Log; import com.android.internal.telephony.GsmAlphabet; -import com.android.internal.telephony.EncodeException; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; import com.android.internal.telephony.SmsMessageBase.SubmitPduBase; @@ -54,6 +53,10 @@ public class SmsMessage { public static final int ENCODING_7BIT = 1; public static final int ENCODING_8BIT = 2; public static final int ENCODING_16BIT = 3; + /** + * @hide This value is not defined in global standard. Only in Korea, this is used. + */ + public static final int ENCODING_KSC5601 = 4; /** The maximum number of payload bytes per message */ public static final int MAX_USER_DATA_BYTES = 140; diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 27e08d4..9ef41f2 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -272,13 +272,17 @@ public class TelephonyManager { public static final int PHONE_TYPE_GSM = Phone.PHONE_TYPE_GSM; /** Phone radio is CDMA. */ public static final int PHONE_TYPE_CDMA = Phone.PHONE_TYPE_CDMA; + /** Phone is via SIP. */ + public static final int PHONE_TYPE_SIP = Phone.PHONE_TYPE_SIP; /** - * Returns a constant indicating the device phone type. + * Returns a constant indicating the device phone type. This + * indicates the type of radio used to transmit voice calls. * * @see #PHONE_TYPE_NONE * @see #PHONE_TYPE_GSM * @see #PHONE_TYPE_CDMA + * @see #PHONE_TYPE_SIP */ public int getPhoneType() { try{ @@ -393,11 +397,15 @@ public class TelephonyManager { public static final int NETWORK_TYPE_IDEN = 11; /** Current network is EVDO revision B*/ public static final int NETWORK_TYPE_EVDO_B = 12; + /** Current network is LTE */ + public static final int NETWORK_TYPE_LTE = 13; + /** Current network is eHRPD */ + public static final int NETWORK_TYPE_EHRPD = 14; /** * Returns a constant indicating the radio technology (network type) - * currently in use on the device. + * currently in use on the device for data transmission. * @return the network type * * @see #NETWORK_TYPE_UNKNOWN @@ -412,6 +420,9 @@ public class TelephonyManager { * @see #NETWORK_TYPE_EVDO_A * @see #NETWORK_TYPE_EVDO_B * @see #NETWORK_TYPE_1xRTT + * @see #NETWORK_TYPE_IDEN + * @see #NETWORK_TYPE_LTE + * @see #NETWORK_TYPE_EHRPD */ public int getNetworkType() { try{ @@ -462,6 +473,10 @@ public class TelephonyManager { return "CDMA - EvDo rev. B"; case NETWORK_TYPE_1xRTT: return "CDMA - 1xRTT"; + case NETWORK_TYPE_LTE: + return "LTE"; + case NETWORK_TYPE_EHRPD: + return "CDMA - eHRPD"; default: return "UNKNOWN"; } @@ -787,6 +802,10 @@ public class TelephonyManager { } } + /** Data connection state: Unknown. Used before we know the state. + * @hide + */ + public static final int DATA_UNKNOWN = -1; /** Data connection state: Disconnected. IP traffic not available. */ public static final int DATA_DISCONNECTED = 0; /** Data connection state: Currently setting up a data connection. */ @@ -912,4 +931,25 @@ public class TelephonyManager { return null; } } + + /** + * @return true if the current device is "voice capable". + * <p> + * "Voice capable" means that this device supports circuit-switched + * (i.e. voice) phone calls over the telephony network, and is allowed + * to display the in-call UI while a cellular voice call is active. + * This will be false on "data only" devices which can't make voice + * calls and don't support any in-call UI. + * <p> + * Note: the meaning of this flag is subtly different from the + * PackageManager.FEATURE_TELEPHONY system feature, which is available + * on any device with a telephony radio, even if the device is + * data-only. + * + * @hide pending API review + */ + public boolean isVoiceCapable() { + return mContext.getResources().getBoolean( + com.android.internal.R.bool.config_voice_capable); + } } diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java index f7506c6..82fcb6a 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfo.java +++ b/telephony/java/com/android/internal/telephony/CallerInfo.java @@ -71,6 +71,7 @@ public class CallerInfo { */ public String name; public String phoneNumber; + public String nomalizedNumber; public String cnapName; public int numberPresentation; @@ -151,6 +152,12 @@ public class CallerInfo { info.phoneNumber = cursor.getString(columnIndex); } + // Look for the normalized number + columnIndex = cursor.getColumnIndex(PhoneLookup.NORMALIZED_NUMBER); + if (columnIndex != -1) { + info.nomalizedNumber = cursor.getString(columnIndex); + } + // Look for the label/type combo columnIndex = cursor.getColumnIndex(PhoneLookup.LABEL); if (columnIndex != -1) { diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java index 79bb832..c47e076 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java +++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java @@ -20,6 +20,7 @@ import android.content.AsyncQueryHandler; import android.content.Context; import android.database.Cursor; import android.database.SQLException; +import android.location.CountryDetector; import android.net.Uri; import android.os.Handler; import android.os.Looper; @@ -240,7 +241,11 @@ public class CallerInfoAsyncQuery { // Use the number entered by the user for display. if (!TextUtils.isEmpty(cw.number)) { - mCallerInfo.phoneNumber = PhoneNumberUtils.formatNumber(cw.number); + CountryDetector detector = (CountryDetector) mQueryContext.getSystemService( + Context.COUNTRY_DETECTOR); + mCallerInfo.phoneNumber = PhoneNumberUtils.formatNumber(cw.number, + mCallerInfo.nomalizedNumber, + detector.detectCountry().getCountryIso()); } } diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java index 5de0426..27a4dca 100644 --- a/telephony/java/com/android/internal/telephony/CommandsInterface.java +++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java @@ -27,8 +27,8 @@ import android.os.Handler; */ public interface CommandsInterface { enum RadioState { - RADIO_OFF, /* Radio explictly powered off (eg CFUN=0) */ - RADIO_UNAVAILABLE, /* Radio unavailable (eg, resetting or not booted) */ + RADIO_OFF, /* Radio explicitly powered off (e.g. CFUN=0) */ + RADIO_UNAVAILABLE, /* Radio unavailable (e.g. resetting or not booted) */ SIM_NOT_READY, /* Radio is on, but the SIM interface is not ready */ SIM_LOCKED_OR_ABSENT, /* SIM PIN locked, PUK required, network personalization, or SIM absent */ @@ -121,7 +121,7 @@ public interface CommandsInterface { // See 27.007 +CCFC or +CLCK static final int SERVICE_CLASS_NONE = 0; // no user input static final int SERVICE_CLASS_VOICE = (1 << 0); - static final int SERVICE_CLASS_DATA = (1 << 1); //synoym for 16+32+64+128 + static final int SERVICE_CLASS_DATA = (1 << 1); //synonym for 16+32+64+128 static final int SERVICE_CLASS_FAX = (1 << 2); static final int SERVICE_CLASS_SMS = (1 << 3); static final int SERVICE_CLASS_DATA_SYNC = (1 << 4); @@ -952,19 +952,19 @@ public interface CommandsInterface { void writeSmsToRuim(int status, String pdu, Message response); /** - * @deprecated * @param apn * @param user * @param password * @param response */ + @Deprecated void setupDefaultPDP(String apn, String user, String password, Message response); /** - * @deprecated * @param cid * @param response */ + @Deprecated void deactivateDefaultPDP(int cid, Message response); void setRadioPower(boolean on, Message response); @@ -974,7 +974,7 @@ public interface CommandsInterface { void acknowledgeLastIncomingCdmaSms(boolean success, int cause, Message response); /** - * parameters equivilient to 27.007 AT+CRSM command + * parameters equivalent to 27.007 AT+CRSM command * response.obj will be an AsyncResult * response.obj.userObj will be a IccIoResult on success */ @@ -1079,7 +1079,7 @@ public interface CommandsInterface { /** * (AsyncResult)response.obj).result will be an Integer representing - * the sum of enabled serivice classes (sum of SERVICE_CLASS_*) + * the sum of enabled service classes (sum of SERVICE_CLASS_*) * * @param facility one of CB_FACILTY_* * @param password password or "" if not required @@ -1152,7 +1152,7 @@ public interface CommandsInterface { /** * Request to enable/disable network state change notifications when - * location informateion (lac and/or cid) has changed. + * location information (lac and/or cid) has changed. * * @param enable true to enable, false to disable * @param response callback message @@ -1183,7 +1183,7 @@ public interface CommandsInterface { /** * Indicates to the vendor ril that StkService is running - * rand is eady to receive RIL_UNSOL_STK_XXXX commands. + * and is ready to receive RIL_UNSOL_STK_XXXX commands. * * @param result callback message */ diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java index 6634017..c3ad9e6 100644 --- a/telephony/java/com/android/internal/telephony/DataConnection.java +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -21,11 +21,20 @@ import com.android.internal.telephony.gsm.ApnSetting; import com.android.internal.util.HierarchicalState; import com.android.internal.util.HierarchicalStateMachine; +import android.net.LinkAddress; +import android.net.LinkCapabilities; +import android.net.LinkProperties; import android.os.AsyncResult; import android.os.Message; import android.os.SystemProperties; import android.util.EventLog; +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; + /** * {@hide} * @@ -60,7 +69,7 @@ import android.util.EventLog; * EVENT_GET_LAST_FAIL_DONE, * EVENT_DEACTIVATE_DONE. * } - * ++ # mInactiveState + * ++ # mInactiveState * e(doNotifications) * x(clearNotifications) { * EVENT_RESET { notifiyDisconnectCompleted }. @@ -252,13 +261,13 @@ public abstract class DataConnection extends HierarchicalStateMachine { protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100; //***** Member Variables + protected int mId; protected int mTag; protected PhoneBase phone; + protected RetryManager mRetryMgr; protected int cid; - protected String interfaceName; - protected String ipAddress; - protected String gatewayAddress; - protected String[] dnsServers; + protected LinkProperties mLinkProperties = new LinkProperties(); + protected LinkCapabilities mCapabilities = new LinkCapabilities(); protected long createTime; protected long lastFailTime; protected FailCause lastFailCause; @@ -278,13 +287,12 @@ public abstract class DataConnection extends HierarchicalStateMachine { //***** Constructor - protected DataConnection(PhoneBase phone, String name) { + protected DataConnection(PhoneBase phone, String name, RetryManager rm) { super(name); if (DBG) log("DataConnection constructor E"); this.phone = phone; + mRetryMgr = rm; this.cid = -1; - this.dnsServers = new String[2]; - clearSettings(); setDbg(false); @@ -353,8 +361,8 @@ public abstract class DataConnection extends HierarchicalStateMachine { if (dp.onCompletedMsg != null) { Message msg = dp.onCompletedMsg; - log(String.format("msg.what=%d msg.obj=%s", - msg.what, ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>"))); + log(String.format("msg=%s msg.obj=%s", msg.toString(), + ((msg.obj instanceof String) ? (String) msg.obj : "<no-reason>"))); AsyncResult.forMessage(msg); msg.sendToTarget(); } @@ -367,6 +375,10 @@ public abstract class DataConnection extends HierarchicalStateMachine { clearSettings(); } + public RetryManager getRetryMgr() { + return mRetryMgr; + } + /** * Clear all settings called when entering mInactiveState. */ @@ -377,11 +389,7 @@ public abstract class DataConnection extends HierarchicalStateMachine { this.lastFailTime = -1; this.lastFailCause = FailCause.NONE; - interfaceName = null; - ipAddress = null; - gatewayAddress = null; - dnsServers[0] = null; - dnsServers[1] = null; + mLinkProperties = new LinkProperties(); } /** @@ -416,35 +424,67 @@ public abstract class DataConnection extends HierarchicalStateMachine { // for (int i = 0; i < response.length; i++) { // log(" response[" + i + "]='" + response[i] + "'"); // } + + // Start with clean network properties and if we have + // a failure we'll clear again at the bottom of this code. + LinkProperties linkProperties = new LinkProperties(); if (response.length >= 2) { cid = Integer.parseInt(response[0]); - interfaceName = response[1]; - if (response.length > 2) { - ipAddress = response[2]; + String interfaceName = response[1]; + result = SetupResult.SUCCESS; + + try { String prefix = "net." + interfaceName + "."; - gatewayAddress = SystemProperties.get(prefix + "gw"); + + NetworkInterface networkInterface = NetworkInterface.getByName(interfaceName); + linkProperties.setInterfaceName(interfaceName); + + // TODO: Get gateway and dns via RIL interface not property? + String gatewayAddress = SystemProperties.get(prefix + "gw"); + linkProperties.setGateway(InetAddress.getByName(gatewayAddress)); + + for (InterfaceAddress addr : networkInterface.getInterfaceAddresses()) { + linkProperties.addLinkAddress(new LinkAddress(addr)); + } + // TODO: Get gateway and dns via RIL interface not property? + String dnsServers[] = new String[2]; dnsServers[0] = SystemProperties.get(prefix + "dns1"); dnsServers[1] = SystemProperties.get(prefix + "dns2"); - if (DBG) { - log("interface=" + interfaceName + " ipAddress=" + ipAddress - + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0] - + " DNS2=" + dnsServers[1]); - } - if (isDnsOk(dnsServers)) { - result = SetupResult.SUCCESS; + linkProperties.addDns(InetAddress.getByName(dnsServers[0])); + linkProperties.addDns(InetAddress.getByName(dnsServers[1])); } else { result = SetupResult.ERR_BadDns; } - } else { - result = SetupResult.SUCCESS; + } catch (UnknownHostException e1) { + log("onSetupCompleted: UnknowHostException " + e1); + e1.printStackTrace(); + result = SetupResult.ERR_Other; + } catch (SocketException e2) { + log("onSetupCompleted: SocketException " + e2); + e2.printStackTrace(); + result = SetupResult.ERR_Other; } } else { + log("onSetupCompleted: error; expected number of responses >= 2 was " + + response.length); result = SetupResult.ERR_Other; } + + // An error occurred so clear properties + if (result != SetupResult.SUCCESS) { + log("onSetupCompleted with an error clearing LinkProperties"); + linkProperties.clear(); + } + mLinkProperties = linkProperties; } - if (DBG) log("DataConnection setup result='" + result + "' on cid=" + cid); + if (DBG) { + log("DataConnection setup result='" + result + "' on cid=" + cid); + if (result == SetupResult.SUCCESS) { + log("LinkProperties: " + mLinkProperties.toString()); + } + } return result; } @@ -606,7 +646,16 @@ public abstract class DataConnection extends HierarchicalStateMachine { break; case ERR_BadDns: // Connection succeeded but DNS info is bad so disconnect - EventLog.writeEvent(EventLogTags.PDP_BAD_DNS_ADDRESS, dnsServers[0]); + StringBuilder dnsAddressesSb = new StringBuilder(); + for (InetAddress addr : mLinkProperties.getDnses()) { + if (dnsAddressesSb.length() != 0) dnsAddressesSb.append(" "); + dnsAddressesSb.append(addr.toString()); + } + if (dnsAddressesSb.length() == 0) { + dnsAddressesSb.append("no-dns-addresses"); + } + EventLog.writeEvent(EventLogTags.PDP_BAD_DNS_ADDRESS, + dnsAddressesSb.toString()); tearDownData(cp); transitionTo(mDisconnectingBadDnsState); break; @@ -815,13 +864,13 @@ public abstract class DataConnection extends HierarchicalStateMachine { /** * Connect to the apn and return an AsyncResult in onCompletedMsg. - * Used for cellular networks that use Acess Point Names (APN) such + * Used for cellular networks that use Acesss Point Names (APN) such * as GSM networks. * * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. * With AsyncResult.userObj set to the original msg.obj, * AsyncResult.result = FailCause and AsyncResult.exception = Exception(). - * @param apn is the Acces Point Name to connect to + * @param apn is the Access Point Name to connect to */ public void connect(Message onCompletedMsg, ApnSetting apn) { sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg))); @@ -873,31 +922,29 @@ public abstract class DataConnection extends HierarchicalStateMachine { } /** - * @return the interface name as a string. + * Get the DataConnection ID */ - public String getInterface() { - return interfaceName; + public int getDataConnectionId() { + return mId; } /** - * @return the ip address as a string. - */ - public String getIpAddress() { - return ipAddress; - } - - /** - * @return the gateway address as a string. + * Return the LinkProperties for the connection. + * + * @return a copy of the LinkProperties, is never null. */ - public String getGatewayAddress() { - return gatewayAddress; + public LinkProperties getLinkProperties() { + return new LinkProperties(mLinkProperties); } /** - * @return an array of associated DNS addresses. + * A capability is an Integer/String pair, the capabilities + * are defined in the class LinkSocket#Key. + * + * @return a copy of this connections capabilities, may be empty but never null. */ - public String[] getDnsServers() { - return dnsServers; + public LinkCapabilities getLinkCapabilities() { + return new LinkCapabilities(mCapabilities); } /** diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index 265bf7e..96c90a2 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -16,25 +16,38 @@ package com.android.internal.telephony; +import com.android.internal.telephony.cdma.CDMAPhone; + import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.net.IConnectivityManager; +import android.net.LinkCapabilities; +import android.net.LinkProperties; +import android.net.NetworkInfo; +import android.net.wifi.WifiManager; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; -import android.os.RemoteException; +import android.os.ServiceManager; +import android.preference.PreferenceManager; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.text.TextUtils; import android.util.Log; import java.util.ArrayList; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicInteger; /** * {@hide} - * */ public abstract class DataConnectionTracker extends Handler { - protected static final boolean DBG = false; - protected final String LOG_TAG = "DataConnectionTracker"; + protected static final boolean DBG = true; /** * IDLE: ready to start data connection setup, default state @@ -119,9 +132,10 @@ public abstract class DataConnectionTracker extends Handler { protected boolean mMasterDataEnabled = true; protected boolean[] dataEnabled = new boolean[APN_NUM_TYPES]; + protected int enabledCount = 0; - /* Currently requested APN type */ + /* Currently requested APN type (TODO: This should probably be a parameter not a member) */ protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT; /** Retry configuration: A doubling of retry times from 5secs to 30minutes */ @@ -163,20 +177,27 @@ public abstract class DataConnectionTracker extends Handler { // represents an invalid IP address protected static final String NULL_IP = "0.0.0.0"; + // TODO: See if we can remove INTENT_RECONNECT_ALARM + // having to have different values for GSM and + // CDMA. If so we can then remove the need for + // getActionIntentReconnectAlarm. + protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; // member variables - protected PhoneBase phone; - protected Activity activity = Activity.NONE; - protected State state = State.IDLE; + protected PhoneBase mPhone; + protected Activity mActivity = Activity.NONE; + protected State mState = State.IDLE; protected Handler mDataConnectionTracker = null; - protected long txPkts, rxPkts, sentSinceLastRecv; - protected int netStatPollPeriod; + protected long mTxPkts; + protected long mRxPkts; + protected long mSentSinceLastRecv; + protected int mNetStatPollPeriod; protected int mNoRecvPollCount = 0; - protected boolean netStatPollEnabled = false; + protected boolean mNetStatPollEnabled = false; - /** Manage the behavior of data retry after failure */ + /** Manage the behavior of data retry after failure (TODO: One per connection in the future?) */ protected RetryManager mRetryMgr = new RetryManager(); // wifi connection status will be updated by sticky intent @@ -186,28 +207,125 @@ public abstract class DataConnectionTracker extends Handler { protected PendingIntent mReconnectIntent = null; /** CID of active data connection */ - protected int cidActive; + protected int mCidActive; + + /** indication of our availability (preconditions to trysetupData are met) **/ + protected boolean mAvailability = false; + + // When false we will not auto attach and manully attaching is required. + protected boolean mAutoAttachOnCreation = false; + + // State of screen + // (TODO: Reconsider tying directly to screen, maybe this is + // really a lower power mode") + protected boolean mIsScreenOn = true; + + /** The link properties (dns, gateway, ip, etc) */ + protected LinkProperties mLinkProperties = new LinkProperties(); + + /** The link capabilities */ + protected LinkCapabilities mLinkCapabilities = new LinkCapabilities(); + + /** Allows the generation of unique Id's for DataConnection objects */ + protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0); + + /** The data connections. */ + protected HashMap<Integer, DataConnection> mDataConnections = + new HashMap<Integer, DataConnection>(); + + protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver () + { + @Override + public void onReceive(Context context, Intent intent) + { + String action = intent.getAction(); + if (action.equals(Intent.ACTION_SCREEN_ON)) { + mIsScreenOn = true; + stopNetStatPoll(); + startNetStatPoll(); + } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { + mIsScreenOn = false; + stopNetStatPoll(); + startNetStatPoll(); + } else if (action.equals(getActionIntentReconnectAlarm())) { + log("Reconnect alarm. Previous state was " + mState); + + String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); + if (mState == State.FAILED) { + Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); + msg.arg1 = 0; // tearDown is false + msg.obj = reason; + sendMessage(msg); + } + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); + } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { + final android.net.NetworkInfo networkInfo = (NetworkInfo) + intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); + mIsWifiConnected = (networkInfo != null && networkInfo.isConnected()); + } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { + final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, + WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; + + if (!enabled) { + // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION + // quit and won't report disconnected until next enabling. + mIsWifiConnected = false; + } + } + } + }; - /** + /** * Default constructor */ protected DataConnectionTracker(PhoneBase phone) { super(); - this.phone = phone; + mPhone = phone; + + IntentFilter filter = new IntentFilter(); + filter.addAction(getActionIntentReconnectAlarm()); + filter.addAction(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + + // TODO: Why is this registering the phone as the receiver of the intent + // and not its own handler? + mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); + + // This preference tells us 1) initial condition for "dataEnabled", + // and 2) whether the RIL will setup the baseband to auto-PS attach. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext()); + boolean dataEnabledSetting = true; + try { + dataEnabledSetting = IConnectivityManager.Stub.asInterface(ServiceManager. + getService(Context.CONNECTIVITY_SERVICE)).getMobileDataEnabled(); + } catch (Exception e) { + // nothing to do - use the old behavior and leave data on + } + dataEnabled[APN_DEFAULT_ID] = + !sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false) && + dataEnabledSetting; + if (dataEnabled[APN_DEFAULT_ID]) { + enabledCount++; + } + mAutoAttachOnCreation = dataEnabled[APN_DEFAULT_ID]; } - public abstract void dispose(); + public void dispose() { + mPhone.getContext().unregisterReceiver(this.mIntentReceiver); + } public Activity getActivity() { - return activity; + return mActivity; } public State getState() { - return state; + return mState; } public String getStateInString() { - switch (state) { + switch (mState) { case IDLE: return "IDLE"; case INITING: return "INIT"; case CONNECTING: return "CING"; @@ -220,6 +338,14 @@ public abstract class DataConnectionTracker extends Handler { } /** + * @return the data connections + */ + public ArrayList<DataConnection> getAllDataConnections() { + /** TODO: change return type to Collection? */ + return new ArrayList<DataConnection>(mDataConnections.values()); + } + + /** * The data connection is expected to be setup while device * 1. has Icc card * 2. registered for data service @@ -235,9 +361,9 @@ public abstract class DataConnectionTracker extends Handler { // the shared values. If it is not, then update it. public void setDataOnRoamingEnabled(boolean enabled) { if (getDataOnRoamingEnabled() != enabled) { - Settings.Secure.putInt(phone.getContext().getContentResolver(), + Settings.Secure.putInt(mPhone.getContext().getContentResolver(), Settings.Secure.DATA_ROAMING, enabled ? 1 : 0); - if (phone.getServiceState().getRoaming()) { + if (mPhone.getServiceState().getRoaming()) { if (enabled) { mRetryMgr.resetRetryCount(); } @@ -246,16 +372,19 @@ public abstract class DataConnectionTracker extends Handler { } } - //Retrieve the data roaming setting from the shared preferences. + // Retrieve the data roaming setting from the shared preferences. public boolean getDataOnRoamingEnabled() { try { - return Settings.Secure.getInt(phone.getContext().getContentResolver(), - Settings.Secure.DATA_ROAMING) > 0; + return Settings.Secure.getInt( + mPhone.getContext().getContentResolver(), Settings.Secure.DATA_ROAMING) > 0; } catch (SettingNotFoundException snfe) { return false; } } + + protected abstract String getActionIntentReconnectAlarm(); + // abstract handler methods protected abstract boolean onTrySetupData(String reason); protected abstract void onRoamingOff(); @@ -263,14 +392,14 @@ public abstract class DataConnectionTracker extends Handler { protected abstract void onRadioAvailable(); protected abstract void onRadioOffOrNotAvailable(); protected abstract void onDataSetupComplete(AsyncResult ar); - protected abstract void onDisconnectDone(AsyncResult ar); + protected abstract void onDisconnectDone(int connId, AsyncResult ar); protected abstract void onResetDone(AsyncResult ar); protected abstract void onVoiceCallStarted(); protected abstract void onVoiceCallEnded(); protected abstract void onCleanUpConnection(boolean tearDown, String reason); @Override - public void handleMessage (Message msg) { + public void handleMessage(Message msg) { switch (msg.what) { case EVENT_ENABLE_NEW_APN: @@ -280,7 +409,7 @@ public abstract class DataConnectionTracker extends Handler { case EVENT_TRY_SETUP_DATA: String reason = null; if (msg.obj instanceof String) { - reason = (String)msg.obj; + reason = (String) msg.obj; } onTrySetupData(reason); break; @@ -305,12 +434,13 @@ public abstract class DataConnectionTracker extends Handler { break; case EVENT_DATA_SETUP_COMPLETE: - cidActive = msg.arg1; + mCidActive = msg.arg1; onDataSetupComplete((AsyncResult) msg.obj); break; case EVENT_DISCONNECT_DONE: - onDisconnectDone((AsyncResult) msg.obj); + log("DataConnectoinTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg); + onDisconnectDone(msg.arg1, (AsyncResult) msg.obj); break; case EVENT_VOICE_CALL_STARTED: @@ -323,7 +453,7 @@ public abstract class DataConnectionTracker extends Handler { case EVENT_CLEAN_UP_CONNECTION: boolean tearDown = (msg.arg1 == 0) ? false : true; - onCleanUpConnection(tearDown, (String)msg.obj); + onCleanUpConnection(tearDown, (String) msg.obj); break; case EVENT_SET_MASTER_DATA_ENABLE: @@ -343,20 +473,22 @@ public abstract class DataConnectionTracker extends Handler { /** * Report the current state of data connectivity (enabled or disabled) + * * @return {@code false} if data connectivity has been explicitly disabled, - * {@code true} otherwise. + * {@code true} otherwise. */ public synchronized boolean getDataEnabled() { - return dataEnabled[APN_DEFAULT_ID]; + return (mMasterDataEnabled && dataEnabled[APN_DEFAULT_ID]); } /** * Report on whether data connectivity is enabled + * * @return {@code false} if data connectivity has been explicitly disabled, - * {@code true} otherwise. + * {@code true} otherwise. */ - public boolean getAnyDataEnabled() { - return (enabledCount != 0); + public synchronized boolean getAnyDataEnabled() { + return (mMasterDataEnabled && (enabledCount != 0)); } protected abstract void startNetStatPoll(); @@ -367,6 +499,8 @@ public abstract class DataConnectionTracker extends Handler { protected abstract void log(String s); + protected abstract void loge(String s); + protected int apnTypeToId(String type) { if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) { return APN_DEFAULT_ID; @@ -396,7 +530,7 @@ public abstract class DataConnectionTracker extends Handler { case APN_HIPRI_ID: return Phone.APN_TYPE_HIPRI; default: - Log.e(LOG_TAG, "Unknown id (" + id + ") in apnIdToType"); + log("Unknown id (" + id + ") in apnIdToType"); return Phone.APN_TYPE_DEFAULT; } } @@ -409,19 +543,129 @@ public abstract class DataConnectionTracker extends Handler { protected abstract String getActiveApnString(); - public abstract ArrayList<DataConnection> getAllDataConnections(); + protected abstract void setState(State s); - protected abstract String getInterfaceName(String apnType); + protected LinkProperties getLinkProperties(String apnType) { + int id = apnTypeToId(apnType); + if (isApnIdEnabled(id)) { + return new LinkProperties(mLinkProperties); + } else { + return new LinkProperties(); + } + } - protected abstract String getIpAddress(String apnType); + protected LinkCapabilities getLinkCapabilities(String apnType) { + int id = apnTypeToId(apnType); + if (isApnIdEnabled(id)) { + return new LinkCapabilities(mLinkCapabilities); + } else { + return new LinkCapabilities(); + } + } - protected abstract String getGateway(String apnType); + /** + * Return the LinkProperties for the connection. + * + * @param connection + * @return a copy of the LinkProperties, is never null. + */ + protected LinkProperties getLinkProperties(DataConnection connection) { + return connection.getLinkProperties(); + } - protected abstract String[] getDnsServers(String apnType); + /** + * A capability is an Integer/String pair, the capabilities + * are defined in the class LinkSocket#Key. + * + * @param connection + * @return a copy of this connections capabilities, may be empty but never null. + */ + protected LinkCapabilities getLinkCapabilities(DataConnection connection) { + return connection.getLinkCapabilities(); + } - protected abstract void setState(State s); + // tell all active apns of the current condition + protected void notifyDataConnection(String reason) { + for (int id = 0; id < APN_NUM_TYPES; id++) { + if (dataEnabled[id]) { + mPhone.notifyDataConnection(reason, apnIdToType(id)); + } + } + notifyDataAvailability(reason); + } - protected synchronized boolean isEnabled(int id) { + // a new APN has gone active and needs to send events to catch up with the + // current condition + private void notifyApnIdUpToCurrent(String reason, int apnId) { + switch (mState) { + case IDLE: + case INITING: + break; + case CONNECTING: + case SCANNING: + mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING); + break; + case CONNECTED: + case DISCONNECTING: + mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING); + mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTED); + break; + } + } + + // since we normally don't send info to a disconnected APN, we need to do this specially + private void notifyApnIdDisconnected(String reason, int apnId) { + mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.DISCONNECTED); + } + + // disabled apn's still need avail/unavail notificiations - send them out + protected void notifyOffApnsOfAvailability(String reason, boolean availability) { + if (mAvailability == availability) return; + mAvailability = availability; + for (int id = 0; id < APN_NUM_TYPES; id++) { + if (!isApnIdEnabled(id)) { + notifyApnIdDisconnected(reason, id); + } + } + } + + // we had an availability change - tell the listeners + protected void notifyDataAvailability(String reason) { + // note that we either just turned all off because we lost availability + // or all were off and could now go on, so only have off apns to worry about + notifyOffApnsOfAvailability(reason, isDataPossible()); + } + + /** + * The only circumstances under which we report that data connectivity is not + * possible are + * <ul> + * <li>Data is disallowed (roaming, power state, voice call, etc).</li> + * <li>The current data state is {@code DISCONNECTED} for a reason other than + * having explicitly disabled connectivity. In other words, data is not available + * because the phone is out of coverage or some like reason.</li> + * </ul> + * @return {@code true} if data connectivity is possible, {@code false} otherwise. + */ + protected boolean isDataPossible() { + boolean possible = (isDataAllowed() + && !(getDataEnabled() && (mState == State.FAILED || mState == State.IDLE))); + if (!possible && DBG && isDataAllowed()) { + log("Data not possible. No coverage: dataState = " + mState); + } + return possible; + } + + protected abstract boolean isDataAllowed(); + + public boolean isApnTypeEnabled(String apnType) { + if (apnType == null) { + apnType = getActiveApnString(); + } + return isApnIdEnabled(apnTypeToId(apnType)); + } + + protected synchronized boolean isApnIdEnabled(int id) { if (id != APN_INVALID_ID) { return dataEnabled[id]; } @@ -430,13 +674,13 @@ public abstract class DataConnectionTracker extends Handler { /** * 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. + * + * @param type the APN type (currently the only valid values are + * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}) + * @return Success is indicated by {@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 synchronized int enableApnType(String type) { int id = apnTypeToId(type); @@ -444,41 +688,45 @@ public abstract class DataConnectionTracker extends Handler { return Phone.APN_REQUEST_FAILED; } - if (DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = " - + isApnTypeActive(type) + " and state = " + state); + if (DBG) { + log("enableApnType(" + type + "), isApnTypeActive = " + isApnTypeActive(type) + + ", isApnIdEnabled =" + isApnIdEnabled(id) + " and state = " + mState); + } if (!isApnTypeAvailable(type)) { - if (DBG) Log.d(LOG_TAG, "type not available"); + if (DBG) log("type not available"); return Phone.APN_TYPE_NOT_AVAILABLE; } - // just because it's active doesn't mean we had it explicitly requested before - // (a broad default may handle many types). make sure we mark it enabled - // so if the default is disabled we keep the connection for others - setEnabled(id, true); - - if (isApnTypeActive(type)) { - if (state == State.INITING) return Phone.APN_REQUEST_STARTED; - else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE; + if (isApnIdEnabled(id)) { + return Phone.APN_ALREADY_ACTIVE; + } else { + setEnabled(id, true); } 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. + * 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 + * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}. + * @return Success is indicated by {@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 disconnected. A {@code + * Phone.APN_REQUEST_FAILED} is returned if the type parameter is + * invalid or if the apn wasn't enabled. */ public synchronized int disableApnType(String type) { - if (DBG) Log.d(LOG_TAG, "disableApnType("+type+")"); + if (DBG) log("disableApnType(" + type + ")"); int id = apnTypeToId(type); if (id == APN_INVALID_ID) { return Phone.APN_REQUEST_FAILED; } - if (isEnabled(id)) { + if (isApnIdEnabled(id)) { setEnabled(id, false); if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { if (dataEnabled[APN_DEFAULT_ID]) { @@ -495,9 +743,10 @@ public abstract class DataConnectionTracker extends Handler { } private void setEnabled(int id, boolean enable) { - if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ") with old state = " + - dataEnabled[id] + " and enabledCount = " + enabledCount); - + if (DBG) { + log("setEnabled(" + id + ", " + enable + ") with old state = " + dataEnabled[id] + + " and enabledCount = " + enabledCount); + } Message msg = obtainMessage(EVENT_ENABLE_NEW_APN); msg.arg1 = id; msg.arg2 = (enable ? ENABLED : DISABLED); @@ -506,10 +755,10 @@ public abstract class DataConnectionTracker extends Handler { protected synchronized void onEnableApn(int apnId, int enabled) { if (DBG) { - Log.d(LOG_TAG, "EVENT_APN_ENABLE_REQUEST " + apnId + ", " + enabled); - Log.d(LOG_TAG, " dataEnabled = " + dataEnabled[apnId] + - ", enabledCount = " + enabledCount + - ", isApnTypeActive = " + isApnTypeActive(apnIdToType(apnId))); + log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) + + ", enabled=" + enabled + ", dataEnabled = " + dataEnabled[apnId] + + ", enabledCount = " + enabledCount + ", isApnTypeActive = " + + isApnTypeActive(apnIdToType(apnId))); } if (enabled == ENABLED) { if (!dataEnabled[apnId]) { @@ -520,6 +769,8 @@ public abstract class DataConnectionTracker extends Handler { if (!isApnTypeActive(type)) { mRequestedApnType = type; onEnableNewApn(); + } else { + notifyApnIdUpToCurrent(Phone.REASON_APN_SWITCHED, apnId); } } else { // disable @@ -528,8 +779,17 @@ public abstract class DataConnectionTracker extends Handler { enabledCount--; if (enabledCount == 0) { onCleanUpConnection(true, Phone.REASON_DATA_DISABLED); - } else if (dataEnabled[APN_DEFAULT_ID] == true && - !isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { + } + + // send the disconnect msg manually, since the normal route wont send + // it (it's not enabled) + notifyApnIdDisconnected(Phone.REASON_DATA_DISABLED, apnId); + if (dataEnabled[APN_DEFAULT_ID] == true + && !isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { + // TODO - this is an ugly way to restore the default conn - should be done + // by a real contention manager and policy that disconnects the lower pri + // stuff as enable requests come in and pops them back on as we disable back + // down to the lower pri stuff mRequestedApnType = Phone.APN_TYPE_DEFAULT; onEnableNewApn(); } @@ -547,18 +807,22 @@ public abstract class DataConnectionTracker extends Handler { } /** - * 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 + * 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) { - if (DBG) Log.d(LOG_TAG, "setDataEnabled(" + enable + ")"); + if (DBG) + log("setDataEnabled(" + enable + ")"); Message msg = obtainMessage(EVENT_SET_MASTER_DATA_ENABLE); msg.arg1 = (enable ? ENABLED : DISABLED); @@ -568,15 +832,15 @@ public abstract class DataConnectionTracker extends Handler { protected void onSetDataEnabled(boolean enable) { if (mMasterDataEnabled != enable) { - mMasterDataEnabled = enable; + synchronized (this) { + mMasterDataEnabled = enable; + } if (enable) { mRetryMgr.resetRetryCount(); onTrySetupData(Phone.REASON_DATA_ENABLED); } else { onCleanUpConnection(true, Phone.REASON_DATA_DISABLED); - } + } } } - - } diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java index 057ba0a..52cbd7c 100644 --- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import android.net.LinkCapabilities; +import android.net.LinkProperties; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; @@ -92,26 +94,41 @@ public class DefaultPhoneNotifier implements PhoneNotifier { } } - public void notifyDataConnection(Phone sender, String reason) { + public void notifyDataConnection(Phone sender, String reason, String apnType, + Phone.DataState state) { + doNotifyDataConnection(sender, reason, apnType, state); + } + + private void doNotifyDataConnection(Phone sender, String reason, String apnType, + Phone.DataState state) { + // TODO + // use apnType as the key to which connection we're talking about. + // pass apnType back up to fetch particular for this one. TelephonyManager telephony = TelephonyManager.getDefault(); + LinkProperties linkProperties = null; + LinkCapabilities linkCapabilities = null; + if (state == Phone.DataState.CONNECTED) { + linkProperties = sender.getLinkProperties(apnType); + linkCapabilities = sender.getLinkCapabilities(apnType); + } try { mRegistry.notifyDataConnection( - convertDataState(sender.getDataConnectionState()), + convertDataState(state), sender.isDataConnectivityPossible(), reason, sender.getActiveApn(), - sender.getActiveApnTypes(), - sender.getInterfaceName(null), + apnType, + linkProperties, + linkCapabilities, ((telephony!=null) ? telephony.getNetworkType() : - TelephonyManager.NETWORK_TYPE_UNKNOWN), - sender.getGateway(null)); + TelephonyManager.NETWORK_TYPE_UNKNOWN)); } catch (RemoteException ex) { // system process is dead } } - public void notifyDataConnectionFailed(Phone sender, String reason) { + public void notifyDataConnectionFailed(Phone sender, String reason, String apnType) { try { - mRegistry.notifyDataConnectionFailed(reason); + mRegistry.notifyDataConnectionFailed(reason, apnType); } catch (RemoteException ex) { // system process is dead } @@ -127,6 +144,14 @@ public class DefaultPhoneNotifier implements PhoneNotifier { } } + public void notifyOtaspChanged(Phone sender, int otaspMode) { + try { + mRegistry.notifyOtaspChanged(otaspMode); + } catch (RemoteException ex) { + // system process is dead + } + } + private void log(String s) { Log.d(LOG_TAG, "[PhoneNotifier] " + s); } diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java index 30ee77c..e42827f 100644 --- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java +++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java @@ -16,11 +16,14 @@ package com.android.internal.telephony; -import android.telephony.SmsMessage; +import android.text.TextUtils; import android.util.SparseIntArray; import android.util.Log; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; + /** * This class implements the character set mapping between * the GSM SMS 7-bit alphabet specified in TS 23.038 6.2.1 @@ -320,7 +323,7 @@ public class GsmAlphabet { gsmVal = (0x7f & (pdu[offset + byteOffset] >> shift)); - // if it crosses a byte boundry + // if it crosses a byte boundary if (shift > 1) { // set msb bits to 0 gsmVal &= 0x7f >> (shift - 1); @@ -355,6 +358,32 @@ public class GsmAlphabet { */ public static String gsm8BitUnpackedToString(byte[] data, int offset, int length) { + return gsm8BitUnpackedToString(data, offset, length, ""); + } + + /** + * Convert a GSM alphabet string that's stored in 8-bit unpacked + * format (as it often appears in SIM records) into a String + * + * Field may be padded with trailing 0xff's. The decode stops + * at the first 0xff encountered. + * + * Additionally, in some country(ex. Korea), there are non-ASCII or MBCS characters. + * If a character set is given, characters in data are treat as MBCS. + */ + public static String + gsm8BitUnpackedToString(byte[] data, int offset, int length, String characterset) { + boolean isMbcs = false; + Charset charset = null; + ByteBuffer mbcsBuffer = null; + + if (!TextUtils.isEmpty(characterset) + && !characterset.equalsIgnoreCase("us-ascii") + && Charset.isSupported(characterset)) { + isMbcs = true; + charset = Charset.forName(characterset); + mbcsBuffer = ByteBuffer.allocate(2); + } boolean prevWasEscape; StringBuilder ret = new StringBuilder(length); @@ -380,7 +409,15 @@ public class GsmAlphabet { if (prevWasEscape) { ret.append((char)gsmExtendedToChar.get(c, ' ')); } else { - ret.append((char)gsmToChar.get(c, ' ')); + if (!isMbcs || c < 0x80 || i + 1 >= offset + length) { + ret.append((char)gsmToChar.get(c, ' ')); + } else { + // isMbcs must be true. So both mbcsBuffer and charset are initialized. + mbcsBuffer.clear(); + mbcsBuffer.put(data, i++, 2); + mbcsBuffer.flip(); + ret.append(charset.decode(mbcsBuffer).toString()); + } } prevWasEscape = false; } diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl index 856d663..082c097 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -32,5 +32,6 @@ oneway interface IPhoneStateListener { void onDataConnectionStateChanged(int state, int networkType); void onDataActivity(int direction); void onSignalStrengthsChanged(in SignalStrength signalStrength); + void onOtaspChanged(in int otaspMode); } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 2328717..3c4bb12 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -66,7 +66,7 @@ interface ITelephony { boolean showCallScreenWithDialpad(boolean showDialpad); /** - * End call or go to the Home screen + * End call if there is a call in progress, otherwise does nothing. * * @return whether it hung up */ @@ -239,9 +239,11 @@ interface ITelephony { String getCdmaEriText(); /** - * Returns true if CDMA provisioning needs to run. + * Returns true if OTA service provisioning needs to run. + * Only relevant on some technologies, others will always + * return false. */ - boolean getCdmaNeedsProvisioning(); + boolean needsOtaServiceProvisioning(); /** * Returns the unread count of voicemails diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 87e4b52..3c83e50 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -17,6 +17,8 @@ package com.android.internal.telephony; import android.content.Intent; +import android.net.LinkProperties; +import android.net.LinkCapabilities; import android.os.Bundle; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -32,8 +34,9 @@ interface ITelephonyRegistry { void notifyCallForwardingChanged(boolean cfi); void notifyDataActivity(int state); void notifyDataConnection(int state, boolean isDataConnectivityPossible, - String reason, String apn, in String[] apnTypes, String interfaceName, int networkType, - String gateway); - void notifyDataConnectionFailed(String reason); + String reason, String apn, String apnType, in LinkProperties linkProperties, + in LinkCapabilities linkCapabilities, int networkType); + void notifyDataConnectionFailed(String reason, String apnType); void notifyCellLocation(in Bundle cellLocation); + void notifyOtaspChanged(in int otaspMode); } diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java index 957eddd..df579b0 100644 --- a/telephony/java/com/android/internal/telephony/IccUtils.java +++ b/telephony/java/com/android/internal/telephony/IccUtils.java @@ -16,13 +16,16 @@ package com.android.internal.telephony; +import android.content.res.Resources; +import android.content.res.Resources.NotFoundException; import android.graphics.Bitmap; import android.graphics.Color; import android.util.Log; import com.android.internal.telephony.GsmAlphabet; - import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; /** * Various methods, useful for dealing with SIM data. @@ -150,6 +153,9 @@ public class IccUtils { */ public static String adnStringFieldToString(byte[] data, int offset, int length) { + if (length == 0) { + return ""; + } if (length >= 1) { if (data[offset] == (byte) 0x80) { int ucslen = (length - 1) / 2; @@ -225,7 +231,15 @@ public class IccUtils { return ret.toString(); } - return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length); + Resources resource = Resources.getSystem(); + String defaultCharset = ""; + try { + defaultCharset = + resource.getString(com.android.internal.R.string.gsm_alphabet_default_charset); + } catch (NotFoundException e) { + // Ignore Exception and defaultCharset is set to a empty string. + } + return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length, defaultCharset.trim()); } static int @@ -267,9 +281,11 @@ public class IccUtils { /** - * Converts a byte array into a String hexidecimal characters + * Converts a byte array into a String of hexadecimal characters. + * + * @param bytes an array of bytes * - * null returns null + * @return hex string representation of bytes array */ public static String bytesToHexString(byte[] bytes) { diff --git a/telephony/java/com/android/internal/telephony/MccTable.java b/telephony/java/com/android/internal/telephony/MccTable.java index 5539057..c0bf7ec 100644 --- a/telephony/java/com/android/internal/telephony/MccTable.java +++ b/telephony/java/com/android/internal/telephony/MccTable.java @@ -23,346 +23,13 @@ import android.content.res.Configuration; import android.net.wifi.WifiManager; import android.os.RemoteException; import android.os.SystemProperties; -import android.provider.Settings; import android.text.TextUtils; import android.util.Log; -import java.util.Arrays; - -/** - * 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 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. - -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', 3, '', '', 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, 'Asia/Seoul', 'ko', 13, '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, "Asia/Beijing", 'zh', 13, "China (People's Republic of)"), - (461, 'cn', 2, "Asia/Beijing", 'zh', 13, "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, 'Asia/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)')] - -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 - -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)) - -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 - -ind_codes = ['0x%08x' % mk_ind_code(elt) for elt in mcc_table] - -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' - -def do_autogen_comment(extra_desc=[]): - print ' /' + '**\n * AUTO GENERATED (by the Python code above)' - for line in extra_desc: - print ' * %s' % line - print ' *' + '/' - -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) - -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) - -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] - -*/ +import java.util.ArrayList; +import java.util.Collections; +import java.util.Locale; +import libcore.icu.TimeZones; /** * Mobile Country Code @@ -371,202 +38,130 @@ for i in range(len(orig_table)): */ public final class MccTable { - /** - * AUTO GENERATED (by the Python code above) - */ - private static final String[] TZ_STRINGS = { - "", - "Africa/Johannesburg", - "Asia/Beijing", - "Asia/Seoul", - "Asia/Singapore", - "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" - }; + static final String LOG_TAG = "MccTable"; - /** - * AUTO GENERATED (by the Python code above) - */ - private static final String[] LANG_STRINGS = { - "", "cs", "de", "en", "es", "fr", "it", "ja", "ko", "nl", - "zh" - }; + static ArrayList<MccEntry> table; - /** - * 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 - }; + static class MccEntry implements Comparable<MccEntry> + { + int mcc; + String iso; + int smallestDigitsMnc; + String language; - /** - * 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, 0x6e6c6c79, 0x62650400, 0x667204c5, 0x6d630400, 0x61640400, - 0x657304b4, 0x68750400, 0x62610400, 0x68720400, 0x72730400, 0x697404e6, - 0x766104e6, 0x726f0400, 0x63680512, 0x637a6cd1, 0x736b0400, 0x61746cf2, - 0x67626ca3, 0x67626ca3, 0x646b0400, 0x73650400, 0x6e6f0400, 0x66690400, - 0x6c740400, 0x6c760400, 0x65650400, 0x72750400, 0x75610400, 0x62790400, - 0x6d640400, 0x706c0500, 0x64656c82, 0x67690400, 0x70740400, 0x6c750400, - 0x69650493, 0x69730400, 0x616c0400, 0x6d740400, 0x63790400, 0x67650400, - 0x616d0400, 0x62670400, 0x74720400, 0x666f0400, 0x67650400, 0x676c0400, - 0x736d0400, 0x736c0400, 0x6d6b0400, 0x6c690400, 0x6d650400, 0x63615e00, - 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, 0x6a707457, 0x6a707457, - 0x6b726c38, 0x766e0400, 0x686b0400, 0x6d6f0400, 0x6b680400, 0x6c610400, - 0x636e6c2a, 0x636e6c2a, 0x74770400, 0x6b700400, 0x62640400, 0x6d760400, - 0x6d790400, 0x61755c63, 0x69640400, 0x746c0400, 0x70680400, 0x74680400, - 0x73675c43, 0x626e0400, 0x6e7a0523, 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 - }; + MccEntry(int mnc, String iso, int smallestDigitsMCC) { + this(mnc, iso, smallestDigitsMCC, null); + } - static final String LOG_TAG = "MccTable"; + MccEntry(int mnc, String iso, int smallestDigitsMCC, String language) { + this.mcc = mnc; + this.iso = iso; + this.smallestDigitsMnc = smallestDigitsMCC; + this.language = language; + } + + + public int compareTo(MccEntry o) + { + return mcc - o.mcc; + } + } + + private static MccEntry + entryForMcc(int mcc) + { + int index; + + MccEntry m; + + m = new MccEntry(mcc, null, 0); + + index = Collections.binarySearch(table, m); - /** - * Given a 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; + } else { + return table.get(index); } - int indCode = IND_CODES[index]; - int tzInd = (indCode >>> 4) & 0x001F; - String tz = TZ_STRINGS[tzInd]; - if (tz == "") { + } + + /** + * Returns a default time zone ID for the given MCC. + * @param mcc Mobile Country Code + * @return default TimeZone ID, or null if not specified + */ + public static String defaultTimeZoneForMcc(int mcc) { + MccEntry entry; + + entry = entryForMcc(mcc); + if (entry == null || entry.iso == null) { return null; + } else { + Locale locale; + if (entry.language == null) { + locale = new Locale(entry.iso); + } else { + locale = new Locale(entry.language, entry.iso); + } + String[] tz = TimeZones.forLocale(locale); + if (tz.length == 0) return null; + return tz[0]; } - return tz; } /** - * Given a 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) { - int index = Arrays.binarySearch(MCC_CODES, (short)mcc); - if (index < 0) { + public static String + countryCodeForMcc(int mcc) + { + MccEntry entry; + + entry = entryForMcc(mcc); + + if (entry == null) { 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. */ public static String defaultLanguageForMcc(int mcc) { - int index = Arrays.binarySearch(MCC_CODES, (short)mcc); - if (index < 0) { - return null; - } - int indCode = IND_CODES[index]; - int langInd = indCode & 0x000F; - String lang = LANG_STRINGS[langInd]; - if (lang == "") { + MccEntry entry; + + entry = entryForMcc(mcc); + + if (entry == null) { return null; + } else { + return entry.language; } - return lang; } /** - * Given a GSM Mobile Country Code, returns the corresponding - * smallest number of digits field. Returns 2 if unavailable. + * Given a GSM Mobile Country Code, returns + * the smallest number of digits that M if available. + * Returns 2 if unavailable. */ - public static int smallestDigitsMccForMnc(int mcc) { - int index = Arrays.binarySearch(MCC_CODES, (short)mcc); - if (index < 0) { - return 2; - } - int indCode = IND_CODES[index]; - int smDig = (indCode >>> 9) & 0x0003; - return smDig; - } + public static int + smallestDigitsMccForMnc(int mcc) + { + MccEntry entry; - /** - * 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; + entry = entryForMcc(mcc); + + if (entry == null) { + return 2; + } else { + return entry.smallestDigitsMnc; } - int indCode = IND_CODES[index]; - int wifi = (indCode >>> 11) & 0x000F; - return wifi; } /** @@ -592,7 +187,7 @@ public final class MccTable if (mcc != 0) { setTimezoneFromMccIfNeeded(phone, mcc); setLocaleFromMccIfNeeded(phone, mcc); - setWifiChannelsFromMcc(phone, mcc); + setWifiCountryCodeFromMcc(phone, mcc); } try { Configuration config = ActivityManagerNative.getDefault().getConfiguration(); @@ -648,14 +243,272 @@ public final class MccTable * @param phone PhoneBase to act on (get context from). * @param mcc Mobile Country Code of the SIM or SIM-like entity (build prop on CDMA) */ - private static void setWifiChannelsFromMcc(PhoneBase phone, int mcc) { - int wifiChannels = MccTable.wifiChannelsForMcc(mcc); - if (wifiChannels != 0) { + private static void setWifiCountryCodeFromMcc(PhoneBase phone, int mcc) { + String country = MccTable.countryCodeForMcc(mcc); + if (!country.isEmpty()) { Context context = phone.getContext(); - Log.d(LOG_TAG, "WIFI_NUM_ALLOWED_CHANNELS set to " + wifiChannels); + Log.d(LOG_TAG, "WIFI_COUNTRY_CODE set to " + country); WifiManager wM = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); //persist - wM.setNumAllowedChannels(wifiChannels, true); + wM.setCountryCode(country, true); } } + + 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. + * + */ + + table.add(new MccEntry(202,"gr",2)); //Greece + table.add(new MccEntry(204,"nl",2,"nl")); //Netherlands (Kingdom of the) + table.add(new MccEntry(206,"be",2)); //Belgium + table.add(new MccEntry(208,"fr",2,"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,"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,"it")); //Italy + table.add(new MccEntry(225,"va",2,"it")); //Vatican City State + table.add(new MccEntry(226,"ro",2)); //Romania + table.add(new MccEntry(228,"ch",2,"de")); //Switzerland (Confederation of) + table.add(new MccEntry(230,"cz",2,"cs")); //Czech Republic + table.add(new MccEntry(231,"sk",2)); //Slovak Republic + table.add(new MccEntry(232,"at",2,"de")); //Austria + table.add(new MccEntry(234,"gb",2,"en")); //United Kingdom of Great Britain and Northern Ireland + table.add(new MccEntry(235,"gb",2,"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)); //Poland (Republic of) + table.add(new MccEntry(262,"de",2,"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,"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(289,"ge",2)); //Abkhazia (Georgia) + 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(297,"me",2)); //Montenegro (Republic of) + table.add(new MccEntry(302,"ca",3,"")); //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(423,"ps",2)); //Palestine + 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,"ja")); //Japan + table.add(new MccEntry(441,"jp",2,"ja")); //Japan + table.add(new MccEntry(450,"kr",2,"ko")); //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,"zh")); //China (People's Republic of) + table.add(new MccEntry(461,"cn",2,"zh")); //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,"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,"en")); //Singapore (Republic of) + table.add(new MccEntry(528,"bn",2)); //Brunei Darussalam + table.add(new MccEntry(530,"nz",2, "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,"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); + } } diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index e426e94..2957c7e 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -17,10 +17,10 @@ package com.android.internal.telephony; import android.content.Context; -import android.content.SharedPreferences; +import android.net.LinkCapabilities; +import android.net.LinkProperties; import android.os.Handler; import android.os.Message; -import android.preference.PreferenceManager; import android.telephony.CellLocation; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; @@ -28,7 +28,6 @@ import android.telephony.SignalStrength; import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.gsm.NetworkInfo; -import com.android.internal.telephony.gsm.GsmDataConnection; import com.android.internal.telephony.test.SimulatedRadioControl; import java.util.List; @@ -99,11 +98,12 @@ 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_TYPES_KEY = "apnType"; + static final String DATA_APN_TYPE_KEY = "apnType"; static final String DATA_APN_KEY = "apn"; + static final String DATA_LINK_PROPERTIES_KEY = "linkProperties"; + static final String DATA_LINK_CAPABILITIES_KEY = "linkCapabilities"; static final String DATA_IFACE_NAME_KEY = "iface"; - static final String DATA_GATEWAY_KEY = "gateway"; static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable"; static final String PHONE_IN_ECM_STATE = "phoneinECMState"; @@ -243,11 +243,19 @@ public interface Phone { CellLocation getCellLocation(); /** + * Get the current for the default apn DataState. No change notification + * exists at this interface -- use + * {@link android.telephony.PhoneStateListener} instead. + */ + DataState getDataConnectionState(); + + /** * Get the current DataState. No change notification exists at this * interface -- use * {@link android.telephony.PhoneStateListener} instead. + * @param apnType specify for which apn to get connection state info. */ - DataState getDataConnectionState(); + DataState getDataConnectionState(String apnType); /** * Get the current DataActivityState. No change notification exists at this @@ -313,6 +321,16 @@ public interface Phone { String getActiveApn(); /** + * Return the LinkProperties for the named apn or null if not available + */ + LinkProperties getLinkProperties(String apnType); + + /** + * Return the LinkCapabilities + */ + LinkCapabilities getLinkCapabilities(String apnType); + + /** * Get current signal strength. No change notification available on this * interface. Use <code>PhoneStateNotifier</code> or an equivalent. * An ASU is 0-31 or -1 if unknown (for GSM, dBm = -113 - 2 * asu). @@ -1373,29 +1391,6 @@ public interface Phone { boolean isDataConnectivityPossible(); /** - * Returns the name of the network interface used by the specified APN type. - */ - String getInterfaceName(String apnType); - - /** - * Returns the IP address of the network interface used by the specified - * APN type. - */ - String getIpAddress(String apnType); - - /** - * Returns the gateway for the network interface used by the specified APN - * type. - */ - String getGateway(String apnType); - - /** - * Returns the DNS servers for the network interface used by the specified - * APN type. - */ - public String[] getDnsServers(String apnType); - - /** * Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones. */ String getDeviceId(); @@ -1540,6 +1535,11 @@ public interface Phone { boolean isOtaSpNumber(String dialStr); /** + * Returns true if OTA Service Provisioning needs to be performed. + */ + boolean needsOtaServiceProvisioning(); + + /** * Register for notifications when CDMA call waiting comes * * @param h Handler that receives the notification message. diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index 1674ad6..83080ee 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -21,6 +21,8 @@ import android.app.IActivityManager; import android.content.Context; import android.content.res.Configuration; import android.content.SharedPreferences; +import android.net.LinkCapabilities; +import android.net.LinkProperties; import android.net.wifi.WifiManager; import android.os.AsyncResult; import android.os.Handler; @@ -35,10 +37,8 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.R; -import com.android.internal.telephony.gsm.GsmDataConnection; import com.android.internal.telephony.test.SimulatedRadioControl; -import java.util.List; import java.util.Locale; @@ -558,11 +558,6 @@ public abstract class PhoneBase extends Handler implements Phone { String c = carrierLocales[i].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 = ""; @@ -571,15 +566,15 @@ public abstract class PhoneBase extends Handler implements Phone { } setSystemLocale(language, country); - if (wifiChannels != 0) { + if (!country.isEmpty()) { try { Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS); + Settings.Secure.WIFI_COUNTRY_CODE); } catch (Settings.SettingNotFoundException e) { // note this is not persisting WifiManager wM = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); - wM.setNumAllowedChannels(wifiChannels, false); + wM.setCountryCode(country, false); } } return; @@ -741,8 +736,22 @@ public abstract class PhoneBase extends Handler implements Phone { mNotifier.notifyMessageWaitingChanged(this); } - public void notifyDataConnection(String reason) { - mNotifier.notifyDataConnection(this, reason); + public void notifyDataConnection(String reason, String apnType, + Phone.DataState state) { + mNotifier.notifyDataConnection(this, reason, apnType, state); + } + + public void notifyDataConnection(String reason, String apnType) { + mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType)); + } + + public void notifyDataConnection() { + String apn = getActiveApn(); + mNotifier.notifyDataConnection(this, null, apn, getDataConnectionState(apn)); + } + + public void notifyOtaspChanged(int otaspMode) { + mNotifier.notifyOtaspChanged(this, otaspMode); } public abstract String getPhoneName(); @@ -828,9 +837,19 @@ public abstract class PhoneBase extends Handler implements Phone { logUnexpectedCdmaMethodCall("unregisterForSubscriptionInfoReady"); } + /** + * Returns true if OTA Service Provisioning needs to be performed. + * If not overridden return false. + */ + public boolean needsOtaServiceProvisioning() { + return false; + } + + /** + * Return true if number is an OTASP number. + * If not overridden return false. + */ public boolean isOtaSpNumber(String dialStr) { - // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - logUnexpectedCdmaMethodCall("isOtaSpNumber"); return false; } @@ -920,28 +939,20 @@ public abstract class PhoneBase extends Handler implements Phone { logUnexpectedCdmaMethodCall("unsetOnEcbModeExitResponse"); } - 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[] getActiveApnTypes() { + return mDataConnection.getActiveApnTypes(); } - public String[] getDnsServers(String apnType) { - return mDataConnection.getDnsServers(apnType); + public LinkProperties getLinkProperties(String apnType) { + return mDataConnection.getLinkProperties(apnType); } - public String[] getActiveApnTypes() { - return mDataConnection.getActiveApnTypes(); + public LinkCapabilities getLinkCapabilities(String apnType) { + return mDataConnection.getLinkCapabilities(apnType); } public String getActiveApn() { @@ -956,6 +967,10 @@ public abstract class PhoneBase extends Handler implements Phone { return mDataConnection.disableApnType(type); } + public boolean isDataConnectivityPossible() { + return ((mDataConnection != null) && (mDataConnection.isDataPossible())); + } + /** * simulateDataConnection * @@ -984,7 +999,7 @@ public abstract class PhoneBase extends Handler implements Phone { } mDataConnection.setState(dcState); - notifyDataConnection(null); + notifyDataConnection(null, Phone.APN_TYPE_DEFAULT); } /** @@ -1038,6 +1053,10 @@ public abstract class PhoneBase extends Handler implements Phone { "called, CDMAPhone inactive."); } + public DataState getDataConnectionState() { + return getDataConnectionState(APN_TYPE_DEFAULT); + } + /** * Common error logger method for unexpected calls to GSM/WCDMA-only methods. */ diff --git a/telephony/java/com/android/internal/telephony/PhoneNotifier.java b/telephony/java/com/android/internal/telephony/PhoneNotifier.java index e96eeae..28a8d22 100644 --- a/telephony/java/com/android/internal/telephony/PhoneNotifier.java +++ b/telephony/java/com/android/internal/telephony/PhoneNotifier.java @@ -33,10 +33,13 @@ public interface PhoneNotifier { public void notifyCallForwardingChanged(Phone sender); - public void notifyDataConnection(Phone sender, String reason); + /** TODO - reason should never be null */ + public void notifyDataConnection(Phone sender, String reason, String apnType, + Phone.DataState state); - public void notifyDataConnectionFailed(Phone sender, String reason); + public void notifyDataConnectionFailed(Phone sender, String reason, String apnType); public void notifyDataActivity(Phone sender); + public void notifyOtaspChanged(Phone sender, int otaspMode); } diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java index 77f1e6c..02fdf28 100644 --- a/telephony/java/com/android/internal/telephony/PhoneProxy.java +++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java @@ -20,13 +20,12 @@ package com.android.internal.telephony; import android.app.ActivityManagerNative; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; +import android.net.LinkCapabilities; +import android.net.LinkProperties; import android.os.Handler; import android.os.Message; import android.os.SystemProperties; -import android.preference.PreferenceManager; import android.telephony.CellLocation; -import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.util.Log; @@ -34,7 +33,6 @@ import android.util.Log; import com.android.internal.telephony.cdma.CDMAPhone; import com.android.internal.telephony.gsm.GSMPhone; import com.android.internal.telephony.gsm.NetworkInfo; -import com.android.internal.telephony.gsm.GsmDataConnection; import com.android.internal.telephony.test.SimulatedRadioControl; import java.util.List; @@ -172,7 +170,11 @@ public class PhoneProxy extends Handler implements Phone { } public DataState getDataConnectionState() { - return mActivePhone.getDataConnectionState(); + return mActivePhone.getDataConnectionState(Phone.APN_TYPE_DEFAULT); + } + + public DataState getDataConnectionState(String apnType) { + return mActivePhone.getDataConnectionState(apnType); } public DataActivityState getDataActivityState() { @@ -207,6 +209,14 @@ public class PhoneProxy extends Handler implements Phone { return mActivePhone.getActiveApnTypes(); } + public LinkProperties getLinkProperties(String apnType) { + return mActivePhone.getLinkProperties(apnType); + } + + public LinkCapabilities getLinkCapabilities(String apnType) { + return mActivePhone.getLinkCapabilities(apnType); + } + public String getActiveApn() { return mActivePhone.getActiveApn(); } @@ -664,22 +674,6 @@ public class PhoneProxy extends Handler implements Phone { return mActivePhone.isDataConnectivityPossible(); } - public String getInterfaceName(String apnType) { - return mActivePhone.getInterfaceName(apnType); - } - - public String getIpAddress(String apnType) { - return mActivePhone.getIpAddress(apnType); - } - - public String getGateway(String apnType) { - return mActivePhone.getGateway(apnType); - } - - public String[] getDnsServers(String apnType) { - return mActivePhone.getDnsServers(apnType); - } - public String getDeviceId() { return mActivePhone.getDeviceId(); } @@ -768,6 +762,10 @@ public class PhoneProxy extends Handler implements Phone { mActivePhone.exitEmergencyCallbackMode(); } + public boolean needsOtaServiceProvisioning(){ + return mActivePhone.needsOtaServiceProvisioning(); + } + public boolean isOtaSpNumber(String dialStr){ return mActivePhone.isOtaSpNumber(dialStr); } diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index a9a4be2..35d5564 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -285,9 +285,8 @@ public final class RIL extends BaseCommands implements CommandsInterface { } - //***** Handler implemementation - - public void + //***** Handler implementation + @Override public void handleMessage(Message msg) { RILRequest rr = (RILRequest)(msg.obj); RILRequest req = null; @@ -780,7 +779,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + @Deprecated public void getPDPContextList(Message result) { getDataCallList(result); } @@ -1299,10 +1298,18 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void setupDataCall(String radioTechnology, String profile, String apn, String user, String password, String authType, Message result) { + setupDataCallWithProtocol(radioTechnology, profile, apn, user, password, + authType, "IP", result); + } + + public void + setupDataCallWithProtocol(String radioTechnology, String profile, + String apn, String user, String password, String authType, + String protocolType, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result); - rr.mp.writeInt(6); + rr.mp.writeInt(7); rr.mp.writeString(radioTechnology); rr.mp.writeString(profile); @@ -1310,11 +1317,12 @@ public final class RIL extends BaseCommands implements CommandsInterface { rr.mp.writeString(user); rr.mp.writeString(password); rr.mp.writeString(authType); + rr.mp.writeString(protocolType); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + radioTechnology + " " + profile + " " + apn + " " + user + " " - + password + " " + authType); + + password + " " + authType + " " + protocolType); send(rr); } @@ -2907,7 +2915,11 @@ public final class RIL extends BaseCommands implements CommandsInterface { dataCall.active = p.readInt(); dataCall.type = p.readString(); dataCall.apn = p.readString(); - dataCall.address = p.readString(); + String address = p.readString(); + if (address != null) { + address = address.split(" ")[0]; + } + dataCall.address = address; response.add(dataCall); } diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java index 917e1d8..3a7ce47 100644 --- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java @@ -255,6 +255,7 @@ public abstract class SMSDispatcher extends Handler { mCm.unregisterForOn(this); } + @Override protected void finalize() { Log.d(TAG, "SMSDispatcher finalized"); } @@ -927,14 +928,14 @@ public abstract class SMSDispatcher extends Handler { */ static protected class SmsTracker { // fields need to be public for derived SmsDispatchers - public HashMap mData; + public HashMap<String, Object> mData; public int mRetryCount; public int mMessageRef; public PendingIntent mSentIntent; public PendingIntent mDeliveryIntent; - SmsTracker(HashMap data, PendingIntent sentIntent, + SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent, PendingIntent deliveryIntent) { mData = data; mSentIntent = sentIntent; @@ -943,7 +944,7 @@ public abstract class SMSDispatcher extends Handler { } } - protected SmsTracker SmsTrackerFactory(HashMap data, PendingIntent sentIntent, + protected SmsTracker SmsTrackerFactory(HashMap<String, Object> data, PendingIntent sentIntent, PendingIntent deliveryIntent) { return new SmsTracker(data, sentIntent, deliveryIntent); } diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java index e8bbe5e..3f9ffc3 100644 --- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java @@ -53,6 +53,12 @@ public abstract class ServiceStateTracker extends Handler { public SignalStrength mSignalStrength; + /* The otaspMode passed to PhoneStateListener#onOtaspChanged */ + static public final int OTASP_UNINITIALIZED = 0; + static public final int OTASP_UNKNOWN = 1; + static public final int OTASP_NEEDED = 2; + static public final int OTASP_NOT_NEEDED = 3; + /** * A unique identifier to track requests associated with a poll * and ignore stale responses. The value is a count-down of @@ -268,9 +274,11 @@ public abstract class ServiceStateTracker extends Handler { public abstract void handleMessage(Message msg); + protected abstract Phone getPhone(); protected abstract void handlePollStateResult(int what, AsyncResult ar); protected abstract void updateSpnDisplay(); protected abstract void setPowerStateToDesired(); + protected abstract void log(String s); /** * Clean up existing voice and data connection then turn off radio power. diff --git a/telephony/java/com/android/internal/telephony/SmsHeader.java b/telephony/java/com/android/internal/telephony/SmsHeader.java index 7872eec..7a65162 100644 --- a/telephony/java/com/android/internal/telephony/SmsHeader.java +++ b/telephony/java/com/android/internal/telephony/SmsHeader.java @@ -30,7 +30,7 @@ import java.util.ArrayList; */ public class SmsHeader { - // TODO(cleanup): this datastructure is generally referred to as + // TODO(cleanup): this data structure is generally referred to as // the 'user data header' or UDH, and so the class name should // change to reflect this... diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java index af6c5f8..cbd8606 100644 --- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -16,7 +16,6 @@ package com.android.internal.telephony; -import android.util.Log; import com.android.internal.telephony.SmsHeader; import java.util.Arrays; @@ -366,13 +365,13 @@ public abstract class SmsMessageBase { /** * 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 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." (which is supported here) - * - Multiple addreses separated by commas, no spaces, Subject field delimited + * - Multiple addresses 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() { diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index a113787..136d5b1 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -45,7 +45,7 @@ public interface TelephonyProperties * CDMA networks. */ static final String PROPERTY_OPERATOR_ALPHA = "gsm.operator.alpha"; - //TODO: most of these proprieties are generic, substitute gsm. with phone. bug 1856959 + //TODO: most of these properties are generic, substitute gsm. with phone. bug 1856959 /** Numeric name (MCC+MNC) of current registered operator.<p> * Availability: when registered to a network. Result may be unreliable on @@ -83,12 +83,12 @@ public interface TelephonyProperties /** The MCC+MNC (mobile country code+mobile network code) of the * provider of the SIM. 5 or 6 decimal digits. - * Availablity: SIM state must be "READY" + * Availability: SIM state must be "READY" */ static String PROPERTY_ICC_OPERATOR_NUMERIC = "gsm.sim.operator.numeric"; /** PROPERTY_ICC_OPERATOR_ALPHA is also known as the SPN, or Service Provider Name. - * Availablity: SIM state must be "READY" + * Availability: SIM state must be "READY" */ static String PROPERTY_ICC_OPERATOR_ALPHA = "gsm.sim.operator.alpha"; @@ -127,7 +127,7 @@ public interface TelephonyProperties "ro.telephony.call_ring.multiple"; /** - * The number of milli-seconds between CALL_RING notifications. + * The number of milliseconds 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 f31bf24..b9d5673 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java @@ -61,6 +61,7 @@ import com.android.internal.telephony.PhoneBase; import com.android.internal.telephony.PhoneNotifier; import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.PhoneSubInfo; +import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.UUSInfo; @@ -83,10 +84,6 @@ public class CDMAPhone extends PhoneBase { static final String LOG_TAG = "CDMA"; private static final boolean DBG = true; - // Min values used to by needsActivation - private static final String UNACTIVATED_MIN2_VALUE = "000000"; - private static final String UNACTIVATED_MIN_VALUE = "1111110111"; - // Default Emergency Callback Mode exit timer private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000; @@ -515,14 +512,6 @@ public class CDMAPhone extends PhoneBase { return false; } - public boolean isDataConnectivityPossible() { - boolean noData = mDataConnection.getDataEnabled() && - getDataConnectionState() == DataState.DISCONNECTED; - return !noData && getIccCard().getState() == IccCard.State.READY && - getServiceState().getState() == ServiceState.STATE_IN_SERVICE && - (mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming()); - } - /** * Removes the given MMI from the pending list and notifies registrants that * it is complete. @@ -613,7 +602,7 @@ public class CDMAPhone extends PhoneBase { } } - public DataState getDataConnectionState() { + public DataState getDataConnectionState(String apnType) { DataState ret = DataState.DISCONNECTED; if (mSST == null) { @@ -625,6 +614,8 @@ public class CDMAPhone extends PhoneBase { // If we're out of service, open TCP sockets may still work // but no data will flow ret = DataState.DISCONNECTED; + } else if (mDataConnection.isApnTypeEnabled(apnType) == false) { + ret = DataState.DISCONNECTED; } else { switch (mDataConnection.getState()) { case FAILED: @@ -878,26 +869,6 @@ public class CDMAPhone extends PhoneBase { mRuimRecords.setVoiceMessageWaiting(1, mwi); } - /** - * Returns true if CDMA OTA Service Provisioning needs to be performed. - */ - /* package */ boolean - needsOtaServiceProvisioning() { - String cdmaMin = getCdmaMin(); - boolean needsProvisioning; - if (cdmaMin == null || (cdmaMin.length() < 6)) { - if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: illegal cdmaMin='" - + cdmaMin + "' assume provisioning needed."); - needsProvisioning = true; - } else { - needsProvisioning = (cdmaMin.equals(UNACTIVATED_MIN_VALUE) - || cdmaMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE)) - || SystemProperties.getBoolean("test_cdma_setup", false); - } - if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: ret=" + needsProvisioning); - return needsProvisioning; - } - @Override public void exitEmergencyCallbackMode() { if (mWakeLock.isHeld()) { @@ -1191,6 +1162,14 @@ public class CDMAPhone extends PhoneBase { mSMS.setCellBroadcastConfig(configValuesArray, response); } + /** + * Returns true if OTA Service Provisioning needs to be performed. + */ + @Override + public boolean needsOtaServiceProvisioning() { + return mSST.getOtasp() != ServiceStateTracker.OTASP_NOT_NEEDED; + } + 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; diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java index 3669e60..325c2e1 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java @@ -354,6 +354,24 @@ public final class CdmaCallTracker extends CallTracker { || (foregroundCall.getState() == CdmaCall.State.ACTIVE) || !backgroundCall.getState().isAlive()); + if (!ret) { + log(String.format("canDial is false\n" + + "((serviceState=%d) != ServiceState.STATE_POWER_OFF)::=%s\n" + + "&& pendingMO == null::=%s\n" + + "&& !ringingCall.isRinging()::=%s\n" + + "&& !disableCall.equals(\"true\")::=%s\n" + + "&& (!foregroundCall.getState().isAlive()::=%s\n" + + " || foregroundCall.getState() == CdmaCall.State.ACTIVE::=%s\n" + + " ||!backgroundCall.getState().isAlive())::=%s)", + serviceState, + serviceState != ServiceState.STATE_POWER_OFF, + pendingMO == null, + !ringingCall.isRinging(), + !disableCall.equals("true"), + !foregroundCall.getState().isAlive(), + foregroundCall.getState() == CdmaCall.State.ACTIVE, + !backgroundCall.getState().isAlive())); + } return ret; } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java index 95cb1c6..8072c44 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java @@ -23,6 +23,7 @@ import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.gsm.ApnSetting; import com.android.internal.telephony.Phone; import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.RetryManager; /** * {@hide} @@ -39,23 +40,27 @@ public class CdmaDataConnection extends DataConnection { // ***** Constructor - private CdmaDataConnection(CDMAPhone phone, String name) { - super(phone, name); + private CdmaDataConnection(CDMAPhone phone, String name, RetryManager rm) { + super(phone, name, rm); } /** * Create the connection object * - * @param phone + * @param phone the Phone + * @param id the connection id + * @param rm the RetryManager * @return CdmaDataConnection that was created. */ - static CdmaDataConnection makeDataConnection(CDMAPhone phone) { + static CdmaDataConnection makeDataConnection(CDMAPhone phone, int id, RetryManager rm) { synchronized (mCountLock) { mCount += 1; } - CdmaDataConnection cdmaDc = new CdmaDataConnection(phone, "CdmaDataConnection-" + mCount); + CdmaDataConnection cdmaDc = new CdmaDataConnection(phone, + "CdmaDataConnection-" + mCount, rm); cdmaDc.start(); if (DBG) cdmaDc.log("Made " + cdmaDc.getName()); + cdmaDc.mId = id; return cdmaDc; } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java index 9f2a44b..7c652c5 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -18,23 +18,13 @@ package com.android.internal.telephony.cdma; import android.app.AlarmManager; import android.app.PendingIntent; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.net.ConnectivityManager; -import android.net.IConnectivityManager; -import android.net.NetworkInfo; import android.net.TrafficStats; -import android.net.wifi.WifiManager; import android.os.AsyncResult; 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.telephony.ServiceState; import android.telephony.TelephonyManager; import android.telephony.cdma.CdmaCellLocation; @@ -48,10 +38,9 @@ import com.android.internal.telephony.DataConnection.FailCause; import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.EventLogTags; +import com.android.internal.telephony.RetryManager; import com.android.internal.telephony.gsm.ApnSetting; import com.android.internal.telephony.Phone; -import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.ServiceStateTracker; import java.util.ArrayList; @@ -63,20 +52,11 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { private CDMAPhone mCdmaPhone; - // Indicates baseband will not auto-attach - private boolean noAutoAttach = false; - private boolean mIsScreenOn = true; - //useful for debugging - boolean failNextConnect = false; + boolean mFailNextConnect = false; - /** - * dataConnectionList holds all the Data connection - */ - private ArrayList<DataConnection> dataConnectionList; - - /** Currently active CdmaDataConnection */ - private CdmaDataConnection mActiveDataConnection; + /** The DataConnection being setup */ + private CdmaDataConnection mPendingDataConnection; private boolean mPendingRestartRadio = false; private static final int TIME_DELAYED_TO_RESTART_RADIO = @@ -87,10 +67,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { */ private static final int DATA_CONNECTION_POOL_SIZE = 1; - private static final int POLL_CONNECTION_MILLIS = 5 * 1000; private static final String INTENT_RECONNECT_ALARM = - "com.android.internal.telephony.cdma-reconnect"; - private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; + "com.android.internal.telephony.cdma-reconnect"; /** * Constants for the data connection activity: @@ -114,49 +92,6 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { // if we have no active Apn this is null protected ApnSetting mActiveApn; - // Possibly promote to base class, the only difference is - // the INTENT_RECONNECT_ALARM action is a different string. - // Do consider technology changes if it is promoted. - BroadcastReceiver mIntentReceiver = new BroadcastReceiver () - { - @Override - public void onReceive(Context context, Intent intent) - { - String action = intent.getAction(); - if (action.equals(Intent.ACTION_SCREEN_ON)) { - mIsScreenOn = true; - stopNetStatPoll(); - startNetStatPoll(); - } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - mIsScreenOn = false; - stopNetStatPoll(); - startNetStatPoll(); - } else if (action.equals((INTENT_RECONNECT_ALARM))) { - Log.d(LOG_TAG, "Data reconnect alarm. Previous state was " + state); - - String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); - if (state == State.FAILED) { - cleanUpConnection(false, reason); - } - trySetupData(reason); - } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - final android.net.NetworkInfo networkInfo = (NetworkInfo) - intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); - mIsWifiConnected = (networkInfo != null && networkInfo.isConnected()); - } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; - - if (!enabled) { - // when wifi got disabeled, the NETWORK_STATE_CHANGED_ACTION - // quit and wont report disconnected til next enalbing. - mIsWifiConnected = false; - } - } - } - }; - - /* Constructor */ CdmaDataConnectionTracker(CDMAPhone p) { @@ -176,79 +111,49 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); p.mCM.registerForCdmaOtaProvision(this, EVENT_CDMA_OTA_PROVISION, null); - IntentFilter filter = new IntentFilter(); - filter.addAction(INTENT_RECONNECT_ALARM); - filter.addAction(Intent.ACTION_SCREEN_ON); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - - // 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; createAllDataConnectionList(); - - // This preference tells us 1) initial condition for "dataEnabled", - // and 2) whether the RIL will setup the baseband to auto-PS attach. - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext()); - - boolean dataEnabledSetting = true; - try { - dataEnabledSetting = IConnectivityManager.Stub.asInterface(ServiceManager. - getService(Context.CONNECTIVITY_SERVICE)).getMobileDataEnabled(); - } catch (Exception e) { - // nothing to do - use the old behavior and leave data on - } - dataEnabled[APN_DEFAULT_ID] = - !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false) && - dataEnabledSetting; - 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); - } - } } + @Override public void dispose() { + super.dispose(); + // Unregister from all events - phone.mCM.unregisterForAvailable(this); - phone.mCM.unregisterForOffOrNotAvailable(this); + mPhone.mCM.unregisterForAvailable(this); + mPhone.mCM.unregisterForOffOrNotAvailable(this); mCdmaPhone.mRuimRecords.unregisterForRecordsLoaded(this); - phone.mCM.unregisterForNVReady(this); - phone.mCM.unregisterForDataStateChanged(this); + mPhone.mCM.unregisterForNVReady(this); + mPhone.mCM.unregisterForDataStateChanged(this); mCdmaPhone.mCT.unregisterForVoiceCallEnded(this); mCdmaPhone.mCT.unregisterForVoiceCallStarted(this); mCdmaPhone.mSST.unregisterForCdmaDataConnectionAttached(this); mCdmaPhone.mSST.unregisterForCdmaDataConnectionDetached(this); mCdmaPhone.mSST.unregisterForRoamingOn(this); mCdmaPhone.mSST.unregisterForRoamingOff(this); - phone.mCM.unregisterForCdmaOtaProvision(this); + mPhone.mCM.unregisterForCdmaOtaProvision(this); - phone.getContext().unregisterReceiver(this.mIntentReceiver); destroyAllDataConnectionList(); } + @Override protected void finalize() { - if(DBG) Log.d(LOG_TAG, "CdmaDataConnectionTracker finalized"); + if(DBG) log("CdmaDataConnectionTracker finalized"); + } + + @Override + protected String getActionIntentReconnectAlarm() { + return INTENT_RECONNECT_ALARM; } + @Override protected void setState(State s) { if (DBG) log ("setState: " + s); - if (state != s) { + if (mState != s) { EventLog.writeEvent(EventLogTags.CDMA_DATA_STATE_CHANGE, - state.toString(), s.toString()); - state = s; + mState.toString(), s.toString()); + mState = s; } } @@ -267,6 +172,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { return false; } + @Override protected String[] getActiveApnTypes() { String[] result; if (mActiveApn != null) { @@ -278,6 +184,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { return result; } + @Override protected String getActiveApnString() { return null; } @@ -291,84 +198,98 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { * * @return false while no data connection if all above requirements are met. */ + @Override public boolean isDataConnectionAsDesired() { - boolean roaming = phone.getServiceState().getRoaming(); + boolean roaming = mPhone.getServiceState().getRoaming(); - if (((phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) || + if (((mPhone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) || mCdmaPhone.mRuimRecords.getRecordsLoaded()) && (mCdmaPhone.mSST.getCurrentCdmaDataConnectionState() == ServiceState.STATE_IN_SERVICE) && (!roaming || getDataOnRoamingEnabled()) && !mIsWifiConnected ) { - return (state == State.CONNECTED); + return (mState == State.CONNECTED); } return true; } - private boolean isDataAllowed() { - boolean roaming = phone.getServiceState().getRoaming(); - return getAnyDataEnabled() && (!roaming || getDataOnRoamingEnabled()) && mMasterDataEnabled; + @Override + protected boolean isDataAllowed() { + int psState = mCdmaPhone.mSST.getCurrentCdmaDataConnectionState(); + boolean roaming = (mPhone.getServiceState().getRoaming() && !getDataOnRoamingEnabled()); + boolean desiredPowerState = mCdmaPhone.mSST.getDesiredPowerState(); + + boolean allowed = + (psState == ServiceState.STATE_IN_SERVICE || + mAutoAttachOnCreation) && + (mPhone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY || + mCdmaPhone.mRuimRecords.getRecordsLoaded()) && + (mCdmaPhone.mSST.isConcurrentVoiceAndData() || + mPhone.getState() == Phone.State.IDLE) && + !roaming && + mMasterDataEnabled && + desiredPowerState && + !mPendingRestartRadio && + !mCdmaPhone.needsOtaServiceProvisioning(); + if (!allowed && DBG) { + String reason = ""; + if (!((psState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) { + reason += " - psState= " + psState; + } + if (!(mPhone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY || + mCdmaPhone.mRuimRecords.getRecordsLoaded())) { + reason += " - radioState= " + mPhone.mCM.getRadioState() + " - RUIM not loaded"; + } + if (mPhone.getState() != Phone.State.IDLE && + mCdmaPhone.mSST.isConcurrentVoiceAndData()) { + reason += " - concurrentVoiceAndData not allowed and state= " + mPhone.getState(); + } + if (roaming) reason += " - Roaming"; + if (!mMasterDataEnabled) reason += " - mMasterDataEnabled= false"; + if (!desiredPowerState) reason += " - desiredPowerState= false"; + if (mPendingRestartRadio) reason += " - mPendingRestartRadio= true"; + if (mCdmaPhone.needsOtaServiceProvisioning()) reason += " - needs Provisioning"; + log("Data not allowed due to" + reason); + } + return allowed; } private boolean trySetupData(String reason) { if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason)); - if (phone.getSimulatedRadioControl() != null) { + if (mPhone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved setState(State.CONNECTED); - phone.notifyDataConnection(reason); + notifyDataConnection(reason); + notifyOffApnsOfAvailability(reason, true); - Log.i(LOG_TAG, "(fix?) We're on the simulator; assuming data is connected"); + log("(fix?) We're on the simulator; assuming data is connected"); return true; } int psState = mCdmaPhone.mSST.getCurrentCdmaDataConnectionState(); - boolean roaming = phone.getServiceState().getRoaming(); + boolean roaming = mPhone.getServiceState().getRoaming(); boolean desiredPowerState = mCdmaPhone.mSST.getDesiredPowerState(); - if ((state == State.IDLE || state == State.SCANNING) - && (psState == ServiceState.STATE_IN_SERVICE) - && ((phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) || - mCdmaPhone.mRuimRecords.getRecordsLoaded()) - && (mCdmaPhone.mSST.isConcurrentVoiceAndData() || - phone.getState() == Phone.State.IDLE ) - && isDataAllowed() - && desiredPowerState - && !mPendingRestartRadio - && !mCdmaPhone.needsOtaServiceProvisioning()) { - - return setupData(reason); - + if ((mState == State.IDLE || mState == State.SCANNING) && + isDataAllowed() && getAnyDataEnabled()) { + boolean retValue = setupData(reason); + notifyOffApnsOfAvailability(reason, retValue); + return retValue; } else { - if (DBG) { - log("trySetupData: Not ready for data: " + - " dataState=" + state + - " PS state=" + psState + - " radio state=" + phone.mCM.getRadioState() + - " ruim=" + mCdmaPhone.mRuimRecords.getRecordsLoaded() + - " concurrentVoice&Data=" + mCdmaPhone.mSST.isConcurrentVoiceAndData() + - " phoneState=" + phone.getState() + - " dataEnabled=" + getAnyDataEnabled() + - " roaming=" + roaming + - " dataOnRoamingEnable=" + getDataOnRoamingEnabled() + - " desiredPowerState=" + desiredPowerState + - " PendingRestartRadio=" + mPendingRestartRadio + - " MasterDataEnabled=" + mMasterDataEnabled + - " needsOtaServiceProvisioning=" + mCdmaPhone.needsOtaServiceProvisioning()); - } + notifyOffApnsOfAvailability(reason, false); return false; } } /** - * If tearDown is true, this only tears down a CONNECTED session. Presently, - * there is no mechanism for abandoning an INITING/CONNECTING session, - * but would likely involve cancelling pending async requests or - * setting a flag or new state to ignore them when they came in - * @param tearDown true if the underlying DataConnection should be - * disconnected. - * @param reason reason for the clean up. + * Cleanup all connections. + * + * TODO: Cleanup only a specified connection passed as a parameter. + * + * @param tearDown true if the underlying DataConnection should be disconnected. + * @param reason for the clean up. */ private void cleanUpConnection(boolean tearDown, String reason) { if (DBG) log("cleanUpConnection: reason: " + reason); @@ -376,19 +297,21 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { // Clear the reconnect alarm, if set. if (mReconnectIntent != null) { AlarmManager am = - (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); am.cancel(mReconnectIntent); mReconnectIntent = null; } setState(State.DISCONNECTING); + notifyDataAvailability(reason); boolean notificationDeferred = false; - for (DataConnection conn : dataConnectionList) { + for (DataConnection conn : mDataConnections.values()) { if(conn != null) { if (tearDown) { if (DBG) log("cleanUpConnection: teardown, call conn.disconnect"); - conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason)); + conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, + conn.getDataConnectionId(), 0, reason)); notificationDeferred = true; } else { if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously"); @@ -407,10 +330,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } private CdmaDataConnection findFreeDataConnection() { - for (DataConnection connBase : dataConnectionList) { - CdmaDataConnection conn = (CdmaDataConnection) connBase; - if (conn.isInactive()) { - return conn; + for (DataConnection dc : mDataConnections.values()) { + if (dc.isInactive()) { + return (CdmaDataConnection) dc; } } return null; @@ -424,7 +346,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { return false; } - mActiveDataConnection = conn; + /** TODO: We probably want the connection being setup to a parameter passed around */ + mPendingDataConnection = conn; String[] types; if (mRequestedApnType.equals(Phone.APN_TYPE_DUN)) { types = new String[1]; @@ -440,40 +363,43 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { conn.connect(msg, mActiveApn); setState(State.INITING); - phone.notifyDataConnection(reason); + notifyDataConnection(reason); return true; } private void notifyDefaultData(String reason) { setState(State.CONNECTED); - phone.notifyDataConnection(reason); + notifyDataConnection(reason); startNetStatPoll(); mRetryMgr.resetRetryCount(); } private void resetPollStats() { - txPkts = -1; - rxPkts = -1; - sentSinceLastRecv = 0; - netStatPollPeriod = POLL_NETSTAT_MILLIS; + mTxPkts = -1; + mRxPkts = -1; + mSentSinceLastRecv = 0; + mNetStatPollPeriod = POLL_NETSTAT_MILLIS; mNoRecvPollCount = 0; } + @Override protected void startNetStatPoll() { - if (state == State.CONNECTED && netStatPollEnabled == false) { - Log.d(LOG_TAG, "[DataConnection] Start poll NetStat"); + if (mState == State.CONNECTED && mNetStatPollEnabled == false) { + log("[DataConnection] Start poll NetStat"); resetPollStats(); - netStatPollEnabled = true; + mNetStatPollEnabled = true; mPollNetStat.run(); } } + @Override protected void stopNetStatPoll() { - netStatPollEnabled = false; + mNetStatPollEnabled = false; removeCallbacks(mPollNetStat); - Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat"); + log("[DataConnection] Stop poll NetStat"); } + @Override protected void restartRadio() { if (DBG) log("Cleanup connection and wait " + (TIME_DELAYED_TO_RESTART_RADIO / 1000) + "s to restart radio"); @@ -490,73 +416,73 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { Activity newActivity; - preTxPkts = txPkts; - preRxPkts = rxPkts; + preTxPkts = mTxPkts; + preRxPkts = mRxPkts; - txPkts = TrafficStats.getMobileTxPackets(); - rxPkts = TrafficStats.getMobileRxPackets(); + mTxPkts = TrafficStats.getMobileTxPackets(); + mRxPkts = TrafficStats.getMobileRxPackets(); - //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); + //log("rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); - if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { - sent = txPkts - preTxPkts; - received = rxPkts - preRxPkts; + if (mNetStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { + sent = mTxPkts - preTxPkts; + received = mRxPkts - preRxPkts; if ( sent > 0 && received > 0 ) { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; newActivity = Activity.DATAINANDOUT; } else if (sent > 0 && received == 0) { - if (phone.getState() == Phone.State.IDLE) { - sentSinceLastRecv += sent; + if (mPhone.getState() == Phone.State.IDLE) { + mSentSinceLastRecv += sent; } else { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; } newActivity = Activity.DATAOUT; } else if (sent == 0 && received > 0) { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; newActivity = Activity.DATAIN; } else if (sent == 0 && received == 0) { - newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE; + newActivity = (mActivity == Activity.DORMANT) ? mActivity : Activity.NONE; } else { - sentSinceLastRecv = 0; - newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE; + mSentSinceLastRecv = 0; + newActivity = (mActivity == Activity.DORMANT) ? mActivity : Activity.NONE; } - if (activity != newActivity) { - activity = newActivity; - phone.notifyDataActivity(); + if (mActivity != newActivity && mIsScreenOn) { + mActivity = newActivity; + mPhone.notifyDataActivity(); } } - if (sentSinceLastRecv >= NUMBER_SENT_PACKETS_OF_HANG) { + if (mSentSinceLastRecv >= NUMBER_SENT_PACKETS_OF_HANG) { // Packets sent without ack exceeded threshold. if (mNoRecvPollCount == 0) { EventLog.writeEvent( EventLogTags.PDP_RADIO_RESET_COUNTDOWN_TRIGGERED, - sentSinceLastRecv); + mSentSinceLastRecv); } if (mNoRecvPollCount < NO_RECV_POLL_LIMIT) { mNoRecvPollCount++; // Slow down the poll interval to let things happen - netStatPollPeriod = POLL_NETSTAT_SLOW_MILLIS; + mNetStatPollPeriod = POLL_NETSTAT_SLOW_MILLIS; } else { - if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + + if (DBG) log("Sent " + String.valueOf(mSentSinceLastRecv) + " pkts since last received"); // We've exceeded the threshold. Restart the radio. - netStatPollEnabled = false; + mNetStatPollEnabled = false; stopNetStatPoll(); restartRadio(); EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, NO_RECV_POLL_LIMIT); } } else { mNoRecvPollCount = 0; - netStatPollPeriod = POLL_NETSTAT_MILLIS; + mNetStatPollPeriod = POLL_NETSTAT_MILLIS; } - if (netStatPollEnabled) { - mDataConnectionTracker.postDelayed(this, netStatPollPeriod); + if (mNetStatPollEnabled) { + mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod); } } }; @@ -588,7 +514,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { - if (state == State.FAILED) { + if (mState == State.FAILED) { /** * For now With CDMA we never try to reconnect on * error and instead just continue to retry @@ -596,15 +522,15 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { * TODO: Make this configurable? */ int nextReconnectDelay = mRetryMgr.getRetryTimer(); - Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for " + log("Data Connection activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); AlarmManager am = - (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(INTENT_RECONNECT_ALARM); intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason); mReconnectIntent = PendingIntent.getBroadcast( - phone.getContext(), 0, intent, 0); + mPhone.getContext(), 0, intent, 0); am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + nextReconnectDelay, mReconnectIntent); @@ -612,7 +538,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { mRetryMgr.increaseRetryCount(); if (!shouldPostNotification(lastFailCauseCode)) { - Log.d(LOG_TAG,"NOT Posting Data Connection Unavailable notification " + log("NOT Posting Data Connection Unavailable notification " + "-- likely transient error"); } else { notifyNoData(lastFailCauseCode); @@ -622,24 +548,25 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { private void notifyNoData(FailCause lastFailCauseCode) { setState(State.FAILED); + notifyDataAvailability(null); } private void gotoIdleAndNotifyDataConnection(String reason) { if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason); setState(State.IDLE); - phone.notifyDataConnection(reason); + notifyDataConnection(reason); mActiveApn = null; } protected void onRecordsLoaded() { - if (state == State.FAILED) { + if (mState == State.FAILED) { cleanUpConnection(false, null); } sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED)); } protected void onNVReady() { - if (state == State.FAILED) { + if (mState == State.FAILED) { cleanUpConnection(false, null); } sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); @@ -650,12 +577,13 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { */ @Override protected void onEnableNewApn() { - cleanUpConnection(true, Phone.REASON_APN_SWITCHED); + cleanUpConnection(true, Phone.REASON_APN_SWITCHED); } /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected boolean onTrySetupData(String reason) { return trySetupData(reason); } @@ -663,6 +591,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onRoamingOff() { trySetupData(Phone.REASON_ROAMING_OFF); } @@ -670,6 +599,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onRoamingOn() { if (getDataOnRoamingEnabled()) { trySetupData(Phone.REASON_ROAMING_ON); @@ -682,17 +612,20 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onRadioAvailable() { - if (phone.getSimulatedRadioControl() != null) { + if (mPhone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved setState(State.CONNECTED); - phone.notifyDataConnection(null); + notifyDataConnection(null); - Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); + log("We're on the simulator; assuming data is connected"); } - if (state != State.IDLE) { + notifyDataAvailability(null); + + if (mState != State.IDLE) { cleanUpConnection(true, null); } } @@ -700,13 +633,14 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onRadioOffOrNotAvailable() { mRetryMgr.resetRetryCount(); - if (phone.getSimulatedRadioControl() != null) { + if (mPhone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved - Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); + log("We're on the simulator; assuming radio off is meaningless"); } else { if (DBG) log("Radio is off and clean up all connection"); cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF); @@ -716,6 +650,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onDataSetupComplete(AsyncResult ar) { String reason = null; if (ar.userObj instanceof String) { @@ -723,6 +658,10 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } if (ar.exception == null) { + // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected + mLinkProperties = getLinkProperties(mPendingDataConnection); + mLinkCapabilities = getLinkCapabilities(mPendingDataConnection); + // everything is setup notifyDefaultData(reason); } else { @@ -741,8 +680,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * Called when EVENT_DISCONNECT_DONE is received. */ - protected void onDisconnectDone(AsyncResult ar) { - if(DBG) log("EVENT_DISCONNECT_DONE"); + @Override + protected void onDisconnectDone(int connId, AsyncResult ar) { + if(DBG) log("EVENT_DISCONNECT_DONE connId=" + connId); String reason = null; if (ar.userObj instanceof String) { reason = (String) ar.userObj; @@ -762,7 +702,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { onRestartRadio(); } - phone.notifyDataConnection(reason); + notifyDataConnection(reason); mActiveApn = null; if (retryAfterDisconnected(reason)) { trySetupData(reason); @@ -786,25 +726,29 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onVoiceCallStarted() { - if (state == State.CONNECTED && !mCdmaPhone.mSST.isConcurrentVoiceAndData()) { + if (mState == State.CONNECTED && !mCdmaPhone.mSST.isConcurrentVoiceAndData()) { stopNetStatPoll(); - phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); + notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); + notifyDataAvailability(Phone.REASON_VOICE_CALL_STARTED); } } /** * @override com.android.internal.telephony.DataConnectionTracker */ + @Override protected void onVoiceCallEnded() { - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { if (!mCdmaPhone.mSST.isConcurrentVoiceAndData()) { startNetStatPoll(); - phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); + notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); } else { // clean slate after call end. resetPollStats(); } + notifyDataAvailability(Phone.REASON_VOICE_CALL_ENDED); } else { mRetryMgr.resetRetryCount(); // in case data setup was attempted when we were on a voice call @@ -812,39 +756,49 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } } - /** - * @override com.android.internal.telephony.DataConnectionTracker - */ + @Override protected void onCleanUpConnection(boolean tearDown, String reason) { cleanUpConnection(tearDown, reason); } private void createAllDataConnectionList() { - dataConnectionList = new ArrayList<DataConnection>(); CdmaDataConnection dataConn; - for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) { - dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone); - dataConnectionList.add(dataConn); - } + /** TODO: Use one retry manager for all connections for now */ + RetryManager rm = mRetryMgr; + if (!rm.configure(SystemProperties.get("ro.cdma.data_retry_config"))) { + if (!rm.configure(DEFAULT_DATA_RETRY_CONFIG)) { + // Should never happen, log an error and default to a simple linear sequence. + log("Could not configure using DEFAULT_DATA_RETRY_CONFIG=" + + DEFAULT_DATA_RETRY_CONFIG); + rm.configure(20, 2000, 1000); + } + } + + for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) { + int id = mUniqueIdGenerator.getAndIncrement(); + + dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone, id, rm); + mDataConnections.put(id, dataConn); + } } private void destroyAllDataConnectionList() { - if(dataConnectionList != null) { - dataConnectionList.removeAll(dataConnectionList); + if(mDataConnections != null) { + mDataConnections.clear(); } } private void onCdmaDataDetached() { - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { startNetStatPoll(); - phone.notifyDataConnection(Phone.REASON_CDMA_DATA_DETACHED); + notifyDataConnection(Phone.REASON_CDMA_DATA_DETACHED); } else { - if (state == State.FAILED) { + if (mState == State.FAILED) { cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED); mRetryMgr.resetRetryCount(); - CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation()); + CdmaCellLocation loc = (CdmaCellLocation)(mPhone.getCellLocation()); EventLog.writeEvent(EventLogTags.CDMA_DATA_SETUP_FAILED, loc != null ? loc.getBaseStationId() : -1, TelephonyManager.getDefault().getNetworkType()); @@ -871,8 +825,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { private void onRestartRadio() { if (mPendingRestartRadio) { - Log.d(LOG_TAG, "************TURN OFF RADIO**************"); - phone.mCM.setRadioPower(false, null); + log("************TURN OFF RADIO**************"); + mPhone.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 @@ -885,7 +839,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } private void writeEventLogCdmaDataDrop() { - CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation()); + CdmaCellLocation loc = (CdmaCellLocation)(mPhone.getCellLocation()); EventLog.writeEvent(EventLogTags.CDMA_DATA_DROP, loc != null ? loc.getBaseStationId() : -1, TelephonyManager.getDefault().getNetworkType()); @@ -901,7 +855,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { return; } - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { boolean isActiveOrDormantConnectionPresent = false; int connectionState = DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE; @@ -917,7 +871,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { if (!isActiveOrDormantConnectionPresent) { // No active or dormant connection - Log.i(LOG_TAG, "onDataStateChanged: No active connection" + log("onDataStateChanged: No active connection" + "state is CONNECTED, disconnecting/cleanup"); writeEventLogCdmaDataDrop(); cleanUpConnection(true, null); @@ -926,59 +880,27 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { switch (connectionState) { case DATA_CONNECTION_ACTIVE_PH_LINK_UP: - Log.v(LOG_TAG, "onDataStateChanged: active=LINK_ACTIVE && CONNECTED, ignore"); - activity = Activity.NONE; - phone.notifyDataActivity(); + log("onDataStateChanged: active=LINK_ACTIVE && CONNECTED, ignore"); + mActivity = Activity.NONE; + mPhone.notifyDataActivity(); startNetStatPoll(); break; case DATA_CONNECTION_ACTIVE_PH_LINK_DOWN: - Log.v(LOG_TAG, "onDataStateChanged active=LINK_DOWN && CONNECTED, dormant"); - activity = Activity.DORMANT; - phone.notifyDataActivity(); + log("onDataStateChanged active=LINK_DOWN && CONNECTED, dormant"); + mActivity = Activity.DORMANT; + mPhone.notifyDataActivity(); stopNetStatPoll(); break; default: - Log.v(LOG_TAG, "onDataStateChanged: IGNORE unexpected DataCallState.active=" + log("onDataStateChanged: IGNORE unexpected DataCallState.active=" + connectionState); } } else { // TODO: Do we need to do anything? - Log.i(LOG_TAG, "onDataStateChanged: not connected, state=" + state + " ignoring"); - } - } - - protected String getInterfaceName(String apnType) { - if (mActiveDataConnection != null) { - return mActiveDataConnection.getInterface(); - } - return null; - } - - protected String getIpAddress(String apnType) { - if (mActiveDataConnection != null) { - return mActiveDataConnection.getIpAddress(); - } - return null; - } - - protected String getGateway(String apnType) { - if (mActiveDataConnection != null) { - return mActiveDataConnection.getGatewayAddress(); + log("onDataStateChanged: not connected, state=" + mState + " ignoring"); } - return null; - } - - protected String[] getDnsServers(String apnType) { - if (mActiveDataConnection != null) { - return mActiveDataConnection.getDnsServers(); - } - return null; - } - - public ArrayList<DataConnection> getAllDataConnections() { - return dataConnectionList; } private void startDelayedRetry(FailCause cause, String reason) { @@ -986,10 +908,11 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { reconnectAfterFail(cause, reason); } + @Override public void handleMessage (Message msg) { - if (!phone.mIsTheCurrentActivePhone) { - Log.d(LOG_TAG, "Ignore CDMA msgs since CDMA phone is inactive"); + if (!mPhone.mIsTheCurrentActivePhone) { + log("Ignore CDMA msgs since CDMA phone is inactive"); return; } @@ -1026,7 +949,13 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } } + @Override protected void log(String s) { Log.d(LOG_TAG, "[CdmaDataConnectionTracker] " + s); } + + @Override + protected void loge(String s) { + Log.e(LOG_TAG, "[CdmaDataConnectionTracker] " + s); + } } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java index dceff2a..37a33bc 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -70,6 +70,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher { * @param ar AsyncResult passed into the message handler. ar.result should * be a String representing the status report PDU, as ASCII hex. */ + @Override protected void handleStatusReport(AsyncResult ar) { Log.d(TAG, "handleStatusReport is a special GSM function, should never be called in CDMA!"); } @@ -92,6 +93,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected int dispatchMessage(SmsMessageBase smsb) { // If sms is null, means there was a parsing error. @@ -335,6 +337,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void sendData(String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( @@ -343,6 +346,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( @@ -351,6 +355,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void sendMultipartText(String destAddr, String scAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { @@ -359,7 +364,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher { * TODO(cleanup): There is no real code difference between * this and the GSM version, and hence it should be moved to * the base class or consolidated somehow, provided calling - * the proper submitpdu stuff can be arranged. + * the proper submit pdu stuff can be arranged. */ int refNumber = getNextConcatenatedRef() & 0x00FF; @@ -432,8 +437,9 @@ final class CdmaSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void sendSms(SmsTracker tracker) { - HashMap map = tracker.mData; + HashMap<String, Object> map = tracker.mData; // byte smsc[] = (byte[]) map.get("smsc"); // unused for CDMA byte pdu[] = (byte[]) map.get("pdu"); @@ -444,11 +450,13 @@ final class CdmaSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void sendMultipartSms (SmsTracker tracker) { Log.d(TAG, "TODO: CdmaSMSDispatcher.sendMultipartSms not implemented"); } /** {@inheritDoc} */ + @Override protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){ // FIXME unit test leaves cm == null. this should change @@ -469,16 +477,19 @@ final class CdmaSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void activateCellBroadcastSms(int activate, Message response) { mCm.setCdmaBroadcastActivation((activate == 0), response); } /** {@inheritDoc} */ + @Override protected void getCellBroadcastSmsConfig(Message response) { mCm.getCdmaBroadcastConfig(response); } /** {@inheritDoc} */ + @Override protected void setCellBroadcastConfig(int[] configValuesArray, Message response) { mCm.setCdmaBroadcastConfig(configValuesArray, response); } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index d2a4bd8..c006fcf 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -16,6 +16,17 @@ package com.android.internal.telephony.cdma; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.DataConnectionTracker; +import com.android.internal.telephony.EventLogTags; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.MccTable; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.ServiceStateTracker; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.TelephonyProperties; + import android.app.AlarmManager; import android.content.ContentResolver; import android.content.Context; @@ -38,19 +49,8 @@ import android.telephony.cdma.CdmaCellLocation; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; -import android.util.Config; import android.util.TimeUtils; -import com.android.internal.telephony.CommandException; -import com.android.internal.telephony.CommandsInterface; -import com.android.internal.telephony.DataConnectionTracker; -import com.android.internal.telephony.EventLogTags; -import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.MccTable; -import com.android.internal.telephony.ServiceStateTracker; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.TelephonyProperties; - import java.util.Arrays; import java.util.Calendar; import java.util.Date; @@ -66,6 +66,13 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { CdmaCellLocation cellLoc; CdmaCellLocation newCellLoc; + // Min values used to by getOtasp() + private static final String UNACTIVATED_MIN2_VALUE = "000000"; + private static final String UNACTIVATED_MIN_VALUE = "1111110111"; + + // Current Otasp value + int mCurrentOtaspMode = OTASP_UNINITIALIZED; + /** if time between NITZ updates is less than mNitzUpdateSpacing the update may be ignored. */ private static final int NITZ_UPDATE_SPACING_DEFAULT = 1000 * 60 * 10; private int mNitzUpdateSpacing = SystemProperties.getInt("ro.nitz_update_spacing", @@ -447,6 +454,13 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { if (!mIsMinInfoReady) { mIsMinInfoReady = true; } + int otaspMode = getOtasp(); + if (mCurrentOtaspMode != otaspMode) { + Log.d(LOG_TAG, "call phone.notifyOtaspChanged old otaspMode=" + + mCurrentOtaspMode + " new otaspMode=" + otaspMode); + mCurrentOtaspMode = otaspMode; + phone.notifyOtaspChanged(mCurrentOtaspMode); + } phone.getIccCard().broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI, null); } else { @@ -643,6 +657,11 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { curPlmn = plmn; } + @Override + protected Phone getPhone() { + return phone; + } + /** * Handle the result of one of the pollState()-related requests */ @@ -1008,7 +1027,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { mNeedFixZone = false; if (zone != null) { - if (getAutoTime()) { + if (getAutoTimeZone()) { setAndBroadcastNetworkSetTimeZone(zone.getID()); } saveNitzTimeZone(zone.getID()); @@ -1140,7 +1159,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } if (hasCdmaDataConnectionChanged || hasNetworkTypeChanged) { - phone.notifyDataConnection(null); + phone.notifyDataConnection(); } if (hasRoamingOn) { @@ -1460,7 +1479,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } if (zone != null) { - if (getAutoTime()) { + if (getAutoTimeZone()) { setAndBroadcastNetworkSetTimeZone(zone.getID()); } saveNitzTimeZone(zone.getID()); @@ -1550,6 +1569,14 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } } + private boolean getAutoTimeZone() { + try { + return Settings.System.getInt(cr, Settings.System.AUTO_TIME_ZONE) > 0; + } catch (SettingNotFoundException snfe) { + return true; + } + } + private void saveNitzTimeZone(String zoneId) { mSavedTimeZone = zoneId; } @@ -1634,10 +1661,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { return false; } - protected void log(String s) { - Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s); - } - public String getMdnNumber() { return mMdn; } @@ -1693,6 +1716,32 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } } + /** + * Returns OTASP_UNKNOWN, OTASP_NEEDED or OTASP_NOT_NEEDED + */ + int getOtasp() { + int provisioningState; + if (mMin == null || (mMin.length() < 6)) { + if (DBG) Log.d(LOG_TAG, "getOtasp: bad mMin='" + mMin + "'"); + provisioningState = OTASP_UNKNOWN; + } else { + if ((mMin.equals(UNACTIVATED_MIN_VALUE) + || mMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE)) + || SystemProperties.getBoolean("test_cdma_setup", false)) { + provisioningState = OTASP_NEEDED; + } else { + provisioningState = OTASP_NOT_NEEDED; + } + } + if (DBG) Log.d(LOG_TAG, "getOtasp: state=" + provisioningState); + return provisioningState; + } + + @Override + protected void log(String s) { + Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s); + } + private void hangupAndPowerOff() { // hang up all active voice calls phone.mCT.ringingCall.hangupIfAlive(); diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java index e97549d..d84b6ab 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java @@ -68,8 +68,7 @@ public class RuimSmsInterfaceManager extends IccSmsInterfaceManager { ar = (AsyncResult)msg.obj; synchronized (mLock) { if (ar.exception == null) { - mSms = (List<SmsRawData>) - buildValidRawData((ArrayList<byte[]>) ar.result); + mSms = buildValidRawData((ArrayList<byte[]>) ar.result); } else { if(DBG) log("Cannot load Sms records"); if (mSms != null) diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java index d563dc8..8accfd1 100644 --- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -18,11 +18,8 @@ package com.android.internal.telephony.cdma; import android.os.Parcel; import android.os.SystemProperties; -import android.text.format.Time; import android.util.Config; import android.util.Log; -import com.android.internal.telephony.EncodeException; -import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; @@ -34,7 +31,6 @@ 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; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; 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 ab79fe9..cf06dab 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -21,7 +21,6 @@ import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES; import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; import android.util.Log; -import android.util.SparseIntArray; import android.telephony.SmsMessage; @@ -30,10 +29,8 @@ import android.text.format.Time; import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.SmsHeader; -import com.android.internal.telephony.cdma.sms.UserData; import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails; -import com.android.internal.util.HexDump; import com.android.internal.util.BitwiseInputStream; import com.android.internal.util.BitwiseOutputStream; @@ -45,13 +42,13 @@ public final class BearerData { private final static String LOG_TAG = "SMS"; /** - * Bearer Data Subparameter Indentifiers + * Bearer Data Subparameter Identifiers * (See 3GPP2 C.S0015-B, v2.0, table 4.5-1) * NOTE: Commented subparameter types are not implemented. */ private final static byte SUBPARAM_MESSAGE_IDENTIFIER = 0x00; private final static byte SUBPARAM_USER_DATA = 0x01; - private final static byte SUBPARAM_USER_REPONSE_CODE = 0x02; + private final static byte SUBPARAM_USER_RESPONSE_CODE = 0x02; private final static byte SUBPARAM_MESSAGE_CENTER_TIME_STAMP = 0x03; private final static byte SUBPARAM_VALIDITY_PERIOD_ABSOLUTE = 0x04; private final static byte SUBPARAM_VALIDITY_PERIOD_RELATIVE = 0x05; @@ -697,7 +694,7 @@ public final class BearerData { /* * 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. + * and the difference in 4-bit vs. 8-bit is resolved. */ private static void encodeCdmaSmsAddress(CdmaSmsAddress addr) throws CodingException { @@ -805,6 +802,7 @@ public final class BearerData { * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details) * * @param bData an instance of BearerData. + * * @return byte array of raw encoded SMS bearer data. */ public static byte[] encode(BearerData bData) { @@ -915,7 +913,7 @@ public final class BearerData { private static String decodeUtf16(byte[] data, int offset, int numFields) throws CodingException { - // Start reading from the next 16-bit aligned boundry after offset. + // Start reading from the next 16-bit aligned boundary after offset. int padding = offset % 2; numFields -= (offset + padding) / 2; try { @@ -961,7 +959,7 @@ public final class BearerData { private static String decode7bitGsm(byte[] data, int offset, int numFields) throws CodingException { - // Start reading from the next 7-bit aligned boundry after offset. + // Start reading from the next 7-bit aligned boundary after offset. int offsetBits = offset * 8; int offsetSeptets = (offsetBits + 6) / 7; numFields -= offsetSeptets; @@ -1554,7 +1552,7 @@ public final class BearerData { case SUBPARAM_USER_DATA: decodeSuccess = decodeUserData(bData, inStream); break; - case SUBPARAM_USER_REPONSE_CODE: + case SUBPARAM_USER_RESPONSE_CODE: decodeSuccess = decodeUserResponseCode(bData, inStream); break; case SUBPARAM_REPLY_OPTION: 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 4f00163..4a60231 100644 --- a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java +++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java @@ -19,7 +19,7 @@ package com.android.internal.telephony.cdma.sms; import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress; -public final class SmsEnvelope{ +public final class SmsEnvelope { /** * Message Types * (See 3GPP2 C.S0015-B 3.4.1) diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index 3959c67..fc03d1a 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -287,7 +287,7 @@ public class GSMPhone extends PhoneBase { return mPendingMMIs; } - public DataState getDataConnectionState() { + public DataState getDataConnectionState(String apnType) { DataState ret = DataState.DISCONNECTED; if (mSST == null) { @@ -300,6 +300,8 @@ public class GSMPhone extends PhoneBase { // If we're out of service, open TCP sockets may still work // but no data will flow ret = DataState.DISCONNECTED; + } else if (mDataConnection.isApnTypeEnabled(apnType) == false) { + ret = DataState.DISCONNECTED; } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */ switch (mDataConnection.getState()) { case FAILED: @@ -401,8 +403,8 @@ public class GSMPhone extends PhoneBase { } /*package*/ void - notifyDataConnectionFailed(String reason) { - mNotifier.notifyDataConnectionFailed(this, reason); + notifyDataConnectionFailed(String reason, String apnType) { + mNotifier.notifyDataConnectionFailed(this, reason, apnType); } /*package*/ void @@ -1091,27 +1093,6 @@ public class GSMPhone extends PhoneBase { } /** - * The only circumstances under which we report that data connectivity is not - * possible are - * <ul> - * <li>Data roaming is disallowed and we are roaming.</li> - * <li>The current data state is {@code DISCONNECTED} for a reason other than - * having explicitly disabled connectivity. In other words, data is not available - * because the phone is out of coverage or some like reason.</li> - * </ul> - * @return {@code true} if data connectivity is possible, {@code false} otherwise. - */ - public boolean isDataConnectivityPossible() { - // TODO: Currently checks if any GPRS connection is active. Should it only - // check for "default"? - boolean noData = mDataConnection.getDataEnabled() && - getDataConnectionState() == DataState.DISCONNECTED; - return !noData && getIccCard().getState() == SimCard.State.READY && - getServiceState().getState() == ServiceState.STATE_IN_SERVICE && - (mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming()); - } - - /** * Removes the given MMI from the pending list and notifies * registrants that it is complete. * @param mmi MMI that is done diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java index 09d46dd..d428099 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java @@ -23,6 +23,7 @@ import android.util.Patterns; import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.Phone; import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.RetryManager; /** * {@hide} @@ -53,23 +54,27 @@ public class GsmDataConnection extends DataConnection { private ApnSetting apn; //***** Constructor - private GsmDataConnection(GSMPhone phone, String name) { - super(phone, name); + private GsmDataConnection(GSMPhone phone, String name, RetryManager rm) { + super(phone, name, rm); } /** * Create the connection object * - * @param phone + * @param phone the Phone + * @param id the connection id + * @param rm the RetryManager * @return GsmDataConnection that was created. */ - static GsmDataConnection makeDataConnection(GSMPhone phone) { + static GsmDataConnection makeDataConnection(GSMPhone phone, int id, RetryManager rm) { synchronized (mCountLock) { mCount += 1; } - GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount); + GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount, rm); gsmDc.start(); if (DBG) gsmDc.log("Made " + gsmDc.getName()); + gsmDc.mId = id; + gsmDc.mRetryMgr = rm; return gsmDc; } @@ -180,8 +185,8 @@ public class GsmDataConnection extends DataConnection { @Override protected boolean isDnsOk(String[] domainNameServers) { - if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1]) - && !((GSMPhone) phone).isDnsCheckDisabled()) { + if (NULL_IP.equals(domainNameServers[0]) && NULL_IP.equals(domainNameServers[1]) + && !((GSMPhone) phone).isDnsCheckDisabled()) { // Work around a race condition where QMI does not fill in DNS: // Deactivate PDP and let DataConnectionTracker retry. // Do not apply the race condition workaround for MMS APN @@ -189,6 +194,9 @@ public class GsmDataConnection extends DataConnection { // Otherwise, the default APN will not be restored anymore. if (!apn.types[0].equals(Phone.APN_TYPE_MMS) || !isIpAddress(apn.mmsProxy)) { + log(String.format( + "isDnsOk: return false apn.types[0]=%s APN_TYPE_MMS=%s isIpAddress(%s)=%s", + apn.types[0], Phone.APN_TYPE_MMS, apn.mmsProxy, isIpAddress(apn.mmsProxy))); return false; } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index e7d57bc..2aca9ad 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -18,28 +18,19 @@ package com.android.internal.telephony.gsm; import android.app.AlarmManager; import android.app.PendingIntent; -import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; import android.database.ContentObserver; import android.database.Cursor; -import android.net.ConnectivityManager; -import android.net.IConnectivityManager; -import android.net.NetworkInfo; +import android.net.ProxyProperties; import android.net.TrafficStats; import android.net.Uri; -import android.net.wifi.WifiManager; import android.os.AsyncResult; 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.Settings; import android.provider.Telephony; import android.telephony.ServiceState; @@ -58,7 +49,11 @@ import com.android.internal.telephony.EventLogTags; import com.android.internal.telephony.DataConnection.FailCause; import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.HashMap; /** * {@hide} @@ -83,9 +78,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { //***** Instance Variables - // Indicates baseband will not auto-attach - private boolean noAutoAttach = false; - private boolean mReregisterOnReconnectFailure = false; private ContentResolver mResolver; @@ -93,13 +85,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // Count of PDP reset attempts; reset when we see incoming, // call reRegisterNetwork, or pingTest succeeds. 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; + boolean mFailNextConnect = false; /** * allApns holds all apns for this sim spn, retrieved from @@ -107,104 +98,49 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * * Create once after simcard info is loaded */ - private ArrayList<ApnSetting> allApns = null; + private ArrayList<ApnSetting> mAllApns = null; /** * waitingApns holds all apns that are waiting to be connected * * It is a subset of allApns and has the same format */ - private ArrayList<ApnSetting> waitingApns = null; + private ArrayList<ApnSetting> mWaitingApns = null; - private ApnSetting preferredApn = null; + private ApnSetting mPreferredApn = null; /* Currently active APN */ protected ApnSetting mActiveApn; - /** - * pdpList holds all the PDP connection, i.e. IP Link in GPRS - */ - private ArrayList<DataConnection> pdpList; + /** The DataConnection being setup */ + private GsmDataConnection mPendingDataConnection; - /** Currently active DataConnection */ - private GsmDataConnection mActivePdp; + /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */ + private HashMap<String, Integer> mApnToDataConnectionId = + new HashMap<String, Integer>(); /** Is packet service restricted by network */ private boolean mIsPsRestricted = false; //***** Constants - // TODO: Increase this to match the max number of simultaneous - // PDP contexts we plan to support. - /** - * Pool size of DataConnection objects. - */ - private static final int PDP_CONNECTION_POOL_SIZE = 1; - private static final int POLL_PDP_MILLIS = 5 * 1000; private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect"; - private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason"; static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn"); static final String APN_ID = "apn_id"; private boolean canSetPreferApn = false; - // for tracking retries on the default APN - private RetryManager mDefaultRetryManager; - // for tracking retries on a secondary APN - private RetryManager mSecondaryRetryManager; - - BroadcastReceiver mIntentReceiver = new BroadcastReceiver () - { - @Override - public void onReceive(Context context, Intent intent) - { - String action = intent.getAction(); - if (action.equals(Intent.ACTION_SCREEN_ON)) { - mIsScreenOn = true; - stopNetStatPoll(); - startNetStatPoll(); - } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - mIsScreenOn = false; - stopNetStatPoll(); - startNetStatPoll(); - } else if (action.equals((INTENT_RECONNECT_ALARM))) { - Log.d(LOG_TAG, "GPRS reconnect alarm. Previous state was " + state); - - String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON); - if (state == State.FAILED) { - Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); - msg.arg1 = 0; // tearDown is false - msg.obj = (String) reason; - sendMessage(msg); - } - sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); - } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - final android.net.NetworkInfo networkInfo = (NetworkInfo) - intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); - mIsWifiConnected = (networkInfo != null && networkInfo.isConnected()); - } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; - - if (!enabled) { - // when wifi got disabled, the NETWORK_STATE_CHANGED_ACTION - // quit and won't report disconnected til next enabling. - mIsWifiConnected = false; - } - } - } - }; - /** Watches for changes to the APN db. */ - private ApnChangeObserver apnObserver; + private ApnChangeObserver mApnObserver; //***** Constructor 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); @@ -218,73 +154,26 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { p.mSST.registerForPsRestrictedEnabled(this, EVENT_PS_RESTRICT_ENABLED, null); p.mSST.registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, null); - IntentFilter filter = new IntentFilter(); - filter.addAction(INTENT_RECONNECT_ALARM); - filter.addAction(Intent.ACTION_SCREEN_ON); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - - // 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; - mResolver = phone.getContext().getContentResolver(); + mResolver = mPhone.getContext().getContentResolver(); - apnObserver = new ApnChangeObserver(); + mApnObserver = new ApnChangeObserver(); p.getContext().getContentResolver().registerContentObserver( - Telephony.Carriers.CONTENT_URI, true, apnObserver); - - createAllPdpList(); - - // This preference tells us 1) initial condition for "dataEnabled", - // and 2) whether the RIL will setup the baseband to auto-PS attach. - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext()); - boolean dataEnabledSetting = true; - try { - dataEnabledSetting = IConnectivityManager.Stub.asInterface(ServiceManager. - getService(Context.CONNECTIVITY_SERVICE)).getMobileDataEnabled(); - } catch (Exception e) { - // nothing to do - use the old behavior and leave data on - } - dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false) && - dataEnabledSetting; - 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); - } - } - - mDefaultRetryManager = mRetryMgr; - mSecondaryRetryManager = new RetryManager(); + Telephony.Carriers.CONTENT_URI, true, mApnObserver); - if (!mSecondaryRetryManager.configure(SystemProperties.get( - "ro.gsm.2nd_data_retry_config"))) { - if (!mSecondaryRetryManager.configure(SECONDARY_DATA_RETRY_CONFIG)) { - // Should never happen, log an error and default to a simple sequence. - Log.e(LOG_TAG, "Could note configure using SECONDARY_DATA_RETRY_CONFIG=" - + SECONDARY_DATA_RETRY_CONFIG); - mSecondaryRetryManager.configure("max_retries=3, 333, 333, 333"); - } - } + /** Create the default connection */ + createDataConnection(Phone.APN_TYPE_DEFAULT); } + @Override public void dispose() { + super.dispose(); + //Unregister for all events - phone.mCM.unregisterForAvailable(this); - phone.mCM.unregisterForOffOrNotAvailable(this); + mPhone.mCM.unregisterForAvailable(this); + mPhone.mCM.unregisterForOffOrNotAvailable(this); mGsmPhone.mSIMRecords.unregisterForRecordsLoaded(this); - phone.mCM.unregisterForDataStateChanged(this); + mPhone.mCM.unregisterForDataStateChanged(this); mGsmPhone.mCT.unregisterForVoiceCallEnded(this); mGsmPhone.mCT.unregisterForVoiceCallStarted(this); mGsmPhone.mSST.unregisterForGprsAttached(this); @@ -294,29 +183,36 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { mGsmPhone.mSST.unregisterForPsRestrictedEnabled(this); mGsmPhone.mSST.unregisterForPsRestrictedDisabled(this); - phone.getContext().unregisterReceiver(this.mIntentReceiver); - phone.getContext().getContentResolver().unregisterContentObserver(this.apnObserver); + mPhone.getContext().getContentResolver().unregisterContentObserver(this.mApnObserver); - destroyAllPdpList(); + destroyDataConnections(); } + @Override protected void finalize() { - if(DBG) Log.d(LOG_TAG, "GsmDataConnectionTracker finalized"); + if(DBG) log("finalize"); } + @Override + protected String getActionIntentReconnectAlarm() { + return INTENT_RECONNECT_ALARM; + } + + @Override protected void setState(State s) { if (DBG) log ("setState: " + s); - if (state != s) { - EventLog.writeEvent(EventLogTags.GSM_DATA_STATE_CHANGE, state.toString(), s.toString()); - state = s; + if (mState != s) { + EventLog.writeEvent(EventLogTags.GSM_DATA_STATE_CHANGE, mState.toString(), s.toString()); + mState = s; } - if (state == State.FAILED) { - if (waitingApns != null) - waitingApns.clear(); // when teardown the connection and set to IDLE + if (mState == State.FAILED) { + if (mWaitingApns != null) + mWaitingApns.clear(); // when tear down the connection and set to IDLE } } + @Override public String[] getActiveApnTypes() { String[] result; if (mActiveApn != null) { @@ -328,6 +224,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return result; } + @Override protected String getActiveApnString() { String result = null; if (mActiveApn != null) { @@ -345,15 +242,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * * @return false while no data connection if all above requirements are met. */ + @Override public boolean isDataConnectionAsDesired() { - boolean roaming = phone.getServiceState().getRoaming(); + boolean roaming = mPhone.getServiceState().getRoaming(); if (mGsmPhone.mSIMRecords.getRecordsLoaded() && mGsmPhone.mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE && (!roaming || getDataOnRoamingEnabled()) && !mIsWifiConnected && !mIsPsRestricted ) { - return (state == State.CONNECTED); + return (mState == State.CONNECTED); } return true; } @@ -370,8 +268,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return (fetchDunApn() != null); } - if (allApns != null) { - for (ApnSetting apn : allApns) { + if (mAllApns != null) { + for (ApnSetting apn : mAllApns) { if (apn.canHandleType(type)) { return true; } @@ -380,20 +278,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return false; } - /** - * Formerly this method was ArrayList<GsmDataConnection> getAllPdps() - */ - public ArrayList<DataConnection> getAllDataConnections() { - ArrayList<DataConnection> pdps = (ArrayList<DataConnection>)pdpList.clone(); - return pdps; - } - - private boolean isDataAllowed() { - boolean roaming = phone.getServiceState().getRoaming(); - return getAnyDataEnabled() && (!roaming || getDataOnRoamingEnabled()) && - mMasterDataEnabled; - } - //****** Called from ServiceStateTracker /** * Invoked when ServiceStateTracker observes a transition from GPRS @@ -405,15 +289,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * when GPRS detaches, but we should stop the network polling. */ stopNetStatPoll(); - phone.notifyDataConnection(Phone.REASON_GPRS_DETACHED); + notifyDataConnection(Phone.REASON_GPRS_DETACHED); } private void onGprsAttached() { - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { startNetStatPoll(); - phone.notifyDataConnection(Phone.REASON_GPRS_ATTACHED); + notifyDataConnection(Phone.REASON_GPRS_ATTACHED); } else { - if (state == State.FAILED) { + if (mState == State.FAILED) { cleanUpConnection(false, Phone.REASON_GPRS_ATTACHED); mRetryMgr.resetRetryCount(); } @@ -421,74 +305,91 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + @Override + protected boolean isDataAllowed() { + int gprsState = mGsmPhone.mSST.getCurrentGprsState(); + boolean desiredPowerState = mGsmPhone.mSST.getDesiredPowerState(); + + boolean allowed = + (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) && + mGsmPhone.mSIMRecords.getRecordsLoaded() && + mPhone.getState() == Phone.State.IDLE && + mMasterDataEnabled && + (!mPhone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) && + !mIsPsRestricted && + desiredPowerState; + if (!allowed && DBG) { + String reason = ""; + if (!((gprsState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) { + reason += " - gprs= " + gprsState; + } + if (!mGsmPhone.mSIMRecords.getRecordsLoaded()) reason += " - SIM not loaded"; + if (mPhone.getState() != Phone.State.IDLE) { + reason += " - PhoneState= " + mPhone.getState(); + } + if (!mMasterDataEnabled) reason += " - mMasterDataEnabled= false"; + if (mPhone.getServiceState().getRoaming() && getDataOnRoamingEnabled()) { + reason += " - Roaming"; + } + if (mIsPsRestricted) reason += " - mIsPsRestricted= true"; + if (!desiredPowerState) reason += " - desiredPowerState= false"; + log("Data not allowed due to" + reason); + } + return allowed; + } + private boolean trySetupData(String reason) { if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason)); - Log.d(LOG_TAG, "[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted); + log("[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted); - if (phone.getSimulatedRadioControl() != null) { + if (mPhone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved setState(State.CONNECTED); - phone.notifyDataConnection(reason); + notifyDataConnection(reason); - Log.i(LOG_TAG, "(fix?) We're on the simulator; assuming data is connected"); + log("(fix?) We're on the simulator; assuming data is connected"); return true; } int gprsState = mGsmPhone.mSST.getCurrentGprsState(); boolean desiredPowerState = mGsmPhone.mSST.getDesiredPowerState(); - if ((state == State.IDLE || state == State.SCANNING) - && (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach) - && mGsmPhone.mSIMRecords.getRecordsLoaded() - && phone.getState() == Phone.State.IDLE - && isDataAllowed() - && !mIsPsRestricted - && desiredPowerState ) { - - if (state == State.IDLE) { - waitingApns = buildWaitingApns(); - if (waitingApns.isEmpty()) { + if (((mState == State.IDLE) || (mState == State.SCANNING)) && + isDataAllowed() && getAnyDataEnabled()) { + + if (mState == State.IDLE) { + mWaitingApns = buildWaitingApns(mRequestedApnType); + if (mWaitingApns.isEmpty()) { if (DBG) log("No APN found"); notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN); + notifyOffApnsOfAvailability(reason, false); return false; } else { - log ("Create from allApns : " + apnListToString(allApns)); + log ("Create from allApns : " + apnListToString(mAllApns)); } } if (DBG) { - log ("Setup waitngApns : " + apnListToString(waitingApns)); + log ("Setup waitngApns : " + apnListToString(mWaitingApns)); } - return setupData(reason); + boolean retValue = setupData(reason); + notifyOffApnsOfAvailability(reason, retValue); + return retValue; } else { - if (DBG) - log("trySetupData: Not ready for data: " + - " dataState=" + state + - " gprsState=" + gprsState + - " sim=" + mGsmPhone.mSIMRecords.getRecordsLoaded() + - " UMTS=" + mGsmPhone.mSST.isConcurrentVoiceAndData() + - " phoneState=" + phone.getState() + - " isDataAllowed=" + isDataAllowed() + - " dataEnabled=" + getAnyDataEnabled() + - " roaming=" + phone.getServiceState().getRoaming() + - " dataOnRoamingEnable=" + getDataOnRoamingEnabled() + - " ps restricted=" + mIsPsRestricted + - " desiredPowerState=" + desiredPowerState + - " MasterDataEnabled=" + mMasterDataEnabled); + notifyOffApnsOfAvailability(reason, false); return false; } } /** - * If tearDown is true, this only tears down a CONNECTED session. Presently, - * there is no mechanism for abandoning an INITING/CONNECTING session, - * but would likely involve cancelling pending async requests or - * setting a flag or new state to ignore them when they came in - * @param tearDown true if the underlying GsmDataConnection should be - * disconnected. - * @param reason reason for the clean up. + * Cleanup all connections. + * + * TODO: Cleanup only a specified connection passed as a parameter. + * + * @param tearDown true if the underlying DataConnection should be disconnected. + * @param reason for the clean up. */ private void cleanUpConnection(boolean tearDown, String reason) { if (DBG) log("Clean up connection due to " + reason); @@ -496,7 +397,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // Clear the reconnect alarm, if set. if (mReconnectIntent != null) { AlarmManager am = - (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); am.cancel(mReconnectIntent); mReconnectIntent = null; } @@ -504,10 +405,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { setState(State.DISCONNECTING); boolean notificationDeferred = false; - for (DataConnection conn : pdpList) { + for (DataConnection conn : mDataConnections.values()) { if (tearDown) { if (DBG) log("cleanUpConnection: teardown, call conn.disconnect"); - conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason)); + conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, + conn.getDataConnectionId(), 0, reason)); notificationDeferred = true; } else { if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously"); @@ -565,87 +467,49 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return result; } - private GsmDataConnection findFreePdp() { - for (DataConnection conn : pdpList) { - GsmDataConnection pdp = (GsmDataConnection) conn; - if (pdp.isInactive()) { - return pdp; + private GsmDataConnection findFreeDataConnection() { + for (DataConnection dc : mDataConnections.values()) { + if (dc.isInactive()) { + log("found free GsmDataConnection"); + return (GsmDataConnection) dc; } } + log("NO free GsmDataConnection"); return null; } private boolean setupData(String reason) { ApnSetting apn; - GsmDataConnection pdp; + GsmDataConnection gdc; apn = getNextApn(); if (apn == null) return false; - pdp = findFreePdp(); - if (pdp == null) { + gdc = findFreeDataConnection(); + if (gdc == null) { if (DBG) log("setupData: No free GsmDataConnection found!"); return false; } mActiveApn = apn; - mActivePdp = pdp; + mPendingDataConnection = gdc; Message msg = obtainMessage(); msg.what = EVENT_DATA_SETUP_COMPLETE; msg.obj = reason; - pdp.connect(msg, apn); + gdc.connect(msg, apn); setState(State.INITING); - phone.notifyDataConnection(reason); + notifyDataConnection(reason); return true; } - protected String getInterfaceName(String apnType) { - if (mActivePdp != null && - (apnType == null || - (mActiveApn != null && mActiveApn.canHandleType(apnType)))) { - return mActivePdp.getInterface(); - } - return null; - } - - protected String getIpAddress(String apnType) { - if (mActivePdp != null && - (apnType == null || - (mActiveApn != null && mActiveApn.canHandleType(apnType)))) { - return mActivePdp.getIpAddress(); - } - return null; - } - - public String getGateway(String apnType) { - if (mActivePdp != null && - (apnType == null || - (mActiveApn != null && mActiveApn.canHandleType(apnType)))) { - return mActivePdp.getGatewayAddress(); - } - return null; - } - - protected String[] getDnsServers(String apnType) { - if (mActivePdp != null && - (apnType == null || - (mActiveApn != null && mActiveApn.canHandleType(apnType)))) { - return mActivePdp.getDnsServers(); - } - return null; - } - - private boolean - pdpStatesHasCID (ArrayList<DataCallState> states, int cid) { + private boolean dataCallStatesHasCID (ArrayList<DataCallState> states, int cid) { for (int i = 0, s = states.size() ; i < s ; i++) { if (states.get(i).cid == cid) return true; } - return false; } - private boolean - pdpStatesHasActiveCID (ArrayList<DataCallState> states, int cid) { + private boolean dataCallStatesHasActiveCID (ArrayList<DataCallState> states, int cid) { for (int i = 0, s = states.size() ; i < s ; i++) { if ((states.get(i).cid == cid) && (states.get(i).active != 0)) { return true; @@ -661,7 +525,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private void onApnChanged() { boolean isConnected; - isConnected = (state != State.IDLE && state != State.FAILED); + isConnected = (mState != State.IDLE && mState != State.FAILED); // The "current" may no longer be valid. MMS depends on this to send properly. mGsmPhone.updateCurrentCarrierInProvider(); @@ -669,7 +533,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // TODO: It'd be nice to only do this if the changed entrie(s) // match the current operator. createAllApnList(); - if (state != State.DISCONNECTING) { + if (mState != State.DISCONNECTING) { cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED); if (!isConnected) { // reset reconnect timer @@ -686,10 +550,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * via an unsolicited response (which could have happened at any * previous state */ - protected void onPdpStateChanged (AsyncResult ar, boolean explicitPoll) { - ArrayList<DataCallState> pdpStates; + private void onDataStateChanged (AsyncResult ar, boolean explicitPoll) { + ArrayList<DataCallState> dataCallStates; - pdpStates = (ArrayList<DataCallState>)(ar.result); + dataCallStates = (ArrayList<DataCallState>)(ar.result); if (ar.exception != null) { // This is probably "radio not available" or something @@ -698,42 +562,42 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return; } - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { // The way things are supposed to work, the PDP list // should not contain the CID after it disconnects. // However, the way things really work, sometimes the PDP // context is still listed with active = false, which // makes it hard to distinguish an activating context from // an activated-and-then deactivated one. - if (!pdpStatesHasCID(pdpStates, cidActive)) { + if (!dataCallStatesHasCID(dataCallStates, mCidActive)) { // It looks like the PDP context has deactivated. // Tear everything down and try to reconnect. - Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting"); + log("PDP connection has dropped. Reconnecting"); // Add an event log when the network drops PDP - GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); + GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation()); EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, loc != null ? loc.getCid() : -1, TelephonyManager.getDefault().getNetworkType()); cleanUpConnection(true, null); return; - } else if (!pdpStatesHasActiveCID(pdpStates, cidActive)) { + } else if (!dataCallStatesHasActiveCID(dataCallStates, mCidActive)) { // Here, we only consider this authoritative if we asked for the // PDP list. If it was an unsolicited response, we poll again // to make sure everyone agrees on the initial state. if (!explicitPoll) { // We think it disconnected but aren't sure...poll from our side - phone.mCM.getPDPContextList( + mPhone.mCM.getPDPContextList( this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); } else { - Log.i(LOG_TAG, "PDP connection has dropped (active=false case). " + log("PDP connection has dropped (active=false case). " + " Reconnecting"); // Log the network drop on the event log. - GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); + GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation()); EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, loc != null ? loc.getCid() : -1, TelephonyManager.getDefault().getNetworkType()); @@ -746,7 +610,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private void notifyDefaultData(String reason) { setState(State.CONNECTED); - phone.notifyDataConnection(reason); + notifyDataConnection(reason); startNetStatPoll(); // reset reconnect timer mRetryMgr.resetRetryCount(); @@ -756,42 +620,30 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private void gotoIdleAndNotifyDataConnection(String reason) { if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason); setState(State.IDLE); - phone.notifyDataConnection(reason); + notifyDataConnection(reason); mActiveApn = null; } - /** - * This is a kludge to deal with the fact that - * the PDP state change notification doesn't always work - * with certain RIL impl's/basebands - * - */ - private void startPeriodicPdpPoll() { - removeMessages(EVENT_POLL_PDP); - - sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS); - } - private void resetPollStats() { - txPkts = -1; - rxPkts = -1; - sentSinceLastRecv = 0; - netStatPollPeriod = POLL_NETSTAT_MILLIS; + mTxPkts = -1; + mRxPkts = -1; + mSentSinceLastRecv = 0; + mNetStatPollPeriod = POLL_NETSTAT_MILLIS; mNoRecvPollCount = 0; } private void doRecovery() { - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { int maxPdpReset = Settings.Secure.getInt(mResolver, Settings.Secure.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT, DEFAULT_MAX_PDP_RESET_FAIL); if (mPdpResetCount < maxPdpReset) { mPdpResetCount++; - EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, sentSinceLastRecv); + EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, mSentSinceLastRecv); cleanUpConnection(true, Phone.REASON_PDP_RESET); } else { mPdpResetCount = 0; - EventLog.writeEvent(EventLogTags.PDP_REREGISTER_NETWORK, sentSinceLastRecv); + EventLog.writeEvent(EventLogTags.PDP_REREGISTER_NETWORK, mSentSinceLastRecv); mGsmPhone.mSST.reRegisterNetwork(null); } // TODO: Add increasingly drastic recovery steps, eg, @@ -799,23 +651,26 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + @Override protected void startNetStatPoll() { - if (state == State.CONNECTED && mPingTestActive == false && netStatPollEnabled == false) { - Log.d(LOG_TAG, "[DataConnection] Start poll NetStat"); + if (mState == State.CONNECTED && mPingTestActive == false && mNetStatPollEnabled == false) { + log("[DataConnection] Start poll NetStat"); resetPollStats(); - netStatPollEnabled = true; + mNetStatPollEnabled = true; mPollNetStat.run(); } } + @Override protected void stopNetStatPoll() { - netStatPollEnabled = false; + mNetStatPollEnabled = false; removeCallbacks(mPollNetStat); - Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat"); + log("[DataConnection] Stop poll NetStat"); } + @Override protected void restartRadio() { - Log.d(LOG_TAG, "************TURN OFF RADIO**************"); + log("************TURN OFF RADIO**************"); cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); mGsmPhone.mSST.powerOffRadioSafely(); /* Note: no need to call setRadioPower(true). Assuming the desired @@ -839,43 +694,43 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { Activity newActivity; - preTxPkts = txPkts; - preRxPkts = rxPkts; + preTxPkts = mTxPkts; + preRxPkts = mRxPkts; - txPkts = TrafficStats.getMobileTxPackets(); - rxPkts = TrafficStats.getMobileRxPackets(); + mTxPkts = TrafficStats.getMobileTxPackets(); + mRxPkts = TrafficStats.getMobileRxPackets(); - //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); + //log("rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); - if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { - sent = txPkts - preTxPkts; - received = rxPkts - preRxPkts; + if (mNetStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { + sent = mTxPkts - preTxPkts; + received = mRxPkts - preRxPkts; if ( sent > 0 && received > 0 ) { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; newActivity = Activity.DATAINANDOUT; mPdpResetCount = 0; } else if (sent > 0 && received == 0) { - if (phone.getState() == Phone.State.IDLE) { - sentSinceLastRecv += sent; + if (mPhone.getState() == Phone.State.IDLE) { + mSentSinceLastRecv += sent; } else { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; } newActivity = Activity.DATAOUT; } else if (sent == 0 && received > 0) { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; newActivity = Activity.DATAIN; mPdpResetCount = 0; } else if (sent == 0 && received == 0) { newActivity = Activity.NONE; } else { - sentSinceLastRecv = 0; + mSentSinceLastRecv = 0; newActivity = Activity.NONE; } - if (activity != newActivity && mIsScreenOn) { - activity = newActivity; - phone.notifyDataActivity(); + if (mActivity != newActivity && mIsScreenOn) { + mActivity = newActivity; + mPhone.notifyDataActivity(); } } @@ -883,11 +738,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { Settings.Secure.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, NUMBER_SENT_PACKETS_OF_HANG); - if (sentSinceLastRecv >= watchdogTrigger) { + if (mSentSinceLastRecv >= watchdogTrigger) { // we already have NUMBER_SENT_PACKETS sent without ack if (mNoRecvPollCount == 0) { EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET_COUNTDOWN_TRIGGERED, - sentSinceLastRecv); + mSentSinceLastRecv); } int noRecvPollLimit = Settings.Secure.getInt(mResolver, @@ -897,21 +752,22 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // It's possible the PDP context went down and we weren't notified. // Start polling the context list in an attempt to recover. if (DBG) log("no DATAIN in a while; polling PDP"); - phone.mCM.getDataCallList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); + mPhone.mCM.getDataCallList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); mNoRecvPollCount++; // Slow down the poll interval to let things happen - netStatPollPeriod = Settings.Secure.getInt(mResolver, + mNetStatPollPeriod = Settings.Secure.getInt(mResolver, Settings.Secure.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, POLL_NETSTAT_SLOW_MILLIS); } else { - if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + + if (DBG) log("Sent " + String.valueOf(mSentSinceLastRecv) + " pkts since last received"); // We've exceeded the threshold. Run ping test as a final check; // it will proceed with recovery if ping fails. stopNetStatPoll(); Thread pingTest = new Thread() { + @Override public void run() { runPingTest(); } @@ -922,17 +778,17 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } else { mNoRecvPollCount = 0; if (mIsScreenOn) { - netStatPollPeriod = Settings.Secure.getInt(mResolver, + mNetStatPollPeriod = Settings.Secure.getInt(mResolver, Settings.Secure.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); } else { - netStatPollPeriod = Settings.Secure.getInt(mResolver, + mNetStatPollPeriod = Settings.Secure.getInt(mResolver, Settings.Secure.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, POLL_NETSTAT_SCREEN_OFF_MILLIS); } } - if (netStatPollEnabled) { - mDataConnectionTracker.postDelayed(this, netStatPollPeriod); + if (mNetStatPollEnabled) { + mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod); } } }; @@ -951,9 +807,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { status = p.waitFor(); } } catch (IOException e) { - Log.w(LOG_TAG, "ping failed: IOException"); + loge("ping failed: IOException"); } catch (Exception e) { - Log.w(LOG_TAG, "exception trying to ping"); + loge("exception trying to ping"); } if (status == 0) { @@ -994,20 +850,21 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) { - if (state == State.FAILED) { + if (mState == State.FAILED) { + /** TODO: Retrieve retry manager from connection itself */ if (!mRetryMgr.isRetryNeeded()) { if (!mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { // if no more retries on a secondary APN attempt, tell the world and revert. - phone.notifyDataConnection(Phone.REASON_APN_FAILED); + notifyDataConnection(Phone.REASON_APN_FAILED); onEnableApn(apnTypeToId(mRequestedApnType), DISABLED); return; } if (mReregisterOnReconnectFailure) { - // We've re-registerd once now just retry forever. + // We've re-registered once now just retry forever. mRetryMgr.retryForeverUsingLastTimeout(); } else { // Try to re-register to the network. - Log.d(LOG_TAG, "PDP activate failed, Reregistering to the network"); + log("PDP activate failed, Reregistering to the network"); mReregisterOnReconnectFailure = true; mGsmPhone.mSST.reRegisterNetwork(null); mRetryMgr.resetRetryCount(); @@ -1016,15 +873,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } int nextReconnectDelay = mRetryMgr.getRetryTimer(); - Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for " + log("PDP activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); AlarmManager am = - (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); + (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(INTENT_RECONNECT_ALARM); intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason); mReconnectIntent = PendingIntent.getBroadcast( - phone.getContext(), 0, intent, 0); + mPhone.getContext(), 0, intent, 0); am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + nextReconnectDelay, mReconnectIntent); @@ -1032,7 +889,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { mRetryMgr.increaseRetryCount(); if (!shouldPostNotification(lastFailCauseCode)) { - Log.d(LOG_TAG,"NOT Posting GPRS Unavailable notification " + log("NOT Posting GPRS Unavailable notification " + "-- likely transient error"); } else { notifyNoData(lastFailCauseCode); @@ -1044,9 +901,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { setState(State.FAILED); } - protected void onRecordsLoaded() { + private void onRecordsLoaded() { createAllApnList(); - if (state == State.FAILED) { + if (mState == State.FAILED) { cleanUpConnection(false, null); } sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED)); @@ -1054,19 +911,29 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { @Override protected void onEnableNewApn() { + log("onEnableNewApn E"); // change our retry manager to use the appropriate numbers for the new APN if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { - mRetryMgr = mDefaultRetryManager; + log("onEnableNewApn default type"); + mRetryMgr = mPendingDataConnection.getRetryMgr(); + mRetryMgr.resetRetryCount(); + } else if (mApnToDataConnectionId.get(mRequestedApnType) == null) { + log("onEnableNewApn mRequestedApnType=" + mRequestedApnType + + " missing, make a new connection"); + int id = createDataConnection(mRequestedApnType); + mRetryMgr = mDataConnections.get(id).getRetryMgr(); + mRetryMgr.resetRetryCount(); } else { - mRetryMgr = mSecondaryRetryManager; + log("oneEnableNewApn connection already exists, nothing to setup"); } - mRetryMgr.resetRetryCount(); // TODO: To support simultaneous PDP contexts, this should really only call // cleanUpConnection if it needs to free up a GsmDataConnection. cleanUpConnection(true, Phone.REASON_APN_SWITCHED); + log("onEnableNewApn X"); } + @Override protected boolean onTrySetupData(String reason) { return trySetupData(reason); } @@ -1086,31 +953,33 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + @Override protected void onRadioAvailable() { - if (phone.getSimulatedRadioControl() != null) { + if (mPhone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved setState(State.CONNECTED); - phone.notifyDataConnection(null); + notifyDataConnection(null); - Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); + log("We're on the simulator; assuming data is connected"); } - if (state != State.IDLE) { + if (mState != State.IDLE) { cleanUpConnection(true, null); } } + @Override protected void onRadioOffOrNotAvailable() { // Make sure our reconnect delay starts at the initial value // next time the radio comes on mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; - if (phone.getSimulatedRadioControl() != null) { + if (mPhone.getSimulatedRadioControl() != null) { // Assume data is connected on the simulator // FIXME this can be improved - Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); + log("We're on the simulator; assuming radio off is meaningless"); } else { if (DBG) log("Radio is off and clean up all connection"); // TODO: Should we reset mRequestedApnType to "default"? @@ -1118,20 +987,43 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + @Override protected void onDataSetupComplete(AsyncResult ar) { + /** TODO: Which connection is completing should be a parameter */ String reason = null; if (ar.userObj instanceof String) { reason = (String) ar.userObj; } if (ar.exception == null) { + // TODO: We should clear LinkProperties/Capabilities when torn down or disconnected + mLinkProperties = getLinkProperties(mPendingDataConnection); + mLinkCapabilities = getLinkCapabilities(mPendingDataConnection); + + ApnSetting apn = mPendingDataConnection.getApn(); + if (apn.proxy != null && apn.proxy.length() != 0) { + try { + ProxyProperties proxy = new ProxyProperties(); + proxy.setSocketAddress(new InetSocketAddress(InetAddress.getByName(apn.proxy), + Integer.parseInt(apn.port))); + mLinkProperties.setHttpProxy(proxy); + } catch (UnknownHostException e) { + loge("UnknownHostException making ProxyProperties: " + e); + } catch (SecurityException e) { + loge("SecurityException making ProxyProperties: " + e); + } catch (NumberFormatException e) { + loge("NumberFormatException making ProxyProperties (" + apn.port + + "): " + e); + } + } + // everything is setup if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { SystemProperties.set("gsm.defaultpdpcontext.active", "true"); - if (canSetPreferApn && preferredApn == null) { - Log.d(LOG_TAG, "PREFERRED APN is null"); - preferredApn = mActiveApn; - setPreferredApn(preferredApn.id); + if (canSetPreferApn && mPreferredApn == null) { + log("PREFERRED APN is null"); + mPreferredApn = mActiveApn; + setPreferredApn(mPreferredApn.id); } } else { SystemProperties.set("gsm.defaultpdpcontext.active", "false"); @@ -1148,22 +1040,23 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if(DBG) log("PDP setup failed " + cause); // Log this failure to the Event Logs. if (cause.isEventLoggable()) { - GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); + GsmCellLocation loc = ((GsmCellLocation)mPhone.getCellLocation()); EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL, cause.ordinal(), loc != null ? loc.getCid() : -1, TelephonyManager.getDefault().getNetworkType()); } - // No try for permanent failure + // Do not retry on permanent failure + // TODO: We should not fail permanently if more Apns to try! if (cause.isPermanentFail()) { notifyNoData(cause); - phone.notifyDataConnection(Phone.REASON_APN_FAILED); + notifyDataConnection(Phone.REASON_APN_FAILED); onEnableApn(apnTypeToId(mRequestedApnType), DISABLED); return; } - waitingApns.remove(0); - if (waitingApns.isEmpty()) { + mWaitingApns.remove(0); + if (mWaitingApns.isEmpty()) { // No more to try, start delayed retry startDelayedRetry(cause, reason); } else { @@ -1179,14 +1072,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { /** * Called when EVENT_DISCONNECT_DONE is received. */ - protected void onDisconnectDone(AsyncResult ar) { + @Override + protected void onDisconnectDone(int connId, AsyncResult ar) { + if(DBG) log("EVENT_DISCONNECT_DONE connId=" + connId); String reason = null; - if(DBG) log("EVENT_DISCONNECT_DONE"); if (ar.userObj instanceof String) { reason = (String) ar.userObj; } setState(State.IDLE); - phone.notifyDataConnection(reason); + notifyDataConnection(reason); mActiveApn = null; if (retryAfterDisconnected(reason)) { trySetupData(reason); @@ -1207,25 +1101,27 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } protected void onPollPdp() { - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { // only poll when connected - phone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); + mPhone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS); } } + @Override protected void onVoiceCallStarted() { - if (state == State.CONNECTED && ! mGsmPhone.mSST.isConcurrentVoiceAndData()) { + if (mState == State.CONNECTED && ! mGsmPhone.mSST.isConcurrentVoiceAndData()) { stopNetStatPoll(); - phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); + notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); } } + @Override protected void onVoiceCallEnded() { - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { if (!mGsmPhone.mSST.isConcurrentVoiceAndData()) { startNetStatPoll(); - phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); + notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); } else { // clean slate after call end. resetPollStats(); @@ -1239,74 +1135,92 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + @Override protected void onCleanUpConnection(boolean tearDown, String reason) { cleanUpConnection(tearDown, reason); } /** - * Based on the sim operator numeric, create a list for all possible pdps - * with all apns associated with that pdp - * - * + * Based on the sim operator numeric, create a list for all possible + * Data Connections and setup the preferredApn. */ private void createAllApnList() { - allApns = new ArrayList<ApnSetting>(); + mAllApns = new ArrayList<ApnSetting>(); String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric(); if (operator != null) { String selection = "numeric = '" + operator + "'"; - Cursor cursor = phone.getContext().getContentResolver().query( + Cursor cursor = mPhone.getContext().getContentResolver().query( Telephony.Carriers.CONTENT_URI, null, selection, null, null); if (cursor != null) { if (cursor.getCount() > 0) { - allApns = createApnList(cursor); - // TODO: Figure out where this fits in. This basically just - // writes the pap-secrets file. No longer tied to GsmDataConnection - // object. Not used on current platform (no ppp). - //GsmDataConnection pdp = pdpList.get(pdp_name); - //if (pdp != null && pdp.dataLink != null) { - // pdp.dataLink.setPasswordInfo(cursor); - //} + mAllApns = createApnList(cursor); } cursor.close(); } } - if (allApns.isEmpty()) { + if (mAllApns.isEmpty()) { if (DBG) log("No APN found for carrier: " + operator); - preferredApn = null; + mPreferredApn = null; notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN); } else { - preferredApn = getPreferredApn(); - Log.d(LOG_TAG, "Get PreferredAPN"); - if (preferredApn != null && !preferredApn.numeric.equals(operator)) { - preferredApn = null; + mPreferredApn = getPreferredApn(); + log("Get PreferredAPN"); + if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) { + mPreferredApn = null; setPreferredApn(-1); } } } - private void createAllPdpList() { - pdpList = new ArrayList<DataConnection>(); - DataConnection pdp; + /** Return the id for a new data connection */ + private int createDataConnection(String apnType) { + log("createDataConnection(" + apnType + ") E"); + RetryManager rm = new RetryManager(); - for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) { - pdp = GsmDataConnection.makeDataConnection(mGsmPhone); - pdpList.add(pdp); - } + if (apnType.equals(Phone.APN_TYPE_DEFAULT)) { + if (!rm.configure(SystemProperties.get("ro.gsm.data_retry_config"))) { + if (!rm.configure(DEFAULT_DATA_RETRY_CONFIG)) { + // Should never happen, log an error and default to a simple linear sequence. + log("Could not configure using DEFAULT_DATA_RETRY_CONFIG=" + + DEFAULT_DATA_RETRY_CONFIG); + rm.configure(20, 2000, 1000); + } + } + } else { + if (!rm.configure(SystemProperties.get("ro.gsm.2nd_data_retry_config"))) { + if (!rm.configure(SECONDARY_DATA_RETRY_CONFIG)) { + // Should never happen, log an error and default to a simple sequence. + log("Could note configure using SECONDARY_DATA_RETRY_CONFIG=" + + SECONDARY_DATA_RETRY_CONFIG); + rm.configure("max_retries=3, 333, 333, 333"); + } + } + } + + int id = mUniqueIdGenerator.getAndIncrement(); + DataConnection conn = GsmDataConnection.makeDataConnection(mGsmPhone, id, rm); + mDataConnections.put(id, conn); + mApnToDataConnectionId.put(apnType, id); + + log("createDataConnection(" + apnType + ") X id=" + id); + return id; } - private void destroyAllPdpList() { - if(pdpList != null) { - GsmDataConnection pdp; - pdpList.removeAll(pdpList); + private void destroyDataConnections() { + if(mDataConnections != null) { + log("destroyDataConnectionList clear mDataConnectionList"); + mDataConnections.clear(); + } else { + log("destroyDataConnectionList mDataConnecitonList is empty, ignore"); } } private ApnSetting fetchDunApn() { - Context c = phone.getContext(); + Context c = mPhone.getContext(); String apnData = Settings.Secure.getString(c.getContentResolver(), Settings.Secure.TETHER_DUN_APN); ApnSetting dunSetting = ApnSetting.fromString(apnData); @@ -1317,14 +1231,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } /** + * Build a list of APNs to be used to create PDP's. * + * @param requestedApnType * @return waitingApns list to be used to create PDP * error when waitingApns.isEmpty() */ - private ArrayList<ApnSetting> buildWaitingApns() { + private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType) { ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>(); - if (mRequestedApnType.equals(Phone.APN_TYPE_DUN)) { + if (requestedApnType.equals(Phone.APN_TYPE_DUN)) { ApnSetting dun = fetchDunApn(); if (dun != null) apnList.add(dun); return apnList; @@ -1332,24 +1248,24 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { String operator = mGsmPhone.mSIMRecords.getSIMOperatorNumeric(); - if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { - if (canSetPreferApn && preferredApn != null) { - Log.i(LOG_TAG, "Preferred APN:" + operator + ":" - + preferredApn.numeric + ":" + preferredApn); - if (preferredApn.numeric.equals(operator)) { - Log.i(LOG_TAG, "Waiting APN set to preferred APN"); - apnList.add(preferredApn); + if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) { + if (canSetPreferApn && mPreferredApn != null) { + log("Preferred APN:" + operator + ":" + + mPreferredApn.numeric + ":" + mPreferredApn); + if (mPreferredApn.numeric.equals(operator)) { + log("Waiting APN set to preferred APN"); + apnList.add(mPreferredApn); return apnList; } else { setPreferredApn(-1); - preferredApn = null; + mPreferredApn = null; } } } - if (allApns != null) { - for (ApnSetting apn : allApns) { - if (apn.canHandleType(mRequestedApnType)) { + if (mAllApns != null) { + for (ApnSetting apn : mAllApns) { + if (apn.canHandleType(requestedApnType)) { apnList.add(apn); } } @@ -1362,7 +1278,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * @return the first apn found in waitingApns, null if none */ private ApnSetting getNextApn() { - ArrayList<ApnSetting> list = waitingApns; + ArrayList<ApnSetting> list = mWaitingApns; ApnSetting apn = null; if (list != null) { @@ -1393,7 +1309,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return; } - ContentResolver resolver = phone.getContext().getContentResolver(); + ContentResolver resolver = mPhone.getContext().getContentResolver(); resolver.delete(PREFERAPN_URI, null, null); if (pos >= 0) { @@ -1404,11 +1320,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } private ApnSetting getPreferredApn() { - if (allApns.isEmpty()) { + if (mAllApns.isEmpty()) { return null; } - Cursor cursor = phone.getContext().getContentResolver().query( + Cursor cursor = mPhone.getContext().getContentResolver().query( PREFERAPN_URI, new String[] { "_id", "name", "apn" }, null, null, Telephony.Carriers.DEFAULT_SORT_ORDER); @@ -1422,7 +1338,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { int pos; cursor.moveToFirst(); pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); - for(ApnSetting p:allApns) { + for(ApnSetting p:mAllApns) { if (p.id == pos && p.canHandleType(mRequestedApnType)) { cursor.close(); return p; @@ -1437,11 +1353,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return null; } + @Override public void handleMessage (Message msg) { - if (DBG) Log.d(LOG_TAG,"GSMDataConnTrack handleMessage "+msg); + if (DBG) log("GSMDataConnTrack handleMessage "+msg); if (!mGsmPhone.mIsTheCurrentActivePhone) { - Log.d(LOG_TAG, "Ignore GSM msgs since GSM phone is inactive"); + log("Ignore GSM msgs since GSM phone is inactive"); return; } @@ -1459,11 +1376,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { break; case EVENT_DATA_STATE_CHANGED: - onPdpStateChanged((AsyncResult) msg.obj, false); + onDataStateChanged((AsyncResult) msg.obj, false); break; case EVENT_GET_PDP_LIST_COMPLETE: - onPdpStateChanged((AsyncResult) msg.obj, true); + onDataStateChanged((AsyncResult) msg.obj, true); break; case EVENT_POLL_PDP: @@ -1491,7 +1408,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * PDP context and notify us with PDP_CONTEXT_CHANGED. * But we should stop the network polling and prevent reset PDP. */ - Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); + log("[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted); stopNetStatPoll(); mIsPsRestricted = true; break; @@ -1501,12 +1418,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * When PS restrict is removed, we need setup PDP connection if * PDP connection is down. */ - Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); + log("[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted); mIsPsRestricted = false; - if (state == State.CONNECTED) { + if (mState == State.CONNECTED) { startNetStatPoll(); } else { - if (state == State.FAILED) { + if (mState == State.FAILED) { cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED); mRetryMgr.resetRetryCount(); mReregisterOnReconnectFailure = false; @@ -1522,7 +1439,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + @Override protected void log(String s) { Log.d(LOG_TAG, "[GsmDataConnectionTracker] " + s); } + + @Override + protected void loge(String s) { + Log.e(LOG_TAG, "[GsmDataConnectionTracker] " + s); + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java index 3079a64..ed7066b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java @@ -56,6 +56,7 @@ final class GsmSMSDispatcher extends SMSDispatcher { * @param ar AsyncResult passed into the message handler. ar.result should * be a String representing the status report PDU, as ASCII hex. */ + @Override protected void handleStatusReport(AsyncResult ar) { String pduString = (String) ar.result; SmsMessage sms = SmsMessage.newFromCDS(pduString); @@ -84,6 +85,7 @@ final class GsmSMSDispatcher extends SMSDispatcher { /** {@inheritDoc} */ + @Override protected int dispatchMessage(SmsMessageBase smsb) { // If sms is null, means there was a parsing error. @@ -151,6 +153,7 @@ final class GsmSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void sendData(String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( @@ -159,6 +162,7 @@ final class GsmSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( @@ -167,6 +171,7 @@ final class GsmSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void sendMultipartText(String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { @@ -306,8 +311,9 @@ final class GsmSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void sendSms(SmsTracker tracker) { - HashMap map = tracker.mData; + HashMap<String, Object> map = tracker.mData; byte smsc[] = (byte[]) map.get("smsc"); byte pdu[] = (byte[]) map.get("pdu"); @@ -322,12 +328,13 @@ final class GsmSMSDispatcher extends SMSDispatcher { * * @param tracker holds the multipart Sms tracker ready to be sent */ + @Override protected void sendMultipartSms (SmsTracker tracker) { ArrayList<String> parts; ArrayList<PendingIntent> sentIntents; ArrayList<PendingIntent> deliveryIntents; - HashMap map = tracker.mData; + HashMap<String, Object> map = tracker.mData; String destinationAddress = (String) map.get("destination"); String scAddress = (String) map.get("scaddress"); @@ -342,6 +349,7 @@ final class GsmSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void acknowledgeLastIncomingSms(boolean success, int result, Message response){ // FIXME unit test leaves cm == null. this should change if (mCm != null) { @@ -350,6 +358,7 @@ final class GsmSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void activateCellBroadcastSms(int activate, Message response) { // Unless CBS is implemented for GSM, this point should be unreachable. Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); @@ -357,6 +366,7 @@ final class GsmSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void getCellBroadcastSmsConfig(Message response){ // Unless CBS is implemented for GSM, this point should be unreachable. Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); @@ -364,6 +374,7 @@ final class GsmSMSDispatcher extends SMSDispatcher { } /** {@inheritDoc} */ + @Override protected void setCellBroadcastConfig(int[] configValuesArray, Message response) { // Unless CBS is implemented for GSM, this point should be unreachable. Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index 6ddb312..632615d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -16,6 +16,18 @@ package com.android.internal.telephony.gsm; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.DataConnectionTracker; +import com.android.internal.telephony.EventLogTags; +import com.android.internal.telephony.IccCard; +import com.android.internal.telephony.MccTable; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.ServiceStateTracker; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.TelephonyProperties; + import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; @@ -47,17 +59,6 @@ import android.util.EventLog; import android.util.Log; import android.util.TimeUtils; -import com.android.internal.telephony.CommandException; -import com.android.internal.telephony.CommandsInterface; -import com.android.internal.telephony.DataConnectionTracker; -import com.android.internal.telephony.EventLogTags; -import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.MccTable; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.ServiceStateTracker; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.TelephonyProperties; - import java.util.Arrays; import java.util.Calendar; import java.util.Date; @@ -226,6 +227,9 @@ final class GsmServiceStateTracker extends ServiceStateTracker { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_LOCALE_CHANGED); phone.getContext().registerReceiver(mIntentReceiver, filter); + + // Gsm doesn't support OTASP so its not needed + phone.notifyOtaspChanged(OTASP_NOT_NEEDED); } public void dispose() { @@ -246,6 +250,11 @@ final class GsmServiceStateTracker extends ServiceStateTracker { if(DBG) Log.d(LOG_TAG, "GsmServiceStateTracker finalized"); } + @Override + protected Phone getPhone() { + return phone; + } + /** * Registration point for transition into GPRS attached. * @param h handler to notify @@ -1001,7 +1010,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { mNeedFixZone = false; if (zone != null) { - if (getAutoTime()) { + if (getAutoTimeZone()) { setAndBroadcastNetworkSetTimeZone(zone.getID()); } saveNitzTimeZone(zone.getID()); @@ -1024,7 +1033,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } if (hasNetworkTypeChanged) { - phone.notifyDataConnection(null); + phone.notifyDataConnection(); } if (hasRoamingOn) { @@ -1481,7 +1490,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } if (zone != null) { - if (getAutoTime()) { + if (getAutoTimeZone()) { setAndBroadcastNetworkSetTimeZone(zone.getID()); } saveNitzTimeZone(zone.getID()); @@ -1551,6 +1560,15 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } } + private boolean getAutoTimeZone() { + try { + return Settings.System.getInt(phone.getContext().getContentResolver(), + Settings.System.AUTO_TIME_ZONE) > 0; + } catch (SettingNotFoundException snfe) { + return true; + } + } + private void saveNitzTimeZone(String zoneId) { mSavedTimeZone = zoneId; } @@ -1666,7 +1684,8 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } } - private void log(String s) { + @Override + protected void log(String s) { Log.d(LOG_TAG, "[GsmServiceStateTracker] " + s); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java index 67ecc77..aab359f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java @@ -87,6 +87,7 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { public void dispose() { } + @Override protected void finalize() { try { super.finalize(); @@ -192,6 +193,7 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { return mSms; } + @Override protected void log(String msg) { Log.d(LOG_TAG, "[SimSmsInterfaceManager] " + msg); } diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java index 9a3c476..e24613f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java @@ -26,7 +26,6 @@ import com.android.internal.telephony.EncodeException; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; -import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; @@ -34,6 +33,7 @@ import java.io.UnsupportedEncodingException; import static android.telephony.SmsMessage.ENCODING_7BIT; import static android.telephony.SmsMessage.ENCODING_8BIT; import static android.telephony.SmsMessage.ENCODING_16BIT; +import static android.telephony.SmsMessage.ENCODING_KSC5601; import static android.telephony.SmsMessage.ENCODING_UNKNOWN; import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES; import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; @@ -45,7 +45,7 @@ import static android.telephony.SmsMessage.MessageClass; * A Short Message Service message. * */ -public class SmsMessage extends SmsMessageBase{ +public class SmsMessage extends SmsMessageBase { static final String LOG_TAG = "GSM"; private MessageClass messageClass; @@ -311,7 +311,7 @@ public class SmsMessage extends SmsMessageBase{ // the receiver's SIM card. You can then send messages to yourself // (on a phone with this change) and they'll end up on the SIM card. bo.write(0x00); - } else { //assume UCS-2 + } else { // assume UCS-2 if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) { // Message too long return null; @@ -377,7 +377,7 @@ public class SmsMessage extends SmsMessageBase{ * @param destinationAddress the address of the destination for the message * @param destinationPort the port to deliver the message to at the * destination - * @param data the dat for the message + * @param data the data for the message * @return a <code>SubmitPdu</code> containing the encoded SC * address, if applicable, and the encoded message. * Returns null on encode error. @@ -482,7 +482,7 @@ public class SmsMessage extends SmsMessageBase{ return bo; } - static class PduParser { + private static class PduParser { byte pdu[]; int cur; SmsHeader userDataHeader; @@ -490,10 +490,6 @@ public class SmsMessage extends SmsMessageBase{ int mUserDataSeptetPadding; int mUserDataSize; - PduParser(String s) { - this(IccUtils.hexStringToBytes(s)); - } - PduParser(byte[] pdu) { this.pdu = pdu; cur = 0; @@ -545,7 +541,7 @@ public class SmsMessage extends SmsMessageBase{ GsmSmsAddress ret; // "The Address-Length field is an integer representation of - // the number field, i.e. excludes any semi octet containing only + // the number field, i.e. excludes any semi-octet containing only // fill bits." // The TOA field is not included as part of this int addressLength = pdu[cur] & 0xff; @@ -573,7 +569,7 @@ public class SmsMessage extends SmsMessageBase{ int second = IccUtils.gsmBcdByteToInt(pdu[cur++]); // For the timezone, the most significant bit of the - // least signficant nibble is the sign byte + // least significant nibble is the sign byte // (meaning the max range of this field is 79 quarter-hours, // which is more than enough) @@ -632,7 +628,7 @@ public class SmsMessage extends SmsMessageBase{ /* * Here we just create the user data length to be the remainder of * the pdu minus the user data header, since userDataLength means - * the number of uncompressed sepets. + * the number of uncompressed septets. */ bufferLen = pdu.length - offset; } else { @@ -671,10 +667,10 @@ public class SmsMessage extends SmsMessageBase{ } /** - * Returns the number of padding bits at the begining of the user data + * Returns the number of padding bits at the beginning of the user data * array before the start of the septets. * - * @return the number of padding bits at the begining of the user data + * @return the number of padding bits at the beginning of the user data * array before the start of the septets */ int getUserDataSeptetPadding() { @@ -694,7 +690,7 @@ public class SmsMessage extends SmsMessageBase{ XXX Not sure what this one is supposed to be doing, and no one is using it. String getUserDataGSM8bit() { - // System.out.println("remainder of pud:" + + // System.out.println("remainder of pdu:" + // HexDump.dumpHexString(pdu, cur, pdu.length - cur)); int count = pdu[cur++] & 0xff; int size = pdu[cur++]; @@ -781,6 +777,27 @@ public class SmsMessage extends SmsMessageBase{ return ret; } + /** + * Interprets the user data payload as KSC-5601 characters, and + * decodes them into a String. + * + * @param byteCount the number of bytes in the user data payload + * @return a String with the decoded characters + */ + String getUserDataKSC5601(int byteCount) { + String ret; + + try { + ret = new String(pdu, cur, byteCount, "KSC5601"); + } catch (UnsupportedEncodingException ex) { + ret = ""; + Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex); + } + + cur += byteCount; + return ret; + } + boolean moreDataPresent() { return (pdu.length > cur); } @@ -827,11 +844,13 @@ public class SmsMessage extends SmsMessageBase{ } /** {@inheritDoc} */ + @Override public int getProtocolIdentifier() { return protocolIdentifier; } /** {@inheritDoc} */ + @Override public boolean isReplace() { return (protocolIdentifier & 0xc0) == 0x40 && (protocolIdentifier & 0x3f) > 0 @@ -839,12 +858,14 @@ public class SmsMessage extends SmsMessageBase{ } /** {@inheritDoc} */ + @Override public boolean isCphsMwiMessage() { return ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear() || ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet(); } /** {@inheritDoc} */ + @Override public boolean isMWIClearMessage() { if (isMwi && (mwiSense == false)) { return true; @@ -855,6 +876,7 @@ public class SmsMessage extends SmsMessageBase{ } /** {@inheritDoc} */ + @Override public boolean isMWISetMessage() { if (isMwi && (mwiSense == true)) { return true; @@ -865,6 +887,7 @@ public class SmsMessage extends SmsMessageBase{ } /** {@inheritDoc} */ + @Override public boolean isMwiDontStore() { if (isMwi && mwiDontStore) { return true; @@ -884,31 +907,34 @@ public class SmsMessage extends SmsMessageBase{ } /** {@inheritDoc} */ + @Override public int getStatus() { return status; } /** {@inheritDoc} */ + @Override public boolean isStatusReportMessage() { return isStatusReportMessage; } /** {@inheritDoc} */ + @Override public boolean isReplyPathPresent() { return replyPathPresent; } /** - * TS 27.005 3.1, <pdu> definition "In the case of SMS: 3GPP TS 24.011 [6] + * TS 27.005 3.1, <pdu> definition "In the case of SMS: 3GPP TS 24.011 [6] * SC address followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format: * ME/TA converts each octet of TP data unit into two IRA character long - * hexad number (e.g. octet with integer value 42 is presented to TE as two + * hex number (e.g. octet with integer value 42 is presented to TE as two * characters 2A (IRA 50 and 65))" ...in the case of cell broadcast, * something else... */ private void parsePdu(byte[] pdu) { mPdu = pdu; - // Log.d(LOG_TAG, "raw sms mesage:"); + // Log.d(LOG_TAG, "raw sms message:"); // Log.d(LOG_TAG, s); PduParser p = new PduParser(pdu); @@ -1107,6 +1133,16 @@ public class SmsMessage extends SmsMessageBase{ Log.w(LOG_TAG, "MWI for fax, email, or other " + (dataCodingScheme & 0xff)); } + } else if ((dataCodingScheme & 0xC0) == 0x80) { + // 3GPP TS 23.038 V7.0.0 (2006-03) section 4 + // 0x80..0xBF == Reserved coding groups + if (dataCodingScheme == 0x84) { + // This value used for KSC5601 by carriers in Korea. + encodingType = ENCODING_KSC5601; + } else { + Log.w(LOG_TAG, "5 - Unsupported SMS data coding scheme " + + (dataCodingScheme & 0xff)); + } } else { Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme " + (dataCodingScheme & 0xff)); @@ -1131,6 +1167,10 @@ public class SmsMessage extends SmsMessageBase{ case ENCODING_16BIT: messageBody = p.getUserDataUCS2(count); break; + + case ENCODING_KSC5601: + messageBody = p.getUserDataKSC5601(count); + break; } if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'"); @@ -1162,6 +1202,7 @@ public class SmsMessage extends SmsMessageBase{ /** * {@inheritDoc} */ + @Override public MessageClass getMessageClass() { return messageClass; } diff --git a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java index b642541..41f3b23 100755 --- a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java +++ b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java @@ -27,8 +27,6 @@ import com.android.internal.telephony.IccConstants; import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.PhoneBase; -import org.apache.harmony.luni.lang.reflect.ListOfTypes; - import java.util.ArrayList; import java.util.HashMap; import java.util.Map; diff --git a/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java b/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java index 154a334..c83f696 100644 --- a/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java +++ b/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java @@ -19,6 +19,7 @@ package com.android.internal.telephony.sip; import com.android.internal.telephony.Call; import com.android.internal.telephony.Connection; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.UUSInfo; import android.net.sip.SipAudioCall; import android.os.SystemClock; @@ -171,4 +172,10 @@ abstract class SipConnectionBase extends Connection { // TODO: add PRESENTATION_URL return Connection.PRESENTATION_ALLOWED; } + + @Override + public UUSInfo getUUSInfo() { + // FIXME: what's this for SIP? + return null; + } } diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java index b154c91..ef31ddd 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java @@ -36,7 +36,6 @@ import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.Connection; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneNotifier; -import com.android.internal.telephony.UUSInfo; import java.text.ParseException; import java.util.List; @@ -70,6 +69,14 @@ public class SipPhone extends SipPhoneBase { mSipManager = SipManager.newInstance(context); } + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof SipPhone)) return false; + SipPhone that = (SipPhone) o; + return mProfile.getUriString().equals(that.mProfile.getUriString()); + } + public String getPhoneName() { return "SIP:" + getUriString(mProfile); } @@ -145,10 +152,6 @@ public class SipPhone extends SipPhoneBase { } } - public Connection dial(String dialString, UUSInfo uusinfo) throws CallStateException { - return dial(dialString); - } - public Connection dial(String dialString) throws CallStateException { synchronized (SipPhone.class) { return dialInternal(dialString); @@ -832,10 +835,6 @@ public class SipPhone extends SipPhoneBase { } } - @Override - public UUSInfo getUUSInfo() { - return null; - } } private static Call.State getCallStateFrom(SipAudioCall sipAudioCall) { diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java index 5499966..afd4d0c 100755 --- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java +++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java @@ -17,6 +17,7 @@ package com.android.internal.telephony.sip; import android.content.Context; +import android.net.LinkProperties; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; @@ -42,6 +43,7 @@ import com.android.internal.telephony.PhoneBase; import com.android.internal.telephony.PhoneNotifier; import com.android.internal.telephony.PhoneSubInfo; import com.android.internal.telephony.TelephonyProperties; +import com.android.internal.telephony.UUSInfo; import java.util.ArrayList; import java.util.List; @@ -62,6 +64,12 @@ abstract class SipPhoneBase extends PhoneBase { public abstract Call getRingingCall(); + public Connection dial(String dialString, UUSInfo uusInfo) + throws CallStateException { + // ignore UUSInfo + return dial(dialString); + } + void migrateFrom(SipPhoneBase from) { migrate(mRingbackRegistrants, from.mRingbackRegistrants); migrate(mPreciseCallStateRegistrants, from.mPreciseCallStateRegistrants); @@ -419,6 +427,18 @@ abstract class SipPhoneBase extends PhoneBase { Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP."); } + //@Override + public boolean needsOtaServiceProvisioning() { + // FIXME: what's this for SIP? + return false; + } + + //@Override + public LinkProperties getLinkProperties(String apnType) { + // FIXME: what's this for SIP? + return null; + } + void updatePhoneState() { State oldState = state; diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java index 9c72e5a..fdcf78d 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java @@ -16,7 +16,6 @@ package com.android.internal.telephony.test; - import android.os.AsyncResult; import android.os.HandlerThread; import android.os.Looper; @@ -27,7 +26,6 @@ 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.UUSInfo; import com.android.internal.telephony.gsm.CallFailCause; @@ -335,7 +333,7 @@ public final class SimulatedCommands extends BaseCommands /** * (AsyncResult)response.obj).result will be an Integer representing - * the sum of enabled serivice classes (sum of SERVICE_CLASS_*) + * the sum of enabled service classes (sum of SERVICE_CLASS_*) * * @param facility one of CB_FACILTY_* * @param pin password or "" if not required @@ -441,7 +439,7 @@ public final class SimulatedCommands extends BaseCommands * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result contains a List of DriverCall * The ar.result List is sorted by DriverCall.index */ @@ -468,7 +466,7 @@ public final class SimulatedCommands extends BaseCommands * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result contains a List of DataCallState */ public void getDataCallList(Message result) { @@ -479,7 +477,7 @@ public final class SimulatedCommands extends BaseCommands * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure * * CLIR_DEFAULT == on "use subscription default value" @@ -496,7 +494,7 @@ public final class SimulatedCommands extends BaseCommands * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure * * CLIR_DEFAULT == on "use subscription default value" @@ -513,7 +511,7 @@ public final class SimulatedCommands extends BaseCommands * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is String containing IMSI on success */ public void getIMSI(Message result) { @@ -524,7 +522,7 @@ public final class SimulatedCommands extends BaseCommands * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is String containing IMEI on success */ public void getIMEI(Message result) { @@ -535,7 +533,7 @@ public final class SimulatedCommands extends BaseCommands * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is String containing IMEISV on success */ public void getIMEISV(Message result) { @@ -547,7 +545,7 @@ public final class SimulatedCommands extends BaseCommands * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure * * 3GPP 22.030 6.5.5 @@ -572,7 +570,7 @@ public final class SimulatedCommands extends BaseCommands * "Releases all held calls or sets User Determined User Busy (UDUB) * for a waiting call." * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure */ public void hangupWaitingOrBackground (Message result) { @@ -593,7 +591,7 @@ public final class SimulatedCommands extends BaseCommands * the other (held or waiting) call." * * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure */ public void hangupForegroundResumeBackground (Message result) { @@ -614,7 +612,7 @@ public final class SimulatedCommands extends BaseCommands * the other (held or waiting) call." * * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure */ public void switchWaitingOrHoldingAndActive (Message result) { @@ -634,7 +632,7 @@ public final class SimulatedCommands extends BaseCommands * "Adds a held call to the conversation" * * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure */ public void conference (Message result) { @@ -654,7 +652,7 @@ public final class SimulatedCommands extends BaseCommands * "Connects the two calls and disconnects the subscriber from both calls" * * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure */ public void explicitCallTransfer (Message result) { @@ -690,7 +688,7 @@ public final class SimulatedCommands extends BaseCommands /** * * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure */ public void acceptCall (Message result) { @@ -708,7 +706,7 @@ public final class SimulatedCommands extends BaseCommands /** * also known as UDUB * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure */ public void rejectCall (Message result) { @@ -785,7 +783,7 @@ public final class SimulatedCommands extends BaseCommands * * @param result is callback message * ((AsyncResult)response.obj).result is an int[] with every - * element representing one avialable BM_*_BAND + * element representing one available BM_*_BAND */ public void queryAvailableBandMode (Message result) { int ret[] = new int [4]; @@ -894,7 +892,7 @@ public final class SimulatedCommands extends BaseCommands /** * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure */ public void sendDtmf(char c, Message result) { @@ -903,7 +901,7 @@ public final class SimulatedCommands extends BaseCommands /** * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure */ public void startDtmf(char c, Message result) { @@ -912,7 +910,7 @@ public final class SimulatedCommands extends BaseCommands /** * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure */ public void stopDtmf(Message result) { @@ -921,7 +919,7 @@ public final class SimulatedCommands extends BaseCommands /** * ar.exception carries exception on failure - * ar.userObject contains the orignal value of result.obj + * ar.userObject contains the original value of result.obj * ar.result is null on success and failure */ public void sendBurstDtmf(String dtmfString, int on, int off, Message result) { @@ -956,6 +954,7 @@ public final class SimulatedCommands extends BaseCommands unimplemented(response); } + @Deprecated public void setupDefaultPDP(String apn, String user, String password, Message result) { unimplemented(result); } @@ -967,9 +966,7 @@ public final class SimulatedCommands extends BaseCommands public void deactivateDataCall(int cid, Message result) {unimplemented(result);} - /** - * @deprecated - */ + @Deprecated public void deactivateDefaultPDP(int cid, Message result) {unimplemented(result);} public void setPreferredNetworkType(int networkType , Message result) { @@ -1046,7 +1043,7 @@ public final class SimulatedCommands extends BaseCommands } /** - * parameters equivilient to 27.007 AT+CRSM command + * parameters equivalent to 27.007 AT+CRSM command * response.obj will be an AsyncResult * response.obj.userObj will be a SimIoResult on success */ |