diff options
Diffstat (limited to 'telephony/java')
12 files changed, 537 insertions, 52 deletions
diff --git a/telephony/java/android/telephony/cdma/CdmaCellLocation.java b/telephony/java/android/telephony/cdma/CdmaCellLocation.java index 84db830..6cfae6a 100644 --- a/telephony/java/android/telephony/cdma/CdmaCellLocation.java +++ b/telephony/java/android/telephony/cdma/CdmaCellLocation.java @@ -81,14 +81,26 @@ public class CdmaCellLocation extends CellLocation { } /** - * @return cdma base station latitude, Integer.MAX_VALUE if unknown + * Latitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0. + * (http://www.3gpp2.org/public_html/specs/C.S0005-A_v6.0.pdf) + * It is represented in units of 0.25 seconds and ranges from -1296000 + * to 1296000, both values inclusive (corresponding to a range of -90 + * to +90 degrees). Integer.MAX_VALUE is considered invalid value. + * + * @return cdma base station latitude in units of 0.25 seconds, Integer.MAX_VALUE if unknown */ public int getBaseStationLatitude() { return this.mBaseStationLatitude; } /** - * @return cdma base station longitude, Integer.MAX_VALUE if unknown + * Longitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0. + * (http://www.3gpp2.org/public_html/specs/C.S0005-A_v6.0.pdf) + * It is represented in units of 0.25 seconds and ranges from -2592000 + * to 2592000, both values inclusive (corresponding to a range of -180 + * to +180 degrees). Integer.MAX_VALUE is considered invalid value. + * + * @return cdma base station longitude in units of 0.25 seconds, Integer.MAX_VALUE if unknown */ public int getBaseStationLongitude() { return this.mBaseStationLongitude; @@ -215,6 +227,22 @@ public class CdmaCellLocation extends CellLocation { this.mNetworkId == -1); } + /** + * Converts latitude or longitude from 0.25 seconds (as defined in the + * 3GPP2 C.S0005-A v6.0 standard) to decimal degrees + * + * @param quartSec latitude or longitude in 0.25 seconds units + * @return latitude or longitude in decimal degrees units + * @throws IllegalArgumentException if value is less than -2592000, + * greater than 2592000, or is not a number. + */ + public static double convertQuartSecToDecDegrees(int quartSec) { + if(Double.isNaN(quartSec) || quartSec < -2592000 || quartSec > 2592000){ + // Invalid value + throw new IllegalArgumentException("Invalid coordiante value:" + quartSec); + } + return ((double)quartSec) / (3600 * 4); + } } diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java index 07f90cd..021602f 100644 --- a/telephony/java/com/android/internal/telephony/Connection.java +++ b/telephony/java/com/android/internal/telephony/Connection.java @@ -28,6 +28,10 @@ public abstract class Connection { public static int PRESENTATION_UNKNOWN = 3; // no specified or unknown by network public static int PRESENTATION_PAYPHONE = 4; // show pay phone info + //Caller Name Display + protected String cnapName; + protected int cnapNamePresentation = PRESENTATION_ALLOWED; + private static String LOG_TAG = "TelephonyConnection"; public enum DisconnectCause { @@ -84,11 +88,11 @@ public abstract class Connection { public abstract String getAddress(); /** - * Gets CDMA CNAP name associated with connection. + * Gets CNAP name associated with connection. * @return cnap name or null if unavailable */ public String getCnapName() { - return null; + return cnapName; } /** @@ -100,12 +104,12 @@ public abstract class Connection { } /** - * Gets CDMA CNAP presentation associated with connection. + * Gets CNAP presentation associated with connection. * @return cnap name or null if unavailable */ public int getCnapNamePresentation() { - return 0; + return cnapNamePresentation; }; /** diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java index cc4adfd..a6bd85e 100644 --- a/telephony/java/com/android/internal/telephony/DataConnection.java +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -17,7 +17,6 @@ package com.android.internal.telephony; -import com.android.internal.telephony.DataCallState.SetupResult; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import com.android.internal.util.State; @@ -39,6 +38,7 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; /** * {@hide} @@ -65,8 +65,7 @@ public abstract class DataConnection extends StateMachine { protected static final boolean DBG = true; protected static final boolean VDBG = false; - protected static Object mCountLock = new Object(); - protected static int mCount; + protected static AtomicInteger mCount = new AtomicInteger(0); protected AsyncChannel mAc; protected List<ApnContext> mApnList = null; @@ -260,12 +259,11 @@ public abstract class DataConnection extends StateMachine { protected abstract void log(String s); - //***** Constructor protected DataConnection(PhoneBase phone, String name, int id, RetryManager rm, DataConnectionTracker dct) { super(name); - setProcessedMessagesSize(100); + setLogRecSize(100); if (DBG) log("DataConnection constructor E"); this.phone = phone; this.mDataConnectionTracker = dct; @@ -287,6 +285,27 @@ public abstract class DataConnection extends StateMachine { } /** + * Shut down this instance and its state machine. + */ + private void shutDown() { + if (DBG) log("shutDown"); + + if (mAc != null) { + mAc.disconnected(); + mAc = null; + } + mApnList = null; + mReconnectIntent = null; + mDataConnectionTracker = null; + mApn = null; + phone = null; + mLinkProperties = null; + mCapabilities = null; + lastFailCause = null; + userData = null; + } + + /** * TearDown the data connection. * * @param o will be returned in AsyncResult.userObj @@ -619,9 +638,11 @@ public abstract class DataConnection extends StateMachine { @Override public void exit() { phone.mCM.unregisterForRilConnected(getHandler()); + shutDown(); } @Override public boolean processMessage(Message msg) { + boolean retVal = HANDLED; AsyncResult ar; switch (msg.what) { @@ -639,14 +660,9 @@ public abstract class DataConnection extends StateMachine { } break; } - case AsyncChannel.CMD_CHANNEL_DISCONNECT: { - if (VDBG) log("CMD_CHANNEL_DISCONNECT"); - mAc.disconnect(); - break; - } case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { if (VDBG) log("CMD_CHANNEL_DISCONNECTED"); - mAc = null; + quit(); break; } case DataConnectionAc.REQ_IS_INACTIVE: { @@ -784,7 +800,7 @@ public abstract class DataConnection extends StateMachine { break; } - return HANDLED; + return retVal; } } private DcDefaultState mDefaultState = new DcDefaultState(); @@ -1215,11 +1231,11 @@ public abstract class DataConnection extends StateMachine { * @return the string for msg.what as our info. */ @Override - protected String getMessageInfo(Message msg) { + protected String getWhatToString(int what) { String info = null; - info = cmdToString(msg.what); + info = cmdToString(what); if (info == null) { - info = DataConnectionAc.cmdToString(msg.what); + info = DataConnectionAc.cmdToString(what); } return info; } diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java index 07d733e..41125dd 100644 --- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java @@ -116,6 +116,12 @@ public abstract class SMSDispatcher extends Handler { /** Don't send SMS (user did not confirm). */ static final int EVENT_STOP_SENDING = 7; // accessed from inner class + /** Confirmation required for third-party apps sending to an SMS short code. */ + private static final int EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE = 8; + + /** Confirmation required for third-party apps sending to an SMS short code. */ + private static final int EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE = 9; + protected final Phone mPhone; protected final Context mContext; protected final ContentResolver mResolver; @@ -288,6 +294,14 @@ public abstract class SMSDispatcher extends Handler { handleReachSentLimit((SmsTracker)(msg.obj)); break; + case EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE: + handleConfirmShortCode(false, (SmsTracker)(msg.obj)); + break; + + case EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE: + handleConfirmShortCode(true, (SmsTracker)(msg.obj)); + break; + case EVENT_SEND_CONFIRMED_SMS: { SmsTracker tracker = (SmsTracker) msg.obj; @@ -906,18 +920,61 @@ public abstract class SMSDispatcher extends Handler { SmsTracker tracker = new SmsTracker(map, sentIntent, deliveryIntent, appPackage, PhoneNumberUtils.extractNetworkPortion(destAddr)); - // check for excessive outgoing SMS usage by this app - if (!mUsageMonitor.check(appPackage, SINGLE_PART_SMS)) { - sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker)); - return; - } + // checkDestination() returns true if the destination is not a premium short code or the + // sending app is approved to send to short codes. Otherwise, a message is sent to our + // handler with the SmsTracker to request user confirmation before sending. + if (checkDestination(tracker)) { + // check for excessive outgoing SMS usage by this app + if (!mUsageMonitor.check(appPackage, SINGLE_PART_SMS)) { + sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker)); + return; + } - int ss = mPhone.getServiceState().getState(); + int ss = mPhone.getServiceState().getState(); - if (ss != ServiceState.STATE_IN_SERVICE) { - handleNotInService(ss, tracker.mSentIntent); + if (ss != ServiceState.STATE_IN_SERVICE) { + handleNotInService(ss, tracker.mSentIntent); + } else { + sendSms(tracker); + } + } + } + + /** + * Check if destination is a potential premium short code and sender is not pre-approved to + * send to short codes. + * + * @param tracker the tracker for the SMS to send + * @return true if the destination is approved; false if user confirmation event was sent + */ + boolean checkDestination(SmsTracker tracker) { + if (mContext.checkCallingOrSelfPermission(SEND_SMS_NO_CONFIRMATION_PERMISSION) + == PackageManager.PERMISSION_GRANTED) { + return true; // app is pre-approved to send to short codes } else { - sendSms(tracker); + String countryIso = mTelephonyManager.getSimCountryIso(); + if (countryIso == null || countryIso.length() != 2) { + Log.e(TAG, "Can't get SIM country code: trying network country code"); + countryIso = mTelephonyManager.getNetworkCountryIso(); + } + + switch (mUsageMonitor.checkDestination(tracker.mDestAddress, countryIso)) { + case SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE: + sendMessage(obtainMessage(EVENT_CONFIRM_SEND_TO_POSSIBLE_PREMIUM_SHORT_CODE, + tracker)); + return false; // wait for user confirmation before sending + + case SmsUsageMonitor.CATEGORY_PREMIUM_SHORT_CODE: + sendMessage(obtainMessage(EVENT_CONFIRM_SEND_TO_PREMIUM_SHORT_CODE, + tracker)); + return false; // wait for user confirmation before sending + + case SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE: + case SmsUsageMonitor.CATEGORY_FREE_SHORT_CODE: + case SmsUsageMonitor.CATEGORY_STANDARD_SHORT_CODE: + default: + return true; // destination is not a premium short code + } } } @@ -986,6 +1043,47 @@ public abstract class SMSDispatcher extends Handler { } /** + * Post an alert for user confirmation when sending to a potential short code. + * @param isPremium true if the destination is known to be a premium short code + * @param tracker the SmsTracker for the current message. + */ + protected void handleConfirmShortCode(boolean isPremium, SmsTracker tracker) { + if (denyIfQueueLimitReached(tracker)) { + return; // queue limit reached; error was returned to caller + } + + int messageId; + int titleId; + if (isPremium) { + messageId = R.string.sms_premium_short_code_confirm_message; + titleId = R.string.sms_premium_short_code_confirm_title; + } else { + messageId = R.string.sms_short_code_confirm_message; + titleId = R.string.sms_short_code_confirm_title; + } + + CharSequence appLabel = getAppLabel(tracker.mAppPackage); + Resources r = Resources.getSystem(); + Spanned messageText = Html.fromHtml(r.getString(messageId, appLabel, tracker.mDestAddress)); + + ConfirmDialogListener listener = new ConfirmDialogListener(tracker); + + AlertDialog d = new AlertDialog.Builder(mContext) + .setTitle(titleId) + .setIcon(R.drawable.stat_sys_warning) + .setMessage(messageText) + .setPositiveButton(r.getString(R.string.sms_short_code_confirm_allow), listener) + .setNegativeButton(r.getString(R.string.sms_short_code_confirm_deny), listener) +// TODO: add third button for "Report malicious app" feature +// .setNeutralButton(r.getString(R.string.sms_short_code_confirm_report), listener) + .setOnCancelListener(listener) + .create(); + + d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + d.show(); + } + + /** * Send the message along to the radio. * * @param tracker holds the SMS message to send diff --git a/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java b/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java index 4a4485d..1804d97 100644 --- a/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java +++ b/telephony/java/com/android/internal/telephony/SmsUsageMonitor.java @@ -60,17 +60,177 @@ public class SmsUsageMonitor { /** Default number of SMS sent in checking period without user permission. */ private static final int DEFAULT_SMS_MAX_COUNT = 30; + /** Return value from {@link #checkDestination} for regular phone numbers. */ + static final int CATEGORY_NOT_SHORT_CODE = 0; + + /** Return value from {@link #checkDestination} for free (no cost) short codes. */ + static final int CATEGORY_FREE_SHORT_CODE = 1; + + /** Return value from {@link #checkDestination} for standard rate (non-premium) short codes. */ + static final int CATEGORY_STANDARD_SHORT_CODE = 2; + + /** Return value from {@link #checkDestination} for possible premium short codes. */ + static final int CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE = 3; + + /** Return value from {@link #checkDestination} for premium short codes. */ + static final int CATEGORY_PREMIUM_SHORT_CODE = 4; + private final int mCheckPeriod; private final int mMaxAllowed; private final HashMap<String, ArrayList<Long>> mSmsStamp = new HashMap<String, ArrayList<Long>>(); + /** Context for retrieving regexes from XML resource. */ + private final Context mContext; + + /** Country code for the cached short code pattern matcher. */ + private String mCurrentCountry; + + /** Cached short code pattern matcher for {@link #mCurrentCountry}. */ + private ShortCodePatternMatcher mCurrentPatternMatcher; + + /** Cached short code regex patterns from secure settings for {@link #mCurrentCountry}. */ + private String mSettingsShortCodePatterns; + + /** Handler for responding to content observer updates. */ + private final SettingsObserverHandler mSettingsObserverHandler; + + /** XML tag for root element. */ + private static final String TAG_SHORTCODES = "shortcodes"; + + /** XML tag for short code patterns for a specific country. */ + private static final String TAG_SHORTCODE = "shortcode"; + + /** XML attribute for the country code. */ + private static final String ATTR_COUNTRY = "country"; + + /** XML attribute for the short code regex pattern. */ + private static final String ATTR_PATTERN = "pattern"; + + /** XML attribute for the premium short code regex pattern. */ + private static final String ATTR_PREMIUM = "premium"; + + /** XML attribute for the free short code regex pattern. */ + private static final String ATTR_FREE = "free"; + + /** XML attribute for the standard rate short code regex pattern. */ + private static final String ATTR_STANDARD = "standard"; + + /** + * SMS short code regex pattern matcher for a specific country. + */ + private static final class ShortCodePatternMatcher { + private final Pattern mShortCodePattern; + private final Pattern mPremiumShortCodePattern; + private final Pattern mFreeShortCodePattern; + private final Pattern mStandardShortCodePattern; + + ShortCodePatternMatcher(String shortCodeRegex, String premiumShortCodeRegex, + String freeShortCodeRegex, String standardShortCodeRegex) { + mShortCodePattern = (shortCodeRegex != null ? Pattern.compile(shortCodeRegex) : null); + mPremiumShortCodePattern = (premiumShortCodeRegex != null ? + Pattern.compile(premiumShortCodeRegex) : null); + mFreeShortCodePattern = (freeShortCodeRegex != null ? + Pattern.compile(freeShortCodeRegex) : null); + mStandardShortCodePattern = (standardShortCodeRegex != null ? + Pattern.compile(standardShortCodeRegex) : null); + } + + int getNumberCategory(String phoneNumber) { + if (mFreeShortCodePattern != null && mFreeShortCodePattern.matcher(phoneNumber) + .matches()) { + return CATEGORY_FREE_SHORT_CODE; + } + if (mStandardShortCodePattern != null && mStandardShortCodePattern.matcher(phoneNumber) + .matches()) { + return CATEGORY_STANDARD_SHORT_CODE; + } + if (mPremiumShortCodePattern != null && mPremiumShortCodePattern.matcher(phoneNumber) + .matches()) { + return CATEGORY_PREMIUM_SHORT_CODE; + } + if (mShortCodePattern != null && mShortCodePattern.matcher(phoneNumber).matches()) { + return CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE; + } + return CATEGORY_NOT_SHORT_CODE; + } + } + + /** + * Observe the secure setting for updated regex patterns. + */ + private static class SettingsObserver extends ContentObserver { + private final int mWhat; + private final Handler mHandler; + + SettingsObserver(Handler handler, int what) { + super(handler); + mHandler = handler; + mWhat = what; + } + + @Override + public void onChange(boolean selfChange) { + mHandler.obtainMessage(mWhat).sendToTarget(); + } + } + + /** + * Handler to update regex patterns when secure setting for the current country is updated. + */ + private class SettingsObserverHandler extends Handler { + /** Current content observer, or null. */ + SettingsObserver mSettingsObserver; + + /** Current country code to watch for settings updates. */ + private String mCountryIso; + + /** Request to start observing a secure setting. */ + static final int OBSERVE_SETTING = 1; + + /** Handler event for updated secure settings. */ + static final int SECURE_SETTINGS_CHANGED = 2; + + /** Send a message to this handler requesting to observe the setting for a new country. */ + void observeSettingForCountry(String countryIso) { + obtainMessage(OBSERVE_SETTING, countryIso).sendToTarget(); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case OBSERVE_SETTING: + if (msg.obj != null && msg.obj instanceof String) { + mCountryIso = (String) msg.obj; + String settingName = getSettingNameForCountry(mCountryIso); + ContentResolver resolver = mContext.getContentResolver(); + + if (mSettingsObserver != null) { + if (VDBG) log("Unregistering old content observer"); + resolver.unregisterContentObserver(mSettingsObserver); + } + + mSettingsObserver = new SettingsObserver(this, SECURE_SETTINGS_CHANGED); + resolver.registerContentObserver( + Settings.Secure.getUriFor(settingName), false, mSettingsObserver); + if (VDBG) log("Registered content observer for " + settingName); + } + break; + + case SECURE_SETTINGS_CHANGED: + loadPatternsFromSettings(mCountryIso); + break; + } + } + } + /** * Create SMS usage monitor. * @param context the context to use to load resources and get TelephonyManager service */ public SmsUsageMonitor(Context context) { + mContext = context; ContentResolver resolver = context.getContentResolver(); mMaxAllowed = Settings.Secure.getInt(resolver, @@ -80,6 +240,83 @@ public class SmsUsageMonitor { mCheckPeriod = Settings.Secure.getInt(resolver, Settings.Secure.SMS_OUTGOING_CHECK_INTERVAL_MS, DEFAULT_SMS_CHECK_PERIOD); + + mSettingsObserverHandler = new SettingsObserverHandler(); + } + + /** + * Return a pattern matcher object for the specified country. + * @param country the country to search for + * @return a {@link ShortCodePatternMatcher} for the specified country, or null if not found + */ + private ShortCodePatternMatcher getPatternMatcher(String country) { + int id = com.android.internal.R.xml.sms_short_codes; + XmlResourceParser parser = mContext.getResources().getXml(id); + + try { + return getPatternMatcher(country, parser); + } catch (XmlPullParserException e) { + Log.e(TAG, "XML parser exception reading short code pattern resource", e); + } catch (IOException e) { + Log.e(TAG, "I/O exception reading short code pattern resource", e); + } finally { + parser.close(); + } + return null; // country not found + } + + /** + * Return a pattern matcher object for the specified country from a secure settings string. + * @return a {@link ShortCodePatternMatcher} for the specified country, or null if not found + */ + private static ShortCodePatternMatcher getPatternMatcher(String country, String settingsPattern) { + // embed pattern tag into an XML document. + String document = "<shortcodes>" + settingsPattern + "</shortcodes>"; + if (VDBG) log("loading updated patterns from: " + document); + + try { + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + XmlPullParser parser = factory.newPullParser(); + parser.setInput(new StringReader(document)); + return getPatternMatcher(country, parser); + } catch (XmlPullParserException e) { + Log.e(TAG, "XML parser exception reading short code pattern from settings", e); + } catch (IOException e) { + Log.e(TAG, "I/O exception reading short code pattern from settings", e); + } + return null; // country not found + } + + /** + * Return a pattern matcher object for the specified country and pattern XML parser. + * @param country the country to search for + * @return a {@link ShortCodePatternMatcher} for the specified country, or null if not found + */ + private static ShortCodePatternMatcher getPatternMatcher(String country, XmlPullParser parser) + throws XmlPullParserException, IOException + { + XmlUtils.beginDocument(parser, TAG_SHORTCODES); + + while (true) { + XmlUtils.nextElement(parser); + + String element = parser.getName(); + if (element == null) break; + + if (element.equals(TAG_SHORTCODE)) { + String currentCountry = parser.getAttributeValue(null, ATTR_COUNTRY); + if (country.equals(currentCountry)) { + String pattern = parser.getAttributeValue(null, ATTR_PATTERN); + String premium = parser.getAttributeValue(null, ATTR_PREMIUM); + String free = parser.getAttributeValue(null, ATTR_FREE); + String standard = parser.getAttributeValue(null, ATTR_STANDARD); + return new ShortCodePatternMatcher(pattern, premium, free, standard); + } + } else { + Log.e(TAG, "Error: skipping unknown XML tag " + element); + } + } + return null; // country not found } /** Clear the SMS application list for disposal. */ @@ -112,6 +349,90 @@ public class SmsUsageMonitor { } /** + * Check if the destination is a possible premium short code. + * NOTE: the caller is expected to strip non-digits from the destination number with + * {@link PhoneNumberUtils#extractNetworkPortion} before calling this method. + * This happens in {@link SMSDispatcher#sendRawPdu} so that we use the same phone number + * for testing and in the user confirmation dialog if the user needs to confirm the number. + * This makes it difficult for malware to fool the user or the short code pattern matcher + * by using non-ASCII characters to make the number appear to be different from the real + * destination phone number. + * + * @param destAddress the destination address to test for possible short code + * @return {@link #CATEGORY_NOT_SHORT_CODE}, {@link #CATEGORY_FREE_SHORT_CODE}, + * {@link #CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE}, or {@link #CATEGORY_PREMIUM_SHORT_CODE}. + */ + public int checkDestination(String destAddress, String countryIso) { + synchronized (mSettingsObserverHandler) { + // always allow emergency numbers + if (PhoneNumberUtils.isEmergencyNumber(destAddress, countryIso)) { + return CATEGORY_NOT_SHORT_CODE; + } + + ShortCodePatternMatcher patternMatcher = null; + + if (countryIso != null) { + // query secure settings and initialize content observer for updated regex patterns + if (mCurrentCountry == null || !countryIso.equals(mCurrentCountry)) { + loadPatternsFromSettings(countryIso); + mSettingsObserverHandler.observeSettingForCountry(countryIso); + } + + if (countryIso.equals(mCurrentCountry)) { + patternMatcher = mCurrentPatternMatcher; + } else { + patternMatcher = getPatternMatcher(countryIso); + mCurrentCountry = countryIso; + mCurrentPatternMatcher = patternMatcher; // may be null if not found + } + } + + if (patternMatcher != null) { + return patternMatcher.getNumberCategory(destAddress); + } else { + // Generic rule: numbers of 5 digits or less are considered potential short codes + Log.e(TAG, "No patterns for \"" + countryIso + "\": using generic short code rule"); + if (destAddress.length() <= 5) { + return CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE; + } else { + return CATEGORY_NOT_SHORT_CODE; + } + } + } + } + + private static String getSettingNameForCountry(String countryIso) { + return Settings.Secure.SMS_SHORT_CODES_PREFIX + countryIso; + } + + /** + * Load regex patterns from secure settings if present. + * @param countryIso the country to search for + */ + void loadPatternsFromSettings(String countryIso) { + synchronized (mSettingsObserverHandler) { + if (VDBG) log("loadPatternsFromSettings(" + countryIso + ") called"); + String settingsPatterns = Settings.Secure.getString( + mContext.getContentResolver(), getSettingNameForCountry(countryIso)); + if (settingsPatterns != null && !settingsPatterns.equals( + mSettingsShortCodePatterns)) { + // settings pattern string has changed: update the pattern matcher + mSettingsShortCodePatterns = settingsPatterns; + ShortCodePatternMatcher matcher = getPatternMatcher(countryIso, settingsPatterns); + if (matcher != null) { + mCurrentCountry = countryIso; + mCurrentPatternMatcher = matcher; + } + } else if (settingsPatterns == null && mSettingsShortCodePatterns != null) { + // pattern string was removed: caller will load default patterns from XML resource + mCurrentCountry = null; + mCurrentPatternMatcher = null; + mSettingsShortCodePatterns = null; + } + } + } + + /** * Remove keys containing only old timestamps. This can happen if an SMS app is used * to send messages and then uninstalled. */ diff --git a/telephony/java/com/android/internal/telephony/TelephonyCapabilities.java b/telephony/java/com/android/internal/telephony/TelephonyCapabilities.java index bd94de2..a122e68 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyCapabilities.java +++ b/telephony/java/com/android/internal/telephony/TelephonyCapabilities.java @@ -177,4 +177,15 @@ public class TelephonyCapabilities { public static boolean supportsAdn(int phoneType) { return phoneType == Phone.PHONE_TYPE_GSM; } + + /** + * Returns true if the device can distinguish the phone's dialing state + * (Call.State.DIALING/ALERTING) and connected state (Call.State.ACTIVE). + * + * Currently this returns true for GSM phones as we cannot know when a CDMA + * phone has transitioned from dialing/active to connected. + */ + public static boolean canDistinguishDialingAndConnected(int phoneType) { + return phoneType == Phone.PHONE_TYPE_GSM; + } } diff --git a/telephony/java/com/android/internal/telephony/cat/CommandDetails.java b/telephony/java/com/android/internal/telephony/cat/CommandDetails.java index 8579535..3e7f722 100644 --- a/telephony/java/com/android/internal/telephony/cat/CommandDetails.java +++ b/telephony/java/com/android/internal/telephony/cat/CommandDetails.java @@ -48,13 +48,14 @@ class CommandDetails extends ValueObject implements Parcelable { } public CommandDetails(Parcel in) { - compRequired = true; + compRequired = in.readInt() != 0; commandNumber = in.readInt(); typeOfCommand = in.readInt(); commandQualifier = in.readInt(); } public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(compRequired ? 1 : 0); dest.writeInt(commandNumber); dest.writeInt(typeOfCommand); dest.writeInt(commandQualifier); @@ -111,4 +112,4 @@ class ItemsIconId extends ValueObject { ComprehensionTlvTag getTag() { return ComprehensionTlvTag.ITEM_ICON_ID_LIST; } -}
\ No newline at end of file +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java index 98ad3b1..6985979 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java @@ -51,7 +51,6 @@ public class CdmaConnection extends Connection { String postDialString; // outgoing calls only boolean isIncoming; boolean disconnected; - String cnapName; int index; // index in CdmaCallTracker.connections[], -1 if unassigned /* @@ -77,7 +76,6 @@ public class CdmaConnection extends Connection { DisconnectCause cause = DisconnectCause.NOT_DISCONNECTED; PostDialState postDialState = PostDialState.NOT_STARTED; int numberPresentation = Connection.PRESENTATION_ALLOWED; - int cnapNamePresentation = Connection.PRESENTATION_ALLOWED; Handler h; @@ -230,14 +228,6 @@ public class CdmaConnection extends Connection { return address; } - public String getCnapName() { - return cnapName; - } - - public int getCnapNamePresentation() { - return cnapNamePresentation; - } - public CdmaCall getCall() { return parent; } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java index 4ef05ea..141736c 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java @@ -51,11 +51,8 @@ public class CdmaDataConnection extends DataConnection { */ static CdmaDataConnection makeDataConnection(CDMAPhone phone, int id, RetryManager rm, DataConnectionTracker dct) { - synchronized (mCountLock) { - mCount += 1; - } - CdmaDataConnection cdmaDc = new CdmaDataConnection(phone, "CdmaDC-" + mCount, - id, rm, dct); + CdmaDataConnection cdmaDc = new CdmaDataConnection(phone, + "CdmaDC-" + mCount.incrementAndGet(), id, rm, dct); cdmaDc.start(); if (DBG) cdmaDc.log("Made " + cdmaDc.getName()); return cdmaDc; diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index 6e9cd51..484bab0 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -1232,7 +1232,7 @@ public class GSMPhone extends PhoneBase { // If the radio shuts off or resets while one of these // is pending, we need to clean up. - for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) { + for (int i = mPendingMMIs.size() - 1; i >= 0; i--) { if (mPendingMMIs.get(i).isPendingUSSD()) { mPendingMMIs.get(i).onUssdFinishedError(); } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java index f7c6025..9e32e8d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java @@ -26,6 +26,7 @@ import android.os.SystemClock; import android.util.Log; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; +import android.text.TextUtils; import com.android.internal.telephony.*; @@ -125,6 +126,8 @@ public class GsmConnection extends Connection { isIncoming = dc.isMT; createTime = System.currentTimeMillis(); + cnapName = dc.name; + cnapNamePresentation = dc.namePresentation; numberPresentation = dc.numberPresentation; uusInfo = dc.uusInfo; @@ -151,6 +154,9 @@ public class GsmConnection extends Connection { index = -1; isIncoming = false; + cnapName = null; + cnapNamePresentation = Connection.PRESENTATION_ALLOWED; + numberPresentation = Connection.PRESENTATION_ALLOWED; createTime = System.currentTimeMillis(); this.parent = parent; @@ -437,6 +443,21 @@ public class GsmConnection extends Connection { changed = true; } + // A null cnapName should be the same as "" + if (TextUtils.isEmpty(dc.name)) { + if (!TextUtils.isEmpty(cnapName)) { + changed = true; + cnapName = ""; + } + } else if (!dc.name.equals(cnapName)) { + changed = true; + cnapName = dc.name; + } + + if (Phone.DEBUG_PHONE) log("--dssds----"+cnapName); + cnapNamePresentation = dc.namePresentation; + numberPresentation = dc.numberPresentation; + if (newParent != parent) { if (parent != null) { parent.detach(this); diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java index 9801721..3e6d9a5 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java @@ -56,10 +56,8 @@ public class GsmDataConnection extends DataConnection { */ static GsmDataConnection makeDataConnection(PhoneBase phone, int id, RetryManager rm, DataConnectionTracker dct) { - synchronized (mCountLock) { - mCount += 1; - } - GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDC-" + mCount, id, rm, dct); + GsmDataConnection gsmDc = new GsmDataConnection(phone, + "GsmDC-" + mCount.incrementAndGet(), id, rm, dct); gsmDc.start(); if (DBG) gsmDc.log("Made " + gsmDc.getName()); return gsmDc; |
