diff options
Diffstat (limited to 'telephony')
90 files changed, 7368 insertions, 1640 deletions
diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java index f763d3f..2edfc23 100644 --- a/telephony/java/android/telephony/CellLocation.java +++ b/telephony/java/android/telephony/CellLocation.java @@ -79,6 +79,11 @@ public abstract class CellLocation { public abstract void fillInNotifierBundle(Bundle bundle); /** + * @hide + */ + public abstract boolean isEmpty(); + + /** * Return a new CellLocation object representing an unknown * location, or null for unknown/none phone radio types. * diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index 1aa1c76..32e7176 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -207,6 +207,42 @@ public class PhoneNumberUtils } /** + * Extracts the network address portion and canonicalize. + * + * This function is equivalent to extractNetworkPortion(), except + * for allowing the PLUS character to occur at arbitrary positions + * in the address portion, not just the first position. + * + * @hide + */ + public static String extractNetworkPortionAlt(String phoneNumber) { + if (phoneNumber == null) { + return null; + } + + int len = phoneNumber.length(); + StringBuilder ret = new StringBuilder(len); + boolean haveSeenPlus = false; + + for (int i = 0; i < len; i++) { + char c = phoneNumber.charAt(i); + if (c == '+') { + if (haveSeenPlus) { + continue; + } + haveSeenPlus = true; + } + if (isDialable(c)) { + ret.append(c); + } else if (isStartsPostDial (c)) { + break; + } + } + + return ret.toString(); + } + + /** * Strips separators from a phone number string. * @param phoneNumber phone number to strip. * @return phone string stripped of separators. @@ -342,6 +378,8 @@ public class PhoneNumberUtils compareLoosely(String a, String b) { int ia, ib; int matched; + int numNonDialableCharsInA = 0; + int numNonDialableCharsInB = 0; if (a == null || b == null) return a == b; @@ -362,6 +400,7 @@ public class PhoneNumberUtils if (!isDialable(ca)) { ia--; skipCmp = true; + numNonDialableCharsInA++; } cb = b.charAt(ib); @@ -369,6 +408,7 @@ public class PhoneNumberUtils if (!isDialable(cb)) { ib--; skipCmp = true; + numNonDialableCharsInB++; } if (!skipCmp) { @@ -380,13 +420,16 @@ public class PhoneNumberUtils } if (matched < MIN_MATCH) { - int aLen = a.length(); + int effectiveALen = a.length() - numNonDialableCharsInA; + int effectiveBLen = b.length() - numNonDialableCharsInB; - // if the input strings match, but their lengths < MIN_MATCH, - // treat them as equal. - if (aLen == b.length() && aLen == matched) { + + // if the number of dialable chars in a and b match, but the matched chars < MIN_MATCH, + // treat them as equal (i.e. 404-04 and 40404) + if (effectiveALen == effectiveBLen && effectiveALen == matched) { return true; } + return false; } @@ -590,7 +633,7 @@ public class PhoneNumberUtils */ public static String toCallerIDMinMatch(String phoneNumber) { - String np = extractNetworkPortion(phoneNumber); + String np = extractNetworkPortionAlt(phoneNumber); return internalGetStrippedReversed(np, MIN_MATCH); } @@ -603,7 +646,7 @@ public class PhoneNumberUtils */ public static String getStrippedReversed(String phoneNumber) { - String np = extractNetworkPortion(phoneNumber); + String np = extractNetworkPortionAlt(phoneNumber); if (np == null) return null; @@ -1017,8 +1060,8 @@ public class PhoneNumberUtils * Breaks the given number down and formats it according to the rules * for the country the number is from. * - * @param source the phone number to format - * @return a locally acceptable formatting of the input, or the raw input if + * @param source The phone number to format + * @return A locally acceptable formatting of the input, or the raw input if * formatting rules aren't known for the number */ public static String formatNumber(String source) { @@ -1028,10 +1071,27 @@ public class PhoneNumberUtils } /** + * Formats the given number with the given formatting type. Currently + * {@link #FORMAT_NANP} and {@link #FORMAT_JAPAN} are supported as a formating type. + * + * @param source the phone number to format + * @param defaultFormattingType The default formatting rules to apply if the number does + * not begin with +<country_code> + * @return The phone number formatted with the given formatting type. + * + * @hide TODO:Shuold be unhidden. + */ + public static String formatNumber(String source, int defaultFormattingType) { + SpannableStringBuilder text = new SpannableStringBuilder(source); + formatNumber(text, defaultFormattingType); + return text.toString(); + } + + /** * Returns the phone number formatting type for the given locale. * * @param locale The locale of interest, usually {@link Locale#getDefault()} - * @return the formatting type for the given locale, or FORMAT_UNKNOWN if the formatting + * @return The formatting type for the given locale, or FORMAT_UNKNOWN if the formatting * rules are not known for the given locale */ public static int getFormatTypeForLocale(Locale locale) { @@ -1041,7 +1101,8 @@ public class PhoneNumberUtils } /** - * Formats a phone number in-place. Currently only supports NANP formatting. + * Formats a phone number in-place. Currently {@link #FORMAT_JAPAN} and {@link #FORMAT_NANP} + * is supported as a second argument. * * @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 @@ -1247,10 +1308,15 @@ public class PhoneNumberUtils // Strip the separators from the number before comparing it // to the list. - number = extractNetworkPortion(number); + number = extractNetworkPortionAlt(number); // retrieve the list of emergency numbers - String numbers = SystemProperties.get("ro.ril.ecclist"); + // check read-write ecclist property first + String numbers = SystemProperties.get("ril.ecclist"); + if (TextUtils.isEmpty(numbers)) { + // then read-only ecclist property since old RIL only uses this + numbers = SystemProperties.get("ro.ril.ecclist"); + } if (!TextUtils.isEmpty(numbers)) { // searches through the comma-separated list for a match, @@ -1290,7 +1356,7 @@ public class PhoneNumberUtils // Strip the separators from the number before comparing it // to the list. - number = extractNetworkPortion(number); + number = extractNetworkPortionAlt(number); // compare tolerates null so we need to make sure that we // don't return true when both are null. @@ -1593,7 +1659,7 @@ public class PhoneNumberUtils if (DBG) log("processPlusCodeWithinNanp,networkDialStr=" + networkDialStr); // If there is a plus sign at the beginning of the dial string, // Convert the plus sign to the default IDP since it's an international number - if (networkDialStr != null & + if (networkDialStr != null && networkDialStr.charAt(0) == PLUS_SIGN_CHAR && networkDialStr.length() > 1) { String newStr = networkDialStr.substring(1); diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 4f9cb2e..830af47 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package android.telephony; import android.os.Bundle; diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 446bbc2..1f00885 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -115,6 +115,8 @@ public class ServiceState implements Parcelable { private String mOperatorNumeric; private boolean mIsManualNetworkSelection; + private boolean mIsEmergencyOnly; + //***** CDMA private int mRadioTechnology; private boolean mCssIndicator; @@ -172,6 +174,7 @@ public class ServiceState implements Parcelable { mCdmaDefaultRoamingIndicator = s.mCdmaDefaultRoamingIndicator; mCdmaEriIconIndex = s.mCdmaEriIconIndex; mCdmaEriIconMode = s.mCdmaEriIconMode; + mIsEmergencyOnly = s.mIsEmergencyOnly; } /** @@ -192,6 +195,7 @@ public class ServiceState implements Parcelable { mCdmaDefaultRoamingIndicator = in.readInt(); mCdmaEriIconIndex = in.readInt(); mCdmaEriIconMode = in.readInt(); + mIsEmergencyOnly = in.readInt() != 0; } public void writeToParcel(Parcel out, int flags) { @@ -209,6 +213,7 @@ public class ServiceState implements Parcelable { out.writeInt(mCdmaDefaultRoamingIndicator); out.writeInt(mCdmaEriIconIndex); out.writeInt(mCdmaEriIconMode); + out.writeInt(mIsEmergencyOnly ? 1 : 0); } public int describeContents() { @@ -252,6 +257,13 @@ public class ServiceState implements Parcelable { /** * @hide */ + public boolean isEmergencyOnly() { + return mIsEmergencyOnly; + } + + /** + * @hide + */ public int getCdmaRoamingIndicator(){ return this.mCdmaRoamingIndicator; } @@ -332,7 +344,8 @@ public class ServiceState implements Parcelable { + ((null == mOperatorAlphaShort) ? 0 : mOperatorAlphaShort.hashCode()) + ((null == mOperatorNumeric) ? 0 : mOperatorNumeric.hashCode()) + mCdmaRoamingIndicator - + mCdmaDefaultRoamingIndicator); + + mCdmaDefaultRoamingIndicator + + (mIsEmergencyOnly ? 1 : 0)); } @Override @@ -361,7 +374,8 @@ public class ServiceState implements Parcelable { && equalsHandlesNulls(mSystemId, s.mSystemId) && equalsHandlesNulls(mCdmaRoamingIndicator, s.mCdmaRoamingIndicator) && equalsHandlesNulls(mCdmaDefaultRoamingIndicator, - s.mCdmaDefaultRoamingIndicator)); + s.mCdmaDefaultRoamingIndicator) + && mIsEmergencyOnly == s.mIsEmergencyOnly); } @Override @@ -422,7 +436,8 @@ public class ServiceState implements Parcelable { + " " + mNetworkId + " " + mSystemId + "RoamInd: " + mCdmaRoamingIndicator - + "DefRoamInd: " + mCdmaDefaultRoamingIndicator); + + "DefRoamInd: " + mCdmaDefaultRoamingIndicator + + "EmergOnly: " + mIsEmergencyOnly); } public void setStateOutOfService() { @@ -440,6 +455,7 @@ public class ServiceState implements Parcelable { mCdmaDefaultRoamingIndicator = -1; mCdmaEriIconIndex = -1; mCdmaEriIconMode = -1; + mIsEmergencyOnly = false; } // TODO - can't this be combined with the above func.. @@ -458,6 +474,7 @@ public class ServiceState implements Parcelable { mCdmaDefaultRoamingIndicator = -1; mCdmaEriIconIndex = -1; mCdmaEriIconMode = -1; + mIsEmergencyOnly = false; } public void setState(int state) { @@ -468,6 +485,14 @@ public class ServiceState implements Parcelable { mRoaming = roaming; } + + /** + * @hide + */ + public void setEmergencyOnly(boolean emergencyOnly) { + mIsEmergencyOnly = emergencyOnly; + } + /** * @hide */ @@ -546,6 +571,7 @@ public class ServiceState implements Parcelable { mSystemId = m.getInt("systemId"); mCdmaRoamingIndicator = m.getInt("cdmaRoamingIndicator"); mCdmaDefaultRoamingIndicator = m.getInt("cdmaDefaultRoamingIndicator"); + mIsEmergencyOnly = m.getBoolean("emergencyOnly"); } /** @@ -567,6 +593,7 @@ public class ServiceState implements Parcelable { m.putInt("systemId", mSystemId); m.putInt("cdmaRoamingIndicator", mCdmaRoamingIndicator); m.putInt("cdmaDefaultRoamingIndicator", mCdmaDefaultRoamingIndicator); + m.putBoolean("emergencyOnly", Boolean.valueOf(mIsEmergencyOnly)); } //***** CDMA diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index b8ea4c0..a284ea5 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -237,8 +237,8 @@ public class SmsMessage { /* * TODO(cleanup): It would make some sense if the result of - * preprocessing a message to determine the proper encoding (ie - * the resulting datastructure from calculateLength) could be + * preprocessing a message to determine the proper encoding (i.e. + * the resulting data structure from calculateLength) could be * passed as an argument to the actual final encoding function. * This would better ensure that the logic behind size calculation * actually matched the encoding. @@ -427,7 +427,7 @@ public class SmsMessage { * @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. diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 310fc7f..ab63017 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -46,7 +46,7 @@ import java.util.List; * {@link android.content.Context#getSystemService * Context.getSystemService(Context.TELEPHONY_SERVICE)}. * <p> - * Note that acess to some telephony information is + * Note that access to some telephony information is * permission-protected. Your application cannot access the protected * information unless it has the appropriate permissions declared in * its manifest file. Where permissions apply, they are noted in the @@ -203,7 +203,10 @@ public class TelephonyManager { public CellLocation getCellLocation() { try { Bundle bundle = getITelephony().getCellLocation(); - return CellLocation.newFromBundle(bundle); + CellLocation cl = CellLocation.newFromBundle(bundle); + if (cl.isEmpty()) + return null; + return cl; } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -353,7 +356,7 @@ public class TelephonyManager { } /** - * Returns the ISO country code equivilent of the current registered + * Returns the ISO country code equivalent of the current registered * operator's MCC (Mobile Country Code). * <p> * Availability: Only when user is registered to a network. Result may be @@ -386,6 +389,8 @@ public class TelephonyManager { public static final int NETWORK_TYPE_HSUPA = 9; /** Current network is HSPA */ public static final int NETWORK_TYPE_HSPA = 10; + /** Current network is iDen */ + public static final int NETWORK_TYPE_IDEN = 11; /** Current network is EVDO revision B*/ public static final int NETWORK_TYPE_EVDO_B = 12; diff --git a/telephony/java/android/telephony/cdma/CdmaCellLocation.java b/telephony/java/android/telephony/cdma/CdmaCellLocation.java index 7ef7747..84db830 100644 --- a/telephony/java/android/telephony/cdma/CdmaCellLocation.java +++ b/telephony/java/android/telephony/cdma/CdmaCellLocation.java @@ -26,12 +26,17 @@ public class CdmaCellLocation extends CellLocation { private int mBaseStationId = -1; /** + * @hide + */ + public final static int INVALID_LAT_LONG = Integer.MAX_VALUE; + + /** * Latitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0. * 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. */ - private int mBaseStationLatitude = Integer.MAX_VALUE; + private int mBaseStationLatitude = INVALID_LAT_LONG; /** * Longitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0. @@ -39,7 +44,7 @@ public class CdmaCellLocation extends CellLocation { * to 2592000, both values inclusive (corresponding to a range of -180 * to +180 degrees). Integer.MAX_VALUE is considered invalid value. */ - private int mBaseStationLongitude = Integer.MAX_VALUE; + private int mBaseStationLongitude = INVALID_LAT_LONG; private int mSystemId = -1; private int mNetworkId = -1; @@ -51,8 +56,8 @@ public class CdmaCellLocation extends CellLocation { */ public CdmaCellLocation() { this.mBaseStationId = -1; - this.mBaseStationLatitude = Integer.MAX_VALUE; - this.mBaseStationLongitude = Integer.MAX_VALUE; + this.mBaseStationLatitude = INVALID_LAT_LONG; + this.mBaseStationLongitude = INVALID_LAT_LONG; this.mSystemId = -1; this.mNetworkId = -1; } @@ -60,12 +65,12 @@ public class CdmaCellLocation extends CellLocation { /** * Initialize the object from a bundle. */ - public CdmaCellLocation(Bundle bundleWithValues) { - this.mBaseStationId = bundleWithValues.getInt("baseStationId"); - this.mBaseStationLatitude = bundleWithValues.getInt("baseStationLatitude"); - this.mBaseStationLongitude = bundleWithValues.getInt("baseStationLongitude"); - this.mSystemId = bundleWithValues.getInt("systemId"); - this.mNetworkId = bundleWithValues.getInt("networkId"); + public CdmaCellLocation(Bundle bundle) { + this.mBaseStationId = bundle.getInt("baseStationId", mBaseStationId); + this.mBaseStationLatitude = bundle.getInt("baseStationLatitude", mBaseStationLatitude); + this.mBaseStationLongitude = bundle.getInt("baseStationLongitude", mBaseStationLongitude); + this.mSystemId = bundle.getInt("systemId", mSystemId); + this.mNetworkId = bundle.getInt("networkId", mNetworkId); } /** @@ -108,8 +113,8 @@ public class CdmaCellLocation extends CellLocation { */ public void setStateInvalid() { this.mBaseStationId = -1; - this.mBaseStationLatitude = Integer.MAX_VALUE; - this.mBaseStationLongitude = Integer.MAX_VALUE; + this.mBaseStationLatitude = INVALID_LAT_LONG; + this.mBaseStationLongitude = INVALID_LAT_LONG; this.mSystemId = -1; this.mNetworkId = -1; } @@ -199,6 +204,18 @@ public class CdmaCellLocation extends CellLocation { bundleToFill.putInt("networkId", this.mNetworkId); } + /** + * @hide + */ + public boolean isEmpty() { + return (this.mBaseStationId == -1 && + this.mBaseStationLatitude == INVALID_LAT_LONG && + this.mBaseStationLongitude == INVALID_LAT_LONG && + this.mSystemId == -1 && + this.mNetworkId == -1); + } + + } diff --git a/telephony/java/android/telephony/gsm/GsmCellLocation.java b/telephony/java/android/telephony/gsm/GsmCellLocation.java index 637a11c..fa1f985 100644 --- a/telephony/java/android/telephony/gsm/GsmCellLocation.java +++ b/telephony/java/android/telephony/gsm/GsmCellLocation.java @@ -38,8 +38,8 @@ public class GsmCellLocation extends CellLocation { * Initialize the object from a bundle. */ public GsmCellLocation(Bundle bundle) { - mLac = bundle.getInt("lac"); - mCid = bundle.getInt("cid"); + mLac = bundle.getInt("lac", mLac); + mCid = bundle.getInt("cid", mCid); } /** @@ -119,6 +119,11 @@ public class GsmCellLocation extends CellLocation { m.putInt("lac", mLac); m.putInt("cid", mCid); } -} - + /** + * @hide + */ + public boolean isEmpty() { + return (mLac == -1 && mCid == -1); + } +} diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java index 7421854..b962375 100644 --- a/telephony/java/com/android/internal/telephony/BaseCommands.java +++ b/telephony/java/com/android/internal/telephony/BaseCommands.java @@ -22,7 +22,6 @@ import android.os.RegistrantList; import android.os.Registrant; import android.os.Handler; import android.os.AsyncResult; -import android.provider.Checkin; import android.util.Config; import android.util.Log; @@ -618,13 +617,6 @@ public abstract class BaseCommands implements CommandsInterface { return; } - if (mContext != null && - newState == RadioState.RADIO_UNAVAILABLE && - oldState != RadioState.RADIO_OFF) { - Checkin.updateStats(mContext.getContentResolver(), - Checkin.Stats.Tag.PHONE_RADIO_RESETS, 1, 0.0); - } - mRadioStateChangedRegistrants.notifyRegistrants(); if (mState.isAvailable() && !oldState.isAvailable()) { diff --git a/telephony/java/com/android/internal/telephony/Call.java b/telephony/java/com/android/internal/telephony/Call.java index b95dd11..4967ab8 100644 --- a/telephony/java/com/android/internal/telephony/Call.java +++ b/telephony/java/com/android/internal/telephony/Call.java @@ -18,6 +18,8 @@ package com.android.internal.telephony; import java.util.List; +import android.util.Log; + /** * {@hide} */ @@ -54,6 +56,8 @@ public abstract class Call { // merged, etc. protected boolean isGeneric = false; + protected final String LOG_TAG = "Call"; + /* Instance Methods */ /** Do not modify the List result!!! This list is not yours to keep @@ -235,4 +239,17 @@ public abstract class Call { public void setGeneric(boolean generic) { isGeneric = generic; } + + /** + * Hangup call if it is alive + */ + public void hangupIfAlive() { + if (getState().isAlive()) { + try { + hangup(); + } catch (CallStateException ex) { + Log.w(LOG_TAG, " hangupIfActive: caught " + ex); + } + } + } } diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java index 01b1746..cf89848 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfo.java +++ b/telephony/java/com/android/internal/telephony/CallerInfo.java @@ -22,6 +22,7 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.provider.ContactsContract.PhoneLookup; import android.provider.ContactsContract.CommonDataKinds.Phone; +import static android.provider.ContactsContract.RawContacts; import android.text.TextUtils; import android.telephony.TelephonyManager; import android.telephony.PhoneNumberUtils; @@ -118,7 +119,6 @@ public class CallerInfo { * number. The returned CallerInfo is null if no number is supplied. */ public static CallerInfo getCallerInfo(Context context, Uri contactRef, Cursor cursor) { - CallerInfo info = new CallerInfo(); info.photoResource = 0; info.phoneLabel = null; @@ -132,6 +132,9 @@ public class CallerInfo { if (cursor != null) { if (cursor.moveToFirst()) { + // TODO: photo_id is always available but not taken + // care of here. Maybe we should store it in the + // CallerInfo object as well. int columnIndex; @@ -160,10 +163,34 @@ public class CallerInfo { } } - // Look for the person ID - columnIndex = cursor.getColumnIndex(PhoneLookup._ID); + // Look for the person ID. + + // TODO: This is pretty ugly now, see bug 2269240 for + // more details. With tel: URI the contact id is in + // col "_id" while when we use a + // content://contacts/data/phones URI, the contact id + // is col "contact_id". As a work around we use the + // type of the contact url to figure out which column + // we should look at to get the contact_id. + + final String mimeType = context.getContentResolver().getType(contactRef); + + columnIndex = -1; + if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) { + // content://com.android.contacts/data/phones URL + columnIndex = cursor.getColumnIndex(RawContacts.CONTACT_ID); + } else { + // content://com.android.contacts/phone_lookup URL + // TODO: mime type is null here so we cannot test + // if we have the right url type. phone_lookup URL + // should resolve to a mime type. + columnIndex = cursor.getColumnIndex(PhoneLookup._ID); + } + if (columnIndex != -1) { info.person_id = cursor.getLong(columnIndex); + } else { + Log.e(TAG, "Column missing for " + contactRef); } // look for the custom ringtone, create from the string stored diff --git a/telephony/java/com/android/internal/telephony/CommandException.java b/telephony/java/com/android/internal/telephony/CommandException.java index d7adab3..94c544e 100644 --- a/telephony/java/com/android/internal/telephony/CommandException.java +++ b/telephony/java/com/android/internal/telephony/CommandException.java @@ -41,6 +41,7 @@ public class CommandException extends RuntimeException { SUBSCRIPTION_NOT_AVAILABLE, MODE_NOT_SUPPORTED, FDN_CHECK_FAILURE, + ILLEGAL_SIM_OR_ME, } public CommandException(Error e) { @@ -80,6 +81,8 @@ public class CommandException extends RuntimeException { return new CommandException(Error.MODE_NOT_SUPPORTED); case RILConstants.FDN_CHECK_FAILURE: return new CommandException(Error.FDN_CHECK_FAILURE); + case RILConstants.ILLEGAL_SIM_OR_ME: + return new CommandException(Error.ILLEGAL_SIM_OR_ME); default: Log.e("GSM", "Unrecognized RIL errno " + ril_errno); return new CommandException(Error.INVALID_RESPONSE); diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java index 7809fed..1f8bbcf 100644 --- a/telephony/java/com/android/internal/telephony/DataConnection.java +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -16,43 +16,150 @@ package com.android.internal.telephony; +import com.android.internal.telephony.gsm.ApnSetting; + +import com.android.internal.util.HierarchicalState; +import com.android.internal.util.HierarchicalStateMachine; + import android.os.AsyncResult; -import android.os.Handler; import android.os.Message; -import android.util.Log; +import android.os.SystemProperties; +import android.util.EventLog; /** * {@hide} + * + * DataConnection HierarchicalStateMachine. + * + * This is an abstract base class for representing a single data connection. + * Instances of this class such as <code>CdmaDataConnection</code> and + * <code>GsmDataConnection</code>, * represent a connection via the cellular network. + * There may be multiple data connections and all of them are managed by the + * <code>DataConnectionTracker</code>. + * + * Instances are asynchronous state machines and have two primary entry points + * <code>connect()</code> and <code>disconnect</code>. The message a parameter will be returned + * hen the operation completes. The <code>msg.obj</code> will contain an AsyncResult + * object and <code>AsyncResult.userObj</code> is the original <code>msg.obj</code>. if successful + * with the <code>AsyncResult.result == null</code> and <code>AsyncResult.exception == null</code>. + * If an error <code>AsyncResult.result = FailCause</code> and + * <code>AsyncResult.exception = new Exception()</code>. + * + * The other public methods are provided for debugging. + * + * Below is the state machine description for this class. + * + * DataConnection { + * + mDefaultState { + * EVENT_RESET { clearSettings, notifiyDisconnectCompleted, >mInactiveState }. + * EVENT_CONNECT { notifyConnectCompleted(FailCause.UNKNOWN) }. + * EVENT_DISCONNECT { notifyDisconnectCompleted }. + * + * // Ignored messages + * EVENT_SETUP_DATA_CONNECTION_DONE, + * EVENT_GET_LAST_FAIL_DONE, + * EVENT_DEACTIVATE_DONE. + * } + * ++ # mInactiveState + * e(doNotifications) + * x(clearNotifications) { + * EVENT_RESET { notifiyDisconnectCompleted }. + * EVENT_CONNECT {startConnecting, >mActivatingState }. + * } + * ++ mActivatingState { + * EVENT_DISCONNECT { %EVENT_DISCONNECT }. + * EVENT_SETUP_DATA_CONNECTION_DONE { + * if (SUCCESS) { notifyConnectCompleted(FailCause.NONE), >mActiveState }. + * if (ERR_BadCommand) { + * notifyConnectCompleted(FailCause.UNKNOWN), >mInactiveState }. + * if (ERR_BadDns) { tearDownData($DEACTIVATE_DONE), >mDisconnectingBadDnsState }. + * if (ERR_Other) { getLastDataCallFailCause($EVENT_GET_LAST_FAIL_DONE) }. + * if (ERR_Stale) {}. + * } + * EVENT_GET_LAST_FAIL_DONE { notifyConnectCompleted(result), >mInactive }. + * } + * ++ mActiveState { + * EVENT_DISCONNECT { tearDownData($EVENT_DEACTIVATE_DONE), >mDisconnecting }. + * } + * ++ mDisconnectingState { + * EVENT_DEACTIVATE_DONE { notifyDisconnectCompleted, >mInactiveState }. + * } + * ++ mDisconnectingBadDnsState { + * EVENT_DEACTIVATE_DONE { notifyConnectComplete(FailCause.UNKNOWN), >mInactiveState }. + * } + * } */ -public abstract class DataConnection extends Handler { +public abstract class DataConnection extends HierarchicalStateMachine { + protected static final boolean DBG = true; - // the inherited class + protected static Object mCountLock = new Object(); + protected static int mCount; - public enum State { - ACTIVE, /* has active data connection */ - ACTIVATING, /* during connecting process */ - INACTIVE; /* has empty data connection */ + /** + * Class returned by onSetupConnectionCompleted. + */ + protected enum SetupResult { + ERR_BadCommand, + ERR_BadDns, + ERR_Other, + ERR_Stale, + SUCCESS; + public FailCause mFailCause; + + @Override public String toString() { switch (this) { - case ACTIVE: - return "active"; - case ACTIVATING: - return "setting up"; - default: - return "inactive"; + case ERR_BadCommand: return "Bad Command"; + case ERR_BadDns: return "Bad DNS"; + case ERR_Other: return "Other error"; + case ERR_Stale: return "Stale command"; + case SUCCESS: return "SUCCESS"; + default: return "unknown"; } } + } - public boolean isActive() { - return this == ACTIVE; + /** + * Used internally for saving connecting parameters. + */ + protected static class ConnectionParams { + public ConnectionParams(ApnSetting apn, Message onCompletedMsg) { + this.apn = apn; + this.onCompletedMsg = onCompletedMsg; } - public boolean isInactive() { - return this == INACTIVE; + public int tag; + public ApnSetting apn; + public Message onCompletedMsg; + } + + /** + * An instance used for notification of blockingReset. + * TODO: Remove when blockingReset is removed. + */ + class ResetSynchronouslyLock { + } + + /** + * Used internally for saving disconnecting parameters. + */ + protected static class DisconnectParams { + public DisconnectParams(Message onCompletedMsg) { + this.onCompletedMsg = onCompletedMsg; + } + public DisconnectParams(ResetSynchronouslyLock lockObj) { + this.lockObj = lockObj; } + + public int tag; + public Message onCompletedMsg; + public ResetSynchronouslyLock lockObj; } + /** + * Returned as the reason for a connection failure. + */ public enum FailCause { NONE, OPERATOR_BARRED, @@ -71,8 +178,7 @@ public abstract class DataConnection extends Handler { GPRS_REGISTRATION_FAIL, UNKNOWN, - RADIO_NOT_AVAILABLE, - RADIO_ERROR_RETRY; + RADIO_NOT_AVAILABLE; public boolean isPermanentFail() { return (this == OPERATOR_BARRED) || (this == MISSING_UKNOWN_APN) || @@ -128,117 +234,149 @@ public abstract class DataConnection extends Handler { return "Data Network Registration Failure"; case RADIO_NOT_AVAILABLE: return "Radio Not Available"; - case RADIO_ERROR_RETRY: - return "Transient Radio Rrror"; default: return "Unknown Data Error"; } } } - // ***** Event codes - protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 1; - protected static final int EVENT_GET_LAST_FAIL_DONE = 2; - protected static final int EVENT_LINK_STATE_CHANGED = 3; - protected static final int EVENT_DEACTIVATE_DONE = 4; - protected static final int EVENT_FORCE_RETRY = 5; + // ***** Event codes for driving the state machine + protected static final int EVENT_RESET = 1; + protected static final int EVENT_CONNECT = 2; + protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 3; + protected static final int EVENT_GET_LAST_FAIL_DONE = 4; + protected static final int EVENT_DEACTIVATE_DONE = 5; + protected static final int EVENT_DISCONNECT = 6; //***** Tag IDs for EventLog protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100; - //***** Member Variables + protected int mTag; protected PhoneBase phone; - protected Message onConnectCompleted; - protected Message onDisconnect; protected int cid; protected String interfaceName; protected String ipAddress; protected String gatewayAddress; protected String[] dnsServers; - protected State state; protected long createTime; protected long lastFailTime; protected FailCause lastFailCause; protected static final String NULL_IP = "0.0.0.0"; Object userData; - // receivedDisconnectReq is set when disconnect during activation - protected boolean receivedDisconnectReq; - - /* Instance Methods */ - protected abstract void onSetupConnectionCompleted(AsyncResult ar); - - protected abstract void onDeactivated(AsyncResult ar); - - protected abstract void disconnect(Message msg); - - protected abstract void notifyFail(FailCause cause, Message onCompleted); - - protected abstract void notifyDisconnect(Message msg); + //***** Abstract methods + public abstract String toString(); - protected abstract void onLinkStateChanged(DataLink.LinkState linkState); + protected abstract void onConnect(ConnectionParams cp); protected abstract FailCause getFailCauseFromRequest(int rilCause); - public abstract String toString(); + protected abstract boolean isDnsOk(String[] domainNameServers); protected abstract void log(String s); //***** Constructor - protected DataConnection(PhoneBase phone) { - super(); + protected DataConnection(PhoneBase phone, String name) { + super(name); + if (DBG) log("DataConnection constructor E"); this.phone = phone; - onConnectCompleted = null; - onDisconnect = null; this.cid = -1; - receivedDisconnectReq = false; this.dnsServers = new String[2]; clearSettings(); + + setDbg(false); + addState(mDefaultState); + addState(mInactiveState, mDefaultState); + addState(mActivatingState, mDefaultState); + addState(mActiveState, mDefaultState); + addState(mDisconnectingState, mDefaultState); + addState(mDisconnectingBadDnsState, mDefaultState); + setInitialState(mInactiveState); + if (DBG) log("DataConnection constructor X"); } - protected void setHttpProxy(String httpProxy, String httpPort) { - if (httpProxy == null || httpProxy.length() == 0) { - phone.setSystemProperty("net.gprs.http-proxy", null); - return; + /** + * TearDown the data connection. + * + * @param o will be returned in AsyncResult.userObj + * and is either a DisconnectParams or ConnectionParams. + */ + private void tearDownData(Object o) { + if (phone.mCM.getRadioState().isOn()) { + if (DBG) log("tearDownData radio is on, call deactivateDataCall"); + phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, o)); + } else { + if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately"); + AsyncResult ar = new AsyncResult(o, null, null); + sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, ar)); } + } - if (httpPort == null || httpPort.length() == 0) { - httpPort = "8080"; // Default to port 8080 + /** + * Send the connectionCompletedMsg. + * + * @param cp is the ConnectionParams + * @param cause + */ + private void notifyConnectCompleted(ConnectionParams cp, FailCause cause) { + Message connectionCompletedMsg = cp.onCompletedMsg; + if (connectionCompletedMsg == null) { + return; } - phone.setSystemProperty("net.gprs.http-proxy", - "http://" + httpProxy + ":" + httpPort + "/"); - } + long timeStamp = System.currentTimeMillis(); + connectionCompletedMsg.arg1 = cid; - public String getInterface() { - return interfaceName; - } + if (cause == FailCause.NONE) { + createTime = timeStamp; + AsyncResult.forMessage(connectionCompletedMsg); + } else { + lastFailCause = cause; + lastFailTime = timeStamp; + AsyncResult.forMessage(connectionCompletedMsg, cause, new Exception()); + } + if (DBG) log("notifyConnection at " + timeStamp + " cause=" + cause); - public String getIpAddress() { - return ipAddress; + connectionCompletedMsg.sendToTarget(); } - public String getGatewayAddress() { - return gatewayAddress; - } + /** + * Send ar.userObj if its a message, which is should be back to originator. + * + * @param dp is the DisconnectParams. + */ + private void notifyDisconnectCompleted(DisconnectParams dp) { + if (DBG) log("NotifyDisconnectCompleted"); + + 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>"))); + AsyncResult.forMessage(msg); + msg.sendToTarget(); + } + if (dp.lockObj != null) { + synchronized(dp.lockObj) { + dp.lockObj.notify(); + } + } - public String[] getDnsServers() { - return dnsServers; + clearSettings(); } - public void clearSettings() { - log("DataConnection.clearSettings()"); + /** + * Clear all settings called when entering mInactiveState. + */ + protected void clearSettings() { + if (DBG) log("clearSettings"); - this.state = State.INACTIVE; this.createTime = -1; this.lastFailTime = -1; this.lastFailCause = FailCause.NONE; - receivedDisconnectReq = false; - onConnectCompleted = null; interfaceName = null; ipAddress = null; gatewayAddress = null; @@ -246,80 +384,548 @@ public abstract class DataConnection extends Handler { dnsServers[1] = null; } - protected void onGetLastFailCompleted(AsyncResult ar) { - if (receivedDisconnectReq) { - // Don't bother reporting the error if there's already a - // pending disconnect request, since DataConnectionTracker - // has already updated its state. - notifyDisconnect(onDisconnect); + /** + * Process setup completion. + * + * @param ar is the result + * @return SetupResult. + */ + private SetupResult onSetupConnectionCompleted(AsyncResult ar) { + SetupResult result; + String[] response = ((String[]) ar.result); + ConnectionParams cp = (ConnectionParams) ar.userObj; + + if (ar.exception != null) { + if (DBG) log("DataConnection Init failed " + ar.exception); + + if (ar.exception instanceof CommandException + && ((CommandException) (ar.exception)).getCommandError() + == CommandException.Error.RADIO_NOT_AVAILABLE) { + result = SetupResult.ERR_BadCommand; + result.mFailCause = FailCause.RADIO_NOT_AVAILABLE; + } else { + result = SetupResult.ERR_Other; + } + } else if (cp.tag != mTag) { + if (DBG) { + log("BUG: onSetupConnectionCompleted is stale cp.tag=" + cp.tag + ", mtag=" + mTag); + } + result = SetupResult.ERR_Stale; } else { - FailCause cause = FailCause.UNKNOWN; - - if (ar.exception == null) { - int rilFailCause = ((int[]) (ar.result))[0]; - cause = getFailCauseFromRequest(rilFailCause); +// log("onSetupConnectionCompleted received " + response.length + " response strings:"); +// for (int i = 0; i < response.length; i++) { +// log(" response[" + i + "]='" + response[i] + "'"); +// } + if (response.length >= 2) { + cid = Integer.parseInt(response[0]); + interfaceName = response[1]; + if (response.length > 2) { + ipAddress = response[2]; + String prefix = "net." + interfaceName + "."; + gatewayAddress = SystemProperties.get(prefix + "gw"); + 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; + } else { + result = SetupResult.ERR_BadDns; + } + } else { + result = SetupResult.SUCCESS; + } + } else { + result = SetupResult.ERR_Other; } - notifyFail(cause, onConnectCompleted); } + + if (DBG) log("DataConnection setup result='" + result + "' on cid=" + cid); + return result; } - protected void onForceRetry() { - if (receivedDisconnectReq) { - notifyDisconnect(onDisconnect); - } else { - notifyFail(FailCause.RADIO_ERROR_RETRY, onConnectCompleted); + /** + * The parent state for all other states. + */ + private class DcDefaultState extends HierarchicalState { + @Override + protected boolean processMessage(Message msg) { + AsyncResult ar; + + switch (msg.what) { + case EVENT_RESET: + if (DBG) log("DcDefaultState: msg.what=EVENT_RESET"); + clearSettings(); + if (msg.obj != null) { + notifyDisconnectCompleted((DisconnectParams) msg.obj); + } + transitionTo(mInactiveState); + break; + + case EVENT_CONNECT: + if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected"); + ConnectionParams cp = (ConnectionParams) msg.obj; + notifyConnectCompleted(cp, FailCause.UNKNOWN); + break; + + case EVENT_DISCONNECT: + if (DBG) log("DcDefaultState: msg.what=EVENT_DISCONNECT"); + notifyDisconnectCompleted((DisconnectParams) msg.obj); + break; + + default: + if (DBG) { + log("DcDefaultState: shouldn't happen but ignore msg.what=" + msg.what); + } + break; + } + + return true; } } + private DcDefaultState mDefaultState = new DcDefaultState(); + + /** + * The state machine is inactive and expects a EVENT_CONNECT. + */ + private class DcInactiveState extends HierarchicalState { + private ConnectionParams mConnectionParams = null; + private FailCause mFailCause = null; + private DisconnectParams mDisconnectParams = null; + + public void setEnterNotificationParams(ConnectionParams cp, FailCause cause) { + log("DcInactiveState: setEnterNoticationParams cp,cause"); + mConnectionParams = cp; + mFailCause = cause; + } - @Override - public void handleMessage(Message msg) { - AsyncResult ar; + public void setEnterNotificationParams(DisconnectParams dp) { + log("DcInactiveState: setEnterNoticationParams dp"); + mDisconnectParams = dp; + } - log("DataConnection.handleMessage()"); + @Override protected void enter() { + mTag += 1; + + /** + * Now that we've transitioned to Inactive state we + * can send notifications. Previously we sent the + * notifications in the processMessage handler but + * that caused a race condition because the synchronous + * call to isInactive. + */ + if ((mConnectionParams != null) && (mFailCause != null)) { + log("DcInactiveState: enter notifyConnectCompleted"); + notifyConnectCompleted(mConnectionParams, mFailCause); + } + if (mDisconnectParams != null) { + log("DcInactiveState: enter notifyDisconnectCompleted"); + notifyDisconnectCompleted(mDisconnectParams); + } + } - switch (msg.what) { + @Override protected void exit() { + // clear notifications + mConnectionParams = null; + mFailCause = null; + mDisconnectParams = null; + } - case EVENT_SETUP_DATA_CONNECTION_DONE: - onSetupConnectionCompleted((AsyncResult) msg.obj); - break; + @Override protected boolean processMessage(Message msg) { + boolean retVal; + + switch (msg.what) { + case EVENT_RESET: + if (DBG) { + log("DcInactiveState: msg.what=EVENT_RESET, ignore we're already reset"); + } + if (msg.obj != null) { + notifyDisconnectCompleted((DisconnectParams) msg.obj); + } + retVal = true; + break; + + case EVENT_CONNECT: + if (DBG) log("DcInactiveState msg.what=EVENT_CONNECT"); + ConnectionParams cp = (ConnectionParams) msg.obj; + cp.tag = mTag; + onConnect(cp); + transitionTo(mActivatingState); + retVal = true; + break; + + default: + if (DBG) log("DcInactiveState nothandled msg.what=" + msg.what); + retVal = false; + break; + } + return retVal; + } + } + private DcInactiveState mInactiveState = new DcInactiveState(); + + /** + * The state machine is activating a connection. + */ + private class DcActivatingState extends HierarchicalState { + @Override protected boolean processMessage(Message msg) { + boolean retVal; + AsyncResult ar; + ConnectionParams cp; + + switch (msg.what) { + case EVENT_DISCONNECT: + if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT"); + deferMessage(msg); + retVal = true; + break; + + case EVENT_SETUP_DATA_CONNECTION_DONE: + if (DBG) log("DcActivatingState msg.what=EVENT_SETUP_DATA_CONNECTION_DONE"); + + ar = (AsyncResult) msg.obj; + cp = (ConnectionParams) ar.userObj; + + SetupResult result = onSetupConnectionCompleted(ar); + switch (result) { + case SUCCESS: + // All is well + mActiveState.setEnterNotificationParams(cp, FailCause.NONE); + transitionTo(mActiveState); + break; + case ERR_BadCommand: + // Vendor ril rejected the command and didn't connect. + // Transition to inactive but send notifications after + // we've entered the mInactive state. + mInactiveState.setEnterNotificationParams(cp, result.mFailCause); + transitionTo(mInactiveState); + break; + case ERR_BadDns: + // Connection succeeded but DNS info is bad so disconnect + EventLog.writeEvent(EventLogTags.PDP_BAD_DNS_ADDRESS, dnsServers[0]); + tearDownData(cp); + transitionTo(mDisconnectingBadDnsState); + break; + case ERR_Other: + // Request the failure cause and process in this state + phone.mCM.getLastDataCallFailCause( + obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp)); + break; + case ERR_Stale: + // Request is stale, ignore. + break; + default: + throw new RuntimeException("Unkown SetupResult, should not happen"); + } + retVal = true; + break; + + case EVENT_GET_LAST_FAIL_DONE: + ar = (AsyncResult) msg.obj; + cp = (ConnectionParams) ar.userObj; + FailCause cause = FailCause.UNKNOWN; + + if (cp.tag == mTag) { + if (DBG) log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE"); + if (ar.exception == null) { + int rilFailCause = ((int[]) (ar.result))[0]; + cause = getFailCauseFromRequest(rilFailCause); + } + // Transition to inactive but send notifications after + // we've entered the mInactive state. + mInactiveState.setEnterNotificationParams(cp, cause); + transitionTo(mInactiveState); + } else { + if (DBG) { + log("DcActivatingState EVENT_GET_LAST_FAIL_DONE is stale cp.tag=" + + cp.tag + ", mTag=" + mTag); + } + } + + retVal = true; + break; + + default: + if (DBG) log("DcActivatingState not handled msg.what=" + msg.what); + retVal = false; + break; + } + return retVal; + } + } + private DcActivatingState mActivatingState = new DcActivatingState(); + + /** + * The state machine is connected, expecting an EVENT_DISCONNECT. + */ + private class DcActiveState extends HierarchicalState { + private ConnectionParams mConnectionParams = null; + private FailCause mFailCause = null; + + public void setEnterNotificationParams(ConnectionParams cp, FailCause cause) { + log("DcInactiveState: setEnterNoticationParams cp,cause"); + mConnectionParams = cp; + mFailCause = cause; + } - case EVENT_FORCE_RETRY: - onForceRetry(); - break; + @Override public void enter() { + /** + * Now that we've transitioned to Active state we + * can send notifications. Previously we sent the + * notifications in the processMessage handler but + * that caused a race condition because the synchronous + * call to isActive. + */ + if ((mConnectionParams != null) && (mFailCause != null)) { + log("DcActiveState: enter notifyConnectCompleted"); + notifyConnectCompleted(mConnectionParams, mFailCause); + } + } - case EVENT_GET_LAST_FAIL_DONE: - onGetLastFailCompleted((AsyncResult) msg.obj); - break; + @Override protected void exit() { + // clear notifications + mConnectionParams = null; + mFailCause = null; + } - case EVENT_LINK_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - DataLink.LinkState ls = (DataLink.LinkState) ar.result; - onLinkStateChanged(ls); - break; + @Override protected boolean processMessage(Message msg) { + boolean retVal; + + switch (msg.what) { + case EVENT_DISCONNECT: + if (DBG) log("DcActiveState msg.what=EVENT_DISCONNECT"); + DisconnectParams dp = (DisconnectParams) msg.obj; + dp.tag = mTag; + tearDownData(dp); + transitionTo(mDisconnectingState); + retVal = true; + break; + + default: + if (DBG) log("DcActiveState nothandled msg.what=" + msg.what); + retVal = false; + break; + } + return retVal; + } + } + private DcActiveState mActiveState = new DcActiveState(); + + /** + * The state machine is disconnecting. + */ + private class DcDisconnectingState extends HierarchicalState { + @Override protected boolean processMessage(Message msg) { + boolean retVal; + + switch (msg.what) { + case EVENT_DEACTIVATE_DONE: + if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE"); + AsyncResult ar = (AsyncResult) msg.obj; + DisconnectParams dp = (DisconnectParams) ar.userObj; + if (dp.tag == mTag) { + // Transition to inactive but send notifications after + // we've entered the mInactive state. + mInactiveState.setEnterNotificationParams((DisconnectParams) ar.userObj); + transitionTo(mInactiveState); + } else { + if (DBG) log("DcDisconnectState EVENT_DEACTIVATE_DONE stale dp.tag=" + + dp.tag + " mTag=" + mTag); + } + retVal = true; + break; + + default: + if (DBG) log("DcDisconnectingState not handled msg.what=" + msg.what); + retVal = false; + break; + } + return retVal; + } + } + private DcDisconnectingState mDisconnectingState = new DcDisconnectingState(); + + /** + * The state machine is disconnecting after a bad dns setup + * was found in mInactivatingState. + */ + private class DcDisconnectingBadDnsState extends HierarchicalState { + @Override protected boolean processMessage(Message msg) { + boolean retVal; + + switch (msg.what) { + case EVENT_DEACTIVATE_DONE: + AsyncResult ar = (AsyncResult) msg.obj; + ConnectionParams cp = (ConnectionParams) ar.userObj; + if (cp.tag == mTag) { + if (DBG) log("DcDisconnectingBadDnsState msg.what=EVENT_DEACTIVATE_DONE"); + // Transition to inactive but send notifications after + // we've entered the mInactive state. + mInactiveState.setEnterNotificationParams(cp, FailCause.UNKNOWN); + transitionTo(mInactiveState); + } else { + if (DBG) log("DcDisconnectingBadDnsState EVENT_DEACTIVE_DONE stale dp.tag=" + + cp.tag + ", mTag=" + mTag); + } + retVal = true; + break; + + default: + if (DBG) log("DcDisconnectingBadDnsState not handled msg.what=" + msg.what); + retVal = false; + break; + } + return retVal; + } + } + private DcDisconnectingBadDnsState mDisconnectingBadDnsState = new DcDisconnectingBadDnsState(); + + // ******* public interface + + /** + * Disconnect from the network. + * + * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. + * With AsyncResult.userObj set to the original msg.obj. + */ + public void reset(Message onCompletedMsg) { + sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(onCompletedMsg))); + } - case EVENT_DEACTIVATE_DONE: - onDeactivated((AsyncResult) msg.obj); - break; + /** + * Reset the connection and wait for it to complete. + * TODO: Remove when all callers only need the asynchronous + * reset defined above. + */ + public void resetSynchronously() { + ResetSynchronouslyLock lockObj = new ResetSynchronouslyLock(); + synchronized(lockObj) { + sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(lockObj))); + try { + lockObj.wait(); + } catch (InterruptedException e) { + log("blockingReset: unexpected interrupted of wait()"); + } } } - public State getState() { - log("DataConnection.getState()"); - return state; + /** + * Connect to the apn and return an AsyncResult in onCompletedMsg. + * Used for cellular networks that use Acess 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 + */ + public void connect(Message onCompletedMsg, ApnSetting apn) { + sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg))); + } + + /** + * Connect to the apn and return an AsyncResult in onCompletedMsg. + * + * @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(). + */ + public void connect(Message onCompletedMsg) { + sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(null, onCompletedMsg))); + } + + /** + * Disconnect from the network. + * + * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object. + * With AsyncResult.userObj set to the original msg.obj. + */ + public void disconnect(Message onCompletedMsg) { + sendMessage(obtainMessage(EVENT_DISCONNECT, new DisconnectParams(onCompletedMsg))); + } + + // ****** The following are used for debugging. + + /** + * TODO: This should be an asynchronous call and we wouldn't + * have to use handle the notification in the DcInactiveState.enter. + * + * @return true if the state machine is in the inactive state. + */ + public boolean isInactive() { + boolean retVal = getCurrentState() == mInactiveState; + return retVal; + } + + /** + * TODO: This should be an asynchronous call and we wouldn't + * have to use handle the notification in the DcActiveState.enter. + * + * @return true if the state machine is in the active state. + */ + public boolean isActive() { + boolean retVal = getCurrentState() == mActiveState; + return retVal; + } + + /** + * @return the interface name as a string. + */ + public String getInterface() { + return interfaceName; + } + + /** + * @return the ip address as a string. + */ + public String getIpAddress() { + return ipAddress; + } + + /** + * @return the gateway address as a string. + */ + public String getGatewayAddress() { + return gatewayAddress; + } + + /** + * @return an array of associated DNS addresses. + */ + public String[] getDnsServers() { + return dnsServers; + } + + /** + * @return the current state as a string. + */ + public String getStateAsString() { + String retVal = getCurrentState().getName(); + return retVal; } + /** + * @return the time of when this connection was created. + */ public long getConnectionTime() { - log("DataConnection.getConnectionTime()"); return createTime; } + /** + * @return the time of the last failure. + */ public long getLastFailTime() { - log("DataConnection.getLastFailTime()"); return lastFailTime; } + /** + * @return the last cause of failure. + */ public FailCause getLastFailCause() { - log("DataConnection.getLastFailCause()"); return lastFailCause; } } diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index 52c8b1f..3b9e6cc 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -19,7 +19,6 @@ package com.android.internal.telephony; import android.app.PendingIntent; import android.os.AsyncResult; import android.os.Handler; -import android.os.INetStatService; import android.os.Message; import android.os.RemoteException; import android.provider.Settings; @@ -101,6 +100,7 @@ public abstract class DataConnectionTracker extends Handler { protected static final int EVENT_CDMA_OTA_PROVISION = 35; protected static final int EVENT_RESTART_RADIO = 36; protected static final int EVENT_SET_MASTER_DATA_ENABLE = 37; + protected static final int EVENT_RESET_DONE = 38; /***** Constants *****/ @@ -171,7 +171,6 @@ public abstract class DataConnectionTracker extends Handler { protected Handler mDataConnectionTracker = null; - protected INetStatService netstat; protected long txPkts, rxPkts, sentSinceLastRecv; protected int netStatPollPeriod; protected int mNoRecvPollCount = 0; @@ -265,6 +264,7 @@ public abstract class DataConnectionTracker extends Handler { protected abstract void onRadioOffOrNotAvailable(); protected abstract void onDataSetupComplete(AsyncResult ar); protected abstract void onDisconnectDone(AsyncResult ar); + protected abstract void onResetDone(AsyncResult ar); protected abstract void onVoiceCallStarted(); protected abstract void onVoiceCallEnded(); protected abstract void onCleanUpConnection(boolean tearDown, String reason); @@ -331,6 +331,10 @@ public abstract class DataConnectionTracker extends Handler { onSetDataEnabled(enabled); break; + case EVENT_RESET_DONE: + onResetDone((AsyncResult) msg.obj); + break; + default: Log.e("DATA", "Unidentified event = " + msg.what); break; @@ -440,10 +444,11 @@ public abstract class DataConnectionTracker extends Handler { return Phone.APN_REQUEST_FAILED; } - if(DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = " + if (DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = " + isApnTypeActive(type) + " and state = " + state); if (!isApnTypeAvailable(type)) { + if (DBG) Log.d(LOG_TAG, "type not available"); return Phone.APN_TYPE_NOT_AVAILABLE; } diff --git a/telephony/java/com/android/internal/telephony/DataLink.java b/telephony/java/com/android/internal/telephony/DataLink.java deleted file mode 100644 index 8132d91..0000000 --- a/telephony/java/com/android/internal/telephony/DataLink.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony; - -import android.os.Handler; -import android.os.Registrant; - -/** - * Base class representing the data link layer (eg, PPP). - * - * {@hide} - */ -public abstract class DataLink extends Handler implements DataLinkInterface { - - /** Registrant for link status change notifications. */ - protected Registrant mLinkChangeRegistrant; - protected DataConnectionTracker dataConnection; - - protected DataLink(DataConnectionTracker dc) { - dataConnection = dc; - } - - public void setOnLinkChange(Handler h, int what, Object obj) { - mLinkChangeRegistrant = new Registrant(h, what, obj); - } -} diff --git a/telephony/java/com/android/internal/telephony/DataLinkInterface.java b/telephony/java/com/android/internal/telephony/DataLinkInterface.java deleted file mode 100644 index e8148a8..0000000 --- a/telephony/java/com/android/internal/telephony/DataLinkInterface.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony; - -import android.database.Cursor; -import android.os.Handler; - -/** - * Data link interface. - * - * {@hide} - */ -public interface DataLinkInterface { - /** - * Link state enumeration. - * - */ - enum LinkState { - LINK_UNKNOWN, - LINK_UP, - LINK_DOWN, - LINK_EXITED - } - - /** Normal exit */ - final static int EXIT_OK = 0; - /** Open failed */ - final static int EXIT_OPEN_FAILED = 7; - - /** - * Sets the handler for link state change events. - * - * @param h Handler - * @param what User-defined message code - * @param obj User object - */ - void setOnLinkChange(Handler h, int what, Object obj); - - /** - * Sets up the data link. - */ - void connect(); - - /** - * Tears down the data link. - */ - void disconnect(); - - /** - * Returns the exit code for a data link failure. - * - * @return exit code - */ - int getLastLinkExitCode(); - - /** - * Sets password information that may be required by the data link - * (eg, PAP secrets). - * - * @param cursor cursor to carriers table - */ - void setPasswordInfo(Cursor cursor); -} diff --git a/telephony/java/com/android/internal/telephony/DriverCall.java b/telephony/java/com/android/internal/telephony/DriverCall.java index 2382441..663c284 100644 --- a/telephony/java/com/android/internal/telephony/DriverCall.java +++ b/telephony/java/com/android/internal/telephony/DriverCall.java @@ -74,8 +74,7 @@ public class DriverCall implements Comparable { if (p.hasMore()) { // Some lame implementations return strings // like "NOT AVAILABLE" in the CLCC line - ret.number = PhoneNumberUtils.extractNetworkPortion( - p.nextString()); + ret.number = PhoneNumberUtils.extractNetworkPortionAlt(p.nextString()); if (ret.number.length() == 0) { ret.number = null; diff --git a/telephony/java/com/android/internal/telephony/EventLogTags.logtags b/telephony/java/com/android/internal/telephony/EventLogTags.logtags new file mode 100644 index 0000000..b06c27d --- /dev/null +++ b/telephony/java/com/android/internal/telephony/EventLogTags.logtags @@ -0,0 +1,55 @@ +# See system/core/logcat/event.logtags for a description of the format of this file. + +option java_package com.android.internal.telephony; + +# PDP Context has a bad DNS address +50100 pdp_bad_dns_address (dns_address|3) + +# For data connection on PDP context, reached the data-out-without-data-in +# packet count that triggers a countdown to radio restart +50101 pdp_radio_reset_countdown_triggered (out_packet_count|1|1) + +# Radio restart - timed out with no incoming packets. +50102 pdp_radio_reset (out_packet_count|1|1) + +# PDP context reset - timed out with no incoming packets. +50103 pdp_context_reset (out_packet_count|1|1) + +# Reregister to data network - timed out with no incoming packets. +50104 pdp_reregister_network (out_packet_count|1|1) + +# PDP Setup failures +50105 pdp_setup_fail (cause|1|5), (cid|1|5), (network_type|1|5) + +# Call drops +50106 call_drop (cause|1|5), (cid|1|5), (network_type|1|5) + +# Data network registration failed after successful voice registration +50107 data_network_registration_fail (op_numeric|1|5), (cid|1|5) + +# Suspicious status of data connection while radio poweroff +50108 data_network_status_on_radio_off (dc_state|3), (enable|1|5) + +# PDP drop caused by network +50109 pdp_network_drop (cid|1|5), (network_type|1|5) + +# CDMA data network setup failure +50110 cdma_data_setup_failed (cause|1|5), (cid|1|5), (network_type|1|5) + +# CDMA data network drop +50111 cdma_data_drop (cid|1|5), (network_type|1|5) + +# GSM radio access technology switched +50112 gsm_rat_switched (cid|1|5), (network_from|1|5), (network_to|1|5) + +# GSM data connection state transition +50113 gsm_data_state_change (oldState|3), (newState|3) + +# GSM service state transition +50114 gsm_service_state_change (oldState|1|5), (oldGprsState|1|5), (newState|1|5), (newGprsState|1|5) + +# CDMA data connection state transition +50115 cdma_data_state_change (oldState|3), (newState|3) + +# CDMA service state transition +50116 cdma_service_state_change (oldState|1|5), (oldDataState|1|5), (newState|1|5), (newDataState|1|5) diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java index 0f76633..d3a34ec 100644 --- a/telephony/java/com/android/internal/telephony/IccCard.java +++ b/telephony/java/com/android/internal/telephony/IccCard.java @@ -202,7 +202,7 @@ public abstract class IccCard { /** * Supply the ICC PIN to the ICC * - * When the operation is complete, onComplete will be sent to it's + * When the operation is complete, onComplete will be sent to its * Handler. * * onComplete.obj will be an AsyncResult @@ -468,6 +468,7 @@ public abstract class IccCard { public void broadcastIccStateChangedIntent(String value, String reason) { Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra(Phone.PHONE_NAME_KEY, mPhone.getPhoneName()); intent.putExtra(INTENT_KEY_ICC_STATE, value); intent.putExtra(INTENT_KEY_LOCKED_REASON, reason); diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java index 31cf6a7..9f8e57f 100644 --- a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java @@ -22,10 +22,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.ServiceManager; -import android.telephony.PhoneNumberUtils; -import android.util.Log; -import java.util.ArrayList; import java.util.List; /** @@ -37,7 +34,7 @@ public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub { protected PhoneBase phone; protected AdnRecordCache adnCache; - protected Object mLock = new Object(); + protected final Object mLock = new Object(); protected int recordSize[]; protected boolean success; protected List<AdnRecord> records; @@ -80,8 +77,7 @@ public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub { ar = (AsyncResult)msg.obj; synchronized (mLock) { if (ar.exception == null) { - records = (List<AdnRecord>) - ((ArrayList<AdnRecord>) ar.result); + records = (List<AdnRecord>) ar.result; } else { if(DBG) logd("Cannot load ADN records"); if (records != null) { diff --git a/telephony/java/com/android/internal/telephony/IccProvider.java b/telephony/java/com/android/internal/telephony/IccProvider.java index 8b54ca8..fa91457 100644 --- a/telephony/java/com/android/internal/telephony/IccProvider.java +++ b/telephony/java/com/android/internal/telephony/IccProvider.java @@ -19,8 +19,9 @@ package com.android.internal.telephony; import android.content.ContentProvider; import android.content.UriMatcher; import android.content.ContentValues; -import com.android.internal.database.ArrayListCursor; +import android.database.AbstractCursor; import android.database.Cursor; +import android.database.CursorWindow; import android.net.Uri; import android.os.SystemProperties; import android.os.RemoteException; @@ -35,6 +36,149 @@ import com.android.internal.telephony.IccConstants; import com.android.internal.telephony.AdnRecord; import com.android.internal.telephony.IIccPhoneBook; +/** + * XXX old code -- should be replaced with MatrixCursor. + * @deprecated This is has been replaced by MatrixCursor. +*/ +class ArrayListCursor extends AbstractCursor { + private String[] mColumnNames; + private ArrayList<Object>[] mRows; + + @SuppressWarnings({"unchecked"}) + public ArrayListCursor(String[] columnNames, ArrayList<ArrayList> rows) { + int colCount = columnNames.length; + boolean foundID = false; + // Add an _id column if not in columnNames + for (int i = 0; i < colCount; ++i) { + if (columnNames[i].compareToIgnoreCase("_id") == 0) { + mColumnNames = columnNames; + foundID = true; + break; + } + } + + if (!foundID) { + mColumnNames = new String[colCount + 1]; + System.arraycopy(columnNames, 0, mColumnNames, 0, columnNames.length); + mColumnNames[colCount] = "_id"; + } + + int rowCount = rows.size(); + mRows = new ArrayList[rowCount]; + + for (int i = 0; i < rowCount; ++i) { + mRows[i] = rows.get(i); + if (!foundID) { + mRows[i].add(i); + } + } + } + + @Override + public void fillWindow(int position, CursorWindow window) { + if (position < 0 || position > getCount()) { + return; + } + + window.acquireReference(); + try { + int oldpos = mPos; + mPos = position - 1; + window.clear(); + window.setStartPosition(position); + int columnNum = getColumnCount(); + window.setNumColumns(columnNum); + while (moveToNext() && window.allocRow()) { + for (int i = 0; i < columnNum; i++) { + final Object data = mRows[mPos].get(i); + if (data != null) { + if (data instanceof byte[]) { + byte[] field = (byte[]) data; + if (!window.putBlob(field, mPos, i)) { + window.freeLastRow(); + break; + } + } else { + String field = data.toString(); + if (!window.putString(field, mPos, i)) { + window.freeLastRow(); + break; + } + } + } else { + if (!window.putNull(mPos, i)) { + window.freeLastRow(); + break; + } + } + } + } + + mPos = oldpos; + } catch (IllegalStateException e){ + // simply ignore it + } finally { + window.releaseReference(); + } + } + + @Override + public int getCount() { + return mRows.length; + } + + @Override + public String[] getColumnNames() { + return mColumnNames; + } + + @Override + public byte[] getBlob(int columnIndex) { + return (byte[]) mRows[mPos].get(columnIndex); + } + + @Override + public String getString(int columnIndex) { + Object cell = mRows[mPos].get(columnIndex); + return (cell == null) ? null : cell.toString(); + } + + @Override + public short getShort(int columnIndex) { + Number num = (Number) mRows[mPos].get(columnIndex); + return num.shortValue(); + } + + @Override + public int getInt(int columnIndex) { + Number num = (Number) mRows[mPos].get(columnIndex); + return num.intValue(); + } + + @Override + public long getLong(int columnIndex) { + Number num = (Number) mRows[mPos].get(columnIndex); + return num.longValue(); + } + + @Override + public float getFloat(int columnIndex) { + Number num = (Number) mRows[mPos].get(columnIndex); + return num.floatValue(); + } + + @Override + public double getDouble(int columnIndex) { + Number num = (Number) mRows[mPos].get(columnIndex); + return num.doubleValue(); + } + + @Override + public boolean isNull(int columnIndex) { + return mRows[mPos].get(columnIndex) == null; + } +} + /** * {@hide} diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java index 3e7094e..71936f1 100644 --- a/telephony/java/com/android/internal/telephony/IccUtils.java +++ b/telephony/java/com/android/internal/telephony/IccUtils.java @@ -397,7 +397,7 @@ public class IccUtils { int bits = data[valueIndex++] & 0xFF; int colorNumber = data[valueIndex++] & 0xFF; int clutOffset = ((data[valueIndex++] & 0xFF) << 8) - | data[valueIndex++]; + | (data[valueIndex++] & 0xFF); length = length - 6; int[] colorIndexArray = getCLUT(data, clutOffset, colorNumber); diff --git a/telephony/java/com/android/internal/telephony/MccTable.java b/telephony/java/com/android/internal/telephony/MccTable.java index fc9de96..b73c2f7 100644 --- a/telephony/java/com/android/internal/telephony/MccTable.java +++ b/telephony/java/com/android/internal/telephony/MccTable.java @@ -24,6 +24,7 @@ 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; @@ -106,7 +107,7 @@ mcc_table = [ (294, 'mk', 2, 'The Former Yugoslav Republic of Macedonia'), (295, 'li', 2, 'Liechtenstein (Principality of)'), (297, 'me', 2, 'Montenegro (Republic of)'), - (302, 'ca', 2, '', '', 11, 'Canada'), + (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'), @@ -179,8 +180,8 @@ mcc_table = [ (455, 'mo', 2, '"Macao, China"'), (456, 'kh', 2, 'Cambodia (Kingdom of)'), (457, 'la', 2, "Lao People's Democratic Republic"), - (460, 'cn', 2, "China (People's Republic of)"), - (461, 'cn', 2, "China (People's Republic of)"), + (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)"), @@ -191,7 +192,7 @@ mcc_table = [ (514, 'tl', 2, 'Democratic Republic of Timor-Leste'), (515, 'ph', 2, 'Philippines (Republic of the)'), (520, 'th', 2, 'Thailand'), - (525, 'sg', 2, 'Singapore', 'en', 11, 'Singapore (Republic of)'), + (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)'), @@ -371,11 +372,13 @@ for i in range(len(orig_table)): public final class MccTable { /** - * AUTO GENERATED (by the Python code above) - */ + * AUTO GENERATED (by the Python code above) + */ private static final String[] TZ_STRINGS = { "", "Africa/Johannesburg", + "Asia/Beijing", + "Asia/Singapore", "Asia/Tokyo", "Australia/Sydney", "Europe/Amsterdam", @@ -389,23 +392,22 @@ public final class MccTable "Europe/Vienna", "Europe/Warsaw", "Europe/Zurich", - "Pacific/Auckland", - "Singapore" + "Pacific/Auckland" }; /** - * AUTO GENERATED (by the Python code above) - */ + * AUTO GENERATED (by the Python code above) + */ private static final String[] LANG_STRINGS = { - "", "cs", "de", "en", "es", "fr", "it", "ja", "nl" + "", "cs", "de", "en", "es", "fr", "it", "ja", "nl", "zh" }; /** - * 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. - */ + * 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, @@ -434,25 +436,25 @@ public final class MccTable }; /** - * 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 - */ + * AUTO GENERATED (by the Python code above) + * The values in this table are broken down as follows (msb to lsb): + * iso country code 16 bits + * (unused) 1 bit + * wifi channel 4 bits + * smalled digit 2 bits + * default timezone 5 bits + * default language 4 bits + */ private static final int[] IND_CODES = { - 0x67720400, 0x6e6c6c48, 0x62650400, 0x66720495, 0x6d630400, 0x61640400, - 0x65730484, 0x68750400, 0x62610400, 0x68720400, 0x72730400, 0x697404b6, - 0x766104b6, 0x726f0400, 0x636804e2, 0x637a6ca1, 0x736b0400, 0x61746cc2, - 0x67626c73, 0x67626c73, 0x646b0400, 0x73650400, 0x6e6f0400, 0x66690400, + 0x67720400, 0x6e6c6c68, 0x62650400, 0x667204b5, 0x6d630400, 0x61640400, + 0x657304a4, 0x68750400, 0x62610400, 0x68720400, 0x72730400, 0x697404d6, + 0x766104d6, 0x726f0400, 0x63680502, 0x637a6cc1, 0x736b0400, 0x61746ce2, + 0x67626c93, 0x67626c93, 0x646b0400, 0x73650400, 0x6e6f0400, 0x66690400, 0x6c740400, 0x6c760400, 0x65650400, 0x72750400, 0x75610400, 0x62790400, - 0x6d640400, 0x706c04d0, 0x64656c52, 0x67690400, 0x70740400, 0x6c750400, - 0x69650463, 0x69730400, 0x616c0400, 0x6d740400, 0x63790400, 0x67650400, + 0x6d640400, 0x706c04f0, 0x64656c72, 0x67690400, 0x70740400, 0x6c750400, + 0x69650483, 0x69730400, 0x616c0400, 0x6d740400, 0x63790400, 0x67650400, 0x616d0400, 0x62670400, 0x74720400, 0x666f0400, 0x67650400, 0x676c0400, - 0x736d0400, 0x736c0400, 0x6d6b0400, 0x6c690400, 0x6d650400, 0x63615c00, + 0x736d0400, 0x736c0400, 0x6d6b0400, 0x6c690400, 0x6d650400, 0x63615e00, 0x706d0400, 0x75735e03, 0x75735e03, 0x75735e03, 0x75735e03, 0x75735e03, 0x75735e03, 0x75735e03, 0x70720400, 0x76690400, 0x6d780600, 0x6a6d0600, 0x67700400, 0x62620600, 0x61670600, 0x6b790600, 0x76670600, 0x626d0400, @@ -463,11 +465,11 @@ public final class MccTable 0x6c620400, 0x6a6f0400, 0x73790400, 0x69710400, 0x6b770400, 0x73610400, 0x79650400, 0x6f6d0400, 0x70730400, 0x61650400, 0x696c0400, 0x62680400, 0x71610400, 0x6d6e0400, 0x6e700400, 0x61650400, 0x61650400, 0x69720400, - 0x757a0400, 0x746a0400, 0x6b670400, 0x746d0400, 0x6a707427, 0x6a707427, + 0x757a0400, 0x746a0400, 0x6b670400, 0x746d0400, 0x6a707447, 0x6a707447, 0x6b720400, 0x766e0400, 0x686b0400, 0x6d6f0400, 0x6b680400, 0x6c610400, - 0x636e0400, 0x636e0400, 0x74770400, 0x6b700400, 0x62640400, 0x6d760400, - 0x6d790400, 0x61755c33, 0x69640400, 0x746c0400, 0x70680400, 0x74680400, - 0x73675d03, 0x626e0400, 0x6e7a04f3, 0x6d700400, 0x67750400, 0x6e720400, + 0x636e6c29, 0x636e6c29, 0x74770400, 0x6b700400, 0x62640400, 0x6d760400, + 0x6d790400, 0x61755c53, 0x69640400, 0x746c0400, 0x70680400, 0x74680400, + 0x73675c33, 0x626e0400, 0x6e7a0513, 0x6d700400, 0x67750400, 0x6e720400, 0x70670400, 0x746f0400, 0x73620400, 0x76750400, 0x666a0400, 0x77660400, 0x61730400, 0x6b690400, 0x6e630400, 0x70660400, 0x636b0400, 0x77730400, 0x666d0400, 0x6d680400, 0x70770400, 0x65670400, 0x647a0400, 0x6d610400, @@ -572,34 +574,36 @@ public final class MccTable * @param mccmnc truncated imsi with just the MCC and MNC - MNC assumed to be from 4th to end */ public static void updateMccMncConfiguration(PhoneBase phone, String mccmnc) { - int mcc, mnc; - - try { - mcc = Integer.parseInt(mccmnc.substring(0,3)); - mnc = Integer.parseInt(mccmnc.substring(3)); - } catch (NumberFormatException e) { - Log.e(LOG_TAG, "Error parsing IMSI"); - return; - } + if (!TextUtils.isEmpty(mccmnc)) { + int mcc, mnc; + + try { + mcc = Integer.parseInt(mccmnc.substring(0,3)); + mnc = Integer.parseInt(mccmnc.substring(3)); + } catch (NumberFormatException e) { + Log.e(LOG_TAG, "Error parsing IMSI"); + return; + } - Log.d(LOG_TAG, "updateMccMncConfiguration: mcc=" + mcc + ", mnc=" + mnc); + Log.d(LOG_TAG, "updateMccMncConfiguration: mcc=" + mcc + ", mnc=" + mnc); - if (mcc != 0) { - setTimezoneFromMccIfNeeded(phone, mcc); - setLocaleFromMccIfNeeded(phone, mcc); - setWifiChannelsFromMcc(phone, mcc); - } - try { - Configuration config = ActivityManagerNative.getDefault().getConfiguration(); if (mcc != 0) { - config.mcc = mcc; + setTimezoneFromMccIfNeeded(phone, mcc); + setLocaleFromMccIfNeeded(phone, mcc); + setWifiChannelsFromMcc(phone, mcc); } - if (mnc != 0) { - config.mnc = mnc; + try { + Configuration config = ActivityManagerNative.getDefault().getConfiguration(); + if (mcc != 0) { + config.mcc = mcc; + } + if (mnc != 0) { + config.mnc = mnc; + } + ActivityManagerNative.getDefault().updateConfiguration(config); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Can't update configuration", e); } - ActivityManagerNative.getDefault().updateConfiguration(config); - } catch (RemoteException e) { - Log.e(LOG_TAG, "Can't update configuration", e); } } diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index 24f08cb..f14ab70 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -28,7 +28,7 @@ import android.telephony.SignalStrength; import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.gsm.NetworkInfo; -import com.android.internal.telephony.gsm.PdpConnection; +import com.android.internal.telephony.gsm.GsmDataConnection; import com.android.internal.telephony.test.SimulatedRadioControl; import java.util.List; @@ -1199,21 +1199,7 @@ public interface Phone { void invokeOemRilRequestStrings(String[] strings, Message response); /** - * Get the current active PDP context list - * - * @deprecated - * @param response <strong>On success</strong>, "response" bytes is - * made available as: - * (String[])(((AsyncResult)response.obj).result). - * <strong>On failure</strong>, - * (((AsyncResult)response.obj).result) == null and - * (((AsyncResult)response.obj).exception) being an instance of - * com.android.internal.telephony.gsm.CommandException - */ - void getPdpContextList(Message response); - - /** - * Get the current active Data Call list, substitutes getPdpContextList + * Get the current active Data Call list * * @param response <strong>On success</strong>, "response" bytes is * made available as: @@ -1226,19 +1212,11 @@ public interface Phone { void getDataCallList(Message response); /** - * Get current mutiple PDP link status - * - * @deprecated - * @return list of pdp link connections - */ - List<PdpConnection> getCurrentPdpList (); - - /** * Get current mutiple data connection status * * @return list of data connections */ - List<DataConnection> getCurrentDataConnectionList (); + List<DataConnection> getCurrentDataConnectionList(); /** * Update the ServiceState CellLocation for current network registration. @@ -1434,11 +1412,6 @@ public interface Phone { /* CDMA support methods */ - /* - * TODO(Moto) TODO(Teleca): can getCdmaMin, getEsn, getMeid use more generic calls - * already defined getXxxx above? - */ - /** * Retrieves the MIN for CDMA phones. */ diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index eb406b7..a8f4143 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -35,7 +35,7 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.R; -import com.android.internal.telephony.gsm.PdpConnection; +import com.android.internal.telephony.gsm.GsmDataConnection; import com.android.internal.telephony.test.SimulatedRadioControl; import java.util.List; @@ -114,6 +114,7 @@ public abstract class PhoneBase extends Handler implements Phone { boolean mDoesRilSendMultipleCallRing; int mCallRingContinueToken = 0; int mCallRingDelay; + public boolean mIsTheCurrentActivePhone = true; /** * Set a system property, unless we're in unit test mode @@ -226,6 +227,8 @@ public abstract class PhoneBase extends Handler implements Phone { public void dispose() { synchronized(PhoneProxy.lockForRadioTechnologyChange) { mCM.unSetOnCallRing(this); + mDataConnection.onCleanUpConnection(false, REASON_RADIO_TURNED_OFF); + mIsTheCurrentActivePhone = false; } } @@ -582,7 +585,7 @@ public abstract class PhoneBase extends Handler implements Phone { /** * Utility code to set the system locale if it's not set already - * @param langauge Two character language code desired + * @param language Two character language code desired * @param country Two character country code desired * * {@hide} @@ -691,32 +694,22 @@ public abstract class PhoneBase extends Handler implements Phone { public void setTTYMode(int ttyMode, Message onComplete) { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("setTTYMode"); } public void queryTTYMode(Message onComplete) { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); - } - - /** - * This should only be called in GSM mode. - * Only here for some backward compatibility - * issues concerning the GSMPhone class. - * @deprecated Always returns null. - */ - public List<PdpConnection> getCurrentPdpList() { - return null; + logUnexpectedCdmaMethodCall("queryTTYMode"); } public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("enableEnhancedVoicePrivacy"); } public void getEnhancedVoicePrivacy(Message onComplete) { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("getEnhancedVoicePrivacy"); } public void setBandMode(int bandMode, Message response) { @@ -761,7 +754,7 @@ public abstract class PhoneBase extends Handler implements Phone { * Returns the CDMA ERI icon index to display */ public int getCdmaEriIconIndex() { - Log.e(LOG_TAG, "Error! getCdmaEriIconIndex should never be executed in GSM mode"); + logUnexpectedCdmaMethodCall("getCdmaEriIconIndex"); return -1; } @@ -771,7 +764,7 @@ public abstract class PhoneBase extends Handler implements Phone { * 1 - FLASHING */ public int getCdmaEriIconMode() { - Log.e(LOG_TAG, "Error! getCdmaEriIconMode should never be executed in GSM mode"); + logUnexpectedCdmaMethodCall("getCdmaEriIconMode"); return -1; } @@ -779,82 +772,82 @@ public abstract class PhoneBase extends Handler implements Phone { * Returns the CDMA ERI text, */ public String getCdmaEriText() { - Log.e(LOG_TAG, "Error! getCdmaEriText should never be executed in GSM mode"); + logUnexpectedCdmaMethodCall("getCdmaEriText"); return "GSM nw, no ERI"; } public String getCdmaMin() { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("getCdmaMin"); return null; } public boolean isMinInfoReady() { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("isMinInfoReady"); return false; } public String getCdmaPrlVersion(){ // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("getCdmaPrlVersion"); return null; } public void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("sendBurstDtmf"); } public void exitEmergencyCallbackMode() { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("exitEmergencyCallbackMode"); } public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj) { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("registerForCdmaOtaStatusChange"); } public void unregisterForCdmaOtaStatusChange(Handler h) { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("unregisterForCdmaOtaStatusChange"); } public void registerForSubscriptionInfoReady(Handler h, int what, Object obj) { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("registerForSubscriptionInfoReady"); } public void unregisterForSubscriptionInfoReady(Handler h) { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("unregisterForSubscriptionInfoReady"); } public boolean isOtaSpNumber(String dialStr) { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("isOtaSpNumber"); return false; } public void registerForCallWaiting(Handler h, int what, Object obj){ // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("registerForCallWaiting"); } public void unregisterForCallWaiting(Handler h){ // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("unregisterForCallWaiting"); } public void registerForEcmTimerReset(Handler h, int what, Object obj) { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("registerForEcmTimerReset"); } public void unregisterForEcmTimerReset(Handler h) { // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("unregisterForEcmTimerReset"); } public void registerForSignalInfo(Handler h, int what, Object obj) { @@ -915,12 +908,12 @@ public abstract class PhoneBase extends Handler implements Phone { public void setOnEcbModeExitResponse(Handler h, int what, Object obj){ // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("setOnEcbModeExitResponse"); } public void unsetOnEcbModeExitResponse(Handler h){ // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); + logUnexpectedCdmaMethodCall("unsetOnEcbModeExitResponse"); } public String getInterfaceName(String apnType) { @@ -991,7 +984,7 @@ public abstract class PhoneBase extends Handler implements Phone { } /** - * Notifiy registrants of a new ringing Connection. + * Notify registrants of a new ringing Connection. * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ @@ -1024,4 +1017,13 @@ public abstract class PhoneBase extends Handler implements Phone { + " mCallRingContinueToken=" + mCallRingContinueToken); } } + + /** + * Common error logger method for unexpected calls to CDMA-only methods. + */ + private void logUnexpectedCdmaMethodCall(String name) + { + Log.e(LOG_TAG, "Error! " + name + "() in PhoneBase should not be " + + "called, CDMAPhone inactive."); + } } diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java index 77c7c28..e1511e6 100644 --- a/telephony/java/com/android/internal/telephony/PhoneProxy.java +++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Handler; import android.os.Message; +import android.os.SystemProperties; import android.preference.PreferenceManager; import android.telephony.CellLocation; import android.telephony.PhoneStateListener; @@ -33,15 +34,13 @@ 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.PdpConnection; +import com.android.internal.telephony.gsm.GsmDataConnection; import com.android.internal.telephony.test.SimulatedRadioControl; import java.util.List; public class PhoneProxy extends Handler implements Phone { public final static Object lockForRadioTechnologyChange = new Object(); -// private static boolean radioTechnologyChangeGsmToCdma = false; -// private static boolean radioTechnologyChangeCdmaToGsm = false; private Phone mActivePhone; private String mOutgoingPhone; @@ -50,12 +49,16 @@ public class PhoneProxy extends Handler implements Phone { private IccPhoneBookInterfaceManagerProxy mIccPhoneBookInterfaceManagerProxy; private PhoneSubInfoProxy mPhoneSubInfoProxy; + private boolean mResetModemOnRadioTechnologyChange = false; + private static final int EVENT_RADIO_TECHNOLOGY_CHANGED = 1; private static final String LOG_TAG = "PHONE"; //***** Class Methods public PhoneProxy(Phone phone) { mActivePhone = phone; + mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean( + TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false); mIccSmsInterfaceManagerProxy = new IccSmsInterfaceManagerProxy( phone.getIccSmsInterfaceManager()); mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy( @@ -74,12 +77,15 @@ public class PhoneProxy extends Handler implements Phone { mOutgoingPhone = ((PhoneBase)mActivePhone).getPhoneName(); logd("Switching phone from " + mOutgoingPhone + "Phone to " + (mOutgoingPhone.equals("GSM") ? "CDMAPhone" : "GSMPhone") ); - boolean oldPowerState = false; //old power state to off - if (mCommandsInterface.getRadioState().isOn()) { - oldPowerState = true; - logd("Setting Radio Power to Off"); - mCommandsInterface.setRadioPower(false, null); + boolean oldPowerState = false; // old power state to off + if (mResetModemOnRadioTechnologyChange) { + if (mCommandsInterface.getRadioState().isOn()) { + oldPowerState = true; + logd("Setting Radio Power to Off"); + mCommandsInterface.setRadioPower(false, null); + } } + if(mOutgoingPhone.equals("GSM")) { logd("Make a new CDMAPhone and destroy the old GSMPhone."); @@ -93,8 +99,6 @@ public class PhoneProxy extends Handler implements Phone { //System.gc(); mActivePhone = PhoneFactory.getCdmaPhone(); - logd("Resetting Radio"); - mCommandsInterface.setRadioPower(oldPowerState, null); ((GSMPhone)oldPhone).removeReferences(); oldPhone = null; } else { @@ -111,12 +115,15 @@ public class PhoneProxy extends Handler implements Phone { //System.gc(); mActivePhone = PhoneFactory.getGsmPhone(); - logd("Resetting Radio:"); - mCommandsInterface.setRadioPower(oldPowerState, null); ((CDMAPhone)oldPhone).removeReferences(); oldPhone = null; } + if (mResetModemOnRadioTechnologyChange) { + logd("Resetting Radio"); + mCommandsInterface.setRadioPower(oldPowerState, null); + } + //Set the new interfaces in the proxy's mIccSmsInterfaceManagerProxy.setmIccSmsInterfaceManager( mActivePhone.getIccSmsInterfaceManager()); @@ -127,6 +134,7 @@ public class PhoneProxy extends Handler implements Phone { //Send an Intent to the PhoneApp that we had a radio technology change Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra(Phone.PHONE_NAME_KEY, mActivePhone.getPhoneName()); ActivityManagerNative.broadcastStickyIntent(intent, null); break; @@ -568,24 +576,10 @@ public class PhoneProxy extends Handler implements Phone { mActivePhone.invokeOemRilRequestStrings(strings, response); } - /** - * @deprecated - */ - public void getPdpContextList(Message response) { - mActivePhone.getPdpContextList(response); - } - public void getDataCallList(Message response) { mActivePhone.getDataCallList(response); } - /** - * @deprecated - */ - public List<PdpConnection> getCurrentPdpList() { - return mActivePhone.getCurrentPdpList(); - } - public List<DataConnection> getCurrentDataConnectionList() { return mActivePhone.getCurrentDataConnectionList(); } diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java index 19900c8..1ac2da3 100644 --- a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java +++ b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java @@ -39,6 +39,11 @@ public class PhoneSubInfo extends IPhoneSubInfo.Stub { } protected void finalize() { + try { + super.finalize(); + } catch (Throwable throwable) { + Log.e(LOG_TAG, "Error while finalizing:", throwable); + } Log.d(LOG_TAG, "PhoneSubInfo finalized"); } diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index 7239889..3d410fd 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -208,7 +208,12 @@ public final class RIL extends BaseCommands implements CommandsInterface { private static final boolean DBG = false; static final boolean RILJ_LOGD = Config.LOGD; static final boolean RILJ_LOGV = DBG ? Config.LOGD : Config.LOGV; - static int WAKE_LOCK_TIMEOUT = 5000; + + /** + * Wake lock timeout should be longer than the longest timeout in + * the vendor ril. + */ + private static final int DEFAULT_WAKE_LOCK_TIMEOUT = 30000; //***** Instance Variables @@ -219,6 +224,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILReceiver mReceiver; private Context mContext; WakeLock mWakeLock; + int mWakeLockTimeout; int mRequestMessagesPending; // Is this the first radio state change? @@ -603,6 +609,8 @@ public final class RIL extends BaseCommands implements CommandsInterface { PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); mWakeLock.setReferenceCounted(false); + mWakeLockTimeout = SystemProperties.getInt(TelephonyProperties.PROPERTY_WAKE_LOCK_TIMEOUT, + DEFAULT_WAKE_LOCK_TIMEOUT); mRequestMessagesPending = 0; mContext = context; @@ -797,6 +805,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { rr.mp.writeString(address); rr.mp.writeInt(clirMode); + rr.mp.writeInt(0); // UUS information is absent if (uusInfo == null) { rr.mp.writeInt(0); // UUS information is absent @@ -2010,7 +2019,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { mSender.removeMessages(EVENT_WAKE_LOCK_TIMEOUT); Message msg = mSender.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT); - mSender.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT); + mSender.sendMessageDelayed(msg, mWakeLockTimeout); } } @@ -2197,6 +2206,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_SET_SMSC_ADDRESS: ret = responseVoid(p); break; case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE: ret = responseVoid(p); break; case RIL_REQUEST_REPORT_SMS_MEMORY_STATUS: ret = responseVoid(p); break; + case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING: ret = responseVoid(p); break; default: throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest); //break; @@ -2997,10 +3007,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { numServiceCategories = p.readInt(); if (numServiceCategories == 0) { - // TODO(Teleca) TODO(Moto): The logic of providing default - // values should not be done by this transport layer. And - // needs to be done by the vendor ril or application logic. - // TODO(Google): Remove ASAP + // TODO: The logic of providing default values should + // not be done by this transport layer. And needs to + // be done by the vendor ril or application logic. int numInts; numInts = CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES * CDMA_BSI_NO_OF_INTS_STRUCT + 1; response = new int[numInts]; diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index be1fbf1..71a80e0 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -50,6 +50,9 @@ public interface RILConstants { location */ int MODE_NOT_SUPPORTED = 13; /* HW does not support preferred network type */ int FDN_CHECK_FAILURE = 14; /* send operation barred error when FDN is enabled */ + int ILLEGAL_SIM_OR_ME = 15; /* network selection failure due + to wrong SIM/ME and no + retries needed */ /* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */ int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */ diff --git a/telephony/java/com/android/internal/telephony/RetryManager.java b/telephony/java/com/android/internal/telephony/RetryManager.java index 385b191..779f358 100644 --- a/telephony/java/com/android/internal/telephony/RetryManager.java +++ b/telephony/java/com/android/internal/telephony/RetryManager.java @@ -153,13 +153,17 @@ public class RetryManager { } /** - * Configure for using string which allow arbitary + * Configure for using string which allow arbitrary * sequences of times. See class comments for the * string format. * - * @return true if successfull + * @return true if successful */ public boolean configure(String configStr) { + // Strip quotes if present. + if ((configStr.startsWith("\"") && configStr.endsWith("\""))) { + configStr = configStr.substring(1, configStr.length()-1); + } if (DBG) log("configure: '" + configStr + "'"); if (!TextUtils.isEmpty(configStr)) { diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java index 98d4b1d..ca526a5 100644 --- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java @@ -232,11 +232,11 @@ public abstract class SMSDispatcher extends Handler { createWakelock(); - int check_period = Settings.Gservices.getInt(mResolver, - Settings.Gservices.SMS_OUTGOING_CHECK_INTERVAL_MS, + int check_period = Settings.Secure.getInt(mResolver, + Settings.Secure.SMS_OUTGOING_CHECK_INTERVAL_MS, DEFAULT_SMS_CHECK_PERIOD); - int max_count = Settings.Gservices.getInt(mResolver, - Settings.Gservices.SMS_OUTGOING_CEHCK_MAX_COUNT, + int max_count = Settings.Secure.getInt(mResolver, + Settings.Secure.SMS_OUTGOING_CHECK_MAX_COUNT, DEFAULT_SMS_MAX_COUNT); mCounter = new SmsCounter(max_count, check_period); diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java index be4fdb4..706f260 100644 --- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java @@ -272,6 +272,13 @@ public abstract class ServiceStateTracker extends Handler { protected abstract void updateSpnDisplay(); protected abstract void setPowerStateToDesired(); + /** + * Clean up existing voice and data connection then turn off radio power. + * + * Hang up the existing voice calls to decrease call drop rate. + */ + protected abstract void powerOffRadioSafely(); + /** Cancel a pending (if any) pollState() operation */ protected void cancelPollState() { // This will effectively cancel the rest of the poll requests. diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java index 3c2f2ed..af6c5f8 100644 --- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -21,6 +21,7 @@ import com.android.internal.telephony.SmsHeader; import java.util.Arrays; import static android.telephony.SmsMessage.MessageClass; +import android.provider.Telephony; /** * Base class declaring the specific methods and members for SmsMessage. @@ -386,7 +387,7 @@ public abstract class SmsMessageBase { if (parts.length < 2) return; emailFrom = parts[0]; emailBody = parts[1]; - isEmail = true; + isEmail = Telephony.Mms.isEmailAddress(emailFrom); } } diff --git a/telephony/java/com/android/internal/telephony/TelephonyEventLog.java b/telephony/java/com/android/internal/telephony/TelephonyEventLog.java deleted file mode 100644 index 0f15cb6..0000000 --- a/telephony/java/com/android/internal/telephony/TelephonyEventLog.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony; - -/* This class contains the details related to Telephony Event Logging */ -public final class TelephonyEventLog { - - /* Event log tags */ - public static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100; - public static final int EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED = 50101; - public static final int EVENT_LOG_RADIO_RESET = 50102; - public static final int EVENT_LOG_PDP_RESET = 50103; - public static final int EVENT_LOG_REREGISTER_NETWORK = 50104; - public static final int EVENT_LOG_RADIO_PDP_SETUP_FAIL = 50105; - public static final int EVENT_LOG_CALL_DROP = 50106; - public static final int EVENT_LOG_CGREG_FAIL = 50107; - public static final int EVENT_LOG_DATA_STATE_RADIO_OFF = 50108; - public static final int EVENT_LOG_PDP_NETWORK_DROP = 50109; - public static final int EVENT_LOG_CDMA_DATA_SETUP_FAILED = 50110; - public static final int EVENT_LOG_CDMA_DATA_DROP = 50111; - public static final int EVENT_LOG_GSM_RAT_SWITCHED = 50112; -} diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 2216ec4..3355e8a 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.internal.telephony; /** diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index 55ba149..a113787 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -136,4 +136,15 @@ public interface TelephonyProperties * monotonically, regardless of reboots. */ static final String PROPERTY_CDMA_MSG_ID = "persist.radio.cdma.msgid"; + + /** + * Property to override DEFAULT_WAKE_LOCK_TIMEOUT + */ + static final String PROPERTY_WAKE_LOCK_TIMEOUT = "ro.ril.wake_lock_timeout"; + + /** + * Set to true to indicate that the modem needs to be reset + * when there is a radio technology change. + */ + static final String PROPERTY_RESET_ON_RADIO_TECH_CHANGE = "persist.radio.reset_on_switch"; } diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java index 9970940..a636a4b 100644 --- a/telephony/java/com/android/internal/telephony/WapPushOverSms.java +++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java @@ -109,6 +109,7 @@ public class WapPushOverSms { String mimeType = pduDecoder.getValueString(); if (mimeType == null) { binaryContentType = (int)pduDecoder.getValue32(); + // TODO we should have more generic way to map binaryContentType code to mimeType. switch (binaryContentType) { case WspTypeDecoder.CONTENT_TYPE_B_DRM_RIGHTS_XML: mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML; @@ -128,6 +129,9 @@ public class WapPushOverSms { case WspTypeDecoder.CONTENT_TYPE_B_MMS: mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS; break; + case WspTypeDecoder.CONTENT_TYPE_B_VND_DOCOMO_PF: + mimeType = WspTypeDecoder.CONTENT_MIME_TYPE_B_VND_DOCOMO_PF; + break; default: if (Config.LOGD) { Log.w(LOG_TAG, @@ -148,6 +152,8 @@ public class WapPushOverSms { binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO; } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS)) { binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_MMS; + } else if (mimeType.equals(WspTypeDecoder.CONTENT_MIME_TYPE_B_VND_DOCOMO_PF)) { + binaryContentType = WspTypeDecoder.CONTENT_TYPE_B_VND_DOCOMO_PF; } else { if (Config.LOGD) Log.w(LOG_TAG, "Received PDU. Unknown Content-Type = " + mimeType); return Intents.RESULT_SMS_HANDLED; @@ -155,28 +161,31 @@ public class WapPushOverSms { } index += pduDecoder.getDecodedDataLength(); - int dataIndex = headerStartIndex + headerLength; boolean dispatchedByApplication = false; switch (binaryContentType) { case WspTypeDecoder.CONTENT_TYPE_B_PUSH_CO: - dispatchWapPdu_PushCO(pdu, transactionId, pduType); + dispatchWapPdu_PushCO(pdu, transactionId, pduType, headerStartIndex, headerLength); dispatchedByApplication = true; break; case WspTypeDecoder.CONTENT_TYPE_B_MMS: - dispatchWapPdu_MMS(pdu, transactionId, pduType, dataIndex); + dispatchWapPdu_MMS(pdu, transactionId, pduType, headerStartIndex, headerLength); dispatchedByApplication = true; break; default: break; } if (dispatchedByApplication == false) { - dispatchWapPdu_default(pdu, transactionId, pduType, mimeType, dataIndex); + dispatchWapPdu_default(pdu, transactionId, pduType, mimeType, + headerStartIndex, headerLength); } return Activity.RESULT_OK; } - private void dispatchWapPdu_default( - byte[] pdu, int transactionId, int pduType, String mimeType, int dataIndex) { + private void dispatchWapPdu_default(byte[] pdu, int transactionId, int pduType, + String mimeType, int headerStartIndex, int headerLength) { + byte[] header = new byte[headerLength]; + System.arraycopy(pdu, headerStartIndex, header, 0, header.length); + int dataIndex = headerStartIndex + headerLength; byte[] data; data = new byte[pdu.length - dataIndex]; @@ -186,31 +195,40 @@ public class WapPushOverSms { intent.setType(mimeType); intent.putExtra("transactionId", transactionId); intent.putExtra("pduType", pduType); + intent.putExtra("header", header); intent.putExtra("data", data); mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_WAP_PUSH"); } - private void dispatchWapPdu_PushCO(byte[] pdu, int transactionId, int pduType) { + private void dispatchWapPdu_PushCO(byte[] pdu, int transactionId, int pduType, + int headerStartIndex, int headerLength) { + byte[] header = new byte[headerLength]; + System.arraycopy(pdu, headerStartIndex, header, 0, header.length); + Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION); intent.setType(WspTypeDecoder.CONTENT_MIME_TYPE_B_PUSH_CO); intent.putExtra("transactionId", transactionId); intent.putExtra("pduType", pduType); + intent.putExtra("header", header); intent.putExtra("data", pdu); mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_WAP_PUSH"); } - private void dispatchWapPdu_MMS(byte[] pdu, int transactionId, int pduType, int dataIndex) { - byte[] data; - - data = new byte[pdu.length - dataIndex]; + private void dispatchWapPdu_MMS(byte[] pdu, int transactionId, int pduType, + int headerStartIndex, int headerLength) { + byte[] header = new byte[headerLength]; + System.arraycopy(pdu, headerStartIndex, header, 0, header.length); + int dataIndex = headerStartIndex + headerLength; + byte[] data = new byte[pdu.length - dataIndex]; System.arraycopy(pdu, dataIndex, data, 0, data.length); Intent intent = new Intent(Intents.WAP_PUSH_RECEIVED_ACTION); intent.setType(WspTypeDecoder.CONTENT_MIME_TYPE_B_MMS); intent.putExtra("transactionId", transactionId); intent.putExtra("pduType", pduType); + intent.putExtra("header", header); intent.putExtra("data", data); mSmsDispatcher.dispatch(intent, "android.permission.RECEIVE_MMS"); diff --git a/telephony/java/com/android/internal/telephony/WspTypeDecoder.java b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java index 3bbe0e1..336bc82 100644 --- a/telephony/java/com/android/internal/telephony/WspTypeDecoder.java +++ b/telephony/java/com/android/internal/telephony/WspTypeDecoder.java @@ -30,12 +30,16 @@ public class WspTypeDecoder { public static final int PDU_TYPE_PUSH = 0x06; public static final int PDU_TYPE_CONFIRMED_PUSH = 0x07; + // TODO we should have mapping between those binary code and mime type string. + // see http://www.openmobilealliance.org/tech/omna/omna-wsp-content-type.aspx + public static final int CONTENT_TYPE_B_DRM_RIGHTS_XML = 0x4a; public static final int CONTENT_TYPE_B_DRM_RIGHTS_WBXML = 0x4b; public static final int CONTENT_TYPE_B_PUSH_SI = 0x2e; public static final int CONTENT_TYPE_B_PUSH_SL = 0x30; public static final int CONTENT_TYPE_B_PUSH_CO = 0x32; public static final int CONTENT_TYPE_B_MMS = 0x3e; + public static final int CONTENT_TYPE_B_VND_DOCOMO_PF = 0x0310; public static final String CONTENT_MIME_TYPE_B_DRM_RIGHTS_XML = "application/vnd.oma.drm.rights+xml"; @@ -45,6 +49,7 @@ public class WspTypeDecoder { public static final String CONTENT_MIME_TYPE_B_PUSH_SL = "application/vnd.wap.slc"; public static final String CONTENT_MIME_TYPE_B_PUSH_CO = "application/vnd.wap.coc"; public static final String CONTENT_MIME_TYPE_B_MMS = "application/vnd.wap.mms-message"; + public static final String CONTENT_MIME_TYPE_B_VND_DOCOMO_PF = "application/vnd.docomo.pf"; public static final int PARAMETER_ID_X_WAP_APPLICATION_ID = 0x2f; diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java index ea80ea4..0c591e4 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java @@ -205,10 +205,6 @@ public class CDMAPhone extends PhoneBase { // Sets current entry in the telephony carrier table updateCurrentCarrierInProvider(operatorNumeric); - // Updates MCC MNC device configuration information - MccTable.updateMccMncConfiguration(this, operatorNumeric); - - // Notify voicemails. notifier.notifyMessageWaitingChanged(this); } @@ -266,12 +262,6 @@ public class CDMAPhone extends PhoneBase { } public ServiceState getServiceState() { - int roamInd = mSST.ss.getCdmaRoamingIndicator(); - int defRoamInd = mSST.ss.getCdmaDefaultRoamingIndicator(); - - mSST.ss.setCdmaEriIconIndex(mEriManager.getCdmaEriIconIndex(roamInd, defRoamInd)); - mSST.ss.setCdmaEriIconMode(mEriManager.getCdmaEriIconMode(roamInd, defRoamInd)); - return mSST.ss; } @@ -615,15 +605,7 @@ public class CDMAPhone extends PhoneBase { public DataState getDataConnectionState() { DataState ret = DataState.DISCONNECTED; - if ((SystemProperties.get("adb.connected", "").length() > 0) - && (SystemProperties.get("android.net.use-adb-networking", "") - .length() > 0)) { - // We're connected to an ADB host and we have USB networking - // turned on. No matter what the radio state is, - // we report data connected - - ret = DataState.CONNECTED; - } else if (mSST == null) { + if (mSST == null) { // Radio Technology Change is ongoning, dispose() and removeReferences() have // already been called @@ -719,13 +701,6 @@ public class CDMAPhone extends PhoneBase { mSST.disableLocationUpdates(); } - /** - * @deprecated - */ - public void getPdpContextList(Message response) { - getDataCallList(response); - } - public void getDataCallList(Message response) { mCM.getDataCallList(response); } @@ -750,7 +725,7 @@ public class CDMAPhone extends PhoneBase { public String getVoiceMailNumber() { String number = null; SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); - // TODO(Moto): The default value of voicemail number should be read from a system property + // TODO: The default value of voicemail number should be read from a system property number = sp.getString(VM_NUMBER_CDMA, "*86"); return number; } @@ -852,10 +827,6 @@ public class CDMAPhone extends PhoneBase { } void notifyServiceStateChanged(ServiceState ss) { - // TODO this seems really inefficient. Can't we calc this when the fundamentals change and store in the - // service state? - ss.setCdmaEriIconIndex(this.getCdmaEriIconIndex()); - ss.setCdmaEriIconMode(this.getCdmaEriIconMode()); super.notifyServiceStateChangedP(ss); } @@ -1385,7 +1356,7 @@ public class CDMAPhone extends PhoneBase { @Override public boolean isOtaSpNumber(String dialStr){ boolean isOtaSpNum = false; - String dialableStr = PhoneNumberUtils.extractNetworkPortion(dialStr); + String dialableStr = PhoneNumberUtils.extractNetworkPortionAlt(dialStr); if (dialableStr != null) { isOtaSpNum = isIs683OtaSpDialStr(dialableStr); if (isOtaSpNum == false) { @@ -1398,9 +1369,7 @@ public class CDMAPhone extends PhoneBase { @Override public int getCdmaEriIconIndex() { - int roamInd = getServiceState().getCdmaRoamingIndicator(); - int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator(); - return mEriManager.getCdmaEriIconIndex(roamInd, defRoamInd); + return getServiceState().getCdmaEriIconIndex(); } /** @@ -1410,9 +1379,7 @@ public class CDMAPhone extends PhoneBase { */ @Override public int getCdmaEriIconMode() { - int roamInd = getServiceState().getCdmaRoamingIndicator(); - int defRoamInd = getServiceState().getCdmaDefaultRoamingIndicator(); - return mEriManager.getCdmaEriIconMode(roamInd, defRoamInd); + return getServiceState().getCdmaEriIconMode(); } /** @@ -1459,20 +1426,22 @@ public class CDMAPhone extends PhoneBase { } /** - * Sets the "current" field in the telephony provider according to the build-time - * operator numeric property + * Sets the "current" field in the telephony provider according to the + * build-time operator numeric property * * @return true for success; false otherwise. */ - // TODO(Moto): move this method into PhoneBase, since it looks identical to - // the one in GsmPhone - private boolean updateCurrentCarrierInProvider(String operatorNumeric) { + boolean updateCurrentCarrierInProvider(String operatorNumeric) { if (!TextUtils.isEmpty(operatorNumeric)) { try { Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"); ContentValues map = new ContentValues(); map.put(Telephony.Carriers.NUMERIC, operatorNumeric); getContext().getContentResolver().insert(uri, map); + + // Updates MCC MNC device configuration information + MccTable.updateMccMncConfiguration(this, operatorNumeric); + return true; } catch (SQLException e) { Log.e(LOG_TAG, "Can't store current operator", e); diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java index 81dec21..fbe455e 100755 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java @@ -154,7 +154,7 @@ public class CdmaConnection extends Connection { dialString = formatDialString(dialString); Log.d(LOG_TAG, "[CDMAConn] CdmaConnection:formated dialString=" + dialString); - this.address = PhoneNumberUtils.extractNetworkPortion(dialString); + this.address = PhoneNumberUtils.extractNetworkPortionAlt(dialString); this.postDialString = PhoneNumberUtils.extractPostDialPortion(dialString); index = -1; @@ -592,8 +592,11 @@ public class CdmaConnection extends Connection { if (!isIncoming) { // outgoing calls only processNextPostDialChar(); + } else { + // Only release wake lock for incoming calls, for outgoing calls the wake lock + // will be released after any pause-dial is completed + releaseWakeLock(); } - releaseWakeLock(); } private void @@ -688,6 +691,7 @@ public class CdmaConnection extends Connection { Registrant postDialHandler; if (postDialState == PostDialState.CANCELLED) { + releaseWakeLock(); //Log.v("CDMA", "##### processNextPostDialChar: postDialState == CANCELLED, bail"); return; } @@ -696,6 +700,9 @@ public class CdmaConnection extends Connection { postDialString.length() <= nextPostDialChar) { setPostDialState(PostDialState.COMPLETE); + // We were holding a wake lock until pause-dial was complete, so give it up now + releaseWakeLock(); + // notifyMessage.arg1 is 0 on complete c = 0; } else { @@ -770,19 +777,24 @@ public class CdmaConnection extends Connection { } /** - * Set post dial state and acquire wake lock while switching to "started" - * state, the wake lock will be released if state switches out of "started" + * Set post dial state and acquire wake lock while switching to "started" or "wait" + * state, the wake lock will be released if state switches out of "started" or "wait" * state or after WAKE_LOCK_TIMEOUT_MILLIS. * @param s new PostDialState */ private void setPostDialState(PostDialState s) { - if (postDialState != PostDialState.STARTED - && s == PostDialState.STARTED) { - acquireWakeLock(); - Message msg = h.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT); - h.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT_MILLIS); - } else if (postDialState == PostDialState.STARTED - && s != PostDialState.STARTED) { + if (s == PostDialState.STARTED || + s == PostDialState.PAUSE) { + synchronized (mPartialWakeLock) { + if (mPartialWakeLock.isHeld()) { + h.removeMessages(EVENT_WAKE_LOCK_TIMEOUT); + } else { + acquireWakeLock(); + } + Message msg = h.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT); + h.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT_MILLIS); + } + } else { h.removeMessages(EVENT_WAKE_LOCK_TIMEOUT); releaseWakeLock(); } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java index 4588f36..95cb1c6 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java @@ -16,221 +16,87 @@ package com.android.internal.telephony.cdma; -import android.os.*; -import android.util.EventLog; +import android.os.Message; import android.util.Log; -import com.android.internal.telephony.CommandException; -import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.DataConnection; -import com.android.internal.telephony.DataLink; +import com.android.internal.telephony.gsm.ApnSetting; +import com.android.internal.telephony.Phone; import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.TelephonyEventLog; /** * {@hide} - * */ public class CdmaDataConnection extends DataConnection { private static final String LOG_TAG = "CDMA"; - private static final boolean DBG = true; /** Fail cause of last Data Call activate from RIL_LastDataCallActivateFailCause */ private final static int PS_NET_DOWN_REASON_OPERATOR_DETERMINED_BARRING = 8; - private final static int PS_NET_DOWN_REASON_UNKNOWN_APN = 27; private final static int PS_NET_DOWN_REASON_AUTH_FAILED = 29; private final static int PS_NET_DOWN_REASON_OPTION_NOT_SUPPORTED = 32; private final static int PS_NET_DOWN_REASON_OPTION_UNSUBSCRIBED = 33; -/** It is likely that the number of error codes listed below will be removed - * in the foreseeable future. They have been added, but not agreed upon. - * - */ - private final static int PS_NET_DOWN_REASON_NOT_SPECIFIED = 0; - private final static int PS_NET_DOWN_REASON_CLOSE_IN_PROGRESS = 1; - private final static int PS_NET_DOWN_REASON_NW_INITIATED_TERMINATION = 2; - private final static int PS_NET_DOWN_REASON_APP_PREEMPTED = 3; - private final static int PS_NET_DOWN_REASON_LLC_SNDCP_FAILURE = 25; - private final static int PS_NET_DOWN_REASON_INSUFFICIENT_RESOURCES = 26; - private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP = 28; - private final static int PS_NET_DOWN_REASON_GGSN_REJECT = 30; - private final static int PS_NET_DOWN_REASON_ACTIVATION_REJECT = 31; - private final static int PS_NET_DOWN_REASON_OPTION_TEMP_OOO = 34; - private final static int PS_NET_DOWN_REASON_NSAPI_ALREADY_USED = 35; - private final static int PS_NET_DOWN_REASON_REGULAR_DEACTIVATION = 36; - private final static int PS_NET_DOWN_REASON_QOS_NOT_ACCEPTED = 37; - private final static int PS_NET_DOWN_REASON_NETWORK_FAILURE = 38; - private final static int PS_NET_DOWN_REASON_UMTS_REATTACH_REQ = 39; - private final static int PS_NET_DOWN_REASON_TFT_SEMANTIC_ERROR = 41; - private final static int PS_NET_DOWN_REASON_TFT_SYNTAX_ERROR = 42; - private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP_CONTEXT = 43; - private final static int PS_NET_DOWN_REASON_FILTER_SEMANTIC_ERROR = 44; - private final static int PS_NET_DOWN_REASON_FILTER_SYNTAX_ERROR = 45; - private final static int PS_NET_DOWN_REASON_PDP_WITHOUT_ACTIVE_TFT = 46; - private final static int PS_NET_DOWN_REASON_INVALID_TRANSACTION_ID = 81; - private final static int PS_NET_DOWN_REASON_MESSAGE_INCORRECT_SEMANTIC = 95; - private final static int PS_NET_DOWN_REASON_INVALID_MANDATORY_INFO = 96; - private final static int PS_NET_DOWN_REASON_MESSAGE_TYPE_UNSUPPORTED = 97; - private final static int PS_NET_DOWN_REASON_MSG_TYPE_NONCOMPATIBLE_STATE = 98; - private final static int PS_NET_DOWN_REASON_UNKNOWN_INFO_ELEMENT = 99; - private final static int PS_NET_DOWN_REASON_CONDITIONAL_IE_ERROR = 100; - private final static int PS_NET_DOWN_REASON_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101; - private final static int PS_NET_DOWN_REASON_PROTOCOL_ERROR = 111; - private final static int PS_NET_DOWN_REASON_APN_TYPE_CONFLICT = 112; - private final static int PS_NET_DOWN_REASON_UNKNOWN_CAUSE_CODE = 113; - private final static int PS_NET_DOWN_REASON_INTERNAL_MIN = 200; - private final static int PS_NET_DOWN_REASON_INTERNAL_ERROR = 201; - private final static int PS_NET_DOWN_REASON_INTERNAL_CALL_ENDED = 202; - private final static int PS_NET_DOWN_REASON_INTERNAL_UNKNOWN_CAUSE_CODE = 203; - private final static int PS_NET_DOWN_REASON_INTERNAL_MAX = 204; - private final static int PS_NET_DOWN_REASON_CDMA_LOCK = 500; - private final static int PS_NET_DOWN_REASON_INTERCEPT = 501; - private final static int PS_NET_DOWN_REASON_REORDER = 502; - private final static int PS_NET_DOWN_REASON_REL_SO_REJ = 503; - private final static int PS_NET_DOWN_REASON_INCOM_CALL = 504; - private final static int PS_NET_DOWN_REASON_ALERT_STOP = 505; - private final static int PS_NET_DOWN_REASON_ACTIVATION = 506; - private final static int PS_NET_DOWN_REASON_MAX_ACCESS_PROBE = 507; - private final static int PS_NET_DOWN_REASON_CCS_NOT_SUPPORTED_BY_BS = 508; - private final static int PS_NET_DOWN_REASON_NO_RESPONSE_FROM_BS = 509; - private final static int PS_NET_DOWN_REASON_REJECTED_BY_BS = 510; - private final static int PS_NET_DOWN_REASON_INCOMPATIBLE = 511; - private final static int PS_NET_DOWN_REASON_ALREADY_IN_TC = 512; - private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_GPS = 513; - private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_SMS = 514; - private final static int PS_NET_DOWN_REASON_NO_CDMA_SRV = 515; - private final static int PS_NET_DOWN_REASON_CONF_FAILED = 1000; - private final static int PS_NET_DOWN_REASON_INCOM_REJ = 1001; - private final static int PS_NET_DOWN_REASON_NO_GW_SRV = 1002; - private final static int PS_NET_DOWN_REASON_CD_GEN_OR_BUSY = 1500; - private final static int PS_NET_DOWN_REASON_CD_BILL_OR_AUTH = 1501; - private final static int PS_NET_DOWN_REASON_CHG_HDR = 1502; - private final static int PS_NET_DOWN_REASON_EXIT_HDR = 1503; - private final static int PS_NET_DOWN_REASON_HDR_NO_SESSION = 1504; - private final static int PS_NET_DOWN_REASON_HDR_ORIG_DURING_GPS_FIX = 1505; - private final static int PS_NET_DOWN_REASON_HDR_CS_TIMEOUT = 1506; - private final static int PS_NET_DOWN_REASON_HDR_RELEASED_BY_CM = 1507; - private final static int PS_NET_DOWN_REASON_CLIENT_END = 2000; - private final static int PS_NET_DOWN_REASON_NO_SRV = 2001; - private final static int PS_NET_DOWN_REASON_FADE = 2002; - private final static int PS_NET_DOWN_REASON_REL_NORMAL = 2003; - private final static int PS_NET_DOWN_REASON_ACC_IN_PROG = 2004; - private final static int PS_NET_DOWN_REASON_ACC_FAIL = 2005; - private final static int PS_NET_DOWN_REASON_REDIR_OR_HANDOFF = 2006; - - // ***** Instance Variables // ***** Constructor - CdmaDataConnection(CDMAPhone phone) { - super(phone); + private CdmaDataConnection(CDMAPhone phone, String name) { + super(phone, name); + } - if (DBG) log("CdmaDataConnection <constructor>"); + /** + * Create the connection object + * + * @param phone + * @return CdmaDataConnection that was created. + */ + static CdmaDataConnection makeDataConnection(CDMAPhone phone) { + synchronized (mCountLock) { + mCount += 1; + } + CdmaDataConnection cdmaDc = new CdmaDataConnection(phone, "CdmaDataConnection-" + mCount); + cdmaDc.start(); + if (DBG) cdmaDc.log("Made " + cdmaDc.getName()); + return cdmaDc; } /** - * Setup a data connection + * Begin setting up a data connection, calls setupDataCall + * and the ConnectionParams will be returned with the + * EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj. * - * @param onCompleted - * notify success or not after down + * @param cp is the connection parameters */ - void connect(Message onCompleted) { + @Override + protected void onConnect(ConnectionParams cp) { if (DBG) log("CdmaDataConnection Connecting..."); - state = State.ACTIVATING; - onConnectCompleted = onCompleted; createTime = -1; lastFailTime = -1; lastFailCause = FailCause.NONE; - receivedDisconnectReq = false; - phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_CDMA), - Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), null, null, - null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP), - obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE)); - } - - private void tearDownData(Message msg) { - if (phone.mCM.getRadioState().isOn()) { - phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg)); - } - } - - protected void disconnect(Message msg) { - onDisconnect = msg; - if (state == State.ACTIVE) { - tearDownData(msg); - } else if (state == State.ACTIVATING) { - receivedDisconnectReq = true; + int dataProfile; + if ((cp.apn != null) && (cp.apn.types.length > 0) && (cp.apn.types[0] != null) && + (cp.apn.types[0].equals(Phone.APN_TYPE_DUN))) { + if (DBG) log("CdmaDataConnection using DUN"); + dataProfile = RILConstants.DATA_PROFILE_TETHERED; } else { - // state == INACTIVE. Nothing to do, so notify immediately. - notifyDisconnect(msg); - } - } - - - public String toString() { - return "State=" + state + " create=" + createTime + " lastFail=" - + lastFailTime + " lastFailCause=" + lastFailCause; - } - - - protected void notifyFail(FailCause cause, Message onCompleted) { - if (onCompleted == null) { - return; - } - state = State.INACTIVE; - lastFailCause = cause; - lastFailTime = System.currentTimeMillis(); - onConnectCompleted = null; - - if(DBG) { - log("Notify data connection fail at " + lastFailTime + - " due to " + lastFailCause); + dataProfile = RILConstants.DATA_PROFILE_DEFAULT; } - AsyncResult.forMessage(onCompleted, cause, new Exception()); - onCompleted.sendToTarget(); - } - - protected void notifySuccess(Message onCompleted) { - if (onCompleted == null) { - return; - } - - state = State.ACTIVE; - createTime = System.currentTimeMillis(); - onConnectCompleted = null; - onCompleted.arg1 = cid; - - if (DBG) log("Notify data connection success at " + createTime); - - AsyncResult.forMessage(onCompleted); - onCompleted.sendToTarget(); - } - - protected void notifyDisconnect(Message msg) { - if (DBG) log("Notify data connection disconnect"); - - if (msg != null) { - AsyncResult.forMessage(msg); - msg.sendToTarget(); - } - clearSettings(); + // msg.obj will be returned in AsyncResult.userObj; + Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp); + msg.obj = cp; + phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_CDMA), + Integer.toString(dataProfile), null, null, + null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP), msg); } - protected void onLinkStateChanged(DataLink.LinkState linkState) { - switch (linkState) { - case LINK_UP: - notifySuccess(onConnectCompleted); - break; - - case LINK_DOWN: - case LINK_EXITED: - phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE)); - break; - } + @Override + public String toString() { + return "State=" + getCurrentState().getName() + " create=" + createTime + " lastFail=" + + lastFailTime + " lastFasilCause=" + lastFailCause; } + @Override protected FailCause getFailCauseFromRequest(int rilCause) { FailCause cause; @@ -253,73 +119,19 @@ public class CdmaDataConnection extends DataConnection { return cause; } - protected void log(String s) { - Log.d(LOG_TAG, "[CdmaDataConnection] " + s); - } - @Override - protected void onDeactivated(AsyncResult ar) { - notifyDisconnect((Message) ar.userObj); - if (DBG) log("CDMA Connection Deactivated"); + protected boolean isDnsOk(String[] domainNameServers) { + if ((NULL_IP.equals(domainNameServers[0]) + && NULL_IP.equals(domainNameServers[1]) + && !((CDMAPhone) phone).isDnsCheckDisabled())) { + return false; + } else { + return true; + } } @Override - protected void onSetupConnectionCompleted(AsyncResult ar) { - if (ar.exception != null) { - Log.e(LOG_TAG, "CdmaDataConnection Init failed " + ar.exception); - - if (receivedDisconnectReq) { - // Don't bother reporting the error if there's already a - // pending disconnect request, since DataConnectionTracker - // has already updated its state. - notifyDisconnect(onDisconnect); - } else { - if (ar.exception instanceof CommandException - && ((CommandException) (ar.exception)).getCommandError() - == CommandException.Error.RADIO_NOT_AVAILABLE) { - notifyFail(FailCause.RADIO_NOT_AVAILABLE, onConnectCompleted); - } else { - phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE)); - } - } - } else { - if (receivedDisconnectReq) { - // Don't bother reporting success if there's already a - // pending disconnect request, since DataConnectionTracker - // has already updated its state. - tearDownData(onDisconnect); - } else { - String[] response = ((String[]) ar.result); - cid = Integer.parseInt(response[0]); - - if (response.length > 2) { - interfaceName = response[1]; - ipAddress = response[2]; - String prefix = "net." + interfaceName + "."; - gatewayAddress = SystemProperties.get(prefix + "gw"); - 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 (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1]) - && !((CDMAPhone) phone).isDnsCheckDisabled()) { - // Work around a race condition where QMI does not fill in DNS: - // Deactivate PDP and let DataConnectionTracker retry. - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS, - dnsServers[0]); - phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY)); - return; - } - } - - onLinkStateChanged(DataLink.LinkState.LINK_UP); - - if (DBG) log("CdmaDataConnection setup on cid = " + cid); - } - } + protected void log(String s) { + Log.d(LOG_TAG, "[" + getName() + "] " + s); } } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java index 9bc5e8e..217e1e8 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -23,17 +23,18 @@ 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.INetStatService; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.preference.PreferenceManager; -import android.provider.Checkin; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.telephony.cdma.CdmaCellLocation; @@ -43,13 +44,14 @@ import android.util.Log; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.DataCallState; -import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.DataConnection.FailCause; +import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.DataConnectionTracker; -import com.android.internal.telephony.RetryManager; +import com.android.internal.telephony.EventLogTags; +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 com.android.internal.telephony.TelephonyEventLog; import java.util.ArrayList; @@ -76,9 +78,6 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { /** Currently active CdmaDataConnection */ private CdmaDataConnection mActiveDataConnection; - /** mimic of GSM's mActiveApn */ - private boolean mIsApnActive = false; - private boolean mPendingRestartRadio = false; private static final int TIME_DELAYED_TO_RESTART_RADIO = SystemProperties.getInt("ro.cdma.timetoradiorestart", 60000); @@ -104,8 +103,17 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { private static final String[] mSupportedApnTypes = { Phone.APN_TYPE_DEFAULT, Phone.APN_TYPE_MMS, + Phone.APN_TYPE_DUN, + Phone.APN_TYPE_HIPRI }; + + private static final String[] mDefaultApnTypes = { + Phone.APN_TYPE_DEFAULT, + Phone.APN_TYPE_MMS, Phone.APN_TYPE_HIPRI }; + // if we have no active Apn this is null + protected ApnSetting mActiveApn; + // Possibly promoate to base class, the only difference is // the INTENT_RECONNECT_ALARM action is a different string. // Do consider technology changes if it is promoted. @@ -168,8 +176,6 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); p.mCM.registerForCdmaOtaProvision(this, EVENT_CDMA_OTA_PROVISION, null); - this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat")); - IntentFilter filter = new IntentFilter(); filter.addAction(INTENT_RECONNECT_ALARM); filter.addAction(Intent.ACTION_SCREEN_ON); @@ -189,8 +195,16 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { // and 2) whether the RIL will setup the baseband to auto-PS attach. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext()); + 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); + !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false) && + dataEnabledSetting; if (dataEnabled[APN_DEFAULT_ID]) { enabledCount++; } @@ -232,23 +246,15 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { protected void setState(State s) { if (DBG) log ("setState: " + s); if (state != s) { - if (s == State.INITING) { // request Data connection context - Checkin.updateStats(phone.getContext().getContentResolver(), - Checkin.Stats.Tag.PHONE_CDMA_DATA_ATTEMPTED, 1, 0.0); - } - - if (s == State.CONNECTED) { // pppd is up - Checkin.updateStats(phone.getContext().getContentResolver(), - Checkin.Stats.Tag.PHONE_CDMA_DATA_CONNECTED, 1, 0.0); - } + EventLog.writeEvent(EventLogTags.CDMA_DATA_STATE_CHANGE, + state.toString(), s.toString()); + state = s; } - - state = s; } @Override protected boolean isApnTypeActive(String type) { - return (mIsApnActive && isApnTypeAvailable(type)); + return mActiveApn != null && mActiveApn.canHandleType(type); } @Override @@ -263,10 +269,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { protected String[] getActiveApnTypes() { String[] result; - if (mIsApnActive) { - result = mSupportedApnTypes.clone(); + if (mActiveApn != null) { + result = mActiveApn.types; } else { - // TODO - should this return an empty array? See GSM too. result = new String[1]; result[0] = Phone.APN_TYPE_DEFAULT; } @@ -366,7 +371,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { * @param reason reason for the clean up. */ private void cleanUpConnection(boolean tearDown, String reason) { - if (DBG) log("Clean up connection due to " + reason); + if (DBG) log("cleanUpConnection: reason: " + reason); // Clear the reconnect alarm, if set. if (mReconnectIntent != null) { @@ -378,32 +383,33 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { setState(State.DISCONNECTING); - for (DataConnection connBase : dataConnectionList) { - CdmaDataConnection conn = (CdmaDataConnection) connBase; - + boolean notificationDeferred = false; + for (DataConnection conn : dataConnectionList) { if(conn != null) { if (tearDown) { - Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason); - conn.disconnect(msg); + if (DBG) log("cleanUpConnection: teardown, call conn.disconnect"); + conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason)); + notificationDeferred = true; } else { - conn.clearSettings(); + if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously"); + conn.resetSynchronously(); + notificationDeferred = false; } } } stopNetStatPoll(); - if (!tearDown) { - setState(State.IDLE); - phone.notifyDataConnection(reason); - mIsApnActive = false; + if (!notificationDeferred) { + if (DBG) log("cleanupConnection: !notificationDeferred"); + gotoIdleAndNotifyDataConnection(reason); } } private CdmaDataConnection findFreeDataConnection() { for (DataConnection connBase : dataConnectionList) { CdmaDataConnection conn = (CdmaDataConnection) connBase; - if (conn.getState() == DataConnection.State.INACTIVE) { + if (conn.isInactive()) { return conn; } } @@ -411,7 +417,6 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } private boolean setupData(String reason) { - CdmaDataConnection conn = findFreeDataConnection(); if (conn == null) { @@ -420,12 +425,19 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } mActiveDataConnection = conn; - mIsApnActive = true; + String[] types; + if (mRequestedApnType.equals(Phone.APN_TYPE_DUN)) { + types = new String[1]; + types[0] = Phone.APN_TYPE_DUN; + } else { + types = mDefaultApnTypes; + } + mActiveApn = new ApnSetting(0, "", "", "", "", "", "", "", "", "", "", 0, types); Message msg = obtainMessage(); msg.what = EVENT_DATA_SETUP_COMPLETE; msg.obj = reason; - conn.connect(msg); + conn.connect(msg, mActiveApn); setState(State.INITING); phone.notifyDataConnection(reason); @@ -481,79 +493,70 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { preTxPkts = txPkts; preRxPkts = rxPkts; - // check if netstat is still valid to avoid NullPointerException after NTC - if (netstat != null) { - try { - txPkts = netstat.getMobileTxPackets(); - rxPkts = netstat.getMobileRxPackets(); - } catch (RemoteException e) { - txPkts = 0; - rxPkts = 0; - } + txPkts = TrafficStats.getMobileTxPackets(); + rxPkts = TrafficStats.getMobileRxPackets(); - //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); + //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); - if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { - sent = txPkts - preTxPkts; - received = rxPkts - preRxPkts; + if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { + sent = txPkts - preTxPkts; + received = rxPkts - preRxPkts; - if ( sent > 0 && received > 0 ) { - sentSinceLastRecv = 0; - newActivity = Activity.DATAINANDOUT; - } else if (sent > 0 && received == 0) { - if (phone.getState() == Phone.State.IDLE) { - sentSinceLastRecv += sent; - } else { - sentSinceLastRecv = 0; - } - newActivity = Activity.DATAOUT; - } else if (sent == 0 && received > 0) { - sentSinceLastRecv = 0; - newActivity = Activity.DATAIN; - } else if (sent == 0 && received == 0) { - newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE; + if ( sent > 0 && received > 0 ) { + sentSinceLastRecv = 0; + newActivity = Activity.DATAINANDOUT; + } else if (sent > 0 && received == 0) { + if (phone.getState() == Phone.State.IDLE) { + sentSinceLastRecv += sent; } else { sentSinceLastRecv = 0; - newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE; } + newActivity = Activity.DATAOUT; + } else if (sent == 0 && received > 0) { + sentSinceLastRecv = 0; + newActivity = Activity.DATAIN; + } else if (sent == 0 && received == 0) { + newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE; + } else { + sentSinceLastRecv = 0; + newActivity = (activity == Activity.DORMANT) ? activity : Activity.NONE; + } - if (activity != newActivity) { - activity = newActivity; - phone.notifyDataActivity(); - } + if (activity != newActivity) { + activity = newActivity; + phone.notifyDataActivity(); } + } - if (sentSinceLastRecv >= NUMBER_SENT_PACKETS_OF_HANG) { - // Packets sent without ack exceeded threshold. + if (sentSinceLastRecv >= NUMBER_SENT_PACKETS_OF_HANG) { + // Packets sent without ack exceeded threshold. - if (mNoRecvPollCount == 0) { - EventLog.writeEvent( - TelephonyEventLog.EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED, - sentSinceLastRecv); - } + if (mNoRecvPollCount == 0) { + EventLog.writeEvent( + EventLogTags.PDP_RADIO_RESET_COUNTDOWN_TRIGGERED, + sentSinceLastRecv); + } - if (mNoRecvPollCount < NO_RECV_POLL_LIMIT) { - mNoRecvPollCount++; - // Slow down the poll interval to let things happen - netStatPollPeriod = POLL_NETSTAT_SLOW_MILLIS; - } else { - if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + - " pkts since last received"); - // We've exceeded the threshold. Restart the radio. - netStatPollEnabled = false; - stopNetStatPoll(); - restartRadio(); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_RESET, - NO_RECV_POLL_LIMIT); - } + if (mNoRecvPollCount < NO_RECV_POLL_LIMIT) { + mNoRecvPollCount++; + // Slow down the poll interval to let things happen + netStatPollPeriod = POLL_NETSTAT_SLOW_MILLIS; } else { - mNoRecvPollCount = 0; - netStatPollPeriod = POLL_NETSTAT_MILLIS; + if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + + " pkts since last received"); + // We've exceeded the threshold. Restart the radio. + netStatPollEnabled = false; + stopNetStatPoll(); + restartRadio(); + EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, NO_RECV_POLL_LIMIT); } + } else { + mNoRecvPollCount = 0; + netStatPollPeriod = POLL_NETSTAT_MILLIS; + } - if (netStatPollEnabled) { - mDataConnectionTracker.postDelayed(this, netStatPollPeriod); - } + if (netStatPollEnabled) { + mDataConnectionTracker.postDelayed(this, netStatPollPeriod); } } }; @@ -621,6 +624,13 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { setState(State.FAILED); } + private void gotoIdleAndNotifyDataConnection(String reason) { + if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason); + setState(State.IDLE); + phone.notifyDataConnection(reason); + mActiveApn = null; + } + protected void onRecordsLoaded() { if (state == State.FAILED) { cleanUpConnection(false, null); @@ -640,8 +650,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { */ @Override protected void onEnableNewApn() { - // for cdma we only use this when default data is enabled.. - onTrySetupData(Phone.REASON_DATA_ENABLED); + cleanUpConnection(true, Phone.REASON_APN_SWITCHED); } /** @@ -730,7 +739,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } /** - * @override com.android.internal.telephony.DataConnectionTracker + * Called when EVENT_DISCONNECT_DONE is received. */ protected void onDisconnectDone(AsyncResult ar) { if(DBG) log("EVENT_DISCONNECT_DONE"); @@ -754,13 +763,27 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } phone.notifyDataConnection(reason); - mIsApnActive = false; + mActiveApn = null; if (retryAfterDisconnected(reason)) { trySetupData(reason); } } /** + * Called when EVENT_RESET_DONE is received so goto + * IDLE state and send notifications to those interested. + */ + @Override + protected void onResetDone(AsyncResult ar) { + if (DBG) log("EVENT_RESET_DONE"); + String reason = null; + if (ar.userObj instanceof String) { + reason = (String) ar.userObj; + } + gotoIdleAndNotifyDataConnection(reason); + } + + /** * @override com.android.internal.telephony.DataConnectionTracker */ protected void onVoiceCallStarted() { @@ -801,7 +824,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { CdmaDataConnection dataConn; for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) { - dataConn = new CdmaDataConnection(mCdmaPhone); + dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone); dataConnectionList.add(dataConn); } } @@ -822,11 +845,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { mRetryMgr.resetRetryCount(); CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation()); - int bsid = (loc != null) ? loc.getBaseStationId() : -1; - - EventLog.List val = new EventLog.List(bsid, + EventLog.writeEvent(EventLogTags.CDMA_DATA_SETUP_FAILED, + loc != null ? loc.getBaseStationId() : -1, TelephonyManager.getDefault().getNetworkType()); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CDMA_DATA_SETUP_FAILED, val); } trySetupData(Phone.REASON_CDMA_DATA_DETACHED); } @@ -865,13 +886,12 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { private void writeEventLogCdmaDataDrop() { CdmaCellLocation loc = (CdmaCellLocation)(phone.getCellLocation()); - int bsid = (loc != null) ? loc.getBaseStationId() : -1; - EventLog.List val = new EventLog.List(bsid, + EventLog.writeEvent(EventLogTags.CDMA_DATA_DROP, + loc != null ? loc.getBaseStationId() : -1, TelephonyManager.getDefault().getNetworkType()); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CDMA_DATA_DROP, val); } - protected void onDataStateChanged (AsyncResult ar) { + protected void onDataStateChanged(AsyncResult ar) { ArrayList<DataCallState> dataCallStates = (ArrayList<DataCallState>)(ar.result); if (ar.exception != null) { @@ -882,32 +902,46 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { } if (state == State.CONNECTED) { - if (dataCallStates.size() >= 1) { - switch (dataCallStates.get(0).active) { + boolean isActiveOrDormantConnectionPresent = false; + int connectionState = DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE; + + // Check for an active or dormant connection element in + // the DATA_CALL_LIST array + for (int index = 0; index < dataCallStates.size(); index++) { + connectionState = dataCallStates.get(index).active; + if (connectionState != DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE) { + isActiveOrDormantConnectionPresent = true; + break; + } + } + + if (!isActiveOrDormantConnectionPresent) { + // No active or dormant connection + Log.i(LOG_TAG, "onDataStateChanged: No active connection" + + "state is CONNECTED, disconnecting/cleanup"); + writeEventLogCdmaDataDrop(); + cleanUpConnection(true, null); + return; + } + + switch (connectionState) { case DATA_CONNECTION_ACTIVE_PH_LINK_UP: Log.v(LOG_TAG, "onDataStateChanged: active=LINK_ACTIVE && CONNECTED, ignore"); activity = Activity.NONE; phone.notifyDataActivity(); + startNetStatPoll(); break; - case DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE: - Log.v(LOG_TAG, - "onDataStateChanged active=LINK_INACTIVE && CONNECTED, disconnecting/cleanup"); - writeEventLogCdmaDataDrop(); - cleanUpConnection(true, null); - break; + case DATA_CONNECTION_ACTIVE_PH_LINK_DOWN: Log.v(LOG_TAG, "onDataStateChanged active=LINK_DOWN && CONNECTED, dormant"); activity = Activity.DORMANT; phone.notifyDataActivity(); + stopNetStatPoll(); break; + default: Log.v(LOG_TAG, "onDataStateChanged: IGNORE unexpected DataCallState.active=" - + dataCallStates.get(0).active); - } - } else { - Log.v(LOG_TAG, "onDataStateChanged: network disconnected, clean up"); - writeEventLogCdmaDataDrop(); - cleanUpConnection(true, null); + + connectionState); } } else { // TODO: Do we need to do anything? @@ -954,6 +988,11 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { public void handleMessage (Message msg) { + if (!phone.mIsTheCurrentActivePhone) { + Log.d(LOG_TAG, "Ignore CDMA msgs since CDMA phone is inactive"); + return; + } + switch (msg.what) { case EVENT_RECORDS_LOADED: onRecordsLoaded(); diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaInformationRecords.java b/telephony/java/com/android/internal/telephony/cdma/CdmaInformationRecords.java index 7402769..ce6530a 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaInformationRecords.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaInformationRecords.java @@ -74,7 +74,7 @@ public final class CdmaInformationRecords { break; case RIL_CDMA_T53_RELEASE_INFO_REC: - // TODO(Moto): WHAT to do, for now fall through and throw exception + // TODO: WHAT to do, for now fall through and throw exception default: throw new RuntimeException("RIL_UNSOL_CDMA_INFO_REC: unsupported record. Got " + CdmaInformationRecords.idToString(id) + " "); diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java index aee45bf..ed93aea 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -167,7 +167,8 @@ final class CdmaSMSDispatcher extends SMSDispatcher { // not yet been handled and also do not correspond to the two // kinds that are processed below. if ((SmsEnvelope.TELESERVICE_WMT != teleService) && - (SmsEnvelope.TELESERVICE_WEMT != teleService)) { + (SmsEnvelope.TELESERVICE_WEMT != teleService) && + (SmsEnvelope.MESSAGE_TYPE_BROADCAST != sms.getMessageType())) { return Intents.RESULT_SMS_UNSUPPORTED; } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index e0c3a47..6c71584 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -29,7 +29,6 @@ import android.os.Registrant; import android.os.RegistrantList; import android.os.SystemClock; import android.os.SystemProperties; -import android.provider.Checkin; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.provider.Telephony.Intents; @@ -45,10 +44,10 @@ 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.TelephonyEventLog; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; @@ -358,8 +357,8 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { if (ar.exception == null) { String states[] = (String[])ar.result; int baseStationId = -1; - int baseStationLatitude = Integer.MAX_VALUE; - int baseStationLongitude = Integer.MAX_VALUE; + int baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG; + int baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG; int systemId = -1; int networkId = -1; @@ -374,6 +373,11 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { if (states[6] != null) { baseStationLongitude = Integer.parseInt(states[6]); } + // Some carriers only return lat-lngs of 0,0 + if (baseStationLatitude == 0 && baseStationLongitude == 0) { + baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG; + baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG; + } if (states[8] != null) { systemId = Integer.parseInt(states[8]); } @@ -514,7 +518,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { synchronized(this) { if (mPendingRadioPowerOffAfterDataOff) { if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now."); - cm.setRadioPower(false, null); + hangupAndPowerOff(); mPendingRadioPowerOffAfterDataOff = false; } } @@ -537,38 +541,46 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } else if (!mDesiredPowerState && cm.getRadioState().isOn()) { DataConnectionTracker dcTracker = phone.mDataConnection; if (! dcTracker.isDataConnectionAsDesired()) { - - EventLog.List val = new EventLog.List( + EventLog.writeEvent(EventLogTags.DATA_NETWORK_STATUS_ON_RADIO_OFF, dcTracker.getStateInString(), - (dcTracker.getAnyDataEnabled() ? 1 : 0) ); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF, val); + dcTracker.getAnyDataEnabled() ? 1 : 0); } - Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION); - msg.arg1 = 1; // tearDown is true - msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF; - dcTracker.sendMessage(msg); - synchronized(this) { - if (!mPendingRadioPowerOffAfterDataOff) { - DataConnectionTracker.State currentState = dcTracker.getState(); - if (currentState != DataConnectionTracker.State.CONNECTED - && currentState != DataConnectionTracker.State.DISCONNECTING - && currentState != DataConnectionTracker.State.INITING) { - if (DBG) log("Data disconnected, turn off radio right away."); - cm.setRadioPower(false, null); - } - else if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) { - if (DBG) { - log("Wait up to 30 sec for data to disconnect, then turn off radio."); - } - mPendingRadioPowerOffAfterDataOff = true; - } else { - Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away."); - cm.setRadioPower(false, null); + // If it's on and available and we want it off gracefully + powerOffRadioSafely(); + } // Otherwise, we're in the desired state + } + + @Override + protected void powerOffRadioSafely(){ + // clean data connection + DataConnectionTracker dcTracker = phone.mDataConnection; + + Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION); + msg.arg1 = 1; // tearDown is true + msg.obj = CDMAPhone.REASON_RADIO_TURNED_OFF; + dcTracker.sendMessage(msg); + + synchronized(this) { + if (!mPendingRadioPowerOffAfterDataOff) { + DataConnectionTracker.State currentState = dcTracker.getState(); + if (currentState != DataConnectionTracker.State.CONNECTED + && currentState != DataConnectionTracker.State.DISCONNECTING + && currentState != DataConnectionTracker.State.INITING) { + if (DBG) log("Data disconnected, turn off radio right away."); + hangupAndPowerOff(); + } + else if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) { + if (DBG) { + log("Wait up to 30 sec for data to disconnect, then turn off radio."); } + mPendingRadioPowerOffAfterDataOff = true; + } else { + Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away."); + hangupAndPowerOff(); } } - } // Otherwise, we're in the desired state + } } @Override @@ -597,6 +609,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { || !TextUtils.equals(spn, curSpn) || !TextUtils.equals(plmn, curPlmn)) { Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn); intent.putExtra(Intents.EXTRA_SPN, spn); intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn); @@ -654,8 +667,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { int registrationState = 4; //[0] registrationState int radioTechnology = -1; //[3] radioTechnology int baseStationId = -1; //[4] baseStationId - int baseStationLatitude = Integer.MAX_VALUE; //[5] baseStationLatitude - int baseStationLongitude = Integer.MAX_VALUE; //[6] baseStationLongitude + //[5] baseStationLatitude + int baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG; + //[6] baseStationLongitude + int baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG; int cssIndicator = 0; //[7] init with 0, because it is treated as a boolean int systemId = 0; //[8] systemId int networkId = 0; //[9] networkId @@ -681,6 +696,11 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { if (states[6] != null) { baseStationLongitude = Integer.parseInt(states[6]); } + // Some carriers only return lat-lngs of 0,0 + if (baseStationLatitude == 0 && baseStationLongitude == 0) { + baseStationLatitude = CdmaCellLocation.INVALID_LAT_LONG; + baseStationLongitude = CdmaCellLocation.INVALID_LAT_LONG; + } if (states[7] != null) { cssIndicator = Integer.parseInt(states[7]); } @@ -819,6 +839,12 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } } + int roamingIndicator = newSS.getCdmaRoamingIndicator(); + newSS.setCdmaEriIconIndex(phone.mEriManager.getCdmaEriIconIndex(roamingIndicator, + mDefaultRoamingIndicator)); + newSS.setCdmaEriIconMode(phone.mEriManager.getCdmaEriIconMode(roamingIndicator, + mDefaultRoamingIndicator)); + // NOTE: Some operator may require overriding mCdmaRoaming // (set by the modem), depending on the mRoamingIndicator. @@ -1001,6 +1027,14 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { boolean hasLocationChanged = !newCellLoc.equals(cellLoc); + // Add an event log when connection state changes + if (ss.getState() != newSS.getState() || + cdmaDataConnectionState != newCdmaDataConnectionState) { + EventLog.writeEvent(EventLogTags.CDMA_SERVICE_STATE_CHANGE, + ss.getState(), cdmaDataConnectionState, + newSS.getState(), newCdmaDataConnectionState); + } + ServiceState tss; tss = ss; ss = newSS; @@ -1023,7 +1057,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } if (hasRegistered) { - Checkin.updateStats(cr, Checkin.Stats.Tag.PHONE_CDMA_REGISTERED, 1, 0.0); networkAttachedRegistrants.notifyRegistrants(); } @@ -1453,10 +1486,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { */ long gained = c.getTimeInMillis() - System.currentTimeMillis(); long timeSinceLastUpdate = SystemClock.elapsedRealtime() - mSavedAtTime; - int nitzUpdateSpacing = Settings.Gservices.getInt(cr, - Settings.Gservices.NITZ_UPDATE_SPACING, mNitzUpdateSpacing); - int nitzUpdateDiff = Settings.Gservices.getInt(cr, - Settings.Gservices.NITZ_UPDATE_DIFF, mNitzUpdateDiff); + int nitzUpdateSpacing = Settings.Secure.getInt(cr, + Settings.Secure.NITZ_UPDATE_SPACING, mNitzUpdateSpacing); + int nitzUpdateDiff = Settings.Secure.getInt(cr, + Settings.Secure.NITZ_UPDATE_DIFF, mNitzUpdateDiff); if ((mSavedAtTime == 0) || (timeSinceLastUpdate > nitzUpdateSpacing) || (Math.abs(gained) > nitzUpdateDiff)) { @@ -1512,6 +1545,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); alarm.setTimeZone(zoneId); Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra("time-zone", zoneId); phone.getContext().sendStickyBroadcast(intent); } @@ -1525,6 +1559,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { private void setAndBroadcastNetworkSetTime(long time) { SystemClock.setCurrentTimeMillis(time); Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra("time", time); phone.getContext().sendStickyBroadcast(intent); } @@ -1600,9 +1635,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { * Returns IMSI as MCC + MNC + MIN */ String getImsi() { - // TODO(Moto): When RUIM is enabled, IMSI will come from RUIM - // not build-time props. Moto will provide implementation - // for RUIM-ready case later. + // TODO: When RUIM is enabled, IMSI will come from RUIM not build-time props. String operatorNumeric = SystemProperties.get( TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, ""); @@ -1632,11 +1665,19 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { if (mPendingRadioPowerOffAfterDataOff) { if (DBG) log("Process pending request to turn radio off."); removeMessages(EVENT_SET_RADIO_POWER_OFF); - cm.setRadioPower(false, null); + hangupAndPowerOff(); mPendingRadioPowerOffAfterDataOff = false; return true; } return false; } } + + private void hangupAndPowerOff() { + // hang up all active voice calls + phone.mCT.ringingCall.hangupIfAlive(); + phone.mCT.backgroundCall.hangupIfAlive(); + phone.mCT.foregroundCall.hangupIfAlive(); + cm.setRadioPower(false, null); + } } diff --git a/telephony/java/com/android/internal/telephony/cdma/EriInfo.java b/telephony/java/com/android/internal/telephony/cdma/EriInfo.java index 5c8e23e..3e5d37e 100644 --- a/telephony/java/com/android/internal/telephony/cdma/EriInfo.java +++ b/telephony/java/com/android/internal/telephony/cdma/EriInfo.java @@ -1,4 +1,6 @@ /* + * Copyright (C) 2009 The Android Open Source Project + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at diff --git a/telephony/java/com/android/internal/telephony/cdma/EriManager.java b/telephony/java/com/android/internal/telephony/cdma/EriManager.java index 083fa0b..1bcc90a 100644 --- a/telephony/java/com/android/internal/telephony/cdma/EriManager.java +++ b/telephony/java/com/android/internal/telephony/cdma/EriManager.java @@ -1,4 +1,6 @@ /* + * Copyright (C) 2009 The Android Open Source Project + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -23,9 +25,9 @@ import android.util.Xml; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneBase; - import com.android.internal.util.XmlUtils; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java index 78e89d5..6e12f24 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java @@ -16,22 +16,10 @@ package com.android.internal.telephony.cdma; -import android.content.pm.PackageManager; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Looper; import android.os.Message; -import android.os.ServiceManager; -import android.telephony.PhoneNumberUtils; import android.util.Log; -import com.android.internal.telephony.AdnRecord; -import com.android.internal.telephony.AdnRecordCache; import com.android.internal.telephony.IccPhoneBookInterfaceManager; -import com.android.internal.telephony.PhoneProxy; - -import java.util.ArrayList; -import java.util.List; /** * RuimPhoneBookInterfaceManager to provide an inter-process communication to @@ -42,20 +30,6 @@ import java.util.List; public class RuimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager { static final String LOG_TAG = "CDMA"; - - Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - AsyncResult ar; - - switch(msg.what) { - default: - mBaseHandler.handleMessage(msg); - break; - } - } - }; - public RuimPhoneBookInterfaceManager(CDMAPhone phone) { super(phone); adnCache = phone.mRuimRecords.getAdnCache(); @@ -67,6 +41,11 @@ public class RuimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager } protected void finalize() { + try { + super.finalize(); + } catch (Throwable throwable) { + Log.e(LOG_TAG, "Error while finalizing:", throwable); + } if(DBG) Log.d(LOG_TAG, "RuimPhoneBookInterfaceManager finalized"); } diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java index b9ece8b..87b0c60 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java @@ -166,10 +166,8 @@ public final class RuimRecords extends IccRecords { return null; } - // TODO(Moto): mncLength is not set anywhere. if (mncLength != UNINITIALIZED && mncLength != UNKNOWN) { // Length = length of MCC + length of MNC - // TODO: change spec name // length of mcc = 3 (3GPP2 C.S0005 - Section 2.3) return mImsi.substring(0, 3 + mncLength); } diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java index 9439359..cfcfd98 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java @@ -30,6 +30,7 @@ import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.SmsRawData; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import static android.telephony.SmsManager.STATUS_ON_ICC_FREE; @@ -89,6 +90,11 @@ public class RuimSmsInterfaceManager extends IccSmsInterfaceManager { } protected void finalize() { + try { + super.finalize(); + } catch (Throwable throwable) { + Log.e(LOG_TAG, "Error while finalizing:", throwable); + } if(DBG) Log.d(LOG_TAG, "RuimSmsInterfaceManager finalized"); } @@ -143,7 +149,7 @@ public class RuimSmsInterfaceManager extends IccSmsInterfaceManager { public boolean copyMessageToIccEf(int status, byte[] pdu, byte[] smsc) { //NOTE smsc not used in RUIM if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " + - "pdu=("+ pdu + ")"); + "pdu=("+ Arrays.toString(pdu) + ")"); enforceReceiveAndSend("Copying message to RUIM"); synchronized(mLock) { mSuccess = false; diff --git a/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java index 4b88057..a149e72 100644 --- a/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java +++ b/telephony/java/com/android/internal/telephony/cdma/SignalToneUtil.java @@ -167,7 +167,7 @@ public class SignalToneUtil { IS95_CONST_IR_SIG_TONE_ANSWER), ToneGenerator.TONE_CDMA_ANSWER); hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, - IS95_CONST_IR_SIG_TONE_ABB_RE), ToneGenerator.TONE_CDMA_NETWORK_CALLWAITING); + IS95_CONST_IR_SIG_TONE_CALL_W), ToneGenerator.TONE_CDMA_NETWORK_CALLWAITING); hm.put(signalParamHash(IS95_CONST_IR_SIGNAL_TONE, TAPIAMSSCDMA_SIGNAL_PITCH_UNKNOWN, IS95_CONST_IR_SIG_TONE_PIP), ToneGenerator.TONE_CDMA_PIP); diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java index 3e491d1..403b7a1 100755 --- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -458,11 +458,22 @@ public class SmsMessage extends SmsMessageBase { * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_VMN}, * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WAP} */ - public int getTeleService() { + /* package */ int getTeleService() { return mEnvelope.teleService; } /** + * Returns the message type of the message. + * @return the message type: + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_POINT_TO_POINT}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_BROADCAST}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_ACKNOWLEDGE}, + */ + /* package */ int getMessageType() { + return mEnvelope.messageType; + } + + /** * Decodes pdu to an empty SMS object. * In the CDMA case the pdu is just an internal byte stream representation * of the SMS Java-object. diff --git a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java index 8d807fd..4cbfc87 100644 --- a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java +++ b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java @@ -32,12 +32,12 @@ public class ApnSetting { String user; String password; int authType; - String[] types; + public String[] types; int id; String numeric; - ApnSetting(int id, String numeric, String carrier, String apn, String proxy, String port, + public ApnSetting(int id, String numeric, String carrier, String apn, String proxy, String port, String mmsc, String mmsProxy, String mmsPort, String user, String password, int authType, String[] types) { this.id = id; @@ -73,7 +73,7 @@ public class ApnSetting { return sb.toString(); } - boolean canHandleType(String type) { + public boolean canHandleType(String type) { for (String t : types) { // DEFAULT handles all, and HIPRI is handled by DEFAULT if (t.equals(type) || t.equals(Phone.APN_TYPE_ALL) || diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index b0de4f5..c7b1e5c 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -294,15 +294,7 @@ public class GSMPhone extends PhoneBase { public DataState getDataConnectionState() { DataState ret = DataState.DISCONNECTED; - if ((SystemProperties.get("adb.connected", "").length() > 0) - && (SystemProperties.get("android.net.use-adb-networking", "") - .length() > 0)) { - // We're connected to an ADB host and we have USB networking - // turned on. No matter what the radio state is, - // we report data connected - - ret = DataState.CONNECTED; - } else if (mSST == null) { + if (mSST == null) { // Radio Technology Change is ongoning, dispose() and removeReferences() have // already been called @@ -735,7 +727,7 @@ public class GSMPhone extends PhoneBase { } // Only look at the Network portion for mmi - String networkPortion = PhoneNumberUtils.extractNetworkPortion(newDialString); + String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString); GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this); if (LOCAL_DEBUG) Log.d(LOG_TAG, "dialing w/ mmi '" + mmi + "'..."); @@ -1064,33 +1056,10 @@ public class GSMPhone extends PhoneBase { return mCT.getMute(); } - /** - * @deprecated Do not use. - */ - @Deprecated - public void getPdpContextList(Message response) { - getDataCallList(response); - } - public void getDataCallList(Message response) { mCM.getDataCallList(response); } - /** - * @deprecated Do not use. - */ - @Deprecated - public List<PdpConnection> getCurrentPdpList() { - ArrayList<DataConnection> connections = new ArrayList<DataConnection>(); - ArrayList<PdpConnection> pdp_list = new ArrayList<PdpConnection>(); - - for(int n = 0; n < connections.size(); n++) { - pdp_list.add((PdpConnection) connections.get(n)); - } - - return pdp_list; - } - public List<DataConnection> getCurrentDataConnectionList () { return mDataConnection.getAllDataConnections(); } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java index b82fefd..22fc13e 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java @@ -16,11 +16,16 @@ package com.android.internal.telephony.gsm; -import android.os.*; -import android.telephony.gsm.GsmCellLocation; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.os.Registrant; +import android.os.RegistrantList; +import android.os.SystemProperties; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; import android.telephony.TelephonyManager; +import android.telephony.gsm.GsmCellLocation; import android.util.EventLog; import android.util.Log; @@ -29,14 +34,14 @@ import com.android.internal.telephony.CallTracker; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; import com.android.internal.telephony.DriverCall; +import com.android.internal.telephony.EventLogTags; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.UUSInfo; import com.android.internal.telephony.gsm.CallFailCause; +import com.android.internal.telephony.gsm.GSMPhone; import com.android.internal.telephony.gsm.GsmCall; import com.android.internal.telephony.gsm.GsmConnection; -import com.android.internal.telephony.gsm.GSMPhone; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.TelephonyEventLog; -import com.android.internal.telephony.*; import java.util.List; import java.util.ArrayList; @@ -878,13 +883,10 @@ public final class GsmCallTracker extends CallTracker { causeCode == CallFailCause.QOS_NOT_AVAIL || causeCode == CallFailCause.BEARER_NOT_AVAIL || causeCode == CallFailCause.ERROR_UNSPECIFIED) { - int cid = -1; GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); - if (loc != null) cid = loc.getCid(); - - EventLog.List val = new EventLog.List(causeCode, cid, - TelephonyManager.getDefault().getNetworkType()); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CALL_DROP, val); + EventLog.writeEvent(EventLogTags.CALL_DROP, + causeCode, loc != null ? loc.getCid() : -1, + TelephonyManager.getDefault().getNetworkType()); } for (int i = 0, s = droppedDuringPoll.size() diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java index 0024c9b..7dc2504 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java @@ -146,7 +146,7 @@ public class GsmConnection extends Connection { this.dialString = dialString; - this.address = PhoneNumberUtils.extractNetworkPortion(dialString); + this.address = PhoneNumberUtils.extractNetworkPortionAlt(dialString); this.postDialString = PhoneNumberUtils.extractPostDialPortion(dialString); index = -1; diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java new file mode 100644 index 0000000..d893ec4 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.gsm; + +import android.os.Message; +import android.util.Log; +import android.util.Patterns; + +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.RILConstants; + +/** + * {@hide} + */ +public class GsmDataConnection extends DataConnection { + + private static final String LOG_TAG = "GSM"; + + /** Fail cause of last PDP activate, from RIL_LastPDPActivateFailCause */ + private static final int PDP_FAIL_OPERATOR_BARRED = 0x08; + private static final int PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A; + private static final int PDP_FAIL_MISSING_UKNOWN_APN = 0x1B; + private static final int PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C; + private static final int PDP_FAIL_USER_AUTHENTICATION = 0x1D; + private static final int PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E; + private static final int PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F; + private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20; + private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21; + private static final int PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22; + private static final int PDP_FAIL_NSAPI_IN_USE = 0x23; + private static final int PDP_FAIL_PROTOCOL_ERRORS = 0x6F; + private static final int PDP_FAIL_ERROR_UNSPECIFIED = 0xffff; + + private static final int PDP_FAIL_REGISTRATION_FAIL = -1; + private static final int PDP_FAIL_GPRS_REGISTRATION_FAIL = -2; + + //***** Instance Variables + private ApnSetting apn; + + //***** Constructor + private GsmDataConnection(GSMPhone phone, String name) { + super(phone, name); + } + + /** + * Create the connection object + * + * @param phone + * @return GsmDataConnection that was created. + */ + static GsmDataConnection makeDataConnection(GSMPhone phone) { + synchronized (mCountLock) { + mCount += 1; + } + GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount); + gsmDc.start(); + if (DBG) gsmDc.log("Made " + gsmDc.getName()); + return gsmDc; + } + + /** + * Begin setting up a data connection, calls setupDataCall + * and the ConnectionParams will be returned with the + * EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj. + * + * @param cp is the connection parameters + */ + @Override + protected + void onConnect(ConnectionParams cp) { + apn = cp.apn; + + if (DBG) log("Connecting to carrier: '" + apn.carrier + + "' APN: '" + apn.apn + + "' proxy: '" + apn.proxy + "' port: '" + apn.port); + + setHttpProxy (apn.proxy, apn.port); + + createTime = -1; + lastFailTime = -1; + lastFailCause = FailCause.NONE; + + // msg.obj will be returned in AsyncResult.userObj; + Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp); + msg.obj = cp; + + int authType = apn.authType; + if (authType == -1) { + authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP : + RILConstants.SETUP_DATA_AUTH_NONE; + } + phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_GSM), + Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), apn.apn, apn.user, + apn.password, Integer.toString(authType), msg); + } + + @Override + protected void clearSettings() { + super.clearSettings(); + apn = null; + } + + @Override + public String toString() { + return "State=" + getCurrentState().getName() + " Apn=" + apn + + " create=" + createTime + " lastFail=" + lastFailTime + + " lastFailCause=" + lastFailCause; + } + + @Override + protected FailCause getFailCauseFromRequest(int rilCause) { + FailCause cause; + + switch (rilCause) { + case PDP_FAIL_OPERATOR_BARRED: + cause = FailCause.OPERATOR_BARRED; + break; + case PDP_FAIL_INSUFFICIENT_RESOURCES: + cause = FailCause.INSUFFICIENT_RESOURCES; + break; + case PDP_FAIL_MISSING_UKNOWN_APN: + cause = FailCause.MISSING_UKNOWN_APN; + break; + case PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE: + cause = FailCause.UNKNOWN_PDP_ADDRESS; + break; + case PDP_FAIL_USER_AUTHENTICATION: + cause = FailCause.USER_AUTHENTICATION; + break; + case PDP_FAIL_ACTIVATION_REJECT_GGSN: + cause = FailCause.ACTIVATION_REJECT_GGSN; + break; + case PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED: + cause = FailCause.ACTIVATION_REJECT_UNSPECIFIED; + break; + case PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER: + cause = FailCause.SERVICE_OPTION_OUT_OF_ORDER; + break; + case PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED: + cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED; + break; + case PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED: + cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED; + break; + case PDP_FAIL_NSAPI_IN_USE: + cause = FailCause.NSAPI_IN_USE; + break; + case PDP_FAIL_PROTOCOL_ERRORS: + cause = FailCause.PROTOCOL_ERRORS; + break; + case PDP_FAIL_ERROR_UNSPECIFIED: + cause = FailCause.UNKNOWN; + break; + case PDP_FAIL_REGISTRATION_FAIL: + cause = FailCause.REGISTRATION_FAIL; + break; + case PDP_FAIL_GPRS_REGISTRATION_FAIL: + cause = FailCause.GPRS_REGISTRATION_FAIL; + break; + default: + cause = FailCause.UNKNOWN; + } + return cause; + } + + @Override + protected boolean isDnsOk(String[] domainNameServers) { + if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[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 + // if Proxy is an IP-address. + // Otherwise, the default APN will not be restored anymore. + if (!apn.types[0].equals(Phone.APN_TYPE_MMS) + || !isIpAddress(apn.mmsProxy)) { + return false; + } + } + return true; + } + + @Override + protected void log(String s) { + Log.d(LOG_TAG, "[" + getName() + "] " + s); + } + + public ApnSetting getApn() { + return this.apn; + } + + private void setHttpProxy(String httpProxy, String httpPort) { + if (httpProxy == null || httpProxy.length() == 0) { + phone.setSystemProperty("net.gprs.http-proxy", null); + return; + } + + if (httpPort == null || httpPort.length() == 0) { + httpPort = "8080"; // Default to port 8080 + } + + phone.setSystemProperty("net.gprs.http-proxy", + "http://" + httpProxy + ":" + httpPort + "/"); + } + + private boolean isIpAddress(String address) { + if (address == null) return false; + + return Patterns.IP_ADDRESS.matcher(apn.mmsProxy).matches(); + } +} diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index 7b60474..cbfb550 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -27,18 +27,19 @@ 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.TrafficStats; import android.net.Uri; import android.net.wifi.WifiManager; import android.os.AsyncResult; -import android.os.INetStatService; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.preference.PreferenceManager; -import android.provider.Checkin; import android.provider.Settings; import android.provider.Telephony; import android.telephony.ServiceState; @@ -53,7 +54,7 @@ import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.Phone; import com.android.internal.telephony.RetryManager; -import com.android.internal.telephony.TelephonyEventLog; +import com.android.internal.telephony.EventLogTags; import com.android.internal.telephony.DataConnection.FailCause; import java.io.IOException; @@ -82,7 +83,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { //***** Instance Variables - INetStatService netstat; // Indicates baseband will not auto-attach private boolean noAutoAttach = false; @@ -126,8 +126,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { */ private ArrayList<DataConnection> pdpList; - /** Currently active PdpConnection */ - private PdpConnection mActivePdp; + /** Currently active DataConnection */ + private GsmDataConnection mActivePdp; /** Is packet service restricted by network */ private boolean mIsPsRestricted = false; @@ -137,7 +137,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // TODO: Increase this to match the max number of simultaneous // PDP contexts we plan to support. /** - * Pool size of PdpConnection objects. + * Pool size of DataConnection objects. */ private static final int PDP_CONNECTION_POOL_SIZE = 1; @@ -218,8 +218,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { p.mSST.registerForPsRestrictedEnabled(this, EVENT_PS_RESTRICT_ENABLED, null); p.mSST.registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, null); - this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat")); - IntentFilter filter = new IntentFilter(); filter.addAction(INTENT_RECONNECT_ALARM); filter.addAction(Intent.ACTION_SCREEN_ON); @@ -244,7 +242,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // 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()); - dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false); + 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++; } @@ -301,21 +307,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { protected void setState(State s) { if (DBG) log ("setState: " + s); if (state != s) { - if (s == State.INITING) { // request PDP context - Checkin.updateStats( - phone.getContext().getContentResolver(), - Checkin.Stats.Tag.PHONE_GPRS_ATTEMPTED, 1, 0.0); - } - - if (s == State.CONNECTED) { // pppd is up - Checkin.updateStats( - phone.getContext().getContentResolver(), - Checkin.Stats.Tag.PHONE_GPRS_CONNECTED, 1, 0.0); - } + EventLog.writeEvent(EventLogTags.GSM_DATA_STATE_CHANGE, state.toString(), s.toString()); + state = s; } - state = s; - if (state == State.FAILED) { if (waitingApns != null) waitingApns.clear(); // when teardown the connection and set to IDLE @@ -382,7 +377,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } /** - * Formerly this method was ArrayList<PdpConnection> getAllPdps() + * Formerly this method was ArrayList<GsmDataConnection> getAllPdps() */ public ArrayList<DataConnection> getAllDataConnections() { ArrayList<DataConnection> pdps = (ArrayList<DataConnection>)pdpList.clone(); @@ -452,7 +447,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { waitingApns = buildWaitingApns(); if (waitingApns.isEmpty()) { if (DBG) log("No APN found"); - notifyNoData(PdpConnection.FailCause.MISSING_UKNOWN_APN); + notifyNoData(GsmDataConnection.FailCause.MISSING_UKNOWN_APN); return false; } else { log ("Create from allApns : " + apnListToString(allApns)); @@ -487,7 +482,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * 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 PdpConnection should be + * @param tearDown true if the underlying GsmDataConnection should be * disconnected. * @param reason reason for the clean up. */ @@ -504,21 +499,23 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { setState(State.DISCONNECTING); + boolean notificationDeferred = false; for (DataConnection conn : pdpList) { - PdpConnection pdp = (PdpConnection) conn; if (tearDown) { - Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason); - pdp.disconnect(msg); + if (DBG) log("cleanUpConnection: teardown, call conn.disconnect"); + conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE, reason)); + notificationDeferred = true; } else { - pdp.clearSettings(); + if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously"); + conn.resetSynchronously(); + notificationDeferred = false; } } stopNetStatPoll(); - if (!tearDown) { - setState(State.IDLE); - phone.notifyDataConnection(reason); - mActiveApn = null; + if (!notificationDeferred) { + if (DBG) log("cleanupConnection: !notificationDeferred"); + gotoIdleAndNotifyDataConnection(reason); } } @@ -564,10 +561,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return result; } - private PdpConnection findFreePdp() { + private GsmDataConnection findFreePdp() { for (DataConnection conn : pdpList) { - PdpConnection pdp = (PdpConnection) conn; - if (pdp.getState() == DataConnection.State.INACTIVE) { + GsmDataConnection pdp = (GsmDataConnection) conn; + if (pdp.isInactive()) { return pdp; } } @@ -576,13 +573,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private boolean setupData(String reason) { ApnSetting apn; - PdpConnection pdp; + GsmDataConnection pdp; apn = getNextApn(); if (apn == null) return false; pdp = findFreePdp(); if (pdp == null) { - if (DBG) log("setupData: No free PdpConnection found!"); + if (DBG) log("setupData: No free GsmDataConnection found!"); return false; } mActiveApn = apn; @@ -591,7 +588,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { Message msg = obtainMessage(); msg.what = EVENT_DATA_SETUP_COMPLETE; msg.obj = reason; - pdp.connect(apn, msg); + pdp.connect(msg, apn); setState(State.INITING); phone.notifyDataConnection(reason); @@ -711,12 +708,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting"); // Add an event log when the network drops PDP - int cid = -1; GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); - if (loc != null) cid = loc.getCid(); - EventLog.List val = new EventLog.List(cid, + EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, + loc != null ? loc.getCid() : -1, TelephonyManager.getDefault().getNetworkType()); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val); cleanUpConnection(true, null); return; @@ -734,12 +729,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { + " Reconnecting"); // Log the network drop on the event log. - int cid = -1; GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); - if (loc != null) cid = loc.getCid(); - EventLog.List val = new EventLog.List(cid, + EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, + loc != null ? loc.getCid() : -1, TelephonyManager.getDefault().getNetworkType()); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val); cleanUpConnection(true, null); } @@ -756,6 +749,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { mReregisterOnReconnectFailure = false; } + private void gotoIdleAndNotifyDataConnection(String reason) { + if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason); + setState(State.IDLE); + phone.notifyDataConnection(reason); + mActiveApn = null; + } + /** * This is a kludge to deal with the fact that * the PDP state change notification doesn't always work @@ -778,16 +778,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private void doRecovery() { if (state == State.CONNECTED) { - int maxPdpReset = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT, + 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(TelephonyEventLog.EVENT_LOG_PDP_RESET, sentSinceLastRecv); + EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, sentSinceLastRecv); cleanUpConnection(true, Phone.REASON_PDP_RESET); } else { mPdpResetCount = 0; - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_REREGISTER_NETWORK, sentSinceLastRecv); + EventLog.writeEvent(EventLogTags.PDP_REREGISTER_NETWORK, sentSinceLastRecv); mGsmPhone.mSST.reRegisterNetwork(null); } // TODO: Add increasingly drastic recovery steps, eg, @@ -813,7 +813,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { protected void restartRadio() { Log.d(LOG_TAG, "************TURN OFF RADIO**************"); cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); - phone.mCM.setRadioPower(false, null); + mGsmPhone.mSST.powerOffRadioSafely(); /* 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 @@ -838,13 +838,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { preTxPkts = txPkts; preRxPkts = rxPkts; - try { - txPkts = netstat.getMobileTxPackets(); - rxPkts = netstat.getMobileRxPackets(); - } catch (RemoteException e) { - txPkts = 0; - rxPkts = 0; - } + txPkts = TrafficStats.getMobileTxPackets(); + rxPkts = TrafficStats.getMobileRxPackets(); //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); @@ -880,19 +875,19 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } - int watchdogTrigger = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, + int watchdogTrigger = Settings.Secure.getInt(mResolver, + Settings.Secure.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, NUMBER_SENT_PACKETS_OF_HANG); if (sentSinceLastRecv >= watchdogTrigger) { // we already have NUMBER_SENT_PACKETS sent without ack if (mNoRecvPollCount == 0) { - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED, + EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET_COUNTDOWN_TRIGGERED, sentSinceLastRecv); } - int noRecvPollLimit = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_COUNT, NO_RECV_POLL_LIMIT); + int noRecvPollLimit = Settings.Secure.getInt(mResolver, + Settings.Secure.PDP_WATCHDOG_ERROR_POLL_COUNT, NO_RECV_POLL_LIMIT); if (mNoRecvPollCount < noRecvPollLimit) { // It's possible the PDP context went down and we weren't notified. @@ -903,8 +898,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { mNoRecvPollCount++; // Slow down the poll interval to let things happen - netStatPollPeriod = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, + netStatPollPeriod = Settings.Secure.getInt(mResolver, + Settings.Secure.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, POLL_NETSTAT_SLOW_MILLIS); } else { if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + @@ -923,11 +918,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } else { mNoRecvPollCount = 0; if (mIsScreenOn) { - netStatPollPeriod = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); + netStatPollPeriod = Settings.Secure.getInt(mResolver, + Settings.Secure.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); } else { - netStatPollPeriod = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, + netStatPollPeriod = Settings.Secure.getInt(mResolver, + Settings.Secure.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, POLL_NETSTAT_SCREEN_OFF_MILLIS); } } @@ -941,10 +936,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private void runPingTest () { int status = -1; try { - String address = Settings.Gservices.getString(mResolver, - Settings.Gservices.PDP_WATCHDOG_PING_ADDRESS); - int deadline = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_PING_DEADLINE, DEFAULT_PING_DEADLINE); + String address = Settings.Secure.getString(mResolver, + Settings.Secure.PDP_WATCHDOG_PING_ADDRESS); + int deadline = Settings.Secure.getInt(mResolver, + Settings.Secure.PDP_WATCHDOG_PING_DEADLINE, DEFAULT_PING_DEADLINE); if (DBG) log("pinging " + address + " for " + deadline + "s"); if (address != null && !NULL_IP.equals(address)) { Process p = Runtime.getRuntime() @@ -960,7 +955,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (status == 0) { // ping succeeded. False alarm. Reset netStatPoll. // ("-1" for this event indicates a false alarm) - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_RESET, -1); + EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, -1); mPdpResetCount = 0; sendMessage(obtainMessage(EVENT_START_NETSTAT_POLL)); } else { @@ -974,13 +969,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * seems like it deserves an error notification. * Transient errors are ignored */ - private boolean shouldPostNotification(PdpConnection.FailCause cause) { - boolean shouldPost = true; - // TODO CHECK - // if (dataLink != null) { - // shouldPost = dataLink.getLastLinkExitCode() != DataLink.EXIT_OPEN_FAILED; - //} - return (shouldPost && cause != PdpConnection.FailCause.UNKNOWN); + private boolean shouldPostNotification(GsmDataConnection.FailCause cause) { + return (cause != GsmDataConnection.FailCause.UNKNOWN); } /** @@ -1046,7 +1036,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } - private void notifyNoData(PdpConnection.FailCause lastFailCauseCode) { + private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode) { setState(State.FAILED); } @@ -1069,7 +1059,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { mRetryMgr.resetRetryCount(); // TODO: To support simultaneous PDP contexts, this should really only call - // cleanUpConnection if it needs to free up a PdpConnection. + // cleanUpConnection if it needs to free up a GsmDataConnection. cleanUpConnection(true, Phone.REASON_APN_SWITCHED); } @@ -1149,19 +1139,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // that the existing connection may service that type, in which // case we should try the next type, etc. } else { - PdpConnection.FailCause cause; - cause = (PdpConnection.FailCause) (ar.result); + GsmDataConnection.FailCause cause; + cause = (GsmDataConnection.FailCause) (ar.result); if(DBG) log("PDP setup failed " + cause); // Log this failure to the Event Logs. if (cause.isEventLoggable()) { - int cid = -1; GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); - if (loc != null) cid = loc.getCid(); - - EventLog.List val = new EventLog.List( - cause.ordinal(), cid, + EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL, + cause.ordinal(), loc != null ? loc.getCid() : -1, TelephonyManager.getDefault().getNetworkType()); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL, val); } // No try for permanent failure @@ -1188,6 +1174,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + /** + * Called when EVENT_DISCONNECT_DONE is received. + */ protected void onDisconnectDone(AsyncResult ar) { String reason = null; if(DBG) log("EVENT_DISCONNECT_DONE"); @@ -1202,6 +1191,19 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } + /** + * Called when EVENT_RESET_DONE is received. + */ + @Override + protected void onResetDone(AsyncResult ar) { + if (DBG) log("EVENT_RESET_DONE"); + String reason = null; + if (ar.userObj instanceof String) { + reason = (String) ar.userObj; + } + gotoIdleAndNotifyDataConnection(reason); + } + protected void onPollPdp() { if (state == State.CONNECTED) { // only poll when connected @@ -1259,9 +1261,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { 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 PdpConnection + // writes the pap-secrets file. No longer tied to GsmDataConnection // object. Not used on current platform (no ppp). - //PdpConnection pdp = pdpList.get(pdp_name); + //GsmDataConnection pdp = pdpList.get(pdp_name); //if (pdp != null && pdp.dataLink != null) { // pdp.dataLink.setPasswordInfo(cursor); //} @@ -1273,7 +1275,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (allApns.isEmpty()) { if (DBG) log("No APN found for carrier: " + operator); preferredApn = null; - notifyNoData(PdpConnection.FailCause.MISSING_UKNOWN_APN); + notifyNoData(GsmDataConnection.FailCause.MISSING_UKNOWN_APN); } else { preferredApn = getPreferredApn(); Log.d(LOG_TAG, "Get PreferredAPN"); @@ -1289,14 +1291,14 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { DataConnection pdp; for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) { - pdp = new PdpConnection(mGsmPhone); + pdp = GsmDataConnection.makeDataConnection(mGsmPhone); pdpList.add(pdp); } } private void destroyAllPdpList() { if(pdpList != null) { - PdpConnection pdp; + GsmDataConnection pdp; pdpList.removeAll(pdpList); } } @@ -1361,7 +1363,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return result.toString(); } - private void startDelayedRetry(PdpConnection.FailCause cause, String reason) { + private void startDelayedRetry(GsmDataConnection.FailCause cause, String reason) { notifyNoData(cause); reconnectAfterFail(cause, reason); } @@ -1417,6 +1419,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { public void handleMessage (Message msg) { if (DBG) Log.d(LOG_TAG,"GSMDataConnTrack handleMessage "+msg); + + if (!mGsmPhone.mIsTheCurrentActivePhone) { + Log.d(LOG_TAG, "Ignore GSM msgs since GSM phone is inactive"); + return; + } + switch (msg.what) { case EVENT_RECORDS_LOADED: onRecordsLoaded(); @@ -1497,5 +1505,4 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { protected void log(String s) { Log.d(LOG_TAG, "[GsmDataConnectionTracker] " + s); } - } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index bc7b7fa..50b8eba 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -35,7 +35,6 @@ import android.os.Registrant; import android.os.RegistrantList; import android.os.SystemClock; import android.os.SystemProperties; -import android.provider.Checkin; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.provider.Telephony.Intents; @@ -52,11 +51,11 @@ 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.TelephonyEventLog; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; @@ -103,7 +102,6 @@ final class GsmServiceStateTracker extends ServiceStateTracker { * Mark when service state is in emergency call only mode */ private boolean mEmergencyOnly = false; - private boolean mNewEmergencyOnly = false; private RegistrantList gprsAttachedRegistrants = new RegistrantList(); private RegistrantList gprsDetachedRegistrants = new RegistrantList(); @@ -507,12 +505,9 @@ final class GsmServiceStateTracker extends ServiceStateTracker { // Can't register data sevice while voice service is ok // i.e. CREG is ok while CGREG is not // possible a network or baseband side error - int cid = -1; GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); - if (loc != null) cid = loc.getCid(); - - EventLog.List val = new EventLog.List(ss.getOperatorNumeric(), cid); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CGREG_FAIL, val); + EventLog.writeEvent(EventLogTags.DATA_NETWORK_REGISTRATION_FAIL, + ss.getOperatorNumeric(), loc != null ? loc.getCid() : -1); mReportedGprsNoReg = true; } mStartedGprsRegCheck = false; @@ -543,32 +538,44 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } else if (!mDesiredPowerState && cm.getRadioState().isOn()) { DataConnectionTracker dcTracker = phone.mDataConnection; if (! dcTracker.isDataConnectionAsDesired()) { - - EventLog.List val = new EventLog.List( - dcTracker.getStateInString(), - (dcTracker.getAnyDataEnabled() ? 1 : 0) ); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_DATA_STATE_RADIO_OFF, val); + EventLog.writeEvent(EventLogTags.DATA_NETWORK_STATUS_ON_RADIO_OFF, + dcTracker.getStateInString(), dcTracker.getAnyDataEnabled() ? 1 : 0); } - Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION); - msg.arg1 = 1; // tearDown is true - msg.obj = GSMPhone.REASON_RADIO_TURNED_OFF; - dcTracker.sendMessage(msg); - - // poll data state up to 15 times, with a 100ms delay - // totaling 1.5 sec. Normal data disable action will finish in 100ms. - for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) { - if (dcTracker.getState() != DataConnectionTracker.State.CONNECTED - && dcTracker.getState() != DataConnectionTracker.State.DISCONNECTING) { - Log.d(LOG_TAG, "Data shutdown complete."); - break; - } - SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS); - } - // If it's on and available and we want it off.. - cm.setRadioPower(false, null); + // If it's on and available and we want it off gracefully + powerOffRadioSafely(); } // Otherwise, we're in the desired state } + @Override + protected void powerOffRadioSafely() { + // clean data connection + DataConnectionTracker dcTracker = phone.mDataConnection; + Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_CONNECTION); + msg.arg1 = 1; // tearDown is true + msg.obj = GSMPhone.REASON_RADIO_TURNED_OFF; + dcTracker.sendMessage(msg); + + // poll data state up to 15 times, with a 100ms delay + // totaling 1.5 sec. Normal data disable action will finish in 100ms. + for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) { + if (dcTracker.getState() != DataConnectionTracker.State.CONNECTED + && dcTracker.getState() != DataConnectionTracker.State.DISCONNECTING) { + Log.d(LOG_TAG, "Data shutdown complete."); + break; + } + SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS); + } + + // hang up all active voice calls + if (phone.isInCall()) { + phone.mCT.ringingCall.hangupIfAlive(); + phone.mCT.backgroundCall.hangupIfAlive(); + phone.mCT.foregroundCall.hangupIfAlive(); + } + + cm.setRadioPower(false, null); + } + protected void updateSpnDisplay() { int rule = phone.mSIMRecords.getDisplayRule(ss.getOperatorNumeric()); String spn = phone.mSIMRecords.getServiceProviderName(); @@ -583,12 +590,13 @@ final class GsmServiceStateTracker extends ServiceStateTracker { if (rule != curSpnRule || !TextUtils.equals(spn, curSpn) || !TextUtils.equals(plmn, curPlmn)) { - boolean showSpn = mEmergencyOnly - || (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN; + boolean showSpn = !mEmergencyOnly + && (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN; boolean showPlmn = (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN; Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn); intent.putExtra(Intents.EXTRA_SPN, spn); intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn); @@ -663,9 +671,9 @@ final class GsmServiceStateTracker extends ServiceStateTracker { newSS.setState (regCodeToServiceState(regState)); if (regState == 10 || regState == 12 || regState == 13 || regState == 14) { - mNewEmergencyOnly = true; + mEmergencyOnly = true; } else { - mNewEmergencyOnly = false; + mEmergencyOnly = false; } // LAC and CID are -1 if not avail @@ -732,6 +740,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { roaming = false; } newSS.setRoaming(roaming); + newSS.setEmergencyOnly(mEmergencyOnly); pollStateDone(); } } @@ -877,7 +886,11 @@ final class GsmServiceStateTracker extends ServiceStateTracker { boolean hasLocationChanged = !newCellLoc.equals(cellLoc); - boolean hasEmergencyOnlyChanged = mNewEmergencyOnly != mEmergencyOnly; + // Add an event log when connection state changes + if (ss.getState() != newSS.getState() || gprsState != newGPRSState) { + EventLog.writeEvent(EventLogTags.GSM_SERVICE_STATE_CHANGE, + ss.getState(), gprsState, newSS.getState(), newGPRSState); + } ServiceState tss; tss = ss; @@ -890,9 +903,6 @@ final class GsmServiceStateTracker extends ServiceStateTracker { cellLoc = newCellLoc; newCellLoc = tcl; - mEmergencyOnly = mNewEmergencyOnly; - - // Add an event log when network type switched // TODO: we may add filtering to reduce the event logged, // i.e. check preferred network setting, only switch to 2G, etc @@ -900,8 +910,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { int cid = -1; GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation()); if (loc != null) cid = loc.getCid(); - EventLog.List val = new EventLog.List(cid, networkType, newNetworkType); - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_GSM_RAT_SWITCHED, val); + EventLog.writeEvent(EventLogTags.GSM_RAT_SWITCHED, cid, networkType, newNetworkType); Log.d(LOG_TAG, "RAT switched " + networkTypeToString(networkType) + " -> " + networkTypeToString(newNetworkType) + " at cell " + cid); @@ -918,14 +927,14 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } if (hasRegistered) { - Checkin.updateStats(phone.getContext().getContentResolver(), - Checkin.Stats.Tag.PHONE_GSM_REGISTERED, 1, 0.0); networkAttachedRegistrants.notifyRegistrants(); } if (hasChanged) { String operatorNumeric; + updateSpnDisplay(); + phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA, ss.getOperatorAlphaLong()); @@ -994,10 +1003,6 @@ final class GsmServiceStateTracker extends ServiceStateTracker { phone.notifyServiceStateChanged(ss); } - if (hasChanged || hasEmergencyOnlyChanged) { - updateSpnDisplay(); - } - if (hasGprsAttached) { gprsAttachedRegistrants.notifyRegistrants(); } @@ -1026,9 +1031,9 @@ final class GsmServiceStateTracker extends ServiceStateTracker { if (!mStartedGprsRegCheck && !mReportedGprsNoReg) { mStartedGprsRegCheck = true; - int check_period = Settings.Gservices.getInt( + int check_period = Settings.Secure.getInt( phone.getContext().getContentResolver(), - Settings.Gservices.GPRS_REGISTER_CHECK_PERIOD_MS, + Settings.Secure.GPRS_REGISTER_CHECK_PERIOD_MS, DEFAULT_GPRS_CHECK_PERIOD_MILLIS); sendMessageDelayed(obtainMessage(EVENT_CHECK_REPORT_GPRS), check_period); @@ -1554,6 +1559,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); alarm.setTimeZone(zoneId); Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra("time-zone", zoneId); phone.getContext().sendStickyBroadcast(intent); } @@ -1567,6 +1573,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { private void setAndBroadcastNetworkSetTime(long time) { SystemClock.setCurrentTimeMillis(time); Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); intent.putExtra("time", time); phone.getContext().sendStickyBroadcast(intent); } @@ -1617,7 +1624,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { notificationId = PS_NOTIFICATION; break; case CS_ENABLED: - details = context.getText(com.android.internal.R.string.RestrictedOnAll);; + details = context.getText(com.android.internal.R.string.RestrictedOnAllVoice);; break; case CS_NORMAL_ENABLED: details = context.getText(com.android.internal.R.string.RestrictedOnNormal);; diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java deleted file mode 100644 index cb85002..0000000 --- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.telephony.gsm; - -import android.os.*; -import android.text.util.Regex; -import android.util.EventLog; -import android.util.Log; - -import com.android.internal.telephony.CommandException; -import com.android.internal.telephony.CommandsInterface; -import com.android.internal.telephony.DataConnection; -import com.android.internal.telephony.DataLink; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.TelephonyEventLog; - -/** - * {@hide} - */ -public class PdpConnection extends DataConnection { - - private static final String LOG_TAG = "GSM"; - private static final boolean DBG = true; - - /** Fail cause of last PDP activate, from RIL_LastPDPActivateFailCause */ - private static final int PDP_FAIL_OPERATOR_BARRED = 0x08; - private static final int PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A; - private static final int PDP_FAIL_MISSING_UKNOWN_APN = 0x1B; - private static final int PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C; - private static final int PDP_FAIL_USER_AUTHENTICATION = 0x1D; - private static final int PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E; - private static final int PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F; - private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20; - private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21; - private static final int PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22; - private static final int PDP_FAIL_NSAPI_IN_USE = 0x23; - private static final int PDP_FAIL_PROTOCOL_ERRORS = 0x6F; - private static final int PDP_FAIL_ERROR_UNSPECIFIED = 0xffff; - - private static final int PDP_FAIL_REGISTRATION_FAIL = -1; - private static final int PDP_FAIL_GPRS_REGISTRATION_FAIL = -2; - - //***** Instance Variables - private String pdp_name; - private ApnSetting apn; - - //***** Constructor - PdpConnection(GSMPhone phone) { - super(phone); - } - - /** - * Setup PDP connection for provided apn - * @param apn for this connection - * @param onCompleted notify success or not after down - */ - void connect(ApnSetting apn, Message onCompleted) { - if (DBG) log("Connecting to carrier: '" + apn.carrier - + "' APN: '" + apn.apn - + "' proxy: '" + apn.proxy + "' port: '" + apn.port); - - setHttpProxy (apn.proxy, apn.port); - - state = State.ACTIVATING; - this.apn = apn; - onConnectCompleted = onCompleted; - createTime = -1; - lastFailTime = -1; - lastFailCause = FailCause.NONE; - receivedDisconnectReq = false; - - int authType = apn.authType; - if (authType == -1) { - authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP : - RILConstants.SETUP_DATA_AUTH_NONE; - } - phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_GSM), - Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), apn.apn, apn.user, - apn.password, Integer.toString(authType), - obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE)); - } - - private void tearDownData(Message msg) { - if (phone.mCM.getRadioState().isOn()) { - phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg)); - } - } - - protected void disconnect(Message msg) { - onDisconnect = msg; - if (state == State.ACTIVE) { - tearDownData(msg); - } else if (state == State.ACTIVATING) { - receivedDisconnectReq = true; - } else { - // state == INACTIVE. Nothing to do, so notify immediately. - notifyDisconnect(msg); - } - } - - public void clearSettings() { - super.clearSettings(); - apn = null; - } - - public String toString() { - return "State=" + state + " Apn=" + apn + - " create=" + createTime + " lastFail=" + lastFailTime + - " lastFailCause=" + lastFailCause; - } - - - protected void notifyFail(FailCause cause, Message onCompleted) { - if (onCompleted == null) return; - - state = State.INACTIVE; - lastFailCause = cause; - lastFailTime = System.currentTimeMillis(); - onConnectCompleted = null; - - if (DBG) { - log("Notify PDP fail at " + lastFailTime + - " due to " + lastFailCause); - } - - AsyncResult.forMessage(onCompleted, cause, new Exception()); - onCompleted.sendToTarget(); - } - - protected void notifySuccess(Message onCompleted) { - if (onCompleted == null) { - return; - } - - state = State.ACTIVE; - createTime = System.currentTimeMillis(); - onConnectCompleted = null; - onCompleted.arg1 = cid; - - if (DBG) log("Notify PDP success at " + createTime); - - AsyncResult.forMessage(onCompleted); - onCompleted.sendToTarget(); - } - - protected void notifyDisconnect(Message msg) { - if (DBG) log("Notify PDP disconnect"); - - if (msg != null) { - AsyncResult.forMessage(msg); - msg.sendToTarget(); - } - clearSettings(); - } - - protected void onLinkStateChanged(DataLink.LinkState linkState) { - switch (linkState) { - case LINK_UP: - notifySuccess(onConnectCompleted); - break; - - case LINK_DOWN: - case LINK_EXITED: - phone.mCM.getLastPdpFailCause( - obtainMessage (EVENT_GET_LAST_FAIL_DONE)); - break; - } - } - - protected FailCause getFailCauseFromRequest(int rilCause) { - FailCause cause; - - switch (rilCause) { - case PDP_FAIL_OPERATOR_BARRED: - cause = FailCause.OPERATOR_BARRED; - break; - case PDP_FAIL_INSUFFICIENT_RESOURCES: - cause = FailCause.INSUFFICIENT_RESOURCES; - break; - case PDP_FAIL_MISSING_UKNOWN_APN: - cause = FailCause.MISSING_UKNOWN_APN; - break; - case PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE: - cause = FailCause.UNKNOWN_PDP_ADDRESS; - break; - case PDP_FAIL_USER_AUTHENTICATION: - cause = FailCause.USER_AUTHENTICATION; - break; - case PDP_FAIL_ACTIVATION_REJECT_GGSN: - cause = FailCause.ACTIVATION_REJECT_GGSN; - break; - case PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED: - cause = FailCause.ACTIVATION_REJECT_UNSPECIFIED; - break; - case PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER: - cause = FailCause.SERVICE_OPTION_OUT_OF_ORDER; - break; - case PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED: - cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED; - break; - case PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED: - cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED; - break; - case PDP_FAIL_NSAPI_IN_USE: - cause = FailCause.NSAPI_IN_USE; - break; - case PDP_FAIL_PROTOCOL_ERRORS: - cause = FailCause.PROTOCOL_ERRORS; - break; - case PDP_FAIL_ERROR_UNSPECIFIED: - cause = FailCause.UNKNOWN; - break; - case PDP_FAIL_REGISTRATION_FAIL: - cause = FailCause.REGISTRATION_FAIL; - break; - case PDP_FAIL_GPRS_REGISTRATION_FAIL: - cause = FailCause.GPRS_REGISTRATION_FAIL; - break; - default: - cause = FailCause.UNKNOWN; - } - return cause; - } - - protected void log(String s) { - Log.d(LOG_TAG, "[PdpConnection] " + s); - } - - @Override - protected void onDeactivated(AsyncResult ar) { - notifyDisconnect((Message) ar.userObj); - if (DBG) log("PDP Connection Deactivated"); - } - - @Override - protected void onSetupConnectionCompleted(AsyncResult ar) { - if (ar.exception != null) { - Log.e(LOG_TAG, "PDP Context Init failed " + ar.exception); - - if (receivedDisconnectReq) { - // Don't bother reporting the error if there's already a - // pending disconnect request, since DataConnectionTracker - // has already updated its state. - notifyDisconnect(onDisconnect); - } else { - if ( ar.exception instanceof CommandException && - ((CommandException) (ar.exception)).getCommandError() - == CommandException.Error.RADIO_NOT_AVAILABLE) { - notifyFail(FailCause.RADIO_NOT_AVAILABLE, - onConnectCompleted); - } else { - phone.mCM.getLastPdpFailCause( - obtainMessage(EVENT_GET_LAST_FAIL_DONE)); - } - } - } else { - if (receivedDisconnectReq) { - // Don't bother reporting success if there's already a - // pending disconnect request, since DataConnectionTracker - // has already updated its state. - tearDownData(onDisconnect); - } else { - String[] response = ((String[]) ar.result); - cid = Integer.parseInt(response[0]); - - if (response.length > 2) { - interfaceName = response[1]; - ipAddress = response[2]; - String prefix = "net." + interfaceName + "."; - gatewayAddress = SystemProperties.get(prefix + "gw"); - 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 (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[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 - // if Proxy is an IP-address. - // Otherwise, the default APN will not be restored anymore. - if (!apn.types[0].equals(Phone.APN_TYPE_MMS) - || !isIpAddress(apn.mmsProxy)) { - EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS, - dnsServers[0]); - phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY)); - return; - } - } - } - - onLinkStateChanged(DataLink.LinkState.LINK_UP); - - if (DBG) log("PDP setup on cid = " + cid); - } - } - } - - private boolean isIpAddress(String address) { - if (address == null) return false; - - return Regex.IP_ADDRESS_PATTERN.matcher(apn.mmsProxy).matches(); - } - - public ApnSetting getApn() { - return this.apn; - } -} diff --git a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java index 076da6b..feb508a 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java @@ -16,22 +16,10 @@ package com.android.internal.telephony.gsm; -import android.content.pm.PackageManager; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Looper; import android.os.Message; -import android.os.ServiceManager; -import android.telephony.PhoneNumberUtils; import android.util.Log; -import com.android.internal.telephony.AdnRecord; -import com.android.internal.telephony.AdnRecordCache; import com.android.internal.telephony.IccPhoneBookInterfaceManager; -import com.android.internal.telephony.PhoneProxy; - -import java.util.ArrayList; -import java.util.List; /** * SimPhoneBookInterfaceManager to provide an inter-process communication to @@ -42,20 +30,6 @@ import java.util.List; public class SimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager { static final String LOG_TAG = "GSM"; - - Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - AsyncResult ar; - - switch(msg.what) { - default: - mBaseHandler.handleMessage(msg); - break; - } - } - }; - public SimPhoneBookInterfaceManager(GSMPhone phone) { super(phone); adnCache = phone.mSIMRecords.getAdnCache(); @@ -67,6 +41,11 @@ public class SimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager { } protected void finalize() { + try { + super.finalize(); + } catch (Throwable throwable) { + Log.e(LOG_TAG, "Error while finalizing:", throwable); + } if(DBG) Log.d(LOG_TAG, "SimPhoneBookInterfaceManager finalized"); } diff --git a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java index 875d8d0..2028ca4 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java @@ -25,10 +25,10 @@ import android.util.Log; import com.android.internal.telephony.IccConstants; import com.android.internal.telephony.IccSmsInterfaceManager; import com.android.internal.telephony.IccUtils; -import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.SmsRawData; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import static android.telephony.SmsManager.STATUS_ON_ICC_FREE; @@ -65,8 +65,7 @@ public class SimSmsInterfaceManager 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) @@ -88,6 +87,11 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { } protected void finalize() { + try { + super.finalize(); + } catch (Throwable throwable) { + Log.e(LOG_TAG, "Error while finalizing:", throwable); + } if(DBG) Log.d(LOG_TAG, "SimSmsInterfaceManager finalized"); } @@ -106,7 +110,7 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { updateMessageOnIccEf(int index, int status, byte[] pdu) { if (DBG) log("updateMessageOnIccEf: index=" + index + " status=" + status + " ==> " + - "("+ pdu + ")"); + "("+ Arrays.toString(pdu) + ")"); enforceReceiveAndSend("Updating message on SIM"); synchronized(mLock) { mSuccess = false; @@ -118,7 +122,7 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { mPhone.mCM.deleteSmsOnSim(index, response); } else { byte[] record = makeSmsRecordData(status, pdu); - ((SIMFileHandler)mPhone.getIccFileHandler()).updateEFLinearFixed( + mPhone.getIccFileHandler().updateEFLinearFixed( IccConstants.EF_SMS, index, record, null, response); } @@ -142,7 +146,8 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { */ public boolean copyMessageToIccEf(int status, byte[] pdu, byte[] smsc) { if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " + - "pdu=("+ pdu + "), smsm=(" + smsc +")"); + "pdu=("+ Arrays.toString(pdu) + + "), smsm=(" + Arrays.toString(smsc) +")"); enforceReceiveAndSend("Copying message to SIM"); synchronized(mLock) { mSuccess = false; @@ -175,8 +180,7 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { "Reading messages from SIM"); synchronized(mLock) { Message response = mHandler.obtainMessage(EVENT_LOAD_DONE); - ((SIMFileHandler)mPhone.getIccFileHandler()).loadEFLinearFixedAll(IccConstants.EF_SMS, - response); + mPhone.getIccFileHandler().loadEFLinearFixedAll(IccConstants.EF_SMS, response); try { mLock.wait(); diff --git a/telephony/java/com/android/internal/telephony/gsm/SpnOverride.java b/telephony/java/com/android/internal/telephony/gsm/SpnOverride.java index 9ea30101..918c2d2 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SpnOverride.java +++ b/telephony/java/com/android/internal/telephony/gsm/SpnOverride.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.internal.telephony.gsm; import java.io.File; diff --git a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java index 9caae3d..41e527c 100644 --- a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java +++ b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java @@ -409,7 +409,7 @@ public class UsimPhoneBookManager extends Handler implements IccConstants { case USIM_EFIAP_TAG: case USIM_EFSNE_TAG: data = tlv.getData(); - int efid = data[0] << 8 | data[1]; + int efid = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF); val.put(tag, efid); break; } diff --git a/telephony/java/com/android/internal/telephony/gsm/VoiceMailConstants.java b/telephony/java/com/android/internal/telephony/gsm/VoiceMailConstants.java index d4e1f72..0e49e35 100644 --- a/telephony/java/com/android/internal/telephony/gsm/VoiceMailConstants.java +++ b/telephony/java/com/android/internal/telephony/gsm/VoiceMailConstants.java @@ -28,6 +28,7 @@ import java.io.IOException; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; + import com.android.internal.util.XmlUtils; /** diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java index bfde616..ce4c459 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParamsFactory.java @@ -203,7 +203,7 @@ class CommandParamsFactory extends Handler { } private void sendCmdParams(ResultCode resCode) { - mCaller.sendMessageParamsDecoded(resCode, mCmdParams); + mCaller.sendMsgParamsDecoded(resCode, mCmdParams); } /** diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java b/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java index 1cf38ed..a82177c 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/RilMessageDecoder.java @@ -20,18 +20,18 @@ import com.android.internal.telephony.gsm.SIMFileHandler; import com.android.internal.telephony.IccUtils; import android.os.Handler; -import android.os.HandlerState; -import android.os.HandlerStateMachine; +import com.android.internal.util.HierarchicalState; +import com.android.internal.util.HierarchicalStateMachine; import android.os.Message; /** * Class used for queuing raw ril messages, decoding them into CommanParams * objects and sending the result back to the STK Service. */ -class RilMessageDecoder extends HandlerStateMachine { +class RilMessageDecoder extends HierarchicalStateMachine { // constants - private static final int START = 1; + private static final int CMD_START = 1; private static final int CMD_PARAMS_READY = 2; // members @@ -54,6 +54,7 @@ class RilMessageDecoder extends HandlerStateMachine { public static synchronized RilMessageDecoder getInstance(Handler caller, SIMFileHandler fh) { if (sInstance == null) { sInstance = new RilMessageDecoder(caller, fh); + sInstance.start(); } return sInstance; } @@ -65,7 +66,7 @@ class RilMessageDecoder extends HandlerStateMachine { * @param rilMsg */ public void sendStartDecodingMessageParams(RilMessage rilMsg) { - Message msg = obtainMessage(START); + Message msg = obtainMessage(CMD_START); msg.obj = rilMsg; sendMessage(msg); } @@ -76,7 +77,7 @@ class RilMessageDecoder extends HandlerStateMachine { * @param resCode * @param cmdParams */ - public void sendMessageParamsDecoded(ResultCode resCode, CommandParams cmdParams) { + public void sendMsgParamsDecoded(ResultCode resCode, CommandParams cmdParams) { Message msg = obtainMessage(RilMessageDecoder.CMD_PARAMS_READY); msg.arg1 = resCode.value(); msg.obj = cmdParams; @@ -91,28 +92,31 @@ class RilMessageDecoder extends HandlerStateMachine { private RilMessageDecoder(Handler caller, SIMFileHandler fh) { super("RilMessageDecoder"); - setDbg(false); + + addState(mStateStart); + addState(mStateCmdParamsReady); setInitialState(mStateStart); mCaller = caller; mCmdParamsFactory = CommandParamsFactory.getInstance(this, fh); } - private class StateStart extends HandlerState { - @Override public void processMessage(Message msg) { - if (msg.what == START) { + private class StateStart extends HierarchicalState { + @Override protected boolean processMessage(Message msg) { + if (msg.what == CMD_START) { if (decodeMessageParams((RilMessage)msg.obj)) { transitionTo(mStateCmdParamsReady); } } else { StkLog.d(this, "StateStart unexpected expecting START=" + - START + " got " + msg.what); + CMD_START + " got " + msg.what); } + return true; } } - private class StateCmdParamsReady extends HandlerState { - @Override public void processMessage(Message msg) { + private class StateCmdParamsReady extends HierarchicalState { + @Override protected boolean processMessage(Message msg) { if (msg.what == CMD_PARAMS_READY) { mCurrentRilMessage.mResCode = ResultCode.fromInt(msg.arg1); mCurrentRilMessage.mData = msg.obj; @@ -123,6 +127,7 @@ class RilMessageDecoder extends HandlerStateMachine { + CMD_PARAMS_READY + " got " + msg.what); deferMessage(msg); } + return true; } } diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java b/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java index 9268037..29ed95c 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/StkService.java @@ -467,8 +467,7 @@ public class StkService extends Handler implements AppInterface { sInstance = new StkService(ci, sr, context, fh, sc); StkLog.d(sInstance, "NEW sInstance"); } else if ((sr != null) && (mSimRecords != sr)) { - StkLog.d(sInstance, String.format( - "Reinitialize the Service with SIMRecords sr=0x%x.", sr)); + StkLog.d(sInstance, "Reinitialize the Service with SIMRecords"); mSimRecords = sr; // re-Register for SIM ready event. diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java deleted file mode 100644 index 9e1af31..0000000 --- a/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.telephonytest; - -import junit.framework.TestSuite; - -import android.test.InstrumentationTestRunner; -import android.test.InstrumentationTestSuite; - -/** - * Instrumentation Test Runner for all Telephony unit tests. - * - * Running all tests: - * - * runtest telephony-unit - * or - * adb shell am instrument -w com.android.telephonytest/.TelephonyUnitTestRunner - */ - -public class TelephonyUnitTestRunner extends InstrumentationTestRunner { - - @Override - public TestSuite getAllTests() { - TestSuite suite = new InstrumentationTestSuite(this); - suite.addTestSuite(com.android.telephonytest.unit.CallerInfoUnitTest.class); - suite.addTestSuite(com.android.telephonytest.unit.PhoneNumberUtilsUnitTest.class); - return suite; - } - - @Override - public ClassLoader getLoader() { - return TelephonyUnitTestRunner.class.getClassLoader(); - } -} diff --git a/telephony/tests/TelephonyTest/Android.mk b/telephony/tests/telephonytests/Android.mk index 1ef8448..45e265a 100644 --- a/telephony/tests/TelephonyTest/Android.mk +++ b/telephony/tests/telephonytests/Android.mk @@ -7,6 +7,6 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_JAVA_LIBRARIES := android.test.runner -LOCAL_PACKAGE_NAME := telephonytest +LOCAL_PACKAGE_NAME := FrameworksTelephonyTests include $(BUILD_PACKAGE) diff --git a/telephony/tests/TelephonyTest/AndroidManifest.xml b/telephony/tests/telephonytests/AndroidManifest.xml index b2a481b..6a97423 100644 --- a/telephony/tests/TelephonyTest/AndroidManifest.xml +++ b/telephony/tests/telephonytests/AndroidManifest.xml @@ -16,7 +16,7 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.telephonytest"> + package="com.android.frameworks.telephonytests"> <application> <uses-library android:name="android.test.runner" /> @@ -28,9 +28,10 @@ </intent-filter> </activity> </application> - <instrumentation android:name=".TelephonyUnitTestRunner" - android:targetPackage="com.android.telephonytest" - android:label="Telephony unit tests InstrumentationRunner"> + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.frameworks.telephonytests" + android:label="Frameworks Telephony Tests"> </instrumentation> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> + </manifest> diff --git a/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java new file mode 100644 index 0000000..02590d3 --- /dev/null +++ b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberUtilsTest.java @@ -0,0 +1,475 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.test.suitebuilder.annotation.SmallTest; +import android.text.SpannableStringBuilder; +import android.telephony.PhoneNumberUtils; + +import junit.framework.TestCase; + +public class PhoneNumberUtilsTest extends TestCase { + + @SmallTest + public void testExtractNetworkPortion() throws Exception { + assertEquals( + "+17005554141", + PhoneNumberUtils.extractNetworkPortion("+17005554141") + ); + + assertEquals( + "+17005554141", + PhoneNumberUtils.extractNetworkPortion("+1 (700).555-4141") + ); + + assertEquals( + "17005554141", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-4141") + ); + + // This may seem wrong, but it's probably ok + assertEquals( + "17005554141*#", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-4141*#") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN,1234") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN;1234") + ); + + // An MMI string is unperterbed, even though it contains a + // (valid in this case) embedded + + assertEquals( + "**21**17005554141#", + PhoneNumberUtils.extractNetworkPortion("**21**+17005554141#") + //TODO this is the correct result, although the above + //result has been returned since change 31776 + //"**21**+17005554141#" + ); + + assertEquals("", PhoneNumberUtils.extractNetworkPortion("")); + + assertEquals("", PhoneNumberUtils.extractNetworkPortion(",1234")); + + byte [] b = new byte[20]; + b[0] = (byte) 0x81; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xF0; + assertEquals("17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xF0; + assertEquals("+17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + byte[] bRet = PhoneNumberUtils.networkPortionToCalledPartyBCD("+17005550020"); + assertEquals(7, bRet.length); + for (int i = 0; i < 7; i++) { + assertEquals(b[i], bRet[i]); + } + + bRet = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength("+17005550020"); + assertEquals(8, bRet.length); + assertEquals(bRet[0], 7); + for (int i = 1; i < 8; i++) { + assertEquals(b[i - 1], bRet[i]); + } + + bRet = PhoneNumberUtils.networkPortionToCalledPartyBCD("7005550020"); + assertEquals("7005550020", + PhoneNumberUtils.calledPartyBCDToString(bRet, 0, bRet.length)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xB0; + assertEquals("17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55; + b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xB0; + assertEquals("+17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 7)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1; + assertEquals("*21#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 3)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x2B; b[2] = (byte) 0xB1; + assertEquals("#21#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 3)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1; + assertEquals("*21#+", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 3)); + + b[0] = (byte) 0x81; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0xFB; + assertEquals("**21#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 4)); + + b[0] = (byte) 0x91; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0xFB; + assertEquals("**21#+", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 4)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x9A; b[2] = (byte) 0xA9; b[3] = (byte) 0x71; + b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20; + b[8] = (byte) 0xB0; + assertEquals("*99*17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 9)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x9A; b[2] = (byte) 0xA9; b[3] = (byte) 0x71; + b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20; + b[8] = (byte) 0xB0; + assertEquals("*99*+17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 9)); + + b[0] = (byte) 0x81; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0x1A; + b[4] = (byte) 0x07; b[5] = (byte) 0x50; b[6] = (byte) 0x55; b[7] = (byte) 0x00; + b[8] = (byte) 0x02; b[9] = (byte) 0xFB; + assertEquals("**21*17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 10)); + + b[0] = (byte) 0x91; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0x1A; + b[4] = (byte) 0x07; b[5] = (byte) 0x50; b[6] = (byte) 0x55; b[7] = (byte) 0x00; + b[8] = (byte) 0x02; b[9] = (byte) 0xFB; + assertEquals("**21*+17005550020#", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 10)); + + b[0] = (byte) 0x81; b[1] = (byte) 0x2A; b[2] = (byte) 0xA1; b[3] = (byte) 0x71; + b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20; + b[8] = (byte) 0xF0; + assertEquals("*21*17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 9)); + + b[0] = (byte) 0x91; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1; b[3] = (byte) 0x71; + b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20; + b[8] = (byte) 0xF0; + assertEquals("*21#+17005550020", + PhoneNumberUtils.calledPartyBCDToString(b, 0, 9)); + + assertNull(PhoneNumberUtils.extractNetworkPortion(null)); + assertNull(PhoneNumberUtils.extractPostDialPortion(null)); + assertTrue(PhoneNumberUtils.compare(null, null)); + assertFalse(PhoneNumberUtils.compare(null, "123")); + assertFalse(PhoneNumberUtils.compare("123", null)); + assertNull(PhoneNumberUtils.toCallerIDMinMatch(null)); + assertNull(PhoneNumberUtils.getStrippedReversed(null)); + assertNull(PhoneNumberUtils.stringFromStringAndTOA(null, 1)); + } + + @SmallTest + public void testExtractNetworkPortionAlt() throws Exception { + assertEquals( + "+17005554141", + PhoneNumberUtils.extractNetworkPortionAlt("+17005554141") + ); + + assertEquals( + "+17005554141", + PhoneNumberUtils.extractNetworkPortionAlt("+1 (700).555-4141") + ); + + assertEquals( + "17005554141", + PhoneNumberUtils.extractNetworkPortionAlt("1 (700).555-4141") + ); + + // This may seem wrong, but it's probably ok + assertEquals( + "17005554141*#", + PhoneNumberUtils.extractNetworkPortionAlt("1 (700).555-4141*#") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortionAlt("1 (700).555-41NN") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortionAlt("1 (700).555-41NN,1234") + ); + + assertEquals( + "170055541NN", + PhoneNumberUtils.extractNetworkPortionAlt("1 (700).555-41NN;1234") + ); + + // An MMI string is unperterbed, even though it contains a + // (valid in this case) embedded + + assertEquals( + "**21**+17005554141#", + PhoneNumberUtils.extractNetworkPortionAlt("**21**+17005554141#") + ); + + assertEquals( + "*31#+447966164208", + PhoneNumberUtils.extractNetworkPortionAlt("*31#+447966164208") + ); + + assertEquals( + "*31#+447966164208", + PhoneNumberUtils.extractNetworkPortionAlt("*31# (+44) 79 6616 4208") + ); + + assertEquals("", PhoneNumberUtils.extractNetworkPortionAlt("")); + + assertEquals("", PhoneNumberUtils.extractNetworkPortionAlt(",1234")); + + assertNull(PhoneNumberUtils.extractNetworkPortionAlt(null)); + } + + @SmallTest + public void testB() throws Exception { + assertEquals("", PhoneNumberUtils.extractPostDialPortion("+17005554141")); + assertEquals("", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-4141")); + assertEquals("", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN")); + assertEquals(",1234", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN,1234")); + assertEquals(";1234", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN;1234")); + assertEquals(";1234,;N", + PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN;1-2.34 ,;N")); + } + + @SmallTest + public void testCompare() throws Exception { + // this is odd + assertFalse(PhoneNumberUtils.compare("", "")); + + assertTrue(PhoneNumberUtils.compare("911", "911")); + assertFalse(PhoneNumberUtils.compare("911", "18005550911")); + assertTrue(PhoneNumberUtils.compare("5555", "5555")); + assertFalse(PhoneNumberUtils.compare("5555", "180055555555")); + + assertTrue(PhoneNumberUtils.compare("+17005554141", "+17005554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "+1 (700).555-4141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "+1 (700).555-4141,1234")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "17005554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "7005554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "5554141")); + assertTrue(PhoneNumberUtils.compare("17005554141", "5554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "01117005554141")); + assertTrue(PhoneNumberUtils.compare("+17005554141", "0017005554141")); + assertTrue(PhoneNumberUtils.compare("17005554141", "0017005554141")); + + + assertTrue(PhoneNumberUtils.compare("+17005554141", "**31#+17005554141")); + + assertFalse(PhoneNumberUtils.compare("+1 999 7005554141", "+1 7005554141")); + assertTrue(PhoneNumberUtils.compare("011 1 7005554141", "7005554141")); + + assertFalse(PhoneNumberUtils.compare("011 11 7005554141", "+17005554141")); + + assertFalse(PhoneNumberUtils.compare("+17005554141", "7085882300")); + + assertTrue(PhoneNumberUtils.compare("+44 207 792 3490", "0 207 792 3490")); + + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "00 207 792 3490")); + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "011 207 792 3490")); + + /***** FIXME's ******/ + // + // MMI header should be ignored + assertFalse(PhoneNumberUtils.compare("+17005554141", "**31#17005554141")); + + // It's too bad this is false + // +44 (0) 207 792 3490 is not a dialable number + // but it is commonly how European phone numbers are written + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "+44 (0) 207 792 3490")); + + // The japanese international prefix, for example, messes us up + // But who uses a GSM phone in Japan? + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "010 44 207 792 3490")); + + // The Australian one messes us up too + assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "0011 44 207 792 3490")); + + // The Russian trunk prefix messes us up, as does current + // Russian area codes (which bein with 0) + + assertFalse(PhoneNumberUtils.compare("+7(095)9100766", "8(095)9100766")); + + // 444 is not a valid country code, but + // matchIntlPrefixAndCC doesnt know this + assertTrue(PhoneNumberUtils.compare("+444 207 792 3490", "0 207 792 3490")); + + // compare SMS short code + assertTrue(PhoneNumberUtils.compare("404-04", "40404")); + } + + + @SmallTest + public void testToCallerIDIndexable() throws Exception { + assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("17005554141")); + assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141")); + assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141,1234")); + assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141;1234")); + + //this seems wrong, or at least useless + assertEquals("NN14555", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-41NN")); + + //<shrug> -- these are all not useful, but not terribly wrong + assertEquals("", PhoneNumberUtils.toCallerIDMinMatch("")); + assertEquals("0032", PhoneNumberUtils.toCallerIDMinMatch("2300")); + assertEquals("0032+", PhoneNumberUtils.toCallerIDMinMatch("+2300")); + assertEquals("#130#*", PhoneNumberUtils.toCallerIDMinMatch("*#031#")); + } + + @SmallTest + public void testGetIndexable() throws Exception { + assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141")); + assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141,1234")); + assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141;1234")); + + //this seems wrong, or at least useless + assertEquals("NN145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-41NN")); + + //<shrug> -- these are all not useful, but not terribly wrong + assertEquals("", PhoneNumberUtils.getStrippedReversed("")); + assertEquals("0032", PhoneNumberUtils.getStrippedReversed("2300")); + assertEquals("0032+", PhoneNumberUtils.getStrippedReversed("+2300")); + assertEquals("#130#*", PhoneNumberUtils.getStrippedReversed("*#031#")); + } + + @SmallTest + public void testNanpFormatting() { + SpannableStringBuilder number = new SpannableStringBuilder(); + number.append("8005551212"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("800-555-1212", number.toString()); + + number.clear(); + number.append("800555121"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("800-555-121", number.toString()); + + number.clear(); + number.append("555-1212"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("555-1212", number.toString()); + + number.clear(); + number.append("800-55512"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("800-555-12", number.toString()); + + number.clear(); + number.append("46645"); + PhoneNumberUtils.formatNanpNumber(number); + assertEquals("46645", number.toString()); + } + + @SmallTest + public void testConvertKeypadLettersToDigits() { + assertEquals("1-800-4664-411", + PhoneNumberUtils.convertKeypadLettersToDigits("1-800-GOOG-411")); + assertEquals("18004664411", + PhoneNumberUtils.convertKeypadLettersToDigits("1800GOOG411")); + assertEquals("1-800-466-4411", + PhoneNumberUtils.convertKeypadLettersToDigits("1-800-466-4411")); + assertEquals("18004664411", + PhoneNumberUtils.convertKeypadLettersToDigits("18004664411")); + assertEquals("222-333-444-555-666-7777-888-9999", + PhoneNumberUtils.convertKeypadLettersToDigits( + "ABC-DEF-GHI-JKL-MNO-PQRS-TUV-WXYZ")); + assertEquals("222-333-444-555-666-7777-888-9999", + PhoneNumberUtils.convertKeypadLettersToDigits( + "abc-def-ghi-jkl-mno-pqrs-tuv-wxyz")); + assertEquals("(800) 222-3334", + PhoneNumberUtils.convertKeypadLettersToDigits("(800) ABC-DEFG")); + } + + // To run this test, the device has to be registered with network + public void testCheckAndProcessPlusCode() { + assertEquals("0118475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+8475797000")); + assertEquals("18475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+18475797000")); + assertEquals("0111234567", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+1234567")); + assertEquals("01123456700000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+23456700000")); + assertEquals("01111875767800", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+11875767800")); + assertEquals("8475797000,18475231753", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,+18475231753")); + assertEquals("0118475797000,18475231753", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+8475797000,+18475231753")); + assertEquals("8475797000;0118469312345", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;+8469312345")); + assertEquals("8475797000,0111234567", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,+1234567")); + assertEquals("847597000;01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("847597000;+11875767000")); + assertEquals("8475797000,,0118469312345", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,,+8469312345")); + assertEquals("8475797000;,0118469312345", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,+8469312345")); + assertEquals("8475797000,;18475231753", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,;+18475231753")); + assertEquals("8475797000;,01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,+11875767000")); + assertEquals("8475797000,;01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,;+11875767000")); + assertEquals("8475797000,,,01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,,,+11875767000")); + assertEquals("8475797000;,,01111875767000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000;,,+11875767000")); + assertEquals("+;,8475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+;,8475797000")); + assertEquals("8475797000,", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("8475797000,")); + assertEquals("847+579-7000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("847+579-7000")); + assertEquals(",8475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode(",8475797000")); + assertEquals(";;8475797000,,", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode(";;8475797000,,")); + assertEquals("+this+is$weird;,+", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("+this+is$weird;,+")); + assertEquals("", + PhoneNumberUtils.cdmaCheckAndProcessPlusCode("")); + assertNull(PhoneNumberUtils.cdmaCheckAndProcessPlusCode(null)); + } + + @SmallTest + public void testCheckAndProcessPlusCodeByNumberFormat() { + assertEquals("18475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000", + PhoneNumberUtils.FORMAT_NANP,PhoneNumberUtils.FORMAT_NANP)); + assertEquals("+18475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000", + PhoneNumberUtils.FORMAT_NANP,PhoneNumberUtils.FORMAT_JAPAN)); + assertEquals("+18475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000", + PhoneNumberUtils.FORMAT_NANP,PhoneNumberUtils.FORMAT_UNKNOWN)); + assertEquals("+18475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000", + PhoneNumberUtils.FORMAT_JAPAN,PhoneNumberUtils.FORMAT_JAPAN)); + assertEquals("+18475797000", + PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000", + PhoneNumberUtils.FORMAT_UNKNOWN,PhoneNumberUtils.FORMAT_UNKNOWN)); + } +} diff --git a/telephony/tests/telephonytests/src/android/telephony/PhoneNumberWatcherTest.java b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberWatcherTest.java new file mode 100644 index 0000000..88eaecd --- /dev/null +++ b/telephony/tests/telephonytests/src/android/telephony/PhoneNumberWatcherTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.telephony.PhoneNumberFormattingTextWatcher; +import android.test.suitebuilder.annotation.SmallTest; +import android.text.Selection; +import android.text.SpannableStringBuilder; +import android.text.TextWatcher; + +import junit.framework.TestCase; + +public class PhoneNumberWatcherTest extends TestCase { + @SmallTest + public void testHyphenation() throws Exception { + SpannableStringBuilder number = new SpannableStringBuilder(); + TextWatcher tw = new PhoneNumberFormattingTextWatcher(); + number.append("555-1212"); + // Move the cursor to the left edge + Selection.setSelection(number, 0); + tw.beforeTextChanged(number, 0, 0, 1); + // Insert an 8 at the beginning + number.insert(0, "8"); + tw.afterTextChanged(number); + assertEquals("855-512-12", number.toString()); + } + + @SmallTest + public void testHyphenDeletion() throws Exception { + SpannableStringBuilder number = new SpannableStringBuilder(); + TextWatcher tw = new PhoneNumberFormattingTextWatcher(); + number.append("555-1212"); + // Move the cursor to after the hyphen + Selection.setSelection(number, 4); + // Delete the hyphen + tw.beforeTextChanged(number, 3, 1, 0); + number.delete(3, 4); + tw.afterTextChanged(number); + // Make sure that it deleted the character before the hyphen + assertEquals("551-212", number.toString()); + + // Make sure it deals with left edge boundary case + number.insert(0, "-"); + Selection.setSelection(number, 1); + tw.beforeTextChanged(number, 0, 1, 0); + number.delete(0, 1); + tw.afterTextChanged(number); + // Make sure that it deleted the character before the hyphen + assertEquals("551-212", number.toString()); + } +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/ATResponseParserTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/ATResponseParserTest.java new file mode 100644 index 0000000..81727e4 --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/ATResponseParserTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class ATResponseParserTest extends TestCase { + @SmallTest + public void testBasic() throws Exception { + ATResponseParser p = new ATResponseParser("+CREG: 0"); + + assertEquals(0, p.nextInt()); + + assertFalse(p.hasMore()); + + try { + p.nextInt(); + fail("exception expected"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+CREG: 0,1"); + assertEquals(0, p.nextInt()); + assertEquals(1, p.nextInt()); + assertFalse(p.hasMore()); + + p = new ATResponseParser("+CREG: 0, 1"); + assertEquals(0, p.nextInt()); + assertEquals(1, p.nextInt()); + assertFalse(p.hasMore()); + + p = new ATResponseParser("+CREG: 0, 1,"); + assertEquals(0, p.nextInt()); + assertEquals(1, p.nextInt()); + // this seems odd but is probably OK + assertFalse(p.hasMore()); + try { + p.nextInt(); + fail("exception expected"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+CREG: 0, 1 "); + assertEquals(0, p.nextInt()); + assertEquals(1, p.nextInt()); + assertFalse(p.hasMore()); + + p = new ATResponseParser("0, 1 "); + // no prefix -> exception + try { + p.nextInt(); + fail("exception expected"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+CREG: 0, 1, 5"); + assertFalse(p.nextBoolean()); + assertTrue(p.nextBoolean()); + try { + // is this over-constraining? + p.nextBoolean(); + fail("exception expected"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+CLCC: 1,0,2,0,0,\"+18005551212\",145"); + + assertEquals(1, p.nextInt()); + assertFalse(p.nextBoolean()); + assertEquals(2, p.nextInt()); + assertEquals(0, p.nextInt()); + assertEquals(0, p.nextInt()); + assertEquals("+18005551212", p.nextString()); + assertEquals(145, p.nextInt()); + assertFalse(p.hasMore()); + + p = new ATResponseParser("+CLCC: 1,0,2,0,0,\"+18005551212,145"); + + assertEquals(1, p.nextInt()); + assertFalse(p.nextBoolean()); + assertEquals(2, p.nextInt()); + assertEquals(0, p.nextInt()); + assertEquals(0, p.nextInt()); + try { + p.nextString(); + fail("expected ex"); + } catch (ATParseEx ex) { + //test pass + } + + p = new ATResponseParser("+FOO: \"\""); + assertEquals("", p.nextString()); + } +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/AdnRecordTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/AdnRecordTest.java new file mode 100644 index 0000000..8a4a285 --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/AdnRecordTest.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * {@hide} + */ +public class AdnRecordTest extends TestCase { + + @SmallTest + public void testBasic() throws Exception { + AdnRecord adn; + + // + // Typical record + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C07918150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("+18056377243", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Empty records, empty strings + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); + + assertEquals("", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertTrue(adn.isEmpty()); + + // + // Record too short + // + adn = new AdnRecord(IccUtils.hexStringToBytes( "FF")); + + assertEquals("", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertTrue(adn.isEmpty()); + + // + // TOA = 0xff ("control string") + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C07FF8150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("18056377243", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // TOA = 0x81 (unknown) + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C07818150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("18056377243", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Number Length is too long + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C0F918150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Number Length is zero (invalid) + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C00918150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Number Length is 2, first number byte is FF, TOA is international + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C0291FF50367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // Number Length is 2, first number digit is valid, TOA is international + // + adn = new AdnRecord( + IccUtils.hexStringToBytes("566F696365204D61696C0291F150367742F3FFFFFFFFFFFF")); + + assertEquals("Voice Mail", adn.getAlphaTag()); + assertEquals("+1", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // An extended record + // + adn = new AdnRecord( + IccUtils.hexStringToBytes( + "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + assertTrue(adn.hasExtendedRecord()); + + adn.appendExtRecord(IccUtils.hexStringToBytes("0206092143658709ffffffffff")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678901234567890", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // An extended record with an invalid extension + // + adn = new AdnRecord( + IccUtils.hexStringToBytes( + "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + assertTrue(adn.hasExtendedRecord()); + + adn.appendExtRecord(IccUtils.hexStringToBytes("0106092143658709ffffffffff")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + + // + // An extended record with an invalid extension + // + adn = new AdnRecord( + IccUtils.hexStringToBytes( + "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + assertTrue(adn.hasExtendedRecord()); + + adn.appendExtRecord(IccUtils.hexStringToBytes("020B092143658709ffffffffff")); + + assertEquals("Adgjm", adn.getAlphaTag()); + assertEquals("+18885551212,12345678", adn.getNumber()); + assertFalse(adn.isEmpty()); + } +} + + diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java new file mode 100644 index 0000000..3a9c511 --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmAlphabetTest.java @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import junit.framework.TestCase; + +import android.test.suitebuilder.annotation.LargeTest; +import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.Suppress; + +public class GsmAlphabetTest extends TestCase { + + private static final String sGsmExtendedChars = "{|}\\[~]\f\u20ac"; + + @SmallTest + public void test7bitWithHeader() throws Exception { + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = 1; + concatRef.seqNumber = 2; + concatRef.msgCount = 2; + concatRef.isEightBits = true; + SmsHeader header = new SmsHeader(); + header.concatRef = concatRef; + + String message = "aaaaaaaaaabbbbbbbbbbcccccccccc"; + byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, + SmsHeader.toByteArray(header)); + int septetCount = GsmAlphabet.countGsmSeptets(message, false); + String parsedMessage = GsmAlphabet.gsm7BitPackedToString( + userData, SmsHeader.toByteArray(header).length+2, septetCount, 1); + assertEquals(message, parsedMessage); + } + + // TODO: This method should *really* be a series of individual test methods. + @LargeTest + public void testBasic() throws Exception { + // '@' maps to char 0 + assertEquals(0, GsmAlphabet.charToGsm('@')); + + // `a (a with grave accent) maps to last GSM charater + assertEquals(0x7f, GsmAlphabet.charToGsm('\u00e0')); + + // + // These are the extended chars + // They should all return GsmAlphabet.GSM_EXTENDED_ESCAPE + // + + for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) { + assertEquals(GsmAlphabet.GSM_EXTENDED_ESCAPE, + GsmAlphabet.charToGsm(sGsmExtendedChars.charAt(i))); + + } + + // euro symbol + assertEquals(GsmAlphabet.GSM_EXTENDED_ESCAPE, + GsmAlphabet.charToGsm('\u20ac')); + + // An unmappable char (the 'cent' char) maps to a space + assertEquals(GsmAlphabet.charToGsm(' '), + GsmAlphabet.charToGsm('\u00a2')); + + // unmappable = space = 1 septet + assertEquals(1, GsmAlphabet.countGsmSeptets('\u00a2')); + + // + // Test extended table + // + + for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) { + assertEquals(sGsmExtendedChars.charAt(i), + GsmAlphabet.gsmExtendedToChar( + GsmAlphabet.charToGsmExtended(sGsmExtendedChars.charAt(i)))); + + } + + // Unmappable extended char + assertEquals(GsmAlphabet.charToGsm(' '), + GsmAlphabet.charToGsmExtended('@')); + + // + // gsmToChar() + // + + assertEquals('@', GsmAlphabet.gsmToChar(0)); + + // `a (a with grave accent) maps to last GSM charater + assertEquals('\u00e0', GsmAlphabet.gsmToChar(0x7f)); + + assertEquals('\uffff', + GsmAlphabet.gsmToChar(GsmAlphabet.GSM_EXTENDED_ESCAPE)); + + // Out-of-range/unmappable value + assertEquals(' ', GsmAlphabet.gsmToChar(0x80)); + + // + // gsmExtendedToChar() + // + + assertEquals('{', GsmAlphabet.gsmExtendedToChar(0x28)); + + // No double-escapes + assertEquals(' ', GsmAlphabet.gsmExtendedToChar( + GsmAlphabet.GSM_EXTENDED_ESCAPE)); + + // Unmappable + assertEquals(' ', GsmAlphabet.gsmExtendedToChar(0)); + + // + // stringTo7BitPacked, gsm7BitPackedToString + // + + byte[] packed; + StringBuilder testString = new StringBuilder(300); + + // Check all alignment cases + for (int i = 0; i < 9; i++, testString.append('@')) { + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + } + + // Check full non-extended alphabet + for (int i = 0; i < 0x80; i++) { + char c; + + if (i == GsmAlphabet.GSM_EXTENDED_ESCAPE) { + continue; + } + + c = GsmAlphabet.gsmToChar(i); + testString.append(c); + + // These are all non-extended chars, so it should be + // one septet per char + assertEquals(1, GsmAlphabet.countGsmSeptets(c)); + } + + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + + // Test extended chars too + + testString.append(sGsmExtendedChars); + + for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) { + // These are all extended chars, so it should be + // two septets per char + assertEquals(2, GsmAlphabet.countGsmSeptets(sGsmExtendedChars.charAt(i))); + + } + + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + + // stringTo7BitPacked handles up to 255 septets + + testString.setLength(0); + for (int i = 0; i < 255; i++) { + testString.append('@'); + } + + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + + // > 255 septets throws runtime exception + testString.append('@'); + + try { + GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + fail("expected exception"); + } catch (EncodeException ex) { + // exception expected + } + + // Try 254 septets with 127 extended chars + + testString.setLength(0); + for (int i = 0; i < (255 / 2); i++) { + testString.append('{'); + } + + packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + assertEquals(testString.toString(), + GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0])); + + // > 255 septets throws runtime exception + testString.append('{'); + + try { + GsmAlphabet.stringToGsm7BitPacked(testString.toString()); + fail("expected exception"); + } catch (EncodeException ex) { + // exception expected + } + + // + // 8 bit unpacked format + // + // Note: we compare hex strings here + // because Assert doesnt have array-comparisons + + byte unpacked[]; + + unpacked = IccUtils.hexStringToBytes("566F696365204D61696C"); + assertEquals("Voice Mail", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + assertEquals(IccUtils.bytesToHexString(unpacked), + IccUtils.bytesToHexString( + GsmAlphabet.stringToGsm8BitPacked("Voice Mail"))); + + unpacked = GsmAlphabet.stringToGsm8BitPacked(sGsmExtendedChars); + // two bytes for every extended char + assertEquals(2 * sGsmExtendedChars.length(), unpacked.length); + assertEquals(sGsmExtendedChars, + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // should be two bytes per extended char + assertEquals(2 * sGsmExtendedChars.length(), unpacked.length); + + // Test truncation of unaligned extended chars + unpacked = new byte[3]; + GsmAlphabet.stringToGsm8BitUnpackedField(sGsmExtendedChars, unpacked, + 0, unpacked.length); + + // Should be one extended char and an 0xff at the end + + assertEquals(0xff, 0xff & unpacked[2]); + assertEquals(sGsmExtendedChars.substring(0, 1), + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // Test truncation of normal chars + unpacked = new byte[3]; + GsmAlphabet.stringToGsm8BitUnpackedField("abcd", unpacked, + 0, unpacked.length); + + assertEquals("abc", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // Test truncation of mixed normal and extended chars + unpacked = new byte[3]; + GsmAlphabet.stringToGsm8BitUnpackedField("a{cd", unpacked, + 0, unpacked.length); + + assertEquals("a{", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // Test padding after normal char + unpacked = new byte[3]; + GsmAlphabet.stringToGsm8BitUnpackedField("a", unpacked, + 0, unpacked.length); + + assertEquals("a", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + assertEquals(0xff, 0xff & unpacked[1]); + assertEquals(0xff, 0xff & unpacked[2]); + + // Test malformed input -- escape char followed by end of field + unpacked[0] = 0; + unpacked[1] = 0; + unpacked[2] = GsmAlphabet.GSM_EXTENDED_ESCAPE; + + assertEquals("@@", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length)); + + // non-zero offset + assertEquals("@", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1)); + + // test non-zero offset + unpacked[0] = 0; + GsmAlphabet.stringToGsm8BitUnpackedField("abcd", unpacked, + 1, unpacked.length - 1); + + + assertEquals(0, unpacked[0]); + + assertEquals("ab", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1)); + + // test non-zero offset with truncated extended char + unpacked[0] = 0; + + GsmAlphabet.stringToGsm8BitUnpackedField("a{", unpacked, + 1, unpacked.length - 1); + + assertEquals(0, unpacked[0]); + + assertEquals("a", + GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1)); + } +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java new file mode 100644 index 0000000..3103fc1 --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.gsm.SmsMessage; +import com.android.internal.util.HexDump; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import android.util.Log; + +public class GsmSmsTest extends AndroidTestCase { + + @SmallTest + public void testAddressing() throws Exception { + String pdu = "07914151551512f2040B916105551511f100006060605130308A04D4F29C0E"; + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertEquals("+16505551111", sms.getOriginatingAddress()); + assertEquals("Test", sms.getMessageBody()); + + pdu = "07914151551512f2040B916105551511f100036060924180008A0DA" + + "8695DAC2E8FE9296A794E07"; + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertEquals("+16505551111", sms.getOriginatingAddress()); + assertEquals("(Subject)Test", sms.getMessageBody()); + } + + @SmallTest + public void testUdh() throws Exception { + String pdu = "07914140279510F6440A8111110301003BF56080207130138A8C0B05040B8423F" + + "000032A02010106276170706C69636174696F6E2F766E642E7761702E6D6D732D" + + "6D65737361676500AF848D0185B4848C8298524E453955304A6D7135514141426" + + "66C414141414D7741414236514141414141008D908918802B3135313232393737" + + "3638332F545950453D504C4D4E008A808E022B918805810306977F83687474703" + + "A2F2F36"; + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + SmsHeader header = sms.getUserDataHeader(); + assertNotNull(header); + assertNotNull(header.concatRef); + assertEquals(header.concatRef.refNumber, 42); + assertEquals(header.concatRef.msgCount, 2); + assertEquals(header.concatRef.seqNumber, 1); + assertEquals(header.concatRef.isEightBits, true); + assertNotNull(header.portAddrs); + assertEquals(header.portAddrs.destPort, 2948); + assertEquals(header.portAddrs.origPort, 9200); + assertEquals(header.portAddrs.areEightBits, false); + + pdu = "07914140279510F6440A8111110301003BF56080207130238A3B0B05040B8423F" + + "000032A0202362E3130322E3137312E3135302F524E453955304A6D7135514141" + + "42666C414141414D774141423651414141414100"; + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + header = sms.getUserDataHeader(); + assertNotNull(header); + assertNotNull(header.concatRef); + assertEquals(header.concatRef.refNumber, 42); + assertEquals(header.concatRef.msgCount, 2); + assertEquals(header.concatRef.seqNumber, 2); + assertEquals(header.concatRef.isEightBits, true); + assertNotNull(header.portAddrs); + assertEquals(header.portAddrs.destPort, 2948); + assertEquals(header.portAddrs.origPort, 9200); + assertEquals(header.portAddrs.areEightBits, false); + } + + @SmallTest + public void testUcs2() throws Exception { + String pdu = "07912160130300F4040B914151245584F600087010807121352B1021220" + + "0A900AE00680065006C006C006F"; + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + assertEquals("\u2122\u00a9\u00aehello", sms.getMessageBody()); + } + + @SmallTest + public void testMultipart() throws Exception { + /* + * Multi-part text SMS with septet data. + */ + String pdu = "07916163838408F6440B816105224431F700007060217175830AA0050003" + + "00020162B1582C168BC562B1582C168BC562B1582C168BC562B1582C" + + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C" + + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C" + + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C" + + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562"; + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + assertEquals(sms.getMessageBody(), + "1111111111111111111111111111111111111111" + + "1111111111111111111111111111111111111111" + + "1111111111111111111111111111111111111111" + + "111111111111111111111111111111111"); + + pdu = "07916163838408F6440B816105224431F700007060217185000A23050003" + + "00020262B1582C168BC96432994C2693C96432994C2693C96432990C"; + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + assertEquals("1111111222222222222222222222", sms.getMessageBody()); + } + + @SmallTest + public void testCPHSVoiceMail() throws Exception { + // "set MWI flag" + + String pdu = "07912160130310F20404D0110041006060627171118A0120"; + + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isReplace()); + assertEquals("_@", sms.getOriginatingAddress()); + assertEquals(" ", sms.getMessageBody()); + assertTrue(sms.isMWISetMessage()); + + // "clear mwi flag" + + pdu = "07912160130310F20404D0100041006021924193352B0120"; + + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isMWIClearMessage()); + + // "clear MWI flag" + + pdu = "07912160130310F20404D0100041006060627161058A0120"; + + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isReplace()); + assertEquals("\u0394@", sms.getOriginatingAddress()); + assertEquals(" ", sms.getMessageBody()); + assertTrue(sms.isMWIClearMessage()); + } + + @SmallTest + public void testCingularVoiceMail() throws Exception { + // "set MWI flag" + + String pdu = "07912180958750F84401800500C87020026195702B06040102000200"; + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isMWISetMessage()); + assertTrue(sms.isMwiDontStore()); + + // "clear mwi flag" + + pdu = "07912180958750F84401800500C07020027160112B06040102000000"; + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertTrue(sms.isMWIClearMessage()); + assertTrue(sms.isMwiDontStore()); + } + + @SmallTest + public void testEmailGateway() throws Exception { + String pdu = "07914151551512f204038105f300007011103164638a28e6f71b50c687db" + + "7076d9357eb7412f7a794e07cdeb6275794c07bde8e5391d247e93f3"; + + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertTrue(sms.isEmail()); + assertEquals("foo@example.com", sms.getEmailFrom()); + assertEquals("foo@example.com", sms.getDisplayOriginatingAddress()); + // As of https://android-git.corp.google.com/g/#change,9324 + // getPseudoSubject will always be empty, and any subject is not extracted. + assertEquals("", sms.getPseudoSubject()); + assertEquals("test subject /test body", sms.getDisplayMessageBody()); + assertEquals("test subject /test body", sms.getEmailBody()); + + // email gateway sms test, including gsm extended character set. + pdu = "07914151551512f204038105f400007011103105458a29e6f71b50c687db" + + "7076d9357eb741af0d0a442fcfe9c23739bfe16d289bdee6b5f1813629"; + + sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertTrue(sms.isEmail()); + assertEquals("foo@example.com", sms.getDisplayOriginatingAddress()); + assertEquals("foo@example.com", sms.getEmailFrom()); + assertEquals("{ testBody[^~\\] }", sms.getDisplayMessageBody()); + assertEquals("{ testBody[^~\\] }", sms.getEmailBody()); + } + + @SmallTest + public void testExtendedCharacterTable() throws Exception { + String pdu = "07914151551512f2040B916105551511f100006080615131728A44D4F29C0E2" + + "AE3E96537B94C068DD16179784C2FCB41F4B0985D06B958ADD00FB0E94536AF9749" + + "74DA6D281BA00E95E26D509B946FC3DBF87A25D56A04"; + + SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu)); + + assertEquals("+14155551212", sms.getServiceCenterAddress()); + assertEquals("+16505551111", sms.getOriginatingAddress()); + assertEquals("Test extended character table .,-!?@~_\\/&\"';^|:()<{}>[]=%*+#", + sms.getMessageBody()); + } + + @SmallTest + public void testDecode() throws Exception { + byte[] septets = new byte[(7 * 128 + 7) / 8]; + + int bitOffset = 0; + + for (int i = 0; i < 128; i++) { + int v; + if (i == 0x1b) { + // extended escape char + v = 0; + } else { + v = i; + } + + int byteOffset = bitOffset / 8; + int shift = bitOffset % 8; + + septets[byteOffset] |= v << shift; + + if (shift > 1) { + septets[byteOffset + 1] = (byte) (v >> (8 - shift)); + } + + bitOffset += 7; + } + + String decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, 128); + byte[] reEncoded = GsmAlphabet.stringToGsm7BitPacked(decoded); + + // reEncoded has the count septets byte at the front + assertEquals(reEncoded.length, septets.length + 1); + + for (int i = 0; i < septets.length; i++) { + assertEquals(reEncoded[i + 1], septets[i]); + } + } + +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java new file mode 100644 index 0000000..2d6977c --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import com.android.internal.telephony.MccTable; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import android.util.Log; + +public class MccTableTest extends AndroidTestCase { + private final static String LOG_TAG = "GSM"; + + @SmallTest + public void testTimeZone() throws Exception { + assertEquals(MccTable.defaultTimeZoneForMcc(208), "Europe/Paris"); + assertEquals(MccTable.defaultTimeZoneForMcc(232), "Europe/Vienna"); + assertEquals(MccTable.defaultTimeZoneForMcc(655), "Africa/Johannesburg"); + assertEquals(MccTable.defaultTimeZoneForMcc(440), "Asia/Tokyo"); + assertEquals(MccTable.defaultTimeZoneForMcc(441), "Asia/Tokyo"); + assertEquals(MccTable.defaultTimeZoneForMcc(525), "Asia/Singapore"); + assertEquals(MccTable.defaultTimeZoneForMcc(240), null); // tz not defined, hence default + assertEquals(MccTable.defaultTimeZoneForMcc(0), null); // mcc not defined, hence default + assertEquals(MccTable.defaultTimeZoneForMcc(2000), null); // mcc not defined, hence default + } + + @SmallTest + public void testCountryCode() throws Exception { + assertEquals(MccTable.countryCodeForMcc(270), "lu"); + assertEquals(MccTable.countryCodeForMcc(202), "gr"); + assertEquals(MccTable.countryCodeForMcc(750), "fk"); + assertEquals(MccTable.countryCodeForMcc(646), "mg"); + assertEquals(MccTable.countryCodeForMcc(314), "us"); + assertEquals(MccTable.countryCodeForMcc(300), ""); // mcc not defined, hence default + assertEquals(MccTable.countryCodeForMcc(0), ""); // mcc not defined, hence default + assertEquals(MccTable.countryCodeForMcc(2000), ""); // mcc not defined, hence default + } + + @SmallTest + public void testLang() throws Exception { + assertEquals(MccTable.defaultLanguageForMcc(311), "en"); + assertEquals(MccTable.defaultLanguageForMcc(232), "de"); + assertEquals(MccTable.defaultLanguageForMcc(230), "cs"); + assertEquals(MccTable.defaultLanguageForMcc(204), "nl"); + assertEquals(MccTable.defaultLanguageForMcc(274), null); // lang not defined, hence default + assertEquals(MccTable.defaultLanguageForMcc(0), null); // mcc not defined, hence default + assertEquals(MccTable.defaultLanguageForMcc(2000), null); // mcc not defined, hence default + } + + @SmallTest + public void testSmDigits() throws Exception { + assertEquals(MccTable.smallestDigitsMccForMnc(312), 3); + assertEquals(MccTable.smallestDigitsMccForMnc(430), 2); + assertEquals(MccTable.smallestDigitsMccForMnc(365), 3); + assertEquals(MccTable.smallestDigitsMccForMnc(536), 2); + assertEquals(MccTable.smallestDigitsMccForMnc(352), 2); // sd not defined, hence default + assertEquals(MccTable.smallestDigitsMccForMnc(0), 2); // mcc not defined, hence default + assertEquals(MccTable.smallestDigitsMccForMnc(2000), 2); // mcc not defined, hence default + } + + @SmallTest + public void testWifi() throws Exception { + assertEquals(MccTable.wifiChannelsForMcc(262), 13); + assertEquals(MccTable.wifiChannelsForMcc(234), 13); + assertEquals(MccTable.wifiChannelsForMcc(505), 11); + assertEquals(MccTable.wifiChannelsForMcc(313), 11); + assertEquals(MccTable.wifiChannelsForMcc(330), 0); // wifi not defined, hence default + assertEquals(MccTable.wifiChannelsForMcc(0), 0); // mcc not defined, hence default + assertEquals(MccTable.wifiChannelsForMcc(2000), 0); // mcc not defined, hence default + + } +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java new file mode 100644 index 0000000..b63dc71 --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.telephony; + +import android.os.Parcel; +import android.test.AndroidTestCase; +import android.telephony.NeighboringCellInfo; +import android.test. suitebuilder.annotation.SmallTest; + +import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; +import static android.telephony.TelephonyManager.NETWORK_TYPE_EDGE; +import static android.telephony.TelephonyManager.NETWORK_TYPE_GPRS; +import static android.telephony.TelephonyManager.NETWORK_TYPE_UMTS; + +public class NeighboringCellInfoTest extends AndroidTestCase { + @SmallTest + public void testConstructor() { + int rssi = 31; + NeighboringCellInfo nc; + + nc = new NeighboringCellInfo(rssi, "FFFFFFF", NETWORK_TYPE_EDGE); + assertEquals(NETWORK_TYPE_EDGE, nc.getNetworkType()); + assertEquals(rssi, nc.getRssi()); + assertEquals(0xfff, nc.getLac()); + assertEquals(0xffff, nc.getCid()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getPsc()); + + nc = new NeighboringCellInfo(rssi, "1FF", NETWORK_TYPE_UMTS); + assertEquals(NETWORK_TYPE_UMTS, nc.getNetworkType()); + assertEquals(rssi, nc.getRssi()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getCid()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getLac()); + assertEquals(0x1ff, nc.getPsc()); + + nc = new NeighboringCellInfo(rssi, "1FF", NETWORK_TYPE_UNKNOWN); + assertEquals(NETWORK_TYPE_UNKNOWN, nc.getNetworkType()); + assertEquals(rssi, nc.getRssi()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getCid()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getLac()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getPsc()); + } + + @SmallTest + public void testParcel() { + int rssi = 20; + + NeighboringCellInfo nc = new NeighboringCellInfo(rssi, "12345678", NETWORK_TYPE_GPRS); + assertEquals(NETWORK_TYPE_GPRS, nc.getNetworkType()); + assertEquals(rssi, nc.getRssi()); + assertEquals(0x1234, nc.getLac()); + assertEquals(0x5678, nc.getCid()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nc.getPsc()); + + Parcel p = Parcel.obtain(); + p.setDataPosition(0); + nc.writeToParcel(p, 0); + + p.setDataPosition(0); + NeighboringCellInfo nw = new NeighboringCellInfo(p); + assertEquals(NETWORK_TYPE_GPRS, nw.getNetworkType()); + assertEquals(rssi, nw.getRssi()); + assertEquals(0x1234, nw.getLac()); + assertEquals(0x5678, nw.getCid()); + assertEquals(NeighboringCellInfo.UNKNOWN_CID, nw.getPsc()); + } +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java new file mode 100644 index 0000000..8a66614 --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/SMSDispatcherTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.test.suitebuilder.annotation.MediumTest; +import com.android.internal.telephony.TestPhoneNotifier; +import com.android.internal.telephony.gsm.SmsMessage; +import com.android.internal.telephony.test.SimulatedCommands; +import com.android.internal.telephony.test.SimulatedRadioControl; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.Suppress; + +import java.util.Iterator; + +/** + * {@hide} + */ +public class SMSDispatcherTest extends AndroidTestCase { + @MediumTest + public void testCMT1() throws Exception { + SmsMessage sms; + SmsHeader header; + + String[] lines = new String[2]; + + lines[0] = "+CMT: ,158"; + lines[1] = "07914140279510F6440A8111110301003BF56080426101748A8C0B05040B" + + "8423F000035502010106276170706C69636174696F6E2F766E642E776170" + + "2E6D6D732D6D65737361676500AF848D0185B4848C8298524F347839776F" + + "7547514D4141424C3641414141536741415A4B554141414141008D908918" + + "802B31363530323438363137392F545950453D504C4D4E008A808E028000" + + "88058103093A8083687474703A2F2F36"; + + sms = SmsMessage.newFromCMT(lines); + header = sms.getUserDataHeader(); + assertNotNull(header); + assertNotNull(sms.getUserData()); + assertNotNull(header.concatRef); + assertEquals(header.concatRef.refNumber, 85); + assertEquals(header.concatRef.msgCount, 2); + assertEquals(header.concatRef.seqNumber, 1); + assertEquals(header.concatRef.isEightBits, true); + assertNotNull(header.portAddrs); + assertEquals(header.portAddrs.destPort, 2948); + assertEquals(header.portAddrs.origPort, 9200); + assertEquals(header.portAddrs.areEightBits, false); + } + + @MediumTest + public void testCMT2() throws Exception { + SmsMessage sms; + SmsHeader header; + + String[] lines = new String[2]; + + lines[0] = "+CMT: ,77"; + lines[1] = "07914140279510F6440A8111110301003BF56080426101848A3B0B05040B8423F" + + "00003550202362E3130322E3137312E3135302F524F347839776F7547514D4141" + + "424C3641414141536741415A4B55414141414100"; + + sms = SmsMessage.newFromCMT(lines); + header = sms.getUserDataHeader(); + assertNotNull(header); + assertNotNull(sms.getUserData()); + assertNotNull(header.concatRef); + assertEquals(header.concatRef.refNumber, 85); + assertEquals(header.concatRef.msgCount, 2); + assertEquals(header.concatRef.seqNumber, 2); + assertEquals(header.concatRef.isEightBits, true); + assertNotNull(header.portAddrs); + assertEquals(header.portAddrs.destPort, 2948); + assertEquals(header.portAddrs.origPort, 9200); + assertEquals(header.portAddrs.areEightBits, false); + } + + @MediumTest + public void testEfRecord() throws Exception { + SmsMessage sms; + + String s = "03029111000c9194981492631000f269206190022000a053e4534a05358bd3" + + "69f05804259da0219418a40641536a110a0aea408080604028180e888462c1" + + "50341c0f484432a1542c174c46b3e1743c9f9068442a994ea8946ac56ab95e" + + "b0986c46abd96eb89c6ec7ebf97ec0a070482c1a8fc8a472c96c3a9fd0a874" + + "4aad5aafd8ac76cbed7abfe0b0784c2e9bcfe8b47acd6ebbdff0b87c4eafdb" + + "eff8bc7ecfeffbffffffffffffffffffffffffffff"; + byte[] data = IccUtils.hexStringToBytes(s); + + sms = SmsMessage.createFromEfRecord(1, data); + assertNotNull(sms.getMessageBody()); + } +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/SimPhoneBookTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SimPhoneBookTest.java new file mode 100644 index 0000000..609e768 --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/SimPhoneBookTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.os.ServiceManager; +import android.test.suitebuilder.annotation.Suppress; + +import java.util.List; + +import junit.framework.TestCase; + +@Suppress +public class SimPhoneBookTest extends TestCase { + + public void testBasic() throws Exception { + IIccPhoneBook simPhoneBook = + IIccPhoneBook.Stub.asInterface(ServiceManager.getService("simphonebook")); + assertNotNull(simPhoneBook); + + int size[] = simPhoneBook.getAdnRecordsSize(IccConstants.EF_ADN); + assertNotNull(size); + assertEquals(3, size.length); + assertEquals(size[0] * size[2], size[1]); + assertTrue(size[2] >= 100); + + List<AdnRecord> adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); + // do it twice cause the second time shall read from cache only + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); + assertNotNull(adnRecordList); + + // Test for phone book update + int adnIndex, listIndex = 0; + AdnRecord originalAdn = null; + // We need to maintain the state of the SIM before and after the test. + // Since this test doesn't mock the SIM we try to get a valid ADN record, + // for 3 tries and if this fails, we bail out. + for (adnIndex = 3 ; adnIndex >= 1; adnIndex--) { + listIndex = adnIndex - 1; // listIndex is zero based. + originalAdn = adnRecordList.get(listIndex); + assertNotNull("Original Adn is Null.", originalAdn); + assertNotNull("Original Adn alpha tag is null.", originalAdn.getAlphaTag()); + assertNotNull("Original Adn number is null.", originalAdn.getNumber()); + + if (originalAdn.getNumber().length() > 0 && + originalAdn.getAlphaTag().length() > 0) { + break; + } + } + if (adnIndex == 0) return; + + AdnRecord emptyAdn = new AdnRecord("", ""); + AdnRecord firstAdn = new AdnRecord("John", "4085550101"); + AdnRecord secondAdn = new AdnRecord("Andy", "6505550102"); + String pin2 = null; + + // udpate by index + boolean success = simPhoneBook.updateAdnRecordsInEfByIndex(IccConstants.EF_ADN, + firstAdn.getAlphaTag(), firstAdn.getNumber(), adnIndex, pin2); + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); + AdnRecord tmpAdn = adnRecordList.get(listIndex); + assertTrue(success); + assertTrue(firstAdn.isEqual(tmpAdn)); + + // replace by search + success = simPhoneBook.updateAdnRecordsInEfBySearch(IccConstants.EF_ADN, + firstAdn.getAlphaTag(), firstAdn.getNumber(), + secondAdn.getAlphaTag(), secondAdn.getNumber(), pin2); + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); + tmpAdn = adnRecordList.get(listIndex); + assertTrue(success); + assertFalse(firstAdn.isEqual(tmpAdn)); + assertTrue(secondAdn.isEqual(tmpAdn)); + + // erase be search + success = simPhoneBook.updateAdnRecordsInEfBySearch(IccConstants.EF_ADN, + secondAdn.getAlphaTag(), secondAdn.getNumber(), + emptyAdn.getAlphaTag(), emptyAdn.getNumber(), pin2); + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); + tmpAdn = adnRecordList.get(listIndex); + assertTrue(success); + assertTrue(tmpAdn.isEmpty()); + + // restore the orginial adn + success = simPhoneBook.updateAdnRecordsInEfByIndex(IccConstants.EF_ADN, + originalAdn.getAlphaTag(), originalAdn.getNumber(), adnIndex, + pin2); + adnRecordList = simPhoneBook.getAdnRecordsInEf(IccConstants.EF_ADN); + tmpAdn = adnRecordList.get(listIndex); + assertTrue(success); + assertTrue(originalAdn.isEqual(tmpAdn)); + } +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/SimSmsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SimSmsTest.java new file mode 100644 index 0000000..1609680 --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/SimSmsTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.os.ServiceManager; +import android.test.suitebuilder.annotation.MediumTest; +import android.test.suitebuilder.annotation.Suppress; + +import java.util.List; + +import junit.framework.TestCase; + +public class SimSmsTest extends TestCase { + + @MediumTest + @Suppress // TODO: suppress this test for now since it doesn't work on the emulator + public void testBasic() throws Exception { + + ISms sms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + assertNotNull(sms); + + List<SmsRawData> records = sms.getAllMessagesFromIccEf(); + assertNotNull(records); + assertTrue(records.size() >= 0); + + int firstNullIndex = -1; + int firstValidIndex = -1; + byte[] pdu = null; + for (int i = 0; i < records.size(); i++) { + SmsRawData data = records.get(i); + if (data != null && firstValidIndex == -1) { + firstValidIndex = i; + pdu = data.getBytes(); + } + if (data == null && firstNullIndex == -1) { + firstNullIndex = i; + } + if (firstNullIndex != -1 && firstValidIndex != -1) { + break; + } + } + if (firstNullIndex == -1 || firstValidIndex == -1) + return; + assertNotNull(pdu); + } +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java new file mode 100644 index 0000000..db38ede --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/SimUtilsTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import com.android.internal.telephony.gsm.SimTlv; +import com.android.internal.telephony.IccUtils; +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + + +public class SimUtilsTest extends TestCase { + + @SmallTest + public void testBasic() throws Exception { + byte[] data, data2; + + /* + * bcdToString() + */ + + // An EF[ICCID] record + data = IccUtils.hexStringToBytes("981062400510444868f2"); + assertEquals("8901260450014484862", IccUtils.bcdToString(data, 0, data.length)); + + // skip the first and last bytes + assertEquals("0126045001448486", IccUtils.bcdToString(data, 1, data.length - 2)); + + // Stops on invalid BCD value + data = IccUtils.hexStringToBytes("98F062400510444868f2"); + assertEquals("890", IccUtils.bcdToString(data, 0, data.length)); + + /* + * gsmBcdByteToInt() + */ + + assertEquals(98, IccUtils.gsmBcdByteToInt((byte) 0x89)); + + // Out of range is treated as 0 + assertEquals(8, IccUtils.gsmBcdByteToInt((byte) 0x8c)); + + /* + * cdmaBcdByteToInt() + */ + + assertEquals(89, IccUtils.cdmaBcdByteToInt((byte) 0x89)); + + // Out of range is treated as 0 + assertEquals(80, IccUtils.cdmaBcdByteToInt((byte) 0x8c)); + + /* + * adnStringFieldToString() + */ + + + data = IccUtils.hexStringToBytes("00566f696365204d61696c07918150367742f3ffffffffffff"); + // Again, skip prepended 0 + // (this is an EF[ADN] record) + assertEquals("Voice Mail", IccUtils.adnStringFieldToString(data, 1, data.length - 15)); + + data = IccUtils.hexStringToBytes("809673539A5764002F004DFFFFFFFFFF"); + // (this is from an EF[ADN] record) + assertEquals("\u9673\u539A\u5764/M", IccUtils.adnStringFieldToString(data, 0, data.length)); + + data = IccUtils.hexStringToBytes("810A01566fec6365204de0696cFFFFFF"); + // (this is made up to test since I don't have a real one) + assertEquals("Vo\u00ECce M\u00E0il", IccUtils.adnStringFieldToString(data, 0, data.length)); + + data = IccUtils.hexStringToBytes("820505302D82d32d31"); + // Example from 3GPP TS 11.11 V18.1.3.0 annex B + assertEquals("-\u0532\u0583-1", IccUtils.adnStringFieldToString(data, 0, data.length)); + } + +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/TelephonyUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/TelephonyUtilsTest.java new file mode 100644 index 0000000..3757017 --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/TelephonyUtilsTest.java @@ -0,0 +1,219 @@ +/** + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import com.android.internal.telephony.RetryManager; +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class TelephonyUtilsTest extends TestCase { + + /** + * After first creating the RetryManager + * isRetryNeeded should be false and the time 0 + */ + @SmallTest + public void testRetryManagerEmpty() throws Exception { + RetryManager rm = new RetryManager(); + + assertEquals(0, rm.getRetryCount()); + assertFalse(rm.isRetryForever()); + assertFalse(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + + rm.increaseRetryCount(); + assertFalse(rm.isRetryForever()); + assertFalse(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + + rm.setRetryCount(123); + assertFalse(rm.isRetryForever()); + assertFalse(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + + rm.retryForeverUsingLastTimeout(); + assertTrue(rm.isRetryForever()); + assertTrue(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + + rm.setRetryCount(2); + assertFalse(rm.isRetryForever()); + assertFalse(rm.isRetryNeeded()); + assertEquals(0, rm.getRetryCount()); + assertEquals(0, rm.getRetryTimer()); + } + + /** + * A simple test and that randomization is doing something. + */ + @SmallTest + public void testRetryManagerSimplest() throws Exception { + RetryManager rm = new RetryManager(); + + assertTrue(rm.configure(1, 500, 10)); + int loops = 10; + int count = 0; + for (int i = 0; i < loops; i++) { + assertTrue(rm.isRetryNeeded()); + int time = rm.getRetryTimer(); + assertTrue((time >= 500) && (time < 600)); + if (time == 500) { + count++; + } + } + assertFalse(count == loops); + rm.increaseRetryCount(); + assertFalse(rm.isRetryNeeded()); + rm.setRetryCount(0); + assertTrue(rm.isRetryNeeded()); + } + + /** + * Test multiple values using simple configuration. + */ + @SmallTest + public void testRetryManagerSimple() throws Exception { + RetryManager rm = new RetryManager(); + + assertTrue(rm.configure(3, 1000, 0)); + assertTrue(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + assertEquals(rm.getRetryTimer(), 1000); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertFalse(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + } + + /** + * Test string configuration, simplest + */ + @SmallTest + public void testRetryManageSimpleString() throws Exception { + RetryManager rm = new RetryManager(); + + assertTrue(rm.configure("101")); + assertTrue(rm.isRetryNeeded()); + assertEquals(101, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertFalse(rm.isRetryNeeded()); + } + + /** + * Test infinite retires + */ + @SmallTest + public void testRetryManageInfinite() throws Exception { + RetryManager rm = new RetryManager(); + + assertTrue(rm.configure("1000,2000,3000,max_retries=infinite")); + assertTrue(rm.isRetryNeeded()); + assertEquals(1000, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertEquals(2000, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + // All others are 3000 and isRetryNeeded is always true + for (int i=0; i < 100; i++) { + assertEquals(3000, rm.getRetryTimer()); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + } + } + + /** + * Test string configuration using all options and with quotes. + */ + @SmallTest + public void testRetryManageString() throws Exception { + RetryManager rm = new RetryManager(); + int time; + + assertTrue(rm.configure( + "\"max_retries=4, default_randomization=100,1000, 2000 :200 , 3000\"")); + assertTrue(rm.isRetryNeeded()); + time = rm.getRetryTimer(); + assertTrue((time >= 1000) && (time < 1100)); + + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + time = rm.getRetryTimer(); + assertTrue((time >= 2000) && (time < 2200)); + + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + time = rm.getRetryTimer(); + assertTrue((time >= 3000) && (time < 3100)); + + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + time = rm.getRetryTimer(); + assertTrue((time >= 3000) && (time < 3100)); + + rm.increaseRetryCount(); + assertFalse(rm.isRetryNeeded()); + } + + /** + * Test string configuration using all options. + */ + @SmallTest + public void testRetryManageForever() throws Exception { + RetryManager rm = new RetryManager(); + int time; + + assertTrue(rm.configure("1000, 2000, 3000")); + assertTrue(rm.isRetryNeeded()); + assertFalse(rm.isRetryForever()); + assertEquals(0, rm.getRetryCount()); + assertEquals(1000, rm.getRetryTimer()); + + rm.retryForeverUsingLastTimeout(); + rm.increaseRetryCount(); + rm.increaseRetryCount(); + rm.increaseRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertTrue(rm.isRetryForever()); + assertEquals(3, rm.getRetryCount()); + assertEquals(3000, rm.getRetryTimer()); + + rm.setRetryCount(1); + assertTrue(rm.isRetryNeeded()); + assertFalse(rm.isRetryForever()); + assertEquals(1, rm.getRetryCount()); + assertEquals(2000, rm.getRetryTimer()); + + rm.retryForeverUsingLastTimeout(); + assertTrue(rm.isRetryNeeded()); + assertTrue(rm.isRetryForever()); + rm.resetRetryCount(); + assertTrue(rm.isRetryNeeded()); + assertFalse(rm.isRetryForever()); + assertEquals(0, rm.getRetryCount()); + assertEquals(1000, rm.getRetryTimer()); + } +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java new file mode 100644 index 0000000..427795b --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +/** + * Stub class used for unit tests + */ + +public class TestPhoneNotifier implements PhoneNotifier { + public TestPhoneNotifier() { + } + + public void notifyPhoneState(Phone sender) { + } + + public void notifyServiceState(Phone sender) { + } + + public void notifyCellLocation(Phone sender) { + } + + public void notifySignalStrength(Phone sender) { + } + + public void notifyMessageWaitingChanged(Phone sender) { + } + + public void notifyCallForwardingChanged(Phone sender) { + } + + public void notifyDataConnection(Phone sender, String reason) { + } + + public void notifyDataConnectionFailed(Phone sender, String reason) { + } + + public void notifyDataActivity(Phone sender) { + } +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java new file mode 100644 index 0000000..58e73e0 --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java @@ -0,0 +1,887 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.cdma.sms; + +import android.telephony.TelephonyManager; + +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.cdma.SmsMessage; +import com.android.internal.telephony.cdma.sms.BearerData; +import com.android.internal.telephony.cdma.sms.UserData; +import com.android.internal.telephony.cdma.sms.CdmaSmsAddress; +import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails; +import com.android.internal.util.BitwiseInputStream; +import com.android.internal.util.BitwiseOutputStream; +import com.android.internal.util.HexDump; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import android.util.Log; + +import java.util.ArrayList; + +public class CdmaSmsTest extends AndroidTestCase { + private final static String LOG_TAG = "XXX CdmaSmsTest XXX"; + + @SmallTest + public void testCdmaSmsAddrParsing() throws Exception { + CdmaSmsAddress addr = CdmaSmsAddress.parse("6502531000"); + assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN); + assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); + assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); + assertEquals(addr.numberOfDigits, 10); + assertEquals(addr.origBytes.length, 10); + byte[] data = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10}; + for (int i = 0; i < data.length; i++) { + assertEquals(addr.origBytes[i], data[i]); + } + addr = CdmaSmsAddress.parse("(650) 253-1000"); + assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN); + assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); + assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); + assertEquals(addr.numberOfDigits, 10); + assertEquals(addr.origBytes.length, 10); + byte[] data2 = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10}; + for (int i = 0; i < data2.length; i++) { + assertEquals(addr.origBytes[i], data2[i]); + } + addr = CdmaSmsAddress.parse("650.253.1000"); + assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN); + assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); + assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); + assertEquals(addr.numberOfDigits, 10); + assertEquals(addr.origBytes.length, 10); + byte[] data5 = {6, 5, 10, 2, 5, 3, 1, 10, 10, 10}; + for (int i = 0; i < data2.length; i++) { + assertEquals(addr.origBytes[i], data5[i]); + } + addr = CdmaSmsAddress.parse("(+886) 917 222 555"); + assertEquals(addr.ton, CdmaSmsAddress.TON_INTERNATIONAL_OR_IP); + assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); + assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); + assertEquals(addr.numberOfDigits, 12); + assertEquals(addr.origBytes.length, 12); + byte[] data3 = {8, 8, 6, 9, 1, 7, 2, 2, 2, 5, 5, 5}; + for (int i = 0; i < data3.length; i++) { + assertEquals(addr.origBytes[i], data3[i]); + } + addr = CdmaSmsAddress.parse("(650) *253-1000 #600"); + byte[] data4 = {6, 5, 10, 11, 2, 5, 3, 1, 10, 10, 10, 12, 6, 10, 10}; + for (int i = 0; i < data4.length; i++) { + assertEquals(addr.origBytes[i], data4[i]); + } + String input = "x@y.com,a@b.com"; + addr = CdmaSmsAddress.parse(input); + assertEquals(addr.ton, CdmaSmsAddress.TON_NATIONAL_OR_EMAIL); + assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR); + assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK); + assertEquals(addr.numberOfDigits, 15); + assertEquals(addr.origBytes.length, 15); + assertEquals(new String(addr.origBytes), input); + addr = CdmaSmsAddress.parse("foo bar"); + assertEquals(addr.ton, CdmaSmsAddress.TON_UNKNOWN); + assertEquals(addr.digitMode, CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR); + assertEquals(addr.numberMode, CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK); + assertEquals(addr.numberOfDigits, 6); + assertEquals(addr.origBytes.length, 6); + assertEquals(new String(addr.origBytes), "foobar"); + addr = CdmaSmsAddress.parse("f\noo\tb a\rr"); + assertEquals(new String(addr.origBytes), "foobar"); + assertEquals(CdmaSmsAddress.parse("f\u0000oo bar"), null); + assertEquals(CdmaSmsAddress.parse("f\u0007oo bar"), null); + assertEquals(CdmaSmsAddress.parse("f\u0080oo bar"), null); + assertEquals(CdmaSmsAddress.parse("f\u1ECFboo\u001fbar"), null); + assertEquals(CdmaSmsAddress.parse("f\u0080oo bar"), null); + } + + @SmallTest + public void testUserData7bitGsm() throws Exception { + String pdu = "00031040900112488ea794e074d69e1b7392c270326cde9e98"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals("Test standard SMS", bearerData.userData.payloadStr); + } + + @SmallTest + public void testUserData7bitAscii() throws Exception { + String pdu = "0003100160010610262d5ab500"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals("bjjj", bearerData.userData.payloadStr); + } + + @SmallTest + public void testUserData7bitAsciiTwo() throws Exception { + String pdu = "00031001d00109104539b4d052ebb3d0"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals("SMS Rulz", bearerData.userData.payloadStr); + } + + @SmallTest + public void testUserDataIa5() throws Exception { + String pdu = "00031002100109184539b4d052ebb3d0"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals("SMS Rulz", bearerData.userData.payloadStr); + } + + @SmallTest + public void testUserData7bitAsciiFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "Test standard SMS"; + userData.msgEncoding = UserData.ENCODING_7BIT_ASCII; + userData.msgEncodingSet = true; + bearerData.userData = userData; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(BearerData.MESSAGE_TYPE_DELIVER, revBearerData.messageType); + assertEquals(0, revBearerData.messageId); + assertEquals(false, revBearerData.hasUserDataHeader); + assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding); + assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = "Test \u007f standard \u0000 SMS"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals("Test standard SMS", revBearerData.userData.payloadStr); + userData.payloadStr = "Test \n standard \r SMS"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = ""; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + } + + @SmallTest + public void testUserData7bitGsmFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "Test standard SMS"; + userData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; + userData.msgEncodingSet = true; + bearerData.userData = userData; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(BearerData.MESSAGE_TYPE_DELIVER, revBearerData.messageType); + assertEquals(0, revBearerData.messageId); + assertEquals(false, revBearerData.hasUserDataHeader); + assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding); + assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = "1234567"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = ""; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = "12345678901234567890123456789012345678901234567890" + + "12345678901234567890123456789012345678901234567890" + + "12345678901234567890123456789012345678901234567890" + + "1234567890"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = "Test \u007f illegal \u0000 SMS chars"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals("Test illegal SMS chars", revBearerData.userData.payloadStr); + userData.payloadStr = "More @ testing\nis great^|^~woohoo"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = 0xEE; + concatRef.msgCount = 2; + concatRef.seqNumber = 2; + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + byte[] encodedHeader = SmsHeader.toByteArray(smsHeader); + userData.userDataHeader = smsHeader; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + SmsHeader decodedHeader = revBearerData.userData.userDataHeader; + assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber); + assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount); + assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber); + } + + @SmallTest + public void testUserDataUtf16Feedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "\u0160u\u1E5B\u0301r\u1ECFg\uD835\uDC1At\u00E9\u4E002\u3042"; + userData.msgEncoding = UserData.ENCODING_UNICODE_16; + userData.msgEncodingSet = true; + bearerData.userData = userData; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(BearerData.MESSAGE_TYPE_DELIVER, revBearerData.messageType); + assertEquals(0, revBearerData.messageId); + assertEquals(false, revBearerData.hasUserDataHeader); + assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding); + assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.msgEncoding = UserData.ENCODING_OCTET; + userData.msgEncodingSet = false; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(BearerData.MESSAGE_TYPE_DELIVER, revBearerData.messageType); + assertEquals(0, revBearerData.messageId); + assertEquals(false, revBearerData.hasUserDataHeader); + assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding); + assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = "1234567"; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + userData.payloadStr = ""; + revBearerData = BearerData.decode(BearerData.encode(bearerData)); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + } + + @SmallTest + public void testMonolithicOne() throws Exception { + String pdu = "0003200010010410168d2002010503060812011101590501c706069706180000000701c108" + + "01c00901800a01e00b01030c01c00d01070e05039acc13880f018011020566"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals(bearerData.messageType, BearerData.MESSAGE_TYPE_SUBMIT); + assertEquals(bearerData.messageId, 1); + assertEquals(bearerData.priority, BearerData.PRIORITY_EMERGENCY); + assertEquals(bearerData.privacy, BearerData.PRIVACY_CONFIDENTIAL); + assertEquals(bearerData.userAckReq, true); + assertEquals(bearerData.readAckReq, true); + assertEquals(bearerData.deliveryAckReq, true); + assertEquals(bearerData.reportReq, false); + assertEquals(bearerData.numberOfMessages, 3); + assertEquals(bearerData.alert, BearerData.ALERT_HIGH_PRIO); + assertEquals(bearerData.language, BearerData.LANGUAGE_HEBREW); + assertEquals(bearerData.callbackNumber.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); + assertEquals(bearerData.callbackNumber.numberMode, + CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); + assertEquals(bearerData.callbackNumber.ton, CdmaSmsAddress.TON_UNKNOWN); + assertEquals(bearerData.callbackNumber.numberPlan, CdmaSmsAddress.NUMBERING_PLAN_UNKNOWN); + assertEquals(bearerData.callbackNumber.numberOfDigits, 7); + assertEquals(bearerData.callbackNumber.address, "3598271"); + assertEquals(bearerData.displayMode, BearerData.DISPLAY_MODE_USER); + assertEquals(bearerData.depositIndex, 1382); + assertEquals(bearerData.userResponseCode, 5); + assertEquals(bearerData.msgCenterTimeStamp.year, 2008); + assertEquals(bearerData.msgCenterTimeStamp.month, 11); + assertEquals(bearerData.msgCenterTimeStamp.monthDay, 1); + assertEquals(bearerData.msgCenterTimeStamp.hour, 11); + assertEquals(bearerData.msgCenterTimeStamp.minute, 1); + assertEquals(bearerData.msgCenterTimeStamp.second, 59); + assertEquals(bearerData.validityPeriodAbsolute, null); + assertEquals(bearerData.validityPeriodRelative, 193); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.year, 1997); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.month, 5); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.monthDay, 18); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.hour, 0); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.minute, 0); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.second, 0); + assertEquals(bearerData.deferredDeliveryTimeRelative, 199); + assertEquals(bearerData.hasUserDataHeader, false); + assertEquals(bearerData.userData.msgEncoding, UserData.ENCODING_7BIT_ASCII); + assertEquals(bearerData.userData.numFields, 2); + assertEquals(bearerData.userData.payloadStr, "hi"); + } + + @SmallTest + public void testMonolithicTwo() throws Exception { + String pdu = "0003200010010410168d200201050306081201110159050192060697061800000007013d0" + + "801c00901800a01e00b01030c01c00d01070e05039acc13880f018011020566"; + BearerData bearerData = BearerData.decode(HexDump.hexStringToByteArray(pdu)); + assertEquals(bearerData.messageType, BearerData.MESSAGE_TYPE_SUBMIT); + assertEquals(bearerData.messageId, 1); + assertEquals(bearerData.priority, BearerData.PRIORITY_EMERGENCY); + assertEquals(bearerData.privacy, BearerData.PRIVACY_CONFIDENTIAL); + assertEquals(bearerData.userAckReq, true); + assertEquals(bearerData.readAckReq, true); + assertEquals(bearerData.deliveryAckReq, true); + assertEquals(bearerData.reportReq, false); + assertEquals(bearerData.numberOfMessages, 3); + assertEquals(bearerData.alert, BearerData.ALERT_HIGH_PRIO); + assertEquals(bearerData.language, BearerData.LANGUAGE_HEBREW); + assertEquals(bearerData.callbackNumber.digitMode, CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF); + assertEquals(bearerData.callbackNumber.numberMode, + CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK); + assertEquals(bearerData.callbackNumber.ton, CdmaSmsAddress.TON_UNKNOWN); + assertEquals(bearerData.callbackNumber.numberPlan, CdmaSmsAddress.NUMBERING_PLAN_UNKNOWN); + assertEquals(bearerData.callbackNumber.numberOfDigits, 7); + assertEquals(bearerData.callbackNumber.address, "3598271"); + assertEquals(bearerData.displayMode, BearerData.DISPLAY_MODE_USER); + assertEquals(bearerData.depositIndex, 1382); + assertEquals(bearerData.userResponseCode, 5); + assertEquals(bearerData.msgCenterTimeStamp.year, 2008); + assertEquals(bearerData.msgCenterTimeStamp.month, 11); + assertEquals(bearerData.msgCenterTimeStamp.monthDay, 1); + assertEquals(bearerData.msgCenterTimeStamp.hour, 11); + assertEquals(bearerData.msgCenterTimeStamp.minute, 1); + assertEquals(bearerData.msgCenterTimeStamp.second, 59); + assertEquals(bearerData.validityPeriodAbsolute, null); + assertEquals(bearerData.validityPeriodRelative, 61); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.year, 1997); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.month, 5); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.monthDay, 18); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.hour, 0); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.minute, 0); + assertEquals(bearerData.deferredDeliveryTimeAbsolute.second, 0); + assertEquals(bearerData.deferredDeliveryTimeRelative, 146); + assertEquals(bearerData.hasUserDataHeader, false); + assertEquals(bearerData.userData.msgEncoding, UserData.ENCODING_7BIT_ASCII); + assertEquals(bearerData.userData.numFields, 2); + assertEquals(bearerData.userData.payloadStr, "hi"); + } + + @SmallTest + public void testUserDataHeaderConcatRefFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 55; + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = 0xEE; + concatRef.msgCount = 2; + concatRef.seqNumber = 2; + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + byte[] encodedHeader = SmsHeader.toByteArray(smsHeader); + SmsHeader decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber); + assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount); + assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber); + assertEquals(decodedHeader.concatRef.isEightBits, concatRef.isEightBits); + assertEquals(decodedHeader.portAddrs, null); + UserData userData = new UserData(); + userData.payloadStr = "User Data Header (UDH) feedback test"; + userData.userDataHeader = smsHeader; + bearerData.userData = userData; + byte[] encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + decodedHeader = revBearerData.userData.userDataHeader; + assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber); + assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount); + assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber); + assertEquals(decodedHeader.concatRef.isEightBits, concatRef.isEightBits); + assertEquals(decodedHeader.portAddrs, null); + } + + @SmallTest + public void testUserDataHeaderIllegalConcatRef() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 55; + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = 0x10; + concatRef.msgCount = 0; + concatRef.seqNumber = 2; + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + byte[] encodedHeader = SmsHeader.toByteArray(smsHeader); + SmsHeader decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef, null); + concatRef.isEightBits = false; + encodedHeader = SmsHeader.toByteArray(smsHeader); + decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef, null); + concatRef.msgCount = 1; + concatRef.seqNumber = 2; + encodedHeader = SmsHeader.toByteArray(smsHeader); + decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef, null); + concatRef.msgCount = 1; + concatRef.seqNumber = 0; + encodedHeader = SmsHeader.toByteArray(smsHeader); + decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef, null); + concatRef.msgCount = 2; + concatRef.seqNumber = 1; + encodedHeader = SmsHeader.toByteArray(smsHeader); + decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef.msgCount, 2); + assertEquals(decodedHeader.concatRef.seqNumber, 1); + } + + @SmallTest + public void testUserDataHeaderMixedFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 42; + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = 0x34; + concatRef.msgCount = 5; + concatRef.seqNumber = 2; + concatRef.isEightBits = false; + SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs(); + portAddrs.destPort = 88; + portAddrs.origPort = 66; + portAddrs.areEightBits = false; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + smsHeader.portAddrs = portAddrs; + byte[] encodedHeader = SmsHeader.toByteArray(smsHeader); + SmsHeader decodedHeader = SmsHeader.fromByteArray(encodedHeader); + assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber); + assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount); + assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber); + assertEquals(decodedHeader.concatRef.isEightBits, concatRef.isEightBits); + assertEquals(decodedHeader.portAddrs.destPort, portAddrs.destPort); + assertEquals(decodedHeader.portAddrs.origPort, portAddrs.origPort); + assertEquals(decodedHeader.portAddrs.areEightBits, portAddrs.areEightBits); + UserData userData = new UserData(); + userData.payloadStr = "User Data Header (UDH) feedback test"; + userData.userDataHeader = smsHeader; + bearerData.userData = userData; + byte[] encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + decodedHeader = revBearerData.userData.userDataHeader; + assertEquals(decodedHeader.concatRef.refNumber, concatRef.refNumber); + assertEquals(decodedHeader.concatRef.msgCount, concatRef.msgCount); + assertEquals(decodedHeader.concatRef.seqNumber, concatRef.seqNumber); + assertEquals(decodedHeader.concatRef.isEightBits, concatRef.isEightBits); + assertEquals(decodedHeader.portAddrs.destPort, portAddrs.destPort); + assertEquals(decodedHeader.portAddrs.origPort, portAddrs.origPort); + assertEquals(decodedHeader.portAddrs.areEightBits, portAddrs.areEightBits); + } + + @SmallTest + public void testReplyOption() throws Exception { + String pdu1 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d87450080a0180"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals("Test Acknowledgement 1", bd1.userData.payloadStr); + assertEquals(true, bd1.userAckReq); + assertEquals(false, bd1.deliveryAckReq); + assertEquals(false, bd1.readAckReq); + assertEquals(false, bd1.reportReq); + String pdu2 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d87490080a0140"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals("Test Acknowledgement 2", bd2.userData.payloadStr); + assertEquals(false, bd2.userAckReq); + assertEquals(true, bd2.deliveryAckReq); + assertEquals(false, bd2.readAckReq); + assertEquals(false, bd2.reportReq); + String pdu3 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d874d0080a0120"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals("Test Acknowledgement 3", bd3.userData.payloadStr); + assertEquals(false, bd3.userAckReq); + assertEquals(false, bd3.deliveryAckReq); + assertEquals(true, bd3.readAckReq); + assertEquals(false, bd3.reportReq); + String pdu4 = "0003104090011648b6a794e0705476bf77bceae934fe5f6d94d87510080a0110"; + BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4)); + assertEquals("Test Acknowledgement 4", bd4.userData.payloadStr); + assertEquals(false, bd4.userAckReq); + assertEquals(false, bd4.deliveryAckReq); + assertEquals(false, bd4.readAckReq); + assertEquals(true, bd4.reportReq); + } + + @SmallTest + public void testReplyOptionFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test reply option"; + bearerData.userData = userData; + bearerData.userAckReq = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(true, revBearerData.userAckReq); + assertEquals(false, revBearerData.deliveryAckReq); + assertEquals(false, revBearerData.readAckReq); + assertEquals(false, revBearerData.reportReq); + bearerData.userAckReq = false; + bearerData.deliveryAckReq = true; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(false, revBearerData.userAckReq); + assertEquals(true, revBearerData.deliveryAckReq); + assertEquals(false, revBearerData.readAckReq); + assertEquals(false, revBearerData.reportReq); + bearerData.deliveryAckReq = false; + bearerData.readAckReq = true; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(false, revBearerData.userAckReq); + assertEquals(false, revBearerData.deliveryAckReq); + assertEquals(true, revBearerData.readAckReq); + assertEquals(false, revBearerData.reportReq); + bearerData.readAckReq = false; + bearerData.reportReq = true; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(false, revBearerData.userAckReq); + assertEquals(false, revBearerData.deliveryAckReq); + assertEquals(false, revBearerData.readAckReq); + assertEquals(true, revBearerData.reportReq); + } + + @SmallTest + public void testNumberOfMessages() throws Exception { + // Note that the message text below does not properly reflect + // the message count. The author of these messages was + // apparently unaware that the values are bcd encoded, and the + // values being tested against (not the ones in the message + // text) are actually correct. + String pdu1 = "000310409001124896a794e07595f69f199540ea759a0dc8e00b0163"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals("Test Voice mail 99", bd1.userData.payloadStr); + assertEquals(63, bd1.numberOfMessages); + String pdu2 = "00031040900113489ea794e07595f69f199540ea759a0988c0600b0164"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals("Test Voice mail 100", bd2.userData.payloadStr); + assertEquals(64, bd2.numberOfMessages); + } + + @SmallTest + public void testCallbackNum() throws Exception { + String pdu1 = "00031040900112488ea794e070d436cb638bc5e035ce2f97900e06910431323334"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals("Test Callback nbr", bd1.userData.payloadStr); + assertEquals(CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR, bd1.callbackNumber.digitMode); + assertEquals(CdmaSmsAddress.TON_INTERNATIONAL_OR_IP, bd1.callbackNumber.ton); + assertEquals(CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK, bd1.callbackNumber.numberMode); + assertEquals(CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY, bd1.callbackNumber.numberPlan); + assertEquals("1234", bd1.callbackNumber.address); + } + + @SmallTest + public void testCallbackNumDtmf() throws Exception { + String pdu1 = "00031002300109104539b4d052ebb3d00e07052d4c90a55080"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals("SMS Rulz", bd1.userData.payloadStr); + assertEquals(CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF, bd1.callbackNumber.digitMode); + assertEquals(CdmaSmsAddress.TON_UNKNOWN, bd1.callbackNumber.ton); + assertEquals(CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK, bd1.callbackNumber.numberMode); + assertEquals(CdmaSmsAddress.NUMBERING_PLAN_UNKNOWN, bd1.callbackNumber.numberPlan); + assertEquals("5099214001", bd1.callbackNumber.address); + } + + @SmallTest + public void testCallbackNumFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test callback number"; + bearerData.userData = userData; + CdmaSmsAddress addr = new CdmaSmsAddress(); + addr.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR; + addr.ton = CdmaSmsAddress.TON_NATIONAL_OR_EMAIL; + addr.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK; + addr.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_UNKNOWN; + addr.address = "8005551212"; + addr.numberOfDigits = (byte)addr.address.length(); + bearerData.callbackNumber = addr; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + CdmaSmsAddress revAddr = revBearerData.callbackNumber; + assertEquals(addr.digitMode, revAddr.digitMode); + assertEquals(addr.ton, revAddr.ton); + assertEquals(addr.numberMode, revAddr.numberMode); + assertEquals(addr.numberPlan, revAddr.numberPlan); + assertEquals(addr.numberOfDigits, revAddr.numberOfDigits); + assertEquals(addr.address, revAddr.address); + addr.address = "8*55#1012"; + addr.numberOfDigits = (byte)addr.address.length(); + addr.digitMode = CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + revAddr = revBearerData.callbackNumber; + assertEquals(addr.digitMode, revAddr.digitMode); + assertEquals(addr.numberOfDigits, revAddr.numberOfDigits); + assertEquals(addr.address, revAddr.address); + } + + @SmallTest + public void testPrivacyIndicator() throws Exception { + String pdu1 = "0003104090010c485f4194dfea34becf61b840090140"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.privacy, BearerData.PRIVACY_RESTRICTED); + String pdu2 = "0003104090010c485f4194dfea34becf61b840090180"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.privacy, BearerData.PRIVACY_CONFIDENTIAL); + String pdu3 = "0003104090010c485f4194dfea34becf61b8400901c0"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals(bd3.privacy, BearerData.PRIVACY_SECRET); + } + + @SmallTest + public void testPrivacyIndicatorFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test privacy indicator"; + bearerData.userData = userData; + bearerData.privacy = BearerData.PRIVACY_SECRET; + bearerData.privacyIndicatorSet = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.privacyIndicatorSet, true); + assertEquals(revBearerData.privacy, BearerData.PRIVACY_SECRET); + bearerData.privacy = BearerData.PRIVACY_RESTRICTED; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.privacy, BearerData.PRIVACY_RESTRICTED); + } + + @SmallTest + public void testMsgDeliveryAlert() throws Exception { + String pdu1 = "0003104090010d4866a794e07055965b91d040300c0100"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.alert, 0); + assertEquals(bd1.userData.payloadStr, "Test Alert 0"); + String pdu2 = "0003104090010d4866a794e07055965b91d140300c0140"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.alert, 1); + assertEquals(bd2.userData.payloadStr, "Test Alert 1"); + String pdu3 = "0003104090010d4866a794e07055965b91d240300c0180"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals(bd3.alert, 2); + assertEquals(bd3.userData.payloadStr, "Test Alert 2"); + String pdu4 = "0003104090010d4866a794e07055965b91d340300c01c0"; + BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4)); + assertEquals(bd4.alert, 3); + assertEquals(bd4.userData.payloadStr, "Test Alert 3"); + String pdu5 = "00031000000126114F4CBCFA20DB979F3C39F2A0C9976" + + "69ED979794187665E5D1028EFA7A6840E1062D3D39A900C028000"; + BearerData bd5 = BearerData.decode(HexDump.hexStringToByteArray(pdu5)); + assertEquals(bd5.alert, BearerData.ALERT_MEDIUM_PRIO); + assertEquals(bd5.userData.payloadStr, "test message delivery alert (with 8 bits)"); + String pdu6 = "00031000000126114F4CBCFA20DB979F3C39F2A0C9976" + + "69ED979794187665E5D1028EFA7A6840C1062D3D39A900C00"; + BearerData bd6 = BearerData.decode(HexDump.hexStringToByteArray(pdu6)); + assertEquals(bd6.userData.payloadStr, "test message delivery alert (with 0 bits)"); + assertEquals(bd6.alertIndicatorSet, false); + } + + @SmallTest + public void testMiscParams() throws Exception { + String pdu1 = "00031002400109104539b4d052ebb3d00c0180"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.alert, BearerData.ALERT_MEDIUM_PRIO); + assertEquals(bd1.userData.payloadStr, "SMS Rulz"); + String pdu2 = "00031002500109104539b4d052ebb3d00801800901c0"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.priority, BearerData.PRIORITY_URGENT); + assertEquals(bd2.privacy, BearerData.PRIVACY_SECRET); + assertEquals(bd2.userData.payloadStr, "SMS Rulz"); + String pdu3 = "00031002600109104539b4d052ebb3d00901400c01c0"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals(bd3.privacy, BearerData.PRIVACY_RESTRICTED); + assertEquals(bd3.alert, BearerData.ALERT_HIGH_PRIO); + assertEquals(bd3.userData.payloadStr, "SMS Rulz"); + String pdu4 = "00031002700109104539b4d052ebb3d00f0105"; + BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4)); + assertEquals(bd4.displayMode, BearerData.DISPLAY_MODE_IMMEDIATE); + assertEquals(bd4.userData.payloadStr, "SMS Rulz"); + } + @SmallTest + public void testMsgDeliveryAlertFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test message delivery alert"; + bearerData.userData = userData; + bearerData.alert = BearerData.ALERT_MEDIUM_PRIO; + bearerData.alertIndicatorSet = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.alertIndicatorSet, true); + assertEquals(revBearerData.alert, bearerData.alert); + bearerData.alert = BearerData.ALERT_HIGH_PRIO; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.alertIndicatorSet, true); + assertEquals(revBearerData.alert, bearerData.alert); + } + + @SmallTest + public void testLanguageIndicator() throws Exception { + String pdu1 = "0003104090011748bea794e0731436ef3bd7c2e0352eef27a1c263fe58080d0101"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.userData.payloadStr, "Test Language indicator"); + assertEquals(bd1.language, BearerData.LANGUAGE_ENGLISH); + String pdu2 = "0003104090011748bea794e0731436ef3bd7c2e0352eef27a1c263fe58080d0106"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.userData.payloadStr, "Test Language indicator"); + assertEquals(bd2.language, BearerData.LANGUAGE_CHINESE); + } + + @SmallTest + public void testLanguageIndicatorFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test language indicator"; + bearerData.userData = userData; + bearerData.language = BearerData.LANGUAGE_ENGLISH; + bearerData.languageIndicatorSet = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.languageIndicatorSet, true); + assertEquals(revBearerData.language, bearerData.language); + bearerData.language = BearerData.LANGUAGE_KOREAN; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.languageIndicatorSet, true); + assertEquals(revBearerData.language, bearerData.language); + } + + @SmallTest + public void testDisplayMode() throws Exception { + String pdu1 = "0003104090010c485f4194dfea34becf61b8400f0100"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.displayMode, BearerData.DISPLAY_MODE_IMMEDIATE); + String pdu2 = "0003104090010c485f4194dfea34becf61b8400f0140"; + BearerData bd2 = BearerData.decode(HexDump.hexStringToByteArray(pdu2)); + assertEquals(bd2.displayMode, BearerData.DISPLAY_MODE_DEFAULT); + String pdu3 = "0003104090010c485f4194dfea34becf61b8400f0180"; + BearerData bd3 = BearerData.decode(HexDump.hexStringToByteArray(pdu3)); + assertEquals(bd3.displayMode, BearerData.DISPLAY_MODE_USER); + } + + @SmallTest + public void testDisplayModeFeedback() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 0; + bearerData.hasUserDataHeader = false; + UserData userData = new UserData(); + userData.payloadStr = "test display mode"; + bearerData.userData = userData; + bearerData.displayMode = BearerData.DISPLAY_MODE_IMMEDIATE; + bearerData.displayModeSet = true; + byte []encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.displayModeSet, true); + assertEquals(revBearerData.displayMode, bearerData.displayMode); + bearerData.displayMode = BearerData.DISPLAY_MODE_USER; + encodedSms = BearerData.encode(bearerData); + revBearerData = BearerData.decode(encodedSms); + assertEquals(revBearerData.userData.payloadStr, userData.payloadStr); + assertEquals(revBearerData.displayModeSet, true); + assertEquals(revBearerData.displayMode, bearerData.displayMode); + } + + @SmallTest + public void testIs91() throws Exception { + String pdu1 = "000320001001070c2039acc13880"; + BearerData bd1 = BearerData.decode(HexDump.hexStringToByteArray(pdu1)); + assertEquals(bd1.callbackNumber.address, "3598271"); + String pdu4 = "000320001001080c283c314724b34e"; + BearerData bd4 = BearerData.decode(HexDump.hexStringToByteArray(pdu4)); + assertEquals(bd4.userData.payloadStr, "ABCDEFG"); + } + + @SmallTest + public void testUserDataHeaderWithEightCharMsg() throws Exception { + BearerData bearerData = new BearerData(); + bearerData.messageType = BearerData.MESSAGE_TYPE_DELIVER; + bearerData.messageId = 55; + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = 0xEE; + concatRef.msgCount = 2; + concatRef.seqNumber = 2; + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + UserData userData = new UserData(); + userData.payloadStr = "01234567"; + userData.userDataHeader = smsHeader; + bearerData.userData = userData; + byte[] encodedSms = BearerData.encode(bearerData); + BearerData revBearerData = BearerData.decode(encodedSms); + assertEquals(userData.payloadStr, revBearerData.userData.payloadStr); + } + + @SmallTest + public void testFragmentText() throws Exception { + boolean isCdmaPhone = (TelephonyManager.getDefault().getPhoneType() == + TelephonyManager.PHONE_TYPE_CDMA); + // Valid 160 character ASCII text. + String text1 = "123456789012345678901234567890123456789012345678901234567890" + + "1234567890123456789012345678901234567890123456789012345678901234567890" + + "12345678901234567890123456789["; + TextEncodingDetails ted = SmsMessage.calculateLength(text1, false); + assertEquals(ted.msgCount, 1); + assertEquals(ted.codeUnitCount, 160); + assertEquals(ted.codeUnitSize, 1); + if (isCdmaPhone) { + ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text1); + assertEquals(fragments.size(), 1); + } + + /* + This is not a valid test: we will never encode a single-segment + EMS message. Leaving this here, since we may try to support + this in the future. + + // Valid 160 character GSM text -- the last character is + // non-ASCII, and so this will currently generate a singleton + // EMS message, which is not necessarily supported by Verizon. + String text2 = "123456789012345678901234567890123456789012345678901234567890" + + "1234567890123456789012345678901234567890123456789012345678901234567890" + + "12345678901234567890123456789\u00a3"; // Trailing pound-currency sign. + ted = SmsMessage.calculateLength(text2, false); + assertEquals(ted.msgCount, 1); + assertEquals(ted.codeUnitCount, 160); + assertEquals(ted.codeUnitSize, 1); + if (isCdmaPhone) { + ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text2); + assertEquals(fragments.size(), 1); + } + */ + + // *IF* we supported single-segment EMS, this text would result in a + // single fragment with 7-bit encoding. But we don't, so this text + // results in three fragments of 16-bit encoding. + String text2 = "123456789012345678901234567890123456789012345678901234567890" + + "1234567890123456789012345678901234567890123456789012345678901234567890" + + "12345678901234567890123456789\u00a3"; // Trailing pound-currency sign. + ted = SmsMessage.calculateLength(text2, false); + assertEquals(3, ted.msgCount); + assertEquals(160, ted.codeUnitCount); + assertEquals(3, ted.codeUnitSize); + if (isCdmaPhone) { + ArrayList<String> fragments = android.telephony.SmsMessage.fragmentText(text2); + assertEquals(3, fragments.size()); + } + + } +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java new file mode 100644 index 0000000..b96743a --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMPhoneTest.java @@ -0,0 +1,1938 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF GSMTestHandler.ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.gsm; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.Process; +import android.telephony.ServiceState; +import android.test.AndroidTestCase; +import android.test.PerformanceTestCase; +import android.util.Log; + +import com.android.internal.telephony.Call; +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.MmiCode; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.TestPhoneNotifier; +import com.android.internal.telephony.gsm.CallFailCause; +import com.android.internal.telephony.gsm.GSMPhone; +import com.android.internal.telephony.gsm.GSMTestHandler; +import com.android.internal.telephony.gsm.GsmMmiCode; +import com.android.internal.telephony.gsm.SuppServiceNotification; +import com.android.internal.telephony.test.SimulatedCommands; +import com.android.internal.telephony.test.SimulatedRadioControl; + +import java.util.List; + + +public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase { + private SimulatedRadioControl mRadioControl; + private GSMPhone mGSMPhone; + private GSMTestHandler mGSMTestHandler; + private Handler mHandler; + + private static final int EVENT_PHONE_STATE_CHANGED = 1; + private static final int EVENT_DISCONNECT = 2; + private static final int EVENT_RINGING = 3; + private static final int EVENT_CHANNEL_OPENED = 4; + private static final int EVENT_POST_DIAL = 5; + private static final int EVENT_DONE = 6; + private static final int EVENT_SSN = 7; + private static final int EVENT_MMI_INITIATE = 8; + private static final int EVENT_MMI_COMPLETE = 9; + private static final int EVENT_IN_SERVICE = 10; + private static final int SUPP_SERVICE_FAILED = 11; + private static final int SERVICE_STATE_CHANGED = 12; + private static final int EVENT_OEM_RIL_MESSAGE = 13; + public static final int ANY_MESSAGE = -1; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mGSMTestHandler = new GSMTestHandler(mContext); + + mGSMTestHandler.start(); + synchronized (mGSMTestHandler) { + do { + mGSMTestHandler.wait(); + } while (mGSMTestHandler.getGSMPhone() == null); + } + + mGSMPhone = mGSMTestHandler.getGSMPhone(); + mRadioControl = mGSMTestHandler.getSimulatedCommands(); + + mHandler = mGSMTestHandler.getHandler(); + mGSMPhone.registerForPreciseCallStateChanged(mHandler, EVENT_PHONE_STATE_CHANGED, null); + mGSMPhone.registerForNewRingingConnection(mHandler, EVENT_RINGING, null); + mGSMPhone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null); + + mGSMPhone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL, null); + + mGSMPhone.registerForSuppServiceNotification(mHandler, EVENT_SSN, null); + mGSMPhone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null); + mGSMPhone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null); + mGSMPhone.registerForSuppServiceFailed(mHandler, SUPP_SERVICE_FAILED, null); + + mGSMPhone.registerForServiceStateChanged(mHandler, SERVICE_STATE_CHANGED, null); + + // wait until we get phone in both voice and data service + Message msg; + ServiceState state; + + do { + msg = mGSMTestHandler.waitForMessage(SERVICE_STATE_CHANGED); + assertNotNull("Message Time Out", msg); + state = (ServiceState) ((AsyncResult) msg.obj).result; + } while (state.getState() != ServiceState.STATE_IN_SERVICE); + } + + @Override + protected void tearDown() throws Exception { + mRadioControl.shutdown(); + + mGSMPhone.unregisterForPreciseCallStateChanged(mHandler); + mGSMPhone.unregisterForNewRingingConnection(mHandler); + mGSMPhone.unregisterForDisconnect(mHandler); + mGSMPhone.setOnPostDialCharacter(mHandler, 0, null); + mGSMPhone.unregisterForSuppServiceNotification(mHandler); + mGSMPhone.unregisterForMmiInitiate(mHandler); + mGSMPhone.unregisterForMmiComplete(mHandler); + + mGSMPhone = null; + mRadioControl = null; + mHandler = null; + mGSMTestHandler.cleanup(); + + super.tearDown(); + } + + // These test can only be run once. + public int startPerformance(Intermediates intermediates) { + return 1; + } + + public boolean isPerformanceOnly() { + return false; + } + + + //This test is causing the emulator screen to turn off. I don't understand + //why, but I'm removing it until we can figure it out. + public void brokenTestGeneral() throws Exception { + Connection cn; + Message msg; + AsyncResult ar; + + // IDLE state + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + assertFalse(mGSMPhone.canConference()); + + // One DIALING connection + + mRadioControl.setAutoProgressConnectingCall(false); + + mGSMPhone.dial("+13125551212"); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + + msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED); + assertNotNull("Message Time Out", msg); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.DIALING, mGSMPhone.getForegroundCall().getState()); + assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + /*do { + mGSMTestHandler.waitForMessage(ANY_MESSAGE); + } while (mGSMPhone.getForegroundCall().getConnections().size() == 0);*/ + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DIALING, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(!cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + + assertEquals(Connection.DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause()); + + assertFalse(mGSMPhone.canConference()); + + // One ALERTING connection + + mRadioControl.progressConnectingCallState(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ALERTING, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(!cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + assertFalse(mGSMPhone.canConference()); + + // One ACTIVE connection + + mRadioControl.progressConnectingCallState(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(!cn.isIncoming()); + assertEquals(Connection.PostDialState.COMPLETE, cn.getPostDialState()); + assertFalse(mGSMPhone.canConference()); + + // One disconnected connection + mGSMPhone.getForegroundCall().hangup(); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + assertFalse(mGSMPhone.canConference()); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // Back to idle state + + mGSMPhone.clearDisconnected(); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + + // cn left over from before phone.clearDisconnected(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // One ringing (INCOMING) call + + mRadioControl.triggerRing("18005551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + ar = (AsyncResult) msg.obj; + cn = (Connection) ar.result; + assertTrue(cn.isRinging()); + assertEquals(mGSMPhone.getRingingCall(), cn.getCall()); + + assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getRingingCall().getConnections().get(0); + assertTrue(cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + + assertFalse(mGSMPhone.canConference()); + + // One mobile terminated active call + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getConnections().size() == 1); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + cn = mGSMPhone.getForegroundCall().getConnections().get(0); + assertTrue(cn.isIncoming()); + assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState()); + + assertFalse(mGSMPhone.canConference()); + + // One disconnected (local hangup) call + + try { + Connection conn; + conn = mGSMPhone.getForegroundCall().getConnections().get(0); + conn.hangup(); + } catch (CallStateException ex) { + ex.printStackTrace(); + fail("unexpected ex"); + } + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + + assertFalse(mGSMPhone.canConference()); + + // Back to idle state + + mGSMPhone.clearDisconnected(); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + + // cn left over from before phone.clearDisconnected(); + + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // One ringing call + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getConnections().isEmpty()); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + + // One rejected call + mGSMPhone.rejectCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.IDLE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(1, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + + assertFalse(mGSMPhone.canConference()); + + // Back to idle state + + mGSMPhone.clearDisconnected(); + + assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime()); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + assertFalse(mGSMPhone.canConference()); + assertEquals(Call.State.DISCONNECTED, cn.getState()); + + // One ringing call + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getConnections().isEmpty()); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + + // Ringing call disconnects + + mRadioControl.triggerHangupForeground(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.IDLE); + + assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + + // One Ringing Call + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.RINGING); + + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + + // One answered call + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.OFFHOOK); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // one holding call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // one active call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // One disconnected call in the foreground slot + + mRadioControl.triggerHangupAll(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.IDLE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause()); + + // Test missed calls + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.RINGING); + + mGSMPhone.rejectCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (msg.what != EVENT_DISCONNECT); + + ar = (AsyncResult) msg.obj; + cn = (Connection) ar.result; + + assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause()); + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); + + // Test incoming not missed calls + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.RINGING); + + cn = mGSMPhone.getRingingCall().getEarliestConnection(); + + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.OFFHOOK); + + assertEquals(Connection.DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + + try { + mGSMPhone.getForegroundCall().hangup(); + } catch (CallStateException ex) { + ex.printStackTrace(); + fail("unexpected ex"); + } + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() + != Call.State.DISCONNECTED); + + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + + // + // Test held and hangup held calls + // + + // One ALERTING call + mGSMPhone.dial("+13125551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.OFFHOOK); + + assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + mRadioControl.progressConnectingCallState(); + mRadioControl.progressConnectingCallState(); + + // One ACTIVE call + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + // One ACTIVE call, one ringing call + + mRadioControl.triggerRing("18005551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.RINGING); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + // One HOLDING call, one ACTIVE call + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.OFFHOOK); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertTrue(mGSMPhone.canConference()); + + // Conference the two + mGSMPhone.conference(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertTrue(mGSMPhone.getForegroundCall().isMultiparty()); + assertFalse(mGSMPhone.canConference()); + + // Hold the multiparty call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertTrue(mGSMPhone.getBackgroundCall().isMultiparty()); + assertFalse(mGSMPhone.canConference()); + + // Multiparty call on hold, call waiting added + + mRadioControl.triggerRing("18005558355"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.RINGING); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertTrue(mGSMPhone.getBackgroundCall().isMultiparty()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertFalse(mGSMPhone.canConference()); + + // Hangup conference call, ringing call still around + mGSMPhone.getBackgroundCall().hangup(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.DISCONNECTED); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState()); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + + // Reject waiting call + mGSMPhone.rejectCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.IDLE); + + assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + } + + public void testOutgoingCallFailImmediately() throws Exception { + Message msg; + + // Test outgoing call fail-immediately edge case + // This happens when a call terminated before ever appearing in a + // call list + // This should land the immediately-failing call in the + // ForegroundCall list as an IDLE call + mRadioControl.setNextDialFailImmediately(true); + + Connection cn = mGSMPhone.dial("+13125551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + } + + public void testHangupOnOutgoing() throws Exception { + Connection cn; + Message msg; + + mRadioControl.setAutoProgressConnectingCall(false); + + // Test 1: local hangup in "DIALING" state + mGSMPhone.dial("+13125551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getForegroundCall().getState() != Call.State.DIALING); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + mGSMPhone.getForegroundCall().hangup(); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + + // Test 2: local hangup in "ALERTING" state + mGSMPhone.dial("+13125551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.OFFHOOK); + + mRadioControl.progressConnectingCallState(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } + while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING); + + cn = mGSMPhone.getForegroundCall().getEarliestConnection(); + + mGSMPhone.getForegroundCall().hangup(); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause()); + + // Test 3: local immediate hangup before GSM index is + // assigned (CallTracker.hangupPendingMO case) + + mRadioControl.pauseResponses(); + + cn = mGSMPhone.dial("+13125551212"); + + cn.hangup(); + + mRadioControl.resumeResponses(); + + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + + assertEquals(Connection.DisconnectCause.LOCAL, + mGSMPhone.getForegroundCall().getEarliestConnection().getDisconnectCause()); + } + + public void testHangupOnChannelClose() throws Exception { + mGSMPhone.dial("+13125551212"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getConnections().isEmpty()); + + mRadioControl.shutdown(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + mGSMPhone.clearDisconnected(); + } while (!mGSMPhone.getForegroundCall().getConnections().isEmpty()); + } + + public void testIncallMmiCallDeflection() throws Exception { + Message msg; + + // establish an active call + mGSMPhone.dial("+13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // establish a ringing (WAITING) call + + mRadioControl.triggerRing("18005551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 0 followed by SEND: release all held calls + // or sets UDUB for a waiting call. + mGSMPhone.handleInCallMmiCommands("0"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // change the active call to holding call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 0 followed by SEND: release all held calls + // or sets UDUB for a waiting call. + mGSMPhone.handleInCallMmiCommands("0"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState()); + } + + public void testIncallMmiCallWaiting() throws Exception { + Message msg; + + // establish an active call + mGSMPhone.dial("+13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // establish a ringing (WAITING) call + + mRadioControl.triggerRing("18005551212"); + + do { + msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); + assertNotNull("Message Time Out", msg); + } while (msg.what != EVENT_RINGING); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 1 followed by SEND: release all active calls + // (if any exist) and accepts the other (held or waiting) call. + + mGSMPhone.handleInCallMmiCommands("1"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + + // change the active call to holding call + mGSMPhone.switchHoldingAndActive(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 1 followed by SEND: release all active calls + // (if any exist) and accepts the other (held or waiting) call. + mGSMPhone.handleInCallMmiCommands("1"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + + // at this point, the active call with number==18005551212 should + // have the gsm index of 2 + + mRadioControl.triggerRing("16505550100"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering "12" followed by SEND: release the call with + // gsm index equals to 2. + mGSMPhone.handleInCallMmiCommands("12"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getState() != Phone.State.OFFHOOK); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // at this point, the call with number==16505550100 should + // have the gsm index of 1 + mGSMPhone.dial("+13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE || + mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // at this point, the active call with number==13125551212 should + // have the gsm index of 2 + + // Simulate entering "11" followed by SEND: release the call with + // gsm index equals to 1. This should not be allowed, and a + // Supplementary Service notification must be received. + mGSMPhone.handleInCallMmiCommands("11"); + + msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED); + assertNotNull("Message Time Out", msg); + assertFalse("IncallMmiCallWaiting: command should not work on holding call", msg == null); + + // Simulate entering "12" followed by SEND: release the call with + // gsm index equals to 2. + mGSMPhone.handleInCallMmiCommands("12"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // Simulate entering 1 followed by SEND: release all active calls + // (if any exist) and accepts the other (held or waiting) call. + mGSMPhone.handleInCallMmiCommands("1"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + assertEquals("16505550100", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + + // Simulate entering "11" followed by SEND: release the call with + // gsm index equals to 1. + mGSMPhone.handleInCallMmiCommands("11"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + public void testIncallMmiCallHold() throws Exception { + Message msg; + + // establish an active call + mGSMPhone.dial("13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // establish a ringing (WAITING) call + + mRadioControl.triggerRing("18005551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // simulate entering 2 followed by SEND: place all active calls + // (if any exist) on hold and accepts the other (held or waiting) + // call + + mGSMPhone.handleInCallMmiCommands("2"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING); + + + assertFalse(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, + mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("13125551212", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + + // swap the active and holding calls + mGSMPhone.handleInCallMmiCommands("2"); + + msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED); + assertNotNull("Message Time Out", msg); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("13125551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + + // merge the calls + mGSMPhone.conference(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + assertEquals(2, mGSMPhone.getForegroundCall().getConnections().size()); + + // at this point, we have an active conference call, with + // call(1) = 13125551212 and call(2) = 18005551212 + + // Simulate entering "23" followed by SEND: places all active call + // on hold except call 3. This should fail and a supplementary service + // failed notification should be received. + + mGSMPhone.handleInCallMmiCommands("23"); + + msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED); + assertNotNull("Message Time Out", msg); + assertFalse("IncallMmiCallHold: separate should have failed!", msg == null); + + // Simulate entering "21" followed by SEND: places all active call + // on hold except call 1. + mGSMPhone.handleInCallMmiCommands("21"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("13125551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + } + + public void testIncallMmiMultipartyServices() throws Exception { + // establish an active call + mGSMPhone.dial("13125551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + // dial another call + mGSMPhone.dial("18005551212"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + mGSMPhone.handleInCallMmiCommands("3"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals("13125551212", + mGSMPhone.getForegroundCall().getConnections().get(1).getAddress()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + public void testCallIndex() throws Exception { + Message msg; + + // establish the first call + mGSMPhone.dial("16505550100"); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + String baseNumber = "1650555010"; + + for (int i = 1; i < 6; i++) { + String number = baseNumber + i; + + mGSMPhone.dial(number); + + do { + mRadioControl.progressConnectingCallState(); + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + if (mGSMPhone.getBackgroundCall().getConnections().size() >= 5) { + break; + } + + mGSMPhone.conference(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("16505550105", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // create an incoming call, this call should have the call index + // of 7 + mRadioControl.triggerRing("18005551212"); + + msg = mGSMTestHandler.waitForMessage(EVENT_RINGING); + assertNotNull("Message Time Out", msg); + + assertEquals(Phone.State.RINGING, mGSMPhone.getState()); + assertTrue(mGSMPhone.getRingingCall().isRinging()); + assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + + // hangup the background call and accept the ringing call + mGSMPhone.getBackgroundCall().hangup(); + mGSMPhone.acceptCall(); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getRingingCall().getState() != Call.State.IDLE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals("18005551212", + mGSMPhone.getForegroundCall().getConnections().get(0).getAddress()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("16505550105", + mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress()); + + mGSMPhone.handleInCallMmiCommands("17"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState()); + assertEquals("16505550105", + mGSMPhone.getBackgroundCall().getConnections().get(0). + getAddress()); + + mGSMPhone.handleInCallMmiCommands("1"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE); + + assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + mGSMPhone.handleInCallMmiCommands("16"); + + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE); + + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + } + + public void testPostDialSequences() throws Exception { + Message msg; + AsyncResult ar; + Connection cn; + + mGSMPhone.dial("+13125551212,1234;5N8xx"); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(',', msg.arg1); + assertEquals("1234;5N8", cn.getRemainingPostDialString()); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('1', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('2', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('3', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('4', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals(';', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState()); + assertEquals(Connection.PostDialState.WAIT, ar.userObj); + cn.proceedAfterWaitChar(); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('5', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertEquals('N', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WILD, cn.getPostDialState()); + assertEquals(Connection.PostDialState.WILD, ar.userObj); + cn.proceedAfterWildChar(",6;7"); + + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(',', msg.arg1); + assertEquals("6;78", cn.getRemainingPostDialString()); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('6', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals(';', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState()); + assertEquals(Connection.PostDialState.WAIT, ar.userObj); + cn.proceedAfterWaitChar(); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('7', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals('8', msg.arg1); + ar = (AsyncResult) (msg.obj); + assertEquals(Connection.PostDialState.STARTED, ar.userObj); + + // Bogus chars at end should be ignored + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals(0, msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.COMPLETE, + cn.getPostDialState()); + assertEquals(Connection.PostDialState.COMPLETE, ar.userObj); + } + + public void testPostDialCancel() throws Exception { + Message msg; + AsyncResult ar; + Connection cn; + + mGSMPhone.dial("+13125551212,N"); + mRadioControl.progressConnectingToActive(); + + mRadioControl.progressConnectingToActive(); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertNotNull("Message Time Out", msg); + assertEquals(',', msg.arg1); + + msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL); + assertEquals('N', msg.arg1); + ar = (AsyncResult) (msg.obj); + cn = (Connection) (ar.result); + assertEquals(Connection.PostDialState.WILD, cn.getPostDialState()); + cn.cancelPostDial(); + + assertEquals(Connection.PostDialState.CANCELLED, cn.getPostDialState()); + } + + public void testOutgoingCallFail() throws Exception { + Message msg; + /* + * normal clearing + */ + + mRadioControl.setNextCallFailCause(CallFailCause.NORMAL_CLEARING); + mRadioControl.setAutoProgressConnectingCall(false); + + Connection cn = mGSMPhone.dial("+13125551212"); + + mRadioControl.progressConnectingCallState(); + + // I'm just progressing the call state to + // ensure getCurrentCalls() gets processed... + // Normally these failure conditions would happen in DIALING + // not ALERTING + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (cn.getState() == Call.State.DIALING); + + + mRadioControl.triggerHangupAll(); + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + /* + * busy + */ + + mRadioControl.setNextCallFailCause(CallFailCause.USER_BUSY); + mRadioControl.setAutoProgressConnectingCall(false); + + cn = mGSMPhone.dial("+13125551212"); + + mRadioControl.progressConnectingCallState(); + + // I'm just progressing the call state to + // ensure getCurrentCalls() gets processed... + // Normally these failure conditions would happen in DIALING + // not ALERTING + do { + assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE)); + } while (cn.getState() == Call.State.DIALING); + + + mRadioControl.triggerHangupAll(); + msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT); + assertNotNull("Message Time Out", msg); + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Connection.DisconnectCause.BUSY, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, + mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + + /* + * congestion + */ + + mRadioControl.setNextCallFailCause(CallFailCause.NO_CIRCUIT_AVAIL); + mRadioControl.setAutoProgressConnectingCall(false); + + cn = mGSMPhone.dial("+13125551212"); + + mRadioControl.progressConnectingCallState(); + + // I'm just progressing the call state to + // ensure getCurrentCalls() gets processed... + // Normally these failure conditions would happen in DIALING + // not ALERTING + do { + msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); + assertNotNull("Message Time Out", msg); + } while (cn.getState() == Call.State.DIALING); + + + mRadioControl.triggerHangupAll(); + + // Unlike the while loops above, this one waits + // for a "phone state changed" message back to "idle" + do { + msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE); + assertNotNull("Message Time Out", msg); + } while (!(msg.what == EVENT_PHONE_STATE_CHANGED + && mGSMPhone.getState() == Phone.State.IDLE)); + + assertEquals(Phone.State.IDLE, mGSMPhone.getState()); + + assertEquals(Connection.DisconnectCause.CONGESTION, cn.getDisconnectCause()); + + assertEquals(0, mGSMPhone.getRingingCall().getConnections().size()); + assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size()); + assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size()); + + assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState()); + assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState()); + assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState()); + + assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0); + assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime()); + } + + public void testSSNotification() throws Exception { + // MO + runTest(0, SuppServiceNotification.MO_CODE_UNCONDITIONAL_CF_ACTIVE); + runTest(0, SuppServiceNotification.MO_CODE_CALL_IS_WAITING); + runTest(0, SuppServiceNotification.MO_CODE_CALL_DEFLECTED); + + // MT + runTest(1, SuppServiceNotification.MT_CODE_FORWARDED_CALL); + runTest(1, SuppServiceNotification.MT_CODE_CALL_CONNECTED_ECT); + runTest(1, SuppServiceNotification.MT_CODE_ADDITIONAL_CALL_FORWARDED); + } + + private void runTest(int type, int code) { + Message msg; + + mRadioControl.triggerSsn(type, code); + + msg = mGSMTestHandler.waitForMessage(EVENT_SSN); + assertNotNull("Message Time Out", msg); + AsyncResult ar = (AsyncResult) msg.obj; + + assertNull(ar.exception); + + SuppServiceNotification notification = + (SuppServiceNotification) ar.result; + + assertEquals(type, notification.notificationType); + assertEquals(code, notification.code); + } + + public void testUssd() throws Exception { + // Quick hack to work around a race condition in this test: + // We may initiate a USSD MMI before GSMPhone receives its initial + // GSMTestHandler.EVENT_RADIO_OFF_OR_NOT_AVAILABLE event. When the phone sees this + // event, it will cancel the just issued USSD MMI, which we don't + // want. So sleep a little first. + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + // do nothing + } + + verifyNormal(); + verifyCancel(); + varifyNetworkInitiated(); + } + + private void varifyNetworkInitiated() { + Message msg; + AsyncResult ar; + MmiCode mmi; + + // Receive an incoming NOTIFY + mRadioControl.triggerIncomingUssd("0", "NOTIFY message"); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertFalse(mmi.isUssdRequest()); + + // Receive a REQUEST and send response + mRadioControl.triggerIncomingUssd("1", "REQUEST Message"); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertTrue(mmi.isUssdRequest()); + + mGSMPhone.sendUssdResponse("## TEST: TEST_GSMPhone responding..."); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + GsmMmiCode gsmMmi = (GsmMmiCode) mmi; + assertTrue(gsmMmi.isPendingUSSD()); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertNull(ar.exception); + assertFalse(mmi.isUssdRequest()); + + // Receive a REQUEST and cancel + mRadioControl.triggerIncomingUssd("1", "REQUEST Message"); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertTrue(mmi.isUssdRequest()); + + mmi.cancel(); + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertNull(ar.exception); + assertEquals(MmiCode.State.CANCELLED, mmi.getState()); + + List mmiList = mGSMPhone.getPendingMmiCodes(); + assertEquals(0, mmiList.size()); + } + + private void verifyNormal() throws CallStateException { + Message msg; + AsyncResult ar; + MmiCode mmi; + + mGSMPhone.dial("#646#"); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); + assertNotNull("Message Time Out", msg); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + + ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + assertEquals(MmiCode.State.COMPLETE, mmi.getState()); + } + + + private void verifyCancel() throws CallStateException { + /** + * This case makes an assumption that dial() will add the USSD + * to the "pending MMI codes" list before it returns. This seems + * like reasonable semantics. It also assumes that the USSD + * request in question won't complete until we get back to the + * event loop, thus cancel() is safe. + */ + Message msg; + + mGSMPhone.dial("#646#"); + + List<? extends MmiCode> pendingMmis = mGSMPhone.getPendingMmiCodes(); + + assertEquals(1, pendingMmis.size()); + + MmiCode mmi = pendingMmis.get(0); + assertTrue(mmi.isCancelable()); + mmi.cancel(); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); + assertNotNull("Message Time Out", msg); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + + AsyncResult ar = (AsyncResult) msg.obj; + mmi = (MmiCode) ar.result; + + assertEquals(MmiCode.State.CANCELLED, mmi.getState()); + } + + public void testRilHooks() throws Exception { + // + // These test cases all assume the RIL OEM hooks + // just echo back their input + // + + Message msg; + AsyncResult ar; + + // null byte array + + mGSMPhone.invokeOemRilRequestRaw(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertNull(ar.result); + assertNull(ar.exception); + + // empty byte array + + mGSMPhone.invokeOemRilRequestRaw(new byte[0], mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertEquals(0, ((byte[]) (ar.result)).length); + assertNull(ar.exception); + + // byte array with data + + mGSMPhone.invokeOemRilRequestRaw("Hello".getBytes("utf-8"), + mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertEquals("Hello", new String(((byte[]) (ar.result)), "utf-8")); + assertNull(ar.exception); + + // null strings + + mGSMPhone.invokeOemRilRequestStrings(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertNull(ar.result); + assertNull(ar.exception); + + // empty byte array + + mGSMPhone.invokeOemRilRequestStrings(new String[0], + mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertEquals(0, ((String[]) (ar.result)).length); + assertNull(ar.exception); + + // Strings with data + + String s[] = new String[1]; + + s[0] = "Hello"; + + mGSMPhone.invokeOemRilRequestStrings(s, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE)); + + msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE); + assertNotNull("Message Time Out", msg); + + ar = ((AsyncResult) msg.obj); + + assertEquals("Hello", ((String[]) (ar.result))[0]); + assertEquals(1, ((String[]) (ar.result)).length); + assertNull(ar.exception); + } + + public void testMmi() throws Exception { + mRadioControl.setAutoProgressConnectingCall(false); + + // "valid" MMI sequences + runValidMmi("*#67#", false); + runValidMmi("##43*11#", false); + runValidMmi("#33*1234*11#", false); + runValidMmi("*21*6505551234**5#", false); + runValidMmi("**03**1234*4321*4321#", false); + // pound string + runValidMmi("5308234092307540923#", true); + // short code + runValidMmi("22", true); + // as part of call setup + runValidMmiWithConnect("*31#6505551234"); + + // invalid MMI sequences + runNotMmi("6505551234"); + runNotMmi("1234#*12#34566654"); + runNotMmi("*#*#12#*"); + } + + private void runValidMmi(String dialString, boolean cancelable) throws CallStateException { + Connection c = mGSMPhone.dial(dialString); + assertNull(c); + Message msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE); + assertNotNull("Message Time Out", msg); + // Should not be cancelable. + AsyncResult ar = (AsyncResult) msg.obj; + MmiCode mmi = (MmiCode) ar.result; + assertEquals(cancelable, mmi.isCancelable()); + + msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE); + assertNotNull("Message Time Out", msg); + } + + private void runValidMmiWithConnect(String dialString) throws CallStateException { + mRadioControl.pauseResponses(); + + Connection c = mGSMPhone.dial(dialString); + assertNotNull(c); + + hangup(c); + } + + private void hangup(Connection cn) throws CallStateException { + cn.hangup(); + + mRadioControl.resumeResponses(); + assertNotNull(mGSMTestHandler.waitForMessage(EVENT_DISCONNECT)); + + } + + private void runNotMmi(String dialString) throws CallStateException { + mRadioControl.pauseResponses(); + + Connection c = mGSMPhone.dial(dialString); + assertNotNull(c); + + hangup(c); + } +} diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java new file mode 100644 index 0000000..fb8a5d9 --- /dev/null +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/GSMTestHandler.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.gsm; + +import android.content.Context; + +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.util.Log; + +import com.android.internal.telephony.gsm.GSMPhone; +import com.android.internal.telephony.test.SimulatedCommands; +import com.android.internal.telephony.TestPhoneNotifier; + +/** + * This class creates a HandlerThread which waits for the various messages. + */ +public class GSMTestHandler extends HandlerThread implements Handler.Callback { + + private Handler mHandler; + private Message mCurrentMessage; + + private Boolean mMsgConsumed; + private SimulatedCommands sc; + private GSMPhone mGSMPhone; + private Context mContext; + + private static final int FAIL_TIMEOUT_MILLIS = 5 * 1000; + + public GSMTestHandler(Context context) { + super("GSMPhoneTest"); + mMsgConsumed = false; + mContext = context; + } + + @Override + protected void onLooperPrepared() { + sc = new SimulatedCommands(); + mGSMPhone = new GSMPhone(mContext, sc, new TestPhoneNotifier(), true); + mHandler = new Handler(getLooper(), this); + synchronized (this) { + notifyAll(); + } + } + + public boolean handleMessage(Message msg) { + synchronized (this) { + mCurrentMessage = msg; + this.notifyAll(); + while(!mMsgConsumed) { + try { + this.wait(); + } catch (InterruptedException e) {} + } + mMsgConsumed = false; + } + return true; + } + + + public void cleanup() { + Looper looper = getLooper(); + if (looper != null) looper.quit(); + mHandler = null; + } + + public Handler getHandler() { + return mHandler; + } + + public SimulatedCommands getSimulatedCommands() { + return sc; + } + + public GSMPhone getGSMPhone() { + return mGSMPhone; + } + + public Message waitForMessage(int code) { + Message msg; + while(true) { + msg = null; + synchronized (this) { + try { + this.wait(FAIL_TIMEOUT_MILLIS); + } catch (InterruptedException e) { + } + + // Check if timeout has occurred. + if (mCurrentMessage != null) { + // Consume the message + msg = Message.obtain(); + msg.copyFrom(mCurrentMessage); + mCurrentMessage = null; + mMsgConsumed = true; + this.notifyAll(); + } + } + if (msg == null || code == GSMPhoneTest.ANY_MESSAGE || msg.what == code) return msg; + } + } +} diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java b/telephony/tests/telephonytests/src/com/android/telephonytest/unit/CallerInfoUnitTest.java index 0f24f15..0f24f15 100644 --- a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java +++ b/telephony/tests/telephonytests/src/com/android/telephonytest/unit/CallerInfoUnitTest.java diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java b/telephony/tests/telephonytests/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java index 2d3c548..2d3c548 100644 --- a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java +++ b/telephony/tests/telephonytests/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java |